LWNode_Release_220330_14df3e4 25/273025/1 accepted/tizen/unified/20220331.010041 submit/tizen/20220330.010734 submit/tizen/20220330.012552
authorRyan Hyun Choi <ryan.choi@samsung.com>
Wed, 30 Mar 2022 01:00:09 +0000 (10:00 +0900)
committerRyan Hyun Choi <ryan.choi@samsung.com>
Wed, 30 Mar 2022 01:00:39 +0000 (10:00 +0900)
Change-Id: I09267aa10e47d87950f18a1eb670dff8230b682e
Signed-off-by: Ryan Choi <ryan.choi@samsung.com>
438 files changed:
.gitignore
COPYRIGHT [new file with mode: 0644]
GOVERNANCE.md [new file with mode: 0644]
README.md
common.gypi
configure.py
deps/openssl/openssl/external/perl/Text-Template-1.46/COPYING [deleted file]
deps/uv/include/uv.h
deps/uv/src/unix/core.c
docs/Doxyfile [new file with mode: 0644]
docs/README_Tizen.md [new file with mode: 0644]
docs/css/doxygen-awesome-css/Doxyfile [new file with mode: 0644]
docs/css/doxygen-awesome-css/LICENSE [new file with mode: 0644]
docs/css/doxygen-awesome-css/README.md [new file with mode: 0644]
docs/css/doxygen-awesome-css/docs/doxygen-custom/custom.css [new file with mode: 0644]
docs/css/doxygen-awesome-css/docs/doxygen-custom/footer.html [new file with mode: 0644]
docs/css/doxygen-awesome-css/docs/doxygen-custom/header.html [new file with mode: 0644]
docs/css/doxygen-awesome-css/docs/page.dox [new file with mode: 0644]
docs/css/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js [new file with mode: 0644]
docs/css/doxygen-awesome-css/doxygen-awesome-sidebar-only-darkmode-toggle.css [new file with mode: 0644]
docs/css/doxygen-awesome-css/doxygen-awesome-sidebar-only.css [new file with mode: 0644]
docs/css/doxygen-awesome-css/doxygen-awesome.css [new file with mode: 0644]
docs/css/doxygen-awesome-css/img/screenshot.png [new file with mode: 0644]
docs/css/doxygen-awesome-css/img/theme-variations.drawio.svg [new file with mode: 0644]
docs/css/doxygen-awesome-css/include/MyLibrary/example.hpp [new file with mode: 0644]
docs/css/doxygen-awesome-css/include/MyLibrary/subclass-example.hpp [new file with mode: 0644]
docs/css/doxygen-awesome-css/logo.drawio.svg [new file with mode: 0644]
docs/internal-api.md [new file with mode: 0644]
docs/spec.md [new file with mode: 0644]
lib/assert.js
lib/buffer.js
lib/internal/bootstrap/loaders.js
lib/internal/lwnode/setup.js
lwnode/build-cctest.sh
lwnode/build-modules.sh [new file with mode: 0755]
lwnode/build-sample.sh
lwnode/code/escargotshim/common.gypi
lwnode/code/escargotshim/deps/escargot/build/config.cmake
lwnode/code/escargotshim/deps/escargot/build/escargot.cmake
lwnode/code/escargotshim/deps/escargot/src/Escargot.h
lwnode/code/escargotshim/deps/escargot/src/api/EscargotPublic.cpp
lwnode/code/escargotshim/deps/escargot/src/api/EscargotPublic.h
lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinArray.cpp
lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinAsyncFunction.cpp
lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinAsyncGeneratorFunction.cpp
lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinAtomics.cpp
lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinBigInt.cpp
lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinFunction.cpp
lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinGeneratorFunction.cpp
lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinIntl.cpp
lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinJSON.cpp
lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinNumber.cpp
lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinRegExp.cpp
lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinSharedArrayBuffer.cpp
lwnode/code/escargotshim/deps/escargot/src/builtins/BuiltinString.cpp
lwnode/code/escargotshim/deps/escargot/src/debugger/Debugger.cpp
lwnode/code/escargotshim/deps/escargot/src/debugger/Debugger.h
lwnode/code/escargotshim/deps/escargot/src/debugger/DebuggerTcp.cpp
lwnode/code/escargotshim/deps/escargot/src/debugger/DebuggerTcp.h
lwnode/code/escargotshim/deps/escargot/src/heap/CustomAllocator.cpp
lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCode.cpp
lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCode.h
lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeGenerator.cpp
lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeGenerator.h
lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeInterpreter.cpp
lwnode/code/escargotshim/deps/escargot/src/interpreter/ByteCodeInterpreter.h
lwnode/code/escargotshim/deps/escargot/src/intl/Intl.cpp
lwnode/code/escargotshim/deps/escargot/src/intl/IntlDateTimeFormat.cpp
lwnode/code/escargotshim/deps/escargot/src/intl/IntlDisplayNames.cpp
lwnode/code/escargotshim/deps/escargot/src/intl/IntlDisplayNames.h
lwnode/code/escargotshim/deps/escargot/src/intl/IntlListFormat.cpp
lwnode/code/escargotshim/deps/escargot/src/intl/IntlListFormat.h
lwnode/code/escargotshim/deps/escargot/src/intl/IntlNumberFormat.cpp
lwnode/code/escargotshim/deps/escargot/src/intl/IntlNumberFormat.h
lwnode/code/escargotshim/deps/escargot/src/intl/IntlPluralRules.cpp
lwnode/code/escargotshim/deps/escargot/src/intl/IntlPluralRules.h
lwnode/code/escargotshim/deps/escargot/src/intl/IntlRelativeTimeFormat.cpp
lwnode/code/escargotshim/deps/escargot/src/intl/IntlRelativeTimeFormat.h
lwnode/code/escargotshim/deps/escargot/src/parser/CodeBlock.cpp
lwnode/code/escargotshim/deps/escargot/src/parser/CodeBlock.h
lwnode/code/escargotshim/deps/escargot/src/parser/Lexer.cpp
lwnode/code/escargotshim/deps/escargot/src/parser/Lexer.h
lwnode/code/escargotshim/deps/escargot/src/parser/ParserStringView.h
lwnode/code/escargotshim/deps/escargot/src/parser/Script.cpp
lwnode/code/escargotshim/deps/escargot/src/parser/Script.h
lwnode/code/escargotshim/deps/escargot/src/parser/ScriptParser.cpp
lwnode/code/escargotshim/deps/escargot/src/parser/ast/ArrowFunctionExpressionNode.h
lwnode/code/escargotshim/deps/escargot/src/parser/ast/CallExpressionNode.h
lwnode/code/escargotshim/deps/escargot/src/parser/ast/ClassBodyNode.h
lwnode/code/escargotshim/deps/escargot/src/parser/ast/ForStatementNode.h
lwnode/code/escargotshim/deps/escargot/src/parser/ast/FunctionExpressionNode.h
lwnode/code/escargotshim/deps/escargot/src/parser/ast/ObjectExpressionNode.h
lwnode/code/escargotshim/deps/escargot/src/parser/ast/ProgramNode.h
lwnode/code/escargotshim/deps/escargot/src/parser/ast/ReturnStatementNode.h
lwnode/code/escargotshim/deps/escargot/src/parser/ast/ThisExpressionNode.h
lwnode/code/escargotshim/deps/escargot/src/parser/esprima_cpp/esprima.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/ArgumentsObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/ArgumentsObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ArrayBuffer.cpp [deleted file]
lwnode/code/escargotshim/deps/escargot/src/runtime/ArrayBuffer.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ArrayBufferObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/ArrayBufferObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ArrayObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/ArrayObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/AtomicString.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/AtomicString.h
lwnode/code/escargotshim/deps/escargot/src/runtime/BackingStore.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/BackingStore.h
lwnode/code/escargotshim/deps/escargot/src/runtime/BigIntObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/BigIntObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/BooleanObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/BooleanObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/CompressibleString.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/CompressibleString.h
lwnode/code/escargotshim/deps/escargot/src/runtime/Context.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/Context.h
lwnode/code/escargotshim/deps/escargot/src/runtime/DateObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/EncodedValue.h
lwnode/code/escargotshim/deps/escargot/src/runtime/EnumerateObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/EnumerateObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/EnvironmentRecord.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/EnvironmentRecord.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ErrorObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ExecutionPauser.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/ExecutionState.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/ExecutionState.h
lwnode/code/escargotshim/deps/escargot/src/runtime/FunctionObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/FunctionObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/FunctionObjectInlines.h
lwnode/code/escargotshim/deps/escargot/src/runtime/FunctionTemplate.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/Global.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/GlobalObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/GlobalObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/GlobalObjectProxyObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ModuleNamespaceObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/NativeFunctionObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/Object.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/Object.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ObjectStructure.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/ObjectStructure.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ObjectTemplate.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/ObjectTemplate.h
lwnode/code/escargotshim/deps/escargot/src/runtime/Platform.h
lwnode/code/escargotshim/deps/escargot/src/runtime/PointerValue.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/PointerValue.h
lwnode/code/escargotshim/deps/escargot/src/runtime/PromiseObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/PromiseObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ProxyObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/RegExpObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/RegExpObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ReloadableString.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/ReloadableString.h
lwnode/code/escargotshim/deps/escargot/src/runtime/RopeString.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/RopeString.h
lwnode/code/escargotshim/deps/escargot/src/runtime/SandBox.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/SandBox.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ScriptArrowFunctionObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ScriptAsyncFunctionObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/ScriptAsyncGeneratorFunctionObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ScriptClassMethodFunctionObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ScriptFunctionObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/ScriptFunctionObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ScriptGeneratorFunctionObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ScriptSimpleFunctionObject.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/src/runtime/ScriptVirtualArrowFunctionObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/SharedArrayBufferObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/SharedArrayBufferObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/StaticStrings.h
lwnode/code/escargotshim/deps/escargot/src/runtime/String.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/String.h
lwnode/code/escargotshim/deps/escargot/src/runtime/StringBuilder.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/StringObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/StringObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/StringView.h
lwnode/code/escargotshim/deps/escargot/src/runtime/Template.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/ToStringRecursionPreventer.h
lwnode/code/escargotshim/deps/escargot/src/runtime/TypedArrayObject.h
lwnode/code/escargotshim/deps/escargot/src/runtime/VMInstance.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/VMInstance.h
lwnode/code/escargotshim/deps/escargot/src/runtime/Value.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/Value.h
lwnode/code/escargotshim/deps/escargot/src/runtime/ValueInlines.h
lwnode/code/escargotshim/deps/escargot/src/shell/Shell.cpp
lwnode/code/escargotshim/deps/escargot/src/util/SpinLock.h
lwnode/code/escargotshim/deps/escargot/src/util/TightVector.h
lwnode/code/escargotshim/deps/escargot/src/util/Util.cpp
lwnode/code/escargotshim/deps/escargot/src/wasm/ExportedFunctionObject.cpp
lwnode/code/escargotshim/deps/escargot/third_party/GCutil/windows/GCutil/config.h [deleted file]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/CMakeLists.txt
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/CMakeLists.txt
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/README.md
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/apply-names.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/base-types.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-ir.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-logging.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-logging.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-nop.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-objdump.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-objdump.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-opcnt.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-opcnt.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer-spec.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/c-writer.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/common.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/common.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/config.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-ast.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-ls.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-naming.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/error-formatter.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/expr-visitor.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.def
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/generate-names.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/binary-reader-interp.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/binary-reader-interp.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-inl.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-math.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-util.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-util.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasi.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasm-c-api.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/istream.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/istream.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/intrusive-list.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir-util.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir-util.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-keywords.txt
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/literal.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode-code-table.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.def
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/option-parser.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/prebuilt/lexer-keywords.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/resolve-names.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/shared-validator.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/shared-validator.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/stream.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/string-format.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/string-view.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/string-view.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-binary-reader.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-interp.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-literal.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-option-parser.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/token.def
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/spectest-interp.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-decompile.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-interp.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-objdump.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-opcodecnt.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-strip.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-validate.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2c.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2wat.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wast2json.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wat-desugar.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wat2wasm.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type-checker.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type-checker.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/utf8.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/validator.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/validator.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-parser.cc
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-parser.h
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wat-writer.cc
lwnode/code/escargotshim/deps/escargot/tools/check_tidy.py [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger.py [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger_core.py [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger_tcp.py [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger_tester.sh [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger_websocket.py [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/client_source_multiple.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/client_source_multiple.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_backtrace.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_backtrace.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_async.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_async.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_async_generator.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_async_generator.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_class.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_class.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_generator.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_generator.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_no_arg.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_no_arg.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_promise_then.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_promise_then.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_continue.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_continue.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_delete_pending.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_delete_pending.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_exception.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_exception.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_finish.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_finish.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_list.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_list.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_object.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_object.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_functions.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_functions.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_lines.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_lines.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_unavailable.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_unavailable.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_print.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_print.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_quit.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_quit.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_statements.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_statements.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step2.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step2.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step_class.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step_class.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step_class2.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step_class2.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_syntax_error.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_syntax_error.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_variables.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_variables.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_variables2.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_variables2.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_한글문자.cmd [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_한글문자.expected [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/gen_unicode.py [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/genereate_unicode_pattern_tables.sh [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/kangax/escargot.patch [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/kangax/run-kangax.py [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/run-tests.py [deleted file]
lwnode/code/escargotshim/deps/escargot/tools/visualize_heap_usage.py [deleted file]
lwnode/code/escargotshim/deps/node-bindings/include/node_bindings.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/node-bindings/node_bindings.gyp [new file with mode: 0644]
lwnode/code/escargotshim/deps/node-bindings/src/gmainloop_node_bindings.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/tizen-device-api/src/Extension.cpp [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/Extension.h [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/ExtensionAdapter.cpp [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/ExtensionAdapter.h [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/ExtensionManager.cpp [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/ExtensionManager.h [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/TizenDeviceAPILoaderForEscargot.cpp [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/TizenDeviceAPILoaderForEscargot.h [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension.h [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_Data.h [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_EntryPoints.h [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_Permissions.h [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_Runtime.h [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_SyncMessage.h [deleted file]
lwnode/code/escargotshim/deps/tizen-device-api/src/wrt-common-native-plugin.h [deleted file]
lwnode/code/escargotshim/escargot.gyp
lwnode/code/escargotshim/escargotshim.gyp
lwnode/code/escargotshim/include/lwnode/lwnode.h
lwnode/code/escargotshim/src/api-data.cc
lwnode/code/escargotshim/src/api-environment.cc
lwnode/code/escargotshim/src/api-exception.cc
lwnode/code/escargotshim/src/api-experimental-serialization.cc [new file with mode: 0644]
lwnode/code/escargotshim/src/api-handles.cc
lwnode/code/escargotshim/src/api-scripts.cc
lwnode/code/escargotshim/src/api-serialization.cc
lwnode/code/escargotshim/src/api-template.cc
lwnode/code/escargotshim/src/api.cc
lwnode/code/escargotshim/src/api.h
lwnode/code/escargotshim/src/api/context.cc
lwnode/code/escargotshim/src/api/context.h
lwnode/code/escargotshim/src/api/engine.cc
lwnode/code/escargotshim/src/api/engine.h
lwnode/code/escargotshim/src/api/error-message-template.h [new file with mode: 0644]
lwnode/code/escargotshim/src/api/error-message.cc [new file with mode: 0644]
lwnode/code/escargotshim/src/api/error-message.h [new file with mode: 0644]
lwnode/code/escargotshim/src/api/es-helper.cc
lwnode/code/escargotshim/src/api/es-helper.h
lwnode/code/escargotshim/src/api/extra-data.cc
lwnode/code/escargotshim/src/api/extra-data.h
lwnode/code/escargotshim/src/api/global-handles.cc
lwnode/code/escargotshim/src/api/global-handles.h
lwnode/code/escargotshim/src/api/global.cc [new file with mode: 0644]
lwnode/code/escargotshim/src/api/global.h [new file with mode: 0644]
lwnode/code/escargotshim/src/api/handle.cc
lwnode/code/escargotshim/src/api/handlescope.cc
lwnode/code/escargotshim/src/api/isolate.cc
lwnode/code/escargotshim/src/api/isolate.h
lwnode/code/escargotshim/src/api/serializer.cc [new file with mode: 0644]
lwnode/code/escargotshim/src/api/serializer.h [new file with mode: 0644]
lwnode/code/escargotshim/src/api/stack-trace.cc
lwnode/code/escargotshim/src/api/stack-trace.h
lwnode/code/escargotshim/src/api/utils/debug.cc
lwnode/code/escargotshim/src/api/utils/debug.h
lwnode/code/escargotshim/src/api/utils/gc.cc
lwnode/code/escargotshim/src/api/utils/gc.h
lwnode/code/escargotshim/src/api/utils/logger/color.h [new file with mode: 0644]
lwnode/code/escargotshim/src/api/utils/logger/flags.cc
lwnode/code/escargotshim/src/api/utils/logger/flags.h
lwnode/code/escargotshim/src/api/utils/logger/logger-impl.cc [new file with mode: 0644]
lwnode/code/escargotshim/src/api/utils/logger/logger-impl.h [new file with mode: 0644]
lwnode/code/escargotshim/src/api/utils/logger/logger-util.cc [new file with mode: 0644]
lwnode/code/escargotshim/src/api/utils/logger/logger-util.h [new file with mode: 0644]
lwnode/code/escargotshim/src/api/utils/logger/logger.cc [deleted file]
lwnode/code/escargotshim/src/api/utils/logger/logger.h
lwnode/code/escargotshim/src/api/utils/logger/trace.h
lwnode/code/escargotshim/src/api/utils/misc.h
lwnode/code/escargotshim/src/api/utils/string-util.cc
lwnode/code/escargotshim/src/api/utils/string-util.h
lwnode/code/escargotshim/src/base.cc [new file with mode: 0644]
lwnode/code/escargotshim/src/base.h
lwnode/code/escargotshim/src/lwnode/lwnode-loader.cc
lwnode/code/escargotshim/src/lwnode/lwnode.cc
lwnode/code/tizen/src/node_bindings.cc [deleted file]
lwnode/code/tizen/src/node_bindings.h [deleted file]
lwnode/test.sh [new file with mode: 0755]
packaging/lwnode.spec
src/js_native_api_types.h
src/node.cc
src/node_main_instance.cc
src/node_main_instance.h
src/node_main_lw_runner-inl.h [new file with mode: 0644]
src/node_native_module.cc
src/node_native_module_lwnode-inl.h
tools/eslint-rules/documented-errors.js
tools/eslint-rules/errors.md [new file with mode: 0644]
tools/test.py

index a237d3835aadbe47431f62c8d8c0a37867263622..382a9aa076fb1fedf303fc5d53801b7e529adb6a 100644 (file)
@@ -143,6 +143,9 @@ __pycache__
 .DS_Store
 *~
 
+# === Rules for tools ===
+*.code-workspace
+
 # === lwnode ===
 .circleci/gbs.conf
 kuep_net_signer.sh
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644 (file)
index 0000000..c17c56c
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,12 @@
+Copyright (c) 2022 Samsung Inner Source, Lightweight node.js. All Rights Reserved.
+
+# Code owners
+Code owners in alphabetical order.
+
+```
+Ryan Hyun Choi <ryan.choi@samsung.com>
+Daeyeon Jeong <daeyeon.jeong@samsung.com>
+Haesik Jun <haesik.jun@samsung.com>
+Ho Sung Kim <hs852.kim@samsung.com>
+```
+
diff --git a/GOVERNANCE.md b/GOVERNANCE.md
new file mode 100644 (file)
index 0000000..499c8a1
--- /dev/null
@@ -0,0 +1,102 @@
+# Samsung Inner Source Governance
+
+The *Samsung Inner Source Governance*(the "Governance") sets forth the responsibilities and procedures for technical contribution to, and oversight of, the *Samsung Inner Source Community*(the "Community") within Samsung Electronics. Contributors to the Community **MUST** comply with the terms of the governance as well as any applicable policies of Samsung Electronics.
+
+All the Communities under the *Samsung Inner Source Program*  **MUST** inherit this Governance and each Community is allowed to create its own Community Rule but only as a type of ADDON tailoring. Additionally which **SHOULD** be announced each project wiki page with a title named 'Community Rules' and should be described in [Project List] page  of your project in this portal.
+
+## 1. Guideline for Operation
+Samsung Inner Source Program uses an **OPEN ENVIRONMENT** which the CODE(Github enterprise version) as a source forge.
+The baseline of Inner Source Program repository is **PUBLIC**. If you have any specific reason to make it PRIVATE, you SHOULD make a request via Inner Source Portal. However the request COULD not be accepted if it doesn't have obvious reasons.
+
+## 2. Roles and Responsibilities
+The Samsung Inner Source Community Recognizes the following formal roles: a Developer,  a Committer and a Maintainer.
+Informally, the Community may organize itself and give rights and responsibilities to the necessary people to achieve its goals.
+
+1. A Developer
+
+   A Developer is anyone who wishes to contribute to the project, at any level. Developers are granted the following right to:
+   - Contribute code, documentation, translations, artwork, etc,.
+   - Report defects(bugs) and suggestions for enhancements;
+   - Participate in the process of reviewing contributions by others;
+   - Initiate and participate in discussions in communication channels.
+
+   Developers are required to:
+   - Abide by decisions,  once made. They are welcome to provide new, relevant information to reopen decisions;
+   - Assume responsibility for issues and bugs introduced by one's own contributions;
+   - Respect the 'Rules of Community'(see below);
+   - Provide constructive advices whenever participating in discussions and in the review of contributions.
+
+2. A Committer
+
+   A Committer is a Developer who is also responsible for the maintenance of a particular area of code or of a source code repository. Committers have the following rights and responsibilities, in addition to those listed for Developers:
+   - Right to set goals for the short and medium terms for the repository being maintained;
+   - Responsibility to ensure all contributions to the repository have been reviewed within reasonable time;
+   - Responsibility to monitor discussions in the Community.
+
+3. A Maintainer
+
+   A Maintainer is a Developer who is also responsible for knowing, directing and anticipating the needs of  a given repository. Maintainers have the following rights and responsibilities, in addition to those listed for Committers:
+   - Right to set the overall organization of the source code in the repository;
+   - Right and responsibility to lead the feature development discussion;
+   - Responsibility to ensure the quality of the code to expected levels;
+   - Responsibility to participate in the quality verification and release process, when those happen.
+   - Responsibility of a **representative of the Community**;
+   - Maximum 2 Maintainers are allowed per Community.
+
+   A Maintainer is not a mandatory role of Samsung Inner Source Governance. When the Community decide to go without the role title of a Maintainers, one of the Committer of the Community SHOULD take the written roles and responsibilities  of a Maintainer in Samsung Inner Source Governance.
+
+4. A Benevolent-Leader
+
+   A Benevolent-Leader is a member of the Community who has the final saying in the case of disputes. This is a model followed by many successful Open Source projects, and they are sometimes called the "benevolent dictator". The Benevolent-Leader has the following responsibilities:
+   - Govern Samsung Inner Source Program;
+   - Make calm controversy in Communities and a Program itself.
+
+   A Benevolent-Leader refers to the role, not a person.
+
+5. An Administrator
+
+   An Administrator is a member who help operate and gear to healthy Samsung Inner Source Program. Samsung Inner Source Portal is operated by the Administrator.
+
+6. Selection of Committers and Maintainers
+
+   A candidate for the Committer role should be one of the Developers who has submitted at least 10 non-trivial patches in that repository and has shown characteristics consistent with the requirements of the Committer role. To be a candidate for the Committer or the Maintainer, a Developer can self-nominate with proper evidences.
+
+   The selection process SHOULD be archived by consensus of the Developers active, Committers and Maintainers in that repository. If consensus cannot be achieved, the Benevolent-Leader will make the decision and all decisions MUST be ratified by the Benevolent-Leader.
+
+7. Revocation of Committers/Maintainers status
+
+   A Maintainer or a Committer who intentionally abuses his review privilege may have it temporarily suspended on the request of other Committers or Maintainers. Committers and Maintainers not including the person under consideration should discuss on the revocation of the person. If consensus cannot be reached, the Benevolent-Leader will make the decision and all decisions MUST be ratified by the Benevolent-Leader.
+
+## 3. Rules of Community
+
+1. Samsung Inner Source Program aims for OPEN COLLABORATION.
+
+   1) Egalitarian, Every contributors who is willing to help a project should be welcome.
+   2) Contributions to projects should be judged meritocracy based on the value they bring to the project. For transparency, all the merits SHOULD be come with **OPEN COMMUNICATION** (decisions should be discussed publicly).
+   3) A Community is an individual organizational unit.
+
+   All Community members must abide by rules of common sense, civility and good neighborliness. Frank discussion is welcomed and encouraged with the goal of arriving at the best technical solution possible. Discussion about the people participating in development is not welcomed and ad hominem attacks MUST not be tolerated.
+
+2. All Community members must adhere to these simple rules:
+
+   1) Respect and acknowledge all contributions, suggestions and comments from the Community;
+   2) Listen and be open to all opinions, which are subject to open discussion;
+   3) Help each other and the other developers;
+   4) Assume people mean well;
+   5) **Be humble and bold**.
+
+3. Lazy Consensus and Silent Consent
+
+   1) Lazy Consensus means that developers may proceed with work when they have a reason to believe that other Developers in the Community will agree with the direction, and need not stop to initiate unnecessary discussions about the work. In this case, they should publish their work rapidly (that is, merge proposals to version control) to allow others to raise objections when there are any. When the developer is not sure there will be consensus, they should raise a proposal on the appropriate communication channels. The Silent Consent principle will apply in this case.
+   2) Silent Consent means that those who do not offer a reasoned alternative in course of the discussion implicitly agree with the proposal.
+   3) These principles are valid for **OPEN DISCUSSIONS** in the Github Issues and/or the Primary Communication Channel of the Community. Consensus reached in other ways (such as face-to face discussions or communication on other channels) are to be considered unapproved proposals until submitted to the relevant Github Issues and/or the Primary Communication Channel of the Community. Thus giving dissenting options the opportunity to be voiced.
+
+4. Decision Making in the Samsung Inner Source Community
+
+   1) Decisions are made always at the lowest level possible that is applicable for the decision in a question.
+   2) Individual Developers are making decisions every time they submit changes.
+   3) two or more Developers also make decisions when participating in an **OPEN DISCUSSION**. Their arguments in why a given decision should be made are part of the consensus that needs to be reached for the decision. Any of opinions **SHOULD NOT** be disregarded.
+   4) If those Developers cannot agree and reach consensus on a decision, then the Benevolent-Leader WOULD mediates the situation, avoiding stalemates. Arbitration COULD made by voting of relevant Community members on the issue.
+      - Decisions affecting a project are made by community members of the project.
+      - Decisions that overlap more than one project are made in conjunction by community members of related projects.
+
index ea36b20b6ea46d4df8f9c340ea39e97a45be0177..60036961ea96627ce8756749b5d5fd040f872658 100644 (file)
--- a/README.md
+++ b/README.md
@@ -5,6 +5,8 @@ which runs on top of [Escargot](https://github.com/Samsung/escargot),
 a memory optimized JavaScript Engine developed by Samsung Research,
 instead of the default V8 JS engine.
 
+Memory usage and binary footprint are reported [here](https://pages.github.sec.samsung.net/lws/lwnode-test-results).
+
 ## Supported Platforms
 * Ubuntu 18.04, 16.04
 * Tizen 4.0 and above
@@ -52,3 +54,7 @@ Install `lwnode-devel.rpm` to get the `lwnode` executable.
 
 ## Maintainers
 A list of maintainers can be found in [MAINTAINERS.md](MAINTAINERS.md).
+
+## Governance
+See [GOVERNANCE.md](GOVERNANCE.md)
+
index a9496c79a669b6cc63d1dd448eeab94f9612bcb8..24c09ccddab509fd26e72623f4b8d737ecefc9df 100644 (file)
           '-fno-omit-frame-pointer',
           '-fsanitize=address',
           '-fsanitize-address-use-after-scope',
+          '-Wno-maybe-uninitialized',
         ],
         'defines': [ 'LEAK_SANITIZER', 'V8_USE_ADDRESS_SANITIZER' ],
         'cflags!': [ '-fomit-frame-pointer' ],
index 34800a37984a16b0fc7c07f022a75fac36a3bfe0..a4f11c0b4ddf1530c43552a42effd00b38f50bc6 100755 (executable)
@@ -114,6 +114,11 @@ lwnode_optgroup.add_option('--escargot-threading',
     dest='escargot_threading',
     help='Enable Escargot threading')
 
+lwnode_optgroup.add_option('--escargot-debugger',
+    action='store_true',
+    dest='escargot_debugger',
+    help='Enable Escargot debugging')
+
 parser.add_option_group(lwnode_optgroup)
 
 def get_lwnode_gyp_options():
@@ -158,6 +163,10 @@ def get_lwnode_gyp_options():
   else:
     args += (['-Descargot_threading=0'])
 
+  if options.escargot_debugger:
+    args += (['-Descargot_debugger=1'])
+  else:
+    args += (['-Descargot_debugger=0'])
 
   args += ['-Dnode_core_target_name=lwnode']
   args += ['-Dnode_lib_target_name=liblwnode']
diff --git a/deps/openssl/openssl/external/perl/Text-Template-1.46/COPYING b/deps/openssl/openssl/external/perl/Text-Template-1.46/COPYING
deleted file mode 100644 (file)
index a3f6b12..0000000
+++ /dev/null
@@ -1,340 +0,0 @@
-                   GNU GENERAL PUBLIC LICENSE
-                      Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-                          59 Temple Place - Suite 330, Boston, MA
-                          02111-1307, USA.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                           Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-\f
-                   GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-\f
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-\f
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-\f
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-                           NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-                    END OF TERMS AND CONDITIONS
-\f
-       Appendix: How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) 19yy  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) 19yy name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
-Public License instead of this License.
index 2557961eedba7f8ab5d5a058859613910e3bb382..5f5f38f2465fb79839945a611c556477f11bc86a 100644 (file)
@@ -1797,6 +1797,9 @@ struct uv_loop_s {
 UV_EXTERN void* uv_loop_get_data(const uv_loop_t*);
 UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data);
 
+// @lwnode
+UV_EXTERN int uv_watcher_queue_empty(uv_loop_t* loop);
+
 /* Don't export the private CPP symbols. */
 #undef UV_HANDLE_TYPE_PRIVATE
 #undef UV_REQ_TYPE_PRIVATE
index 1597828c868b383439f7442a3f22eee5d6ac539d..844f1993040f35f9fd3d067954f0cd8eea0ce529 100644 (file)
@@ -1571,7 +1571,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
     buf[*buflen] = '\0';
 
     return 0;
-  } 
+  }
 
   /* Case iii). Search PATH environment variable */
   cloned_path = NULL;
@@ -1611,3 +1611,8 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
   /* Out of tokens (path entries), and no match found */
   return UV_EINVAL;
 }
+
+// @lwnode
+int uv_watcher_queue_empty(uv_loop_t* loop) {
+  return QUEUE_EMPTY(&loop->watcher_queue);
+}
diff --git a/docs/Doxyfile b/docs/Doxyfile
new file mode 100644 (file)
index 0000000..496c428
--- /dev/null
@@ -0,0 +1,2494 @@
+# Doxyfile 1.8.13
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = lwnode
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = 0.1
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = ./docs/api
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = YES
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = YES
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = lwnode/code/escargotshim/src lwnode/code/escargotshim/include
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.pyw \
+                         *.f90 \
+                         *.f95 \
+                         *.f03 \
+                         *.f08 \
+                         *.f \
+                         *.for \
+                         *.tcl \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  = docs/css/doxygen-awesome-css/doxygen-awesome.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = YES
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 350
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = YES
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = svg
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = YES
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               = /usr/bin/dot
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/docs/README_Tizen.md b/docs/README_Tizen.md
new file mode 100644 (file)
index 0000000..eb93e54
--- /dev/null
@@ -0,0 +1,36 @@
+# Introduction
+The development of node.js has created a platform-independent JavaScript runtime environment, where Web developers can run their JavaScript code outside a Web browser. Benefits of using node.js for a Web app developer when creating Web apps includes, but not limited to, reusing already known Web development knowledge, using only JavaScript on both server and client sides, and so on. While node.js provides the state-of-the-art performance and a wide range of supporting libraries, it is not suitable for memory-constrained devices such as TVs, and consumer electronics. This is because node.js is designed to provide better performance by efficiently using a large amount of memory. This goal of node.js conflicts with the goal of optimizing memory usage on these devices in memory-constrained environments. Adopting node.js to these memory-constrained devices is challenging, because the design and implementation of node.js conflict with the physically small amount of memory shipped with these devices.
+
+In this document, we introduce lightweight node.js (LWNode) whose aim is to provide a JavaScript runtime environment for memory-constrained devices. Some advantages of LWNode are as follows:
+
+* LWNode is a memory-optimized node.js for Tizen-based memory-constrained devices such as TVs. Compared to stock node.js, LWNode consumes 30% less amount of memory on TV.
+* Supports a wide range of node.js modules
+
+LWNode is already shipped to the following Samsung products.
+
+* Provides a runtime environment for Spotify on TV
+
+# Expected Values
+LWNode can easily provide a JavaScript runtime environment in a memory-efficient way. In particular, LWNode
+
+* Provides a Tizen-optimized, and memory-efficient JavaScript runtime environment
+* Provides a set of Tizen-specific Web Device APIs
+
+# Requirements
+LWNode is designed to meet the following requirements.
+
+* Functional requirements
+  - Supports Spotify on TV
+  - Supports a set of node.js modules defined in Appendix 1
+  - Supports a set of Tizen Web Device APIs
+* Non-functional requirements
+  - Customizable for various business requirements and target devices
+  - Low memory usage and small memory footprints
+
+# Target Applications
+LWNode supports the following devices.
+
+* Tizen-based devices such as TVs, speakers, etc.
+
+# Appendix 1: Supporting Modules
+A list of supporting modules are described in [spec.md](spec.md).
diff --git a/docs/css/doxygen-awesome-css/Doxyfile b/docs/css/doxygen-awesome-css/Doxyfile
new file mode 100644 (file)
index 0000000..f3435df
--- /dev/null
@@ -0,0 +1,2665 @@
+# Doxyfile 1.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Doxygen Awesome"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "Modern Doxygen theme"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           = ./logo.drawio.svg
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = docs
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all generated output in the proper direction.
+# Possible values are: None, LTR, RTL and Context.
+# The default value is: None.
+
+OUTPUT_TEXT_DIRECTION  = None
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER         = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING       = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines (in the resulting output). You can put ^^ in the value part of an
+# alias to insert a newline as if a physical newline was in the original file.
+# When you need a literal { or } or , in the value part of an alias you have to
+# escape them by means of a backslash (\), this can lead to conflicts with the
+# commands \{ and \} for these it is advised to use the version @{ and @} or use
+# a double escape (\\{ and \\})
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE  = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
+# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 5
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which efficively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS       = 1
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL   = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation. If
+# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# Possible values are: NO, YES and FAIL_ON_WARNINGS.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = include \
+                         README.md \
+                         docs/page.dox
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
+# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
+# *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.pyw \
+                         *.f90 \
+                         *.f95 \
+                         *.f03 \
+                         *.f08 \
+                         *.f18 \
+                         *.f \
+                         *.for \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf \
+                         *.ice
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             = img
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = README.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see:
+# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
+# performance. This can be particularly helpful with template rich C++ code for
+# which doxygen's built-in parser lacks the necessary type information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to
+# YES then doxygen will add the directory of each input to the include path.
+# The default value is: YES.
+
+CLANG_ADD_INC_PATHS    = YES
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the directory containing a file called compile_commands.json. This
+# file is the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
+# options used when the source files were built. This is equivalent to
+# specifying the -p option to a clang tool, such as clang-check. These options
+# will then be passed to the parser. Any options specified with CLANG_OPTIONS
+# will be added as well.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            = docs/doxygen-custom/header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            = docs/doxygen-custom/footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  = doxygen-awesome.css \
+                         doxygen-awesome-sidebar-only.css \
+                         doxygen-awesome-sidebar-only-darkmode-toggle.css \
+                         docs/doxygen-custom/custom.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       = doxygen-awesome-darkmode-toggle.js
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 209
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 255
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 113
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see:
+# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 340
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT    = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE      =
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = https://cdn.jsdelivr.net/npm/mathjax@2
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         =
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD    = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to Sqlite3 output
+#---------------------------------------------------------------------------
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS        = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD     = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = svg
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc and
+# plantuml temporary files.
+# The default value is: YES.
+
+DOT_CLEANUP            = YES
diff --git a/docs/css/doxygen-awesome-css/LICENSE b/docs/css/doxygen-awesome-css/LICENSE
new file mode 100644 (file)
index 0000000..1d8b99a
--- /dev/null
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 jothepro
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/docs/css/doxygen-awesome-css/README.md b/docs/css/doxygen-awesome-css/README.md
new file mode 100644 (file)
index 0000000..7cfd015
--- /dev/null
@@ -0,0 +1,247 @@
+#  Doxygen Awesome
+
+[![GitHub release (latest by date)](https://img.shields.io/github/v/release/jothepro/doxygen-awesome-css)](https://github.com/jothepro/doxygen-awesome-css/releases/latest)
+[![GitHub](https://img.shields.io/github/license/jothepro/doxygen-awesome-css)](https://github.com/jothepro/doxygen-awesome-css/blob/main/LICENSE)
+
+<div style="filter: drop-shadow(0px 3px 15px rgba(0,0,0,0.25))">
+
+[![Screenshot of Doxygen Awesome CSS](img/screenshot.png)](https://jothepro.github.io/doxygen-awesome-css/)
+
+</div>
+<br>
+
+**Doxygen Awesome** is a custom **CSS theme for doxygen** html-documentation with lots of customization parameters.
+
+## Motivation
+
+I really like how the doxygen html-documentation is structured! But IMHO it looks a bit outdated.
+
+This theme is an attemt to update the visuals of doxygen without changing it's overall layout too much.
+
+## Features
+
+- 🌈 Clean, modern design
+- 🚀 Heavily customizable by adjusting CSS-variables
+- 🧩 No changes to the HTML structure of Doxygen required
+- 📱 Improved mobile usability
+- 🌘 Dark mode support!
+- 🥇 Works best with **doxygen 1.9.1** or **1.9.2**
+## Installation
+
+Copy the `css` files from this repository into your project or add this repository as submodule and check out the latest release:
+
+```bash
+git submodule add https://github.com/jothepro/doxygen-awesome-css.git
+cd doxygen-awesome-css
+git checkout v1.5.0
+```
+
+Then make the option `HTML_EXTRA_STYLESHEET` in your Doxyfile point to the `css` files:
+
+```
+# Doxyfile
+# ...
+HTML_EXTRA_STYLESHEET  = doxygen-awesome-css/doxygen-awesome.css
+```
+
+### Variants
+
+There is two variants of the theme.
+
+![theme variations](img/theme-variations.drawio.svg)
+
+1. **Base theme**:
+```
+# Doxyfile
+GENERATE_TREEVIEW      = YES # optional. Also works without treeview
+HTML_EXTRA_STYLESHEET  = doxygen-awesome-css/doxygen-awesome.css
+```
+
+2. **Sidebar-only theme** (experimental):
+```
+# Doxyfile
+GENERATE_TREEVIEW      = YES # required!
+HTML_EXTRA_STYLESHEET  = doxygen-awesome-css/doxygen-awesome.css doxygen-awesome-css/doxygen-awesome-sidebar-only.css
+```
+
+### Dark Mode Toggle (Experimental)
+
+The theme comes with an experimental feature that adds a button to enable and disable the dark theme variant manually.
+
+It requires customizations in both the header & footer html template.
+
+1. Create default header & footer templates:
+   ```bash
+   doxygen -w html header.html footer.html delete_me.css
+   ```
+
+2. Reference the required resources in your `Doxyfile`:
+   ```
+   # Include the required Javascript
+   HTML_EXTRA_FILES       = doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js
+
+   # Add the additional CSS. This is ONLY required for the sidebar-only theme variant!
+   HTML_EXTRA_STYLESHEET  = doxygen-awesome-css/doxygen-awesome.css \ 
+                            doxygen-awesome-css/doxygen-awesome-sidebar-only.css \
+                            doxygen-awesome-css/doxygen-awesome-sidebar-only-darkmode-toggle.css
+
+   # set custom header & footer files generated in previous step
+   HTML_HEADER            = header.html
+   HTML_FOOTER            = footer.html
+   ```
+
+3. In `header.html`, include `doxygen-awesome-darkmode-toggle.js` at the end of the `<head>`:
+   ```html
+   <html> 
+       <head>
+           <!-- ... other metadata & script includes ... -->
+           <script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
+       </head>
+       <body>
+   ```
+4. In `footer.html`, initialize the `doxygen-awesome-dark-mode-toggle` element at the end of the `<body>`:
+   ```html
+           <!-- ... -->
+           <script type="text/javascript">
+               // script for doxygen 1.9.1
+               $(function() {
+                   $(document).ready(function(){
+                      toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle')
+                      toggleButton.title = "Toggle Light/Dark Mode"
+                      document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
+                  })
+               })
+           </script>
+       </body>
+   </html>
+   ```
+   **Attention**: In Doxygen 1.9.2 the searchbox and it's siblings are deleted on every resize, which is why the toggle button has to be re-added every time:
+   ```js
+   $(function() {
+     toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle')
+     toggleButton.title = "Toggle Light/Dark Mode"
+
+     $(document).ready(function(){
+       document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
+     })
+     $(window).resize(function(){
+       document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
+     })
+   })
+   ```
+
+## Examples
+
+- Sidebar-Only theme: [Documentation of this repository](https://jothepro.github.io/doxygen-awesome-css/)
+- Base theme: [libsl3](https://a4z.github.io/libsl3/)
+
+
+## Configuration
+
+### CSS Variables
+
+This theme is highly customizable because a lot of things are parameterized with CSS variables. The following
+list of parameters is not complete! You can easily modify any variable with the developer tools of your browser to find
+out what it does.
+
+To customize the existing theme, add your own `custom.css` and overwrite the variables there:
+```
+HTML_EXTRA_STYLESHEET  = doxygen-awesome-theme/doxygen-awesome.css custom.css
+```
+
+```css
+/* custom.css */
+html {
+    /* define light-mode variable overrides here */
+}
+
+@media (prefers-color-scheme: dark) {
+    html:not(.light-mode) {
+        /* define dark-mode variable overrides here if you DON'T use doxygen-awesome-darkmode-toggle.js */
+    }
+}
+
+html.dark-mode {
+    /* define dark-mode variable overrides here if you DO use doxygen-awesome-darkmode-toggle.js */
+}
+```
+
+| Parameter                         | Default (Light)                                             | Default (Dark)                                              |
+| :-------------------------------- | :---------------------------------------------------------- | ----------------------------------------------------------- |
+| **Color Scheme**:<br>primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ...                                     |||
+| `--primary-color`                 | <span style="background:#1779c4;color:white">#1779c4</span> | <span style="background:#1982d2;color:white">#1982d2</span> |
+| `--primary-dark-color`            | <span style="background:#00559f;color:white">#00559f</span> | <span style="background:#5ca8e2;color:white">#5ca8e2</span> |
+| `--primary-light-color`           | <span style="background:#7aabd6;color:black">#7aabd6</span> | <span style="background:#4779ac;color:white">#4779ac</span> |
+| `--primary-lighter-color`         | <span style="background:#cae1f1;color:black">#cae1f1</span> | <span style="background:#191e21;color:white">#191e21</span> |
+| `--primary-lightest-color`        | <span style="background:#e9f1f8;color:black">#e9f1f8</span> | <span style="background:#191a1c;color:white">#191a1c</span> |
+| **Spacing:**<br>default spacings. Most ui components reference these values for spacing, to provide uniform spacing on the page.                            |||
+| `--spacing-small`                 | `5px`                                                       |                                                             |
+| `--spacing-medium`                | `10px`                                                      |                                                             |
+| `--spacing-large`                 | `16px`                                                      |                                                             |
+| **Border Radius**:<br>border radius for all rounded ui components. Will affect many components, like dropdowns, memitems, codeblocks, ...                   |||
+| `--border-radius-small`           | `4px`                                                       |                                                             |
+| `--border-radius-medium`          | `6px`                                                       |                                                             |
+| `--border-radius-large`           | `8px`                                                       |                                                             |
+| **Content Width**:<br>The content is centered and constrained in its width. To make the content fill the whole page, set the following variable to `auto`.  |||
+| `--content-maxwidth`              | `1000px`                                                     |                                                             |
+| **Code Fragment Colors**:<br>Color-Scheme of multiline codeblocks                                                                                           |||
+| `--fragment-background`           | <span style="background:#282c34;color:white">#282c34</span> |                                                             |
+| `--fragment-foreground`           | <span style="background:#fff;wolor:black">#fff</span>       |                                                             |
+| **Arrow Opacity**:<br>By default the arrows in the sidebar are only visible on hover. You can override this behaviour so they are visible all the time.     |||
+| `--side-nav-arrow-opacity`        | `0`                                                         |                                                             |
+| `--side-nav-arrow-hover-opacity`  | `0.9`                                                       |                                                             |
+| **Darkmode Toggle Icon**:<br>If you have enabled the darkmode toggle button, you can define the icon that is shown for the current mode.                    |||
+| `--darkmode-toggle-button-icon`   | ☀️                                                           | 🌛                                                          |
+| ...and many more                                                                                                                                            |||
+
+If you miss a configuration option or find a bug, please consider [opening an issue](https://github.com/jothepro/doxygen-awesome-css/issues)!
+
+### Doxygen generator
+
+The theme overrides most colors with the `--primary-color-*` variables.
+
+But there is a few small images and graphics that the theme cannot adjust or replace. To make these blend in better with
+the rest, it is recommended to adjust the [doxygen color settings](https://www.doxygen.nl/manual/customize.html#minor_tweaks_colors) 
+to something that matches the chosen color-scheme.
+
+For the default color-scheme, these values work out quite well:
+
+```
+# Doxyfile
+HTML_COLORSTYLE_HUE    = 209
+HTML_COLORSTYLE_SAT    = 255
+HTML_COLORSTYLE_GAMMA  = 113
+```
+
+## Browser support
+
+Tested with
+
+- Chrome 91, Chrome 91 for Android, Chrome 87 for iOS
+- Safari 14, Safari for iOS 14
+- Firefox 89, Firefox Daylight 89 for Android, Firefox Daylight 33 for iOS
+
+## Tips & Tricks
+
+### Class Diagrams with Graphviz
+
+To get the best looking class diagrams for your documentation, generate them with Graphviz as vector graphics with transparent background:
+
+```
+# Doxyfile
+HAVE_DOT = YES
+DOT_IMAGE_FORMAT = svg
+DOT_TRANSPARENT = YES
+```
+
+### Share your own theme customizations
+
+If you customized the theme with custom colors, spacings, font-sizes, etc. and you want to share your creation with others, you can to this [here](https://github.com/jothepro/doxygen-awesome-css/discussions/13).
+
+I am always curious to learn about how you made the theme look even better!
+
+
+## Credits
+
+This theme is heavily inspired by the beautiful [vuepress](https://vuepress.vuejs.org/) static site generator default theme!
diff --git a/docs/css/doxygen-awesome-css/docs/doxygen-custom/custom.css b/docs/css/doxygen-awesome-css/docs/doxygen-custom/custom.css
new file mode 100644 (file)
index 0000000..73bedc4
--- /dev/null
@@ -0,0 +1,16 @@
+.github-corner svg {
+    fill: var(--primary-light-color);
+    color: var(--page-background-color);
+    width: 72px;
+    height: 72px;
+}
+
+@media screen and (max-width: 767px) {
+    .github-corner svg {
+        width: 55px;
+        height: 55px;
+    }
+    #projectnumber {
+        margin-right: 22px;
+    }
+}
diff --git a/docs/css/doxygen-awesome-css/docs/doxygen-custom/footer.html b/docs/css/doxygen-awesome-css/docs/doxygen-custom/footer.html
new file mode 100644 (file)
index 0000000..d4a0439
--- /dev/null
@@ -0,0 +1,30 @@
+<!-- HTML footer for doxygen 1.9.1-->
+<!-- start footer part -->
+<!--BEGIN GENERATE_TREEVIEW-->
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+  <ul>
+    $navpath
+    <li class="footer">$generatedby <a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion </li>
+  </ul>
+</div>
+<!--END GENERATE_TREEVIEW-->
+<!--BEGIN !GENERATE_TREEVIEW-->
+<hr class="footer"/><address class="footer"><small>
+$generatedby&#160;<a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion
+</small></address>
+<!--END !GENERATE_TREEVIEW-->
+<script type="text/javascript">
+  $(function() {
+     toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle')
+     toggleButton.title = "Toggle Light/Dark Mode"
+
+     $(document).ready(function(){
+       document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
+     })
+     $(window).resize(function(){
+       document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
+     })
+   })
+</script>
+</body>
+</html>
diff --git a/docs/css/doxygen-awesome-css/docs/doxygen-custom/header.html b/docs/css/doxygen-awesome-css/docs/doxygen-custom/header.html
new file mode 100644 (file)
index 0000000..0e9d120
--- /dev/null
@@ -0,0 +1,78 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta name="generator" content="Doxygen $doxygenversion"/>
+<meta name="viewport" content="width=device-width, initial-scale=1"/>
+
+<!-- BEGIN opengraph metadata -->
+<meta property="og:title" content="Doxygen Awesome" />
+<meta property="og:image" content="https://repository-images.githubusercontent.com/348492097/4f16df80-88fb-11eb-9d31-4015ff22c452" />
+<meta property="og:description" content="Custom CSS theme for doxygen html-documentation with lots of customization parameters." />
+<meta property="og:url" content="https://jothepro.github.io/doxygen-awesome-css/" />
+<!-- END opengraph metadata -->
+
+<!-- BEGIN twitter metadata -->
+<meta name="twitter:image:src" content="https://repository-images.githubusercontent.com/348492097/4f16df80-88fb-11eb-9d31-4015ff22c452" />
+<meta name="twitter:title" content="Doxygen Awesome" />
+<meta name="twitter:description" content="Custom CSS theme for doxygen html-documentation with lots of customization parameters." />
+<!-- END twitter metadata -->
+
+<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
+<link rel="icon" type="image/svg+xml" href="logo.drawio.svg"/>
+<script type="text/javascript" src="$relpath^jquery.js"></script>
+<script type="text/javascript" src="$relpath^dynsections.js"></script>
+<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
+$treeview
+$search
+$mathjax
+<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
+$extrastylesheet
+</head>
+<body>
+
+<!-- https://tholman.com/github-corners/ -->
+<a href="https://github.com/jothepro/doxygen-awesome-css" class="github-corner" title="View source on GitHub">
+    <svg viewBox="0 0 250 250" style="position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true">
+    <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
+
+
+<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+
+<!--BEGIN TITLEAREA-->
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+  <!--BEGIN PROJECT_LOGO-->
+  <td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
+  <!--END PROJECT_LOGO-->
+  <!--BEGIN PROJECT_NAME-->
+  <td id="projectalign" style="padding-left: 0.5em;">
+   <div id="projectname">$projectname
+   <!--BEGIN PROJECT_NUMBER-->&#160;<span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
+   </div>
+   <!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
+  </td>
+  <!--END PROJECT_NAME-->
+  <!--BEGIN !PROJECT_NAME-->
+   <!--BEGIN PROJECT_BRIEF-->
+    <td style="padding-left: 0.5em;">
+    <div id="projectbrief">$projectbrief</div>
+    </td>
+   <!--END PROJECT_BRIEF-->
+  <!--END !PROJECT_NAME-->
+  <!--BEGIN DISABLE_INDEX-->
+   <!--BEGIN SEARCHENGINE-->
+   <td>$searchbox</td>
+   <!--END SEARCHENGINE-->
+  <!--END DISABLE_INDEX-->
+ </tr>
+ </tbody>
+</table>
+</div>
+<!--END TITLEAREA-->
+<!-- end header part -->
diff --git a/docs/css/doxygen-awesome-css/docs/page.dox b/docs/css/doxygen-awesome-css/docs/page.dox
new file mode 100644 (file)
index 0000000..ab82ae9
--- /dev/null
@@ -0,0 +1,15 @@
+/*!
+
+\page page1 Example Page
+\tableofcontents
+Leading text.
+\section sec An example section
+This page contains the subsections \ref subsection1 and \ref subsection2.
+\subsection subsection1 The first subsection
+Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
+\subsection subsection2 The second subsection
+Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
+
+\note Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
+
+*/
\ No newline at end of file
diff --git a/docs/css/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js b/docs/css/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js
new file mode 100644 (file)
index 0000000..ae72bf7
--- /dev/null
@@ -0,0 +1,115 @@
+/**
+
+Doxygen Awesome
+https://github.com/jothepro/doxygen-awesome-css
+
+MIT License
+
+Copyright (c) 2021 jothepro
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+*/
+
+class DoxygenAwesomeDarkModeToggle extends HTMLElement {
+    static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode"
+    static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode"
+
+    static _staticConstructor = function() {
+        DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference
+        DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
+        // Update the color scheme when the browsers preference changes
+        // without user interaction on the website.
+        window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
+            DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
+        })
+        // Update the color scheme when the tab is made visible again.
+        // It is possible that the appearance was changed in another tab 
+        // while this tab was in the background.
+        document.addEventListener("visibilitychange", visibilityState => {
+            if (document.visibilityState === 'visible') {
+                DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
+            }
+        });
+    }()
+
+    constructor() {
+        super();
+        this.onclick=this.toggleDarkMode
+    }
+
+    /**
+     * @returns `true` for dark-mode, `false` for light-mode system preference
+     */
+    static get systemPreference() {
+        return window.matchMedia('(prefers-color-scheme: dark)').matches
+    }
+
+    /**
+     * @returns `true` for dark-mode, `false` for light-mode user preference
+     */
+    static get userPreference() {
+        return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) || 
+        (DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey))
+    }
+
+    static set userPreference(userPreference) {
+        DoxygenAwesomeDarkModeToggle.darkModeEnabled = userPreference
+        if(!userPreference) {
+            if(DoxygenAwesomeDarkModeToggle.systemPreference) {
+                localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey, true)
+            } else {
+                localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)
+            }
+        } else {
+            if(!DoxygenAwesomeDarkModeToggle.systemPreference) {
+                localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey, true)
+            } else {
+                localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)
+            }
+        }
+        DoxygenAwesomeDarkModeToggle.onUserPreferenceChanged()
+    }
+
+    static enableDarkMode(enable) {
+        let head = document.getElementsByTagName('head')[0]
+        if(enable) {
+            document.documentElement.classList.add("dark-mode")
+            document.documentElement.classList.remove("light-mode")
+        } else {
+            document.documentElement.classList.remove("dark-mode")
+            document.documentElement.classList.add("light-mode")
+        }
+    }
+
+    static onSystemPreferenceChanged() {
+        DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference
+        DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
+    }
+
+    static onUserPreferenceChanged() {
+        DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
+    }
+
+    toggleDarkMode() {
+        DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference
+    }
+}
+
+customElements.define("doxygen-awesome-dark-mode-toggle", DoxygenAwesomeDarkModeToggle);
diff --git a/docs/css/doxygen-awesome-css/doxygen-awesome-sidebar-only-darkmode-toggle.css b/docs/css/doxygen-awesome-css/doxygen-awesome-sidebar-only-darkmode-toggle.css
new file mode 100644 (file)
index 0000000..b988b6f
--- /dev/null
@@ -0,0 +1,40 @@
+
+/**
+
+Doxygen Awesome
+https://github.com/jothepro/doxygen-awesome-css
+
+MIT License
+
+Copyright (c) 2021 jothepro
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+*/
+
+@media screen and (min-width: 768px) {
+
+    #MSearchBox {
+        width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - var(--searchbar-height) - 1px);
+    }
+
+    #MSearchField {
+        width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 66px - var(--searchbar-height));
+    }
+}
diff --git a/docs/css/doxygen-awesome-css/doxygen-awesome-sidebar-only.css b/docs/css/doxygen-awesome-css/doxygen-awesome-sidebar-only.css
new file mode 100644 (file)
index 0000000..655a90c
--- /dev/null
@@ -0,0 +1,108 @@
+/**
+
+Doxygen Awesome
+https://github.com/jothepro/doxygen-awesome-css
+
+MIT License
+
+Copyright (c) 2021 jothepro
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+ */
+
+html {
+    /* side nav width. MUST be = `TREEVIEW_WIDTH`.
+     * Make sure it is wide enought to contain the page title (logo + title + version)
+     */
+    --side-nav-fixed-width: 340px;
+    --menu-display: none;
+
+    --top-height: 120px;
+}
+
+
+@media screen and (min-width: 768px) {
+    html {
+        --searchbar-background: var(--page-background-color);
+    }
+
+    #side-nav {
+        min-width: var(--side-nav-fixed-width);
+        max-width: var(--side-nav-fixed-width);
+        top: var(--top-height);
+        overflow: visible;
+    }
+
+    #nav-tree, #side-nav {
+        height: calc(100vh - var(--top-height)) !important;
+    }
+
+    #nav-tree {
+        padding: 0;
+    }
+
+    #top {
+        display: block;
+        border-bottom: none;
+        height: var(--top-height);
+        margin-bottom: calc(0px - var(--top-height));
+        max-width: var(--side-nav-fixed-width);
+        background: var(--side-nav-background);
+    }
+    #main-nav {
+        float: left;
+        padding-right: 0;
+    }
+
+    .ui-resizable-handle {
+        cursor: default;
+        width: 1px !important;
+        box-shadow: 0 calc(-2 * var(--top-height)) 0 0 var(--separator-color);
+    }
+
+    #nav-path {
+        position: fixed;
+        right: 0;
+        left: var(--side-nav-fixed-width);
+        bottom: 0;
+        width: auto;
+    }
+
+    #doc-content {
+        height: calc(100vh - 31px) !important;
+        padding-bottom: calc(3 * var(--spacing-large));
+        padding-top: calc(var(--top-height) - 80px);
+        box-sizing: border-box;
+        margin-left: var(--side-nav-fixed-width) !important;
+    }
+
+    #MSearchBox {
+        width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)));
+    }
+
+    #MSearchField {
+        width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 65px);
+    }
+
+    #MSearchResultsWindow {
+        left: var(--spacing-medium) !important;
+        right: auto;
+    }
+}
diff --git a/docs/css/doxygen-awesome-css/doxygen-awesome.css b/docs/css/doxygen-awesome-css/doxygen-awesome.css
new file mode 100644 (file)
index 0000000..549c139
--- /dev/null
@@ -0,0 +1,1504 @@
+/**
+
+Doxygen Awesome
+https://github.com/jothepro/doxygen-awesome-css
+
+MIT License
+
+Copyright (c) 2021 jothepro
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+*/
+
+html {
+    /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */
+    --primary-color: #1779c4;
+    --primary-dark-color: #00559f;
+    --primary-light-color: #7aabd6;
+    --primary-lighter-color: #cae1f1;
+    --primary-lightest-color: #e9f1f8;
+
+    /* page base colors */
+    --page-background-color: white;
+    --page-foreground-color: #2c3e50;
+    --page-secondary-foreground-color: #67727e;
+
+    /* color for all separators on the website: hr, borders, ... */
+    --separator-color: #dedede;
+
+    /* border radius for all rounded components. Will affect many components, like dropdowns, memitems, codeblocks, ... */
+    --border-radius-large: 8px;
+    --border-radius-small: 4px;
+    --border-radius-medium: 6px;
+
+    /* default spacings. Most compontest reference these values for spacing, to provide uniform spacing on the page. */
+    --spacing-small: 5px;
+    --spacing-medium: 10px;
+    --spacing-large: 16px;
+
+    /* default box shadow used for raising an element above the normal content. Used in dropdowns, Searchresult, ... */
+    --box-shadow: 0 2px 10px 0 rgba(0,0,0,.1);
+
+    --odd-color: rgba(0,0,0,.03);
+
+    /* font-families. will affect all text on the website
+     * font-family: the normal font for text, headlines, menus
+     * font-family-monospace: used for preformatted text in memtitle, code, fragments
+     */
+    --font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;
+    --font-family-monospace: source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace;
+
+    /* font sizes */
+    --page-font-size: 15.6px;
+    --navigation-font-size: 14.4px;
+    --code-font-size: 14.4px; /* affects code, fragment */
+    --title-font-size: 22px;
+
+    /* content text properties. These only affect the page content, not the navigation or any other ui elements */
+    --content-line-height: 27px;
+    /* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/
+    --content-maxwidth: 1000px;
+
+    /* colors for various content boxes: @warning, @note, @deprecated @bug */
+    --warning-color: #fca49b;
+    --warning-color-dark: #b61825;
+    --warning-color-darker: #75070f;
+    --note-color: rgba(255,229,100,.3);
+    --note-color-dark: #c39900;
+    --note-color-darker: #8d7400;
+    --deprecated-color: rgb(214, 216, 224);
+    --deprecated-color-dark: #5b6269;
+    --deprecated-color-darker: #43454a;
+    --bug-color: rgb(246, 208, 178);
+    --bug-color-dark: #a53a00;
+    --bug-color-darker: #5b1d00;
+    --invariant-color: #b7f8d0;
+    --invariant-color-dark: #00ba44;
+    --invariant-color-darker: #008622;
+
+    /* blockquote colors */
+    --blockquote-background: #f5f5f5;
+    --blockquote-foreground: #727272;
+
+    /* table colors */
+    --tablehead-background: #f1f1f1;
+    --tablehead-foreground: var(--page-foreground-color);
+
+    /* menu-display: block | none
+     * Visibility of the top navigation on screens >= 768px. On smaller screen the menu is always visible.
+     * `GENERATE_TREEVIEW` MUST be enabled!
+     */
+    --menu-display: block;
+
+    --menu-focus-foreground: var(--page-background-color);
+    --menu-focus-background: var(--primary-color);
+    --menu-selected-background: rgba(0,0,0,.05);
+
+
+    --header-background: var(--page-background-color);
+    --header-foreground: var(--page-foreground-color);
+
+    /* searchbar colors */
+    --searchbar-background: var(--side-nav-background);
+    --searchbar-foreground: var(--page-foreground-color);
+
+    /* searchbar size
+     * (`searchbar-width` is only applied on screens >= 768px.
+     * on smaller screens the searchbar will always fill the entire screen width) */
+    --searchbar-height: 33px;
+    --searchbar-width: 210px;
+
+    /* code block colors */
+    --code-background: #f5f5f5;
+    --code-foreground: var(--page-foreground-color);
+
+    /* fragment colors */
+    --fragment-background: #282c34;
+    --fragment-foreground: #ffffff;
+    --fragment-keyword: #cc99cd;
+    --fragment-keywordtype: #ab99cd;
+    --fragment-keywordflow: #e08000;
+    --fragment-token: #7ec699;
+    --fragment-comment: #999999;
+    --fragment-link: #98c0e3;
+    --fragment-preprocessor: #65cabe;
+    --fragment-linenumber-color: #cccccc;
+    --fragment-linenumber-background: #35393c;
+    --fragment-linenumber-border: #1f1f1f;
+    --fragment-lineheight: 20px;
+
+    /* sidebar navigation (treeview) colors */
+    --side-nav-background: #fbfbfb;
+    --side-nav-foreground: var(--page-foreground-color);
+    --side-nav-arrow-opacity: 0;
+    --side-nav-arrow-hover-opacity: 0.9;
+
+    /* height of an item in any tree / collapsable table */
+    --tree-item-height: 30px;
+
+    --darkmode-toggle-button-icon: '☀️'
+}
+
+@media screen and (max-width: 767px) {
+    html {
+        --page-font-size: 16px;
+        --navigation-font-size: 16px;
+        --code-font-size: 15px; /* affects code, fragment */
+        --title-font-size: 22px;
+    }
+}
+
+@media (prefers-color-scheme: dark) {
+    html:not(.light-mode) {
+        color-scheme: dark;
+        
+        --primary-color: #1982d2;
+        --primary-dark-color: #5ca8e2;
+        --primary-light-color: #4779ac;
+        --primary-lighter-color: #191e21;
+        --primary-lightest-color: #191a1c;
+
+        --box-shadow: 0 2px 10px 0 rgba(0,0,0,.35);
+
+        --odd-color: rgba(0,0,0,.1);
+
+        --menu-selected-background: rgba(0,0,0,.4);
+
+        --page-background-color: #1C1D1F;
+        --page-foreground-color: #d2dbde;
+        --page-secondary-foreground-color: #859399;
+        --separator-color: #000000;
+        --side-nav-background: #252628;
+
+        --code-background: #2a2c2f;
+
+        --tablehead-background: #2a2c2f;
+
+        --blockquote-background: #1f2022;
+        --blockquote-foreground: #77848a;
+
+        --warning-color: #b61825;
+        --warning-color-dark: #510a02;
+        --warning-color-darker: #f5b1aa;
+        --note-color: rgb(255, 183, 0);
+        --note-color-dark: #9f7300;
+        --note-color-darker: #645b39;
+        --deprecated-color: rgb(88, 90, 96);
+        --deprecated-color-dark: #262e37;
+        --deprecated-color-darker: #a0a5b0;
+        --bug-color: rgb(248, 113, 0);
+        --bug-color-dark: #812a00;
+        --bug-color-darker: #ffd3be;
+
+        --darkmode-toggle-button-icon: '🌛';
+    }
+}
+
+/* dark mode variables are defined twice, to support both the dark-mode without and with doxygen-awesome-darkmode-toggle.js */
+html.dark-mode {
+    color-scheme: dark;
+
+    --primary-color: #1982d2;
+    --primary-dark-color: #5ca8e2;
+    --primary-light-color: #4779ac;
+    --primary-lighter-color: #191e21;
+    --primary-lightest-color: #191a1c;
+
+    --box-shadow: 0 2px 10px 0 rgba(0,0,0,.35);
+
+    --odd-color: rgba(0,0,0,.1);
+
+    --menu-selected-background: rgba(0,0,0,.4);
+
+    --page-background-color: #1C1D1F;
+    --page-foreground-color: #d2dbde;
+    --page-secondary-foreground-color: #859399;
+    --separator-color: #000000;
+    --side-nav-background: #252628;
+
+    --code-background: #2a2c2f;
+
+    --tablehead-background: #2a2c2f;
+
+    --blockquote-background: #1f2022;
+    --blockquote-foreground: #77848a;
+
+    --warning-color: #b61825;
+    --warning-color-dark: #510a02;
+    --warning-color-darker: #f5b1aa;
+    --note-color: rgb(255, 183, 0);
+    --note-color-dark: #9f7300;
+    --note-color-darker: #645b39;
+    --deprecated-color: rgb(88, 90, 96);
+    --deprecated-color-dark: #262e37;
+    --deprecated-color-darker: #a0a5b0;
+    --bug-color: rgb(248, 113, 0);
+    --bug-color-dark: #812a00;
+    --bug-color-darker: #ffd3be;
+
+    --darkmode-toggle-button-icon: '🌛';
+}
+
+body {
+    color: var(--page-foreground-color);
+    background-color: var(--page-background-color);
+    font-size: var(--page-font-size);
+}
+
+body, table, div, p, dl, #nav-tree .label, .title, .sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, .SelectItem, #MSearchField, .navpath li.navelem a, .navpath li.navelem a:hover {
+    font-family: var(--font-family);
+}
+
+h1, h2, h3, h4, h5 {
+    margin-top: .9em;
+    font-weight: 600;
+    line-height: initial;
+}
+
+p, div, table, dl {
+    font-size: var(--page-font-size);
+}
+
+a:link, a:visited, a:hover, a:focus, a:active {
+    color: var(--primary-color) !important;
+    font-weight: 500;
+}
+
+/*
+ Title and top navigation
+ */
+
+#top {
+    background: var(--header-background);
+    border-bottom: 1px solid var(--separator-color);
+}
+
+@media screen and (min-width: 768px) {
+    #top {
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: space-between;
+        align-items: center;
+    }
+}
+
+#main-nav {
+    flex-grow: 5;
+    padding: var(--spacing-small) var(--spacing-medium);
+}
+
+#titlearea {
+    width: auto;
+    padding: var(--spacing-medium) var(--spacing-large);
+    background: none;
+    color: var(--header-foreground);
+    border-bottom: none;
+}
+
+@media screen and (max-width: 767px) {
+    #titlearea {
+        padding-bottom: var(--spacing-small);
+    }
+}
+
+#titlearea table tbody tr {
+    height: auto !important;
+}
+
+#projectname {
+    font-size: var(--title-font-size);
+    font-weight: 600;
+}
+
+#projectnumber {
+    font-family: inherit;
+    font-size: 60%;
+}
+
+#projectbrief {
+    font-family: inherit;
+    font-size: 80%;
+}
+
+#projectlogo {
+    vertical-align: middle;
+}
+
+#projectlogo img {
+    max-height: calc(var(--title-font-size) * 2);
+    margin-right: var(--spacing-small);
+}
+
+.sm-dox, .tabs, .tabs2, .tabs3 {
+    background: none;
+    padding: 0;
+}
+
+.tabs, .tabs2, .tabs3 {
+    border-bottom: 1px solid var(--separator-color);
+    margin-bottom: -1px;
+}
+
+@media screen and (max-width: 767px) {
+    .sm-dox a span.sub-arrow {
+        background: var(--code-background);
+    }
+}
+
+@media screen and (min-width: 768px) {
+    .sm-dox li, .tablist li {
+        display: var(--menu-display);
+    }
+
+    .sm-dox a span.sub-arrow {
+        border-color: var(--header-foreground) transparent transparent transparent;
+    }
+
+    .sm-dox a:hover span.sub-arrow {
+        border-color: var(--menu-focus-foreground) transparent transparent transparent;
+    }
+
+    .sm-dox ul a span.sub-arrow {
+        border-color: transparent transparent transparent var(--page-foreground-color);
+    }
+
+    .sm-dox ul a:hover span.sub-arrow {
+        border-color: transparent transparent transparent var(--menu-focus-foreground);
+    }
+}
+
+.sm-dox ul {
+    background: var(--page-background-color);
+    box-shadow: var(--box-shadow);
+    border: 1px solid var(--separator-color);
+    border-radius: var(--border-radius-medium) !important;
+    padding: var(--spacing-small);
+    animation: ease-out 150ms slideInMenu;
+}
+
+@keyframes slideInMenu {
+    from {
+        opacity: 0;
+        transform: translate(0px, -2px);
+    }
+
+    to {
+        opacity: 1;
+        transform: translate(0px, 0px);
+    }
+}
+
+.sm-dox ul a {
+    color: var(--page-foreground-color) !important;
+    background: var(--page-background-color);
+    font-size: var(--navigation-font-size);
+}
+
+.sm-dox>li>ul:after {
+    border-bottom-color: var(--page-background-color) !important;
+}
+
+.sm-dox>li>ul:before {
+    border-bottom-color: var(--separator-color) !important;
+}
+
+.sm-dox ul a:hover, .sm-dox ul a:active, .sm-dox ul a:focus {
+    font-size: var(--navigation-font-size) !important;
+    color: var(--menu-focus-foreground) !important;
+    text-shadow: none;
+    background-color: var(--menu-focus-background);
+    border-radius: var(--border-radius-small) !important;
+}
+
+.sm-dox a, .sm-dox a:focus, .tablist li, .tablist li a, .tablist li.current a {
+    text-shadow: none;
+    background: transparent;
+    background-image: none !important;
+    color: var(--header-foreground) !important;
+    font-weight: normal;
+    font-size: var(--navigation-font-size);
+}
+
+.sm-dox a:focus {
+    outline: auto;
+}
+
+.sm-dox a:hover, .sm-dox a:active, .tablist li a:hover {
+    text-shadow: none;
+    font-weight: normal;
+    background: var(--menu-focus-background);
+    color: var(--menu-focus-foreground) !important;
+    border-radius: var(--border-radius-small) !important;
+    font-size: var(--navigation-font-size);
+}
+
+.tablist li.current {
+    border-radius: var(--border-radius-small);
+    background: var(--menu-selected-background);
+}
+
+.tablist li {
+    margin: var(--spacing-small) 0 var(--spacing-small) var(--spacing-small);
+}
+
+.tablist a {
+    padding: 0 var(--spacing-large);
+}
+
+
+/*
+ Search box
+ */
+
+#MSearchBox {
+    height: var(--searchbar-height);
+    background: var(--searchbar-background);
+    border-radius: var(--searchbar-height);
+    border: 1px solid var(--separator-color);
+    overflow: hidden;
+    width: var(--searchbar-width);
+    position: relative;
+    box-shadow: none;
+    display: block;
+    margin-top: 0;
+}
+
+.left #MSearchSelect {
+    left: 0;
+}
+
+.tabs .left #MSearchSelect {
+    padding-left: 0;
+}
+
+.tabs #MSearchBox {
+    position: absolute;
+    right: var(--spacing-medium);
+}
+
+@media screen and (max-width: 767px) {
+    .tabs #MSearchBox {
+        position: relative;
+        right: 0;
+        margin-left: var(--spacing-medium);
+        margin-top: 0;
+    }
+}
+
+#MSearchSelectWindow, #MSearchResultsWindow {
+    z-index: 9999;
+}
+
+#MSearchBox.MSearchBoxActive {
+    border-color: var(--primary-color);
+    box-shadow: inset 0 0 0 1px var(--primary-color);
+}
+
+#main-menu > li:last-child {
+    margin-right: 0;
+}
+
+@media screen and (max-width: 767px) {
+    #main-menu > li:last-child {
+        height: 50px;
+    }
+}
+
+#MSearchField {
+    font-size: var(--navigation-font-size);
+    height: calc(var(--searchbar-height) - 2px);
+    background: transparent;
+    width: calc(var(--searchbar-width) - 64px);
+}
+
+.MSearchBoxActive #MSearchField {
+    color: var(--searchbar-foreground);
+}
+
+#MSearchSelect {
+    top: calc(calc(var(--searchbar-height) / 2) - 11px);
+}
+
+.left #MSearchSelect {
+    padding-left: 8px;
+}
+
+#MSearchBox span.left, #MSearchBox span.right {
+    background: none;
+}
+
+#MSearchBox span.right {
+    padding-top: calc(calc(var(--searchbar-height) / 2) - 12px);
+    position: absolute;
+    right: var(--spacing-small);
+}
+
+.tabs #MSearchBox span.right {
+    top: calc(calc(var(--searchbar-height) / 2) - 12px);
+}
+
+@keyframes slideInSearchResults {
+    from {
+        opacity: 0;
+        transform: translate(0, 15px);
+    }
+
+    to {
+        opacity: 1;
+        transform: translate(0, 20px);
+    }
+}
+
+#MSearchResultsWindow {
+    left: auto !important;
+    right: var(--spacing-medium);
+    border-radius: var(--border-radius-large);
+    border: 1px solid var(--separator-color);
+    transform: translate(0, 20px);
+    box-shadow: var(--box-shadow);
+    animation: ease-out 280ms slideInSearchResults;
+    background: var(--page-background-color);
+}
+
+iframe#MSearchResults {
+    margin: 4px;
+}
+
+iframe {
+    color-scheme: normal;
+}
+
+@media (prefers-color-scheme: dark) {
+    html:not(.light-mode) iframe#MSearchResults {
+        filter: invert() hue-rotate(180deg);
+    }
+}
+
+html.dark-mode iframe#MSearchResults {
+    filter: invert() hue-rotate(180deg);
+}
+
+#MSearchSelectWindow {
+    border: 1px solid var(--separator-color);
+    border-radius: var(--border-radius-medium);
+    box-shadow: var(--box-shadow);
+    background: var(--page-background-color);
+}
+
+#MSearchSelectWindow a.SelectItem {
+    font-size: var(--navigation-font-size);
+    line-height: var(--content-line-height);
+    margin: 0 var(--spacing-small);
+    border-radius: var(--border-radius-small);
+    color: var(--page-foreground-color) !important;
+    font-weight: normal;
+}
+
+#MSearchSelectWindow a.SelectItem:hover {
+    background: var(--menu-focus-background);
+    color: var(--menu-focus-foreground) !important;
+}
+
+@media screen and (max-width: 767px) {
+    #MSearchBox {
+        margin-top: var(--spacing-medium);
+        margin-bottom: var(--spacing-medium);
+        width: calc(100vw - 30px);
+    }
+
+    #main-menu > li:last-child {
+        float: none !important;
+    }
+
+    #MSearchField {
+        width: calc(100vw - 110px);
+    }
+
+    @keyframes slideInSearchResultsMobile {
+        from {
+            opacity: 0;
+            transform: translate(0, 15px);
+        }
+
+        to {
+            opacity: 1;
+            transform: translate(0, 20px);
+        }
+    }
+
+    #MSearchResultsWindow {
+        left: var(--spacing-medium) !important;
+        right: var(--spacing-medium);
+        overflow: auto;
+        transform: translate(0, 20px);
+        animation: ease-out 280ms slideInSearchResultsMobile;
+    }
+
+    /* 
+     * Overwrites for fixing the searchbox on mobile in doxygen 1.9.2 
+     */
+    label.main-menu-btn ~ #searchBoxPos1 {
+        top: 3px !important;
+        right: 6px !important;
+        left: 45px;
+        display: flex;
+    }
+
+    label.main-menu-btn ~ #searchBoxPos1 > #MSearchBox {
+        margin-top: 0;
+        margin-bottom: 0;
+        flex-grow: 2;
+        float: left;
+    }
+}
+
+/*
+ Tree view
+ */
+
+#side-nav {
+    padding: 0 !important;
+    background: var(--side-nav-background);
+}
+
+@media screen and (max-width: 767px) {
+    #side-nav {
+        display: none;
+    }
+
+    #doc-content {
+        margin-left: 0 !important;
+        height: auto !important;
+        padding-bottom: calc(2 * var(--spacing-large));
+    }
+}
+
+#nav-tree {
+    background: transparent;
+}
+
+#nav-tree .label {
+    font-size: var(--navigation-font-size);
+}
+
+#nav-tree .item {
+    height: var(--tree-item-height);
+    line-height: var(--tree-item-height);
+}
+
+#nav-sync {
+    top: 12px !important;
+    right: 12px;
+}
+
+#nav-tree .selected {
+    text-shadow: none;
+    background-image: none;
+    background-color: transparent;
+    box-shadow: inset 4px 0 0 0 var(--primary-color);
+}
+
+#nav-tree a {
+    color: var(--side-nav-foreground) !important;
+    font-weight: normal;
+}
+
+#nav-tree a:focus {
+    outline-style: auto;
+}
+
+#nav-tree .arrow {
+    opacity: var(--side-nav-arrow-opacity);
+}
+
+.arrow {
+    color: inherit;
+    cursor: pointer;
+    font-size: 45%;
+    vertical-align: middle;
+    margin-right: 2px;
+    font-family: serif;
+    height: auto;
+    text-align: right;
+}
+
+#nav-tree div.item:hover .arrow, #nav-tree a:focus .arrow {
+    opacity: var(--side-nav-arrow-hover-opacity);
+}
+
+#nav-tree .selected a {
+    color: var(--primary-color) !important;
+    font-weight: bolder;
+    font-weight: 600;
+}
+
+.ui-resizable-e {
+    background: var(--separator-color);
+    width: 1px;
+}
+
+/*
+ Contents
+ */
+
+div.header {
+    border-bottom: 1px solid var(--separator-color);
+    background-color: var(--page-background-color);
+    background-image: none;
+}
+
+div.contents, div.header .title, div.header .summary {
+    max-width: var(--content-maxwidth);
+}
+
+div.contents, div.header .title  {
+    line-height: initial;
+    margin: calc(var(--spacing-medium) + .2em) auto var(--spacing-medium) auto;
+}
+
+div.header .summary {
+    margin: var(--spacing-medium) auto 0 auto;
+}
+
+div.headertitle {
+    padding: 0;
+}
+
+div.header .title {
+    font-weight: 600;
+    font-size: 210%;
+    padding: var(--spacing-medium) var(--spacing-large);
+    word-break: break-word;
+}
+
+div.header .summary {
+    width: auto;
+    display: block;
+    float: none;
+    padding: 0 var(--spacing-large);
+}
+
+td.memSeparator {
+    border-color: var(--separator-color);
+}
+
+.mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams {
+    background: var(--code-background);
+}
+
+.mdescRight {
+    color: var(--page-secondary-foreground-color);
+}
+
+span.mlabel {
+    background: var(--primary-color);
+    border: none;
+    padding: 4px 9px;
+    border-radius: 12px;
+    margin-right: var(--spacing-medium);
+}
+
+span.mlabel:last-of-type {
+    margin-right: 2px;
+}
+
+div.contents {
+    padding: 0 var(--spacing-large);
+}
+
+div.contents p, div.contents li {
+    line-height: var(--content-line-height);
+}
+
+div.contents div.dyncontent {
+    margin: var(--spacing-medium) 0;
+}
+
+@media (prefers-color-scheme: dark) {
+    html:not(.light-mode) div.contents div.dyncontent img,
+    html:not(.light-mode) div.contents center img,
+    html:not(.light-mode) div.contents table img,
+    html:not(.light-mode) div.contents div.dyncontent iframe,
+    html:not(.light-mode) div.contents center iframe,
+    html:not(.light-mode) div.contents table iframe {
+        filter: hue-rotate(180deg) invert();
+    }
+}
+
+html.dark-mode div.contents div.dyncontent img,
+html.dark-mode div.contents center img,
+html.dark-mode div.contents table img,
+html.dark-mode div.contents div.dyncontent iframe,
+html.dark-mode div.contents center iframe,
+html.dark-mode div.contents table iframe {
+    filter: hue-rotate(180deg) invert();
+}
+
+h2.groupheader {
+    border-bottom: 1px solid var(--separator-color);
+    color: var(--page-foreground-color);
+}
+
+blockquote {
+    padding: var(--spacing-small) var(--spacing-medium);
+    background: var(--blockquote-background);
+    color: var(--blockquote-foreground);
+    border-left: 2px solid var(--blockquote-foreground);
+    margin: 0;
+}
+
+blockquote p {
+    margin: var(--spacing-small) 0 var(--spacing-medium) 0;
+}
+.paramname {
+    font-weight: 600;
+    color: var(--primary-dark-color);
+}
+
+.glow {
+    text-shadow: 0 0 15px var(--primary-light-color) !important;
+}
+
+.alphachar a {
+    color: var(--page-foreground-color);
+}
+
+/*
+ Table of Contents
+ */
+
+div.toc {
+    background-color: var(--side-nav-background);
+    border: 1px solid var(--separator-color);
+    border-radius: var(--border-radius-medium);
+    box-shadow: var(--box-shadow);
+    padding: 0 var(--spacing-large);
+    margin: 0 0 var(--spacing-medium) var(--spacing-medium);
+}
+
+div.toc h3 {
+    color: var(--side-nav-foreground);
+    font-size: var(--navigation-font-size);
+    margin: var(--spacing-large) 0;
+}
+
+div.toc li {
+    font-size: var(--navigation-font-size);
+    padding: 0;
+    background: none;
+}
+
+div.toc li:before {
+    content: '↓';
+    font-weight: 800;
+    font-family: var(--font-family);
+    margin-right: var(--spacing-small);
+    color: var(--side-nav-foreground);
+    opacity: .4;
+}
+
+div.toc ul li.level1 {
+    margin: 0;
+}
+
+div.toc ul li.level2, div.toc ul li.level3 {
+    margin-top: 0;
+}
+
+
+@media screen and (max-width: 767px) {
+    div.toc {
+        float: none;
+        width: auto;
+        margin: 0 0 var(--spacing-medium) 0;
+    }
+}
+
+/*
+ Code & Fragments
+ */
+
+code, div.fragment, pre.fragment {
+    border-radius: var(--border-radius-small);
+    border: none;
+    overflow: hidden;
+}
+
+code {
+    display: inline;
+    background: var(--code-background);
+    color: var(--code-foreground);
+    padding: 2px 6px;
+    word-break: break-word;
+}
+
+div.fragment, pre.fragment {
+    margin: var(--spacing-medium) 0;
+    padding: 14px 16px;
+    background: var(--fragment-background);
+    color: var(--fragment-foreground);
+    overflow-x: auto;
+}
+
+@media screen and (max-width: 767px) {
+    div.fragment, pre.fragment {
+        border-top-right-radius: 0;
+        border-bottom-right-radius: 0;
+    }
+
+    .contents > div.fragment, .textblock > div.fragment, .textblock > pre.fragment {
+        margin: var(--spacing-medium) calc(0px - var(--spacing-large));
+        border-radius: 0;
+    }
+
+    .textblock li > .fragment {
+        margin: var(--spacing-medium) calc(0px - var(--spacing-large));
+    }
+
+    .memdoc li > .fragment {
+        margin: var(--spacing-medium) calc(0px - var(--spacing-medium));
+    }
+
+    .memdoc > div.fragment, .memdoc > pre.fragment, dl dd > div.fragment, dl dd pre.fragment {
+        margin: var(--spacing-medium) calc(0px - var(--spacing-medium));
+        border-radius: 0;
+    }
+}
+
+code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span {
+    font-family: var(--font-family-monospace);
+    font-size: var(--code-font-size) !important;
+}
+
+div.line:after {
+    margin-right: var(--spacing-medium);
+}
+
+div.fragment .line, pre.fragment {
+    white-space: pre;
+    word-wrap: initial;
+    line-height: var(--fragment-lineheight);
+}
+
+div.fragment span.keyword {
+    color: var(--fragment-keyword);
+}
+
+div.fragment span.keywordtype {
+    color: var(--fragment-keywordtype);
+}
+
+div.fragment span.keywordflow {
+    color: var(--fragment-keywordflow);
+}
+
+div.fragment span.stringliteral {
+    color: var(--fragment-token)
+}
+
+div.fragment span.comment {
+    color: var(--fragment-comment);
+}
+
+div.fragment a.code {
+    color: var(--fragment-link) !important;
+}
+
+div.fragment span.preprocessor {
+    color: var(--fragment-preprocessor);
+}
+
+div.fragment span.lineno {
+    display: inline-block;
+    width: 27px;
+    border-right: none;
+    background: var(--fragment-linenumber-background);
+    color: var(--fragment-linenumber-color);
+}
+
+div.fragment span.lineno a {
+    background: none;
+    color: var(--fragment-link) !important;
+}
+
+div.fragment .line:first-child .lineno {
+    box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border);
+}
+
+/*
+ dl warning, attention, note, deprecated, bug, ...
+ */
+
+dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre {
+    padding: var(--spacing-medium);
+    margin: var(--spacing-medium) 0;
+    color: var(--page-background-color);
+    overflow: hidden;
+    margin-left: 0;
+    border-radius: var(--border-radius-small);
+}
+
+dl.section dd {
+    margin-bottom: 2px;
+}
+
+dl.warning, dl.attention {
+    background: var(--warning-color);
+    border-left: 8px solid var(--warning-color-dark);
+    color: var(--warning-color-darker);
+}
+
+dl.warning dt, dl.attention dt {
+    color: var(--warning-color-dark);
+}
+
+dl.note {
+    background: var(--note-color);
+    border-left: 8px solid var(--note-color-dark);
+    color: var(--note-color-darker);
+}
+
+dl.note dt {
+    color: var(--note-color-dark);
+}
+
+dl.bug {
+    background: var(--bug-color);
+    border-left: 8px solid var(--bug-color-dark);
+    color: var(--bug-color-darker);
+}
+
+dl.bug dt a {
+    color: var(--bug-color-dark) !important;
+}
+
+dl.deprecated {
+    background: var(--deprecated-color);
+    border-left: 8px solid var(--deprecated-color-dark);
+    color: var(--deprecated-color-darker);
+}
+
+dl.deprecated dt a {
+    color: var(--deprecated-color-dark) !important;
+}
+
+dl.section dd, dl.bug dd, dl.deprecated dd {
+    margin-inline-start: 0px;
+}
+
+dl.invariant, dl.pre {
+    background: var(--invariant-color);
+    border-left: 8px solid var(--invariant-color-dark);
+    color: var(--invariant-color-darker);
+}
+
+/*
+ memitem
+ */
+
+div.memdoc, div.memproto, h2.memtitle {
+    box-shadow: none;
+    background-image: none;
+    border: none;
+}
+
+div.memdoc {
+    padding: 0 var(--spacing-medium);
+    background: var(--page-background-color);
+}
+
+h2.memtitle, div.memitem {
+    border: 1px solid var(--separator-color);
+}
+
+div.memproto, h2.memtitle {
+    background: var(--code-background);
+    text-shadow: none;
+}
+
+h2.memtitle {
+    font-weight: 500;
+    font-family: monospace, fixed;
+    border-bottom: none;
+    border-top-left-radius: var(--border-radius-medium);
+    border-top-right-radius: var(--border-radius-medium);
+    word-break: break-all;
+}
+
+a:target + h2.memtitle, a:target + h2.memtitle + div.memitem {
+    border-color: var(--primary-light-color);
+}
+
+a:target + h2.memtitle {
+    box-shadow: -3px -3px 3px 0 var(--primary-lightest-color), 3px -3px 3px 0 var(--primary-lightest-color);
+}
+
+a:target + h2.memtitle + div.memitem {
+    box-shadow: 0 0 10px 0 var(--primary-lighter-color);
+}
+
+div.memitem {
+    border-top-right-radius: var(--border-radius-medium);
+    border-bottom-right-radius: var(--border-radius-medium);
+    border-bottom-left-radius: var(--border-radius-medium);
+    overflow: hidden;
+    display: block !important;
+}
+
+div.memdoc {
+    border-radius: 0;
+}
+
+div.memproto {
+    border-radius: 0 var(--border-radius-small) 0 0;
+    overflow: auto;
+    border-bottom: 1px solid var(--separator-color);
+    padding: var(--spacing-medium);
+    margin-bottom: -1px;
+}
+
+div.memtitle {
+    border-top-right-radius: var(--border-radius-medium);
+    border-top-left-radius: var(--border-radius-medium);
+}
+
+div.memproto table.memname {
+    font-family: monospace, fixed;
+    color: var(--page-foreground-color);
+}
+
+table.mlabels, table.mlabels > tbody {
+    display: block;
+}
+
+td.mlabels-left {
+    width: auto;
+}
+
+table.mlabels > tbody > tr:first-child {
+    display: flex;
+    justify-content: space-between;
+    flex-wrap: wrap;
+}
+
+.memname, .memitem span.mlabels {
+    margin: 0
+}
+
+/*
+ reflist
+ */
+
+dl.reflist {
+    box-shadow: var(--box-shadow);
+    border-radius: var(--border-radius-medium);
+    border: 1px solid var(--separator-color);
+    overflow: hidden;
+    padding: 0;
+}
+
+
+dl.reflist dt, dl.reflist dd {
+    box-shadow: none;
+    text-shadow: none;
+    background-image: none;
+    border: none;
+    padding: 12px;
+}
+
+
+dl.reflist dt {
+    font-weight: 500;
+    border-radius: 0;
+    background: var(--code-background);
+    border-bottom: 1px solid var(--separator-color);
+    color: var(--page-foreground-color)
+}
+
+
+dl.reflist dd {
+    background: none;
+}
+
+/*
+ Table
+ */
+
+table.markdownTable, table.fieldtable {
+    width: 100%;
+    border: 1px solid var(--separator-color);
+    margin: var(--spacing-medium) 0;
+}
+
+table.fieldtable {
+    box-shadow: none;
+    border-radius: var(--border-radius-small);
+}
+
+th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone {
+    background: var(--tablehead-background);
+    color: var(--tablehead-foreground);
+    font-weight: 600;
+    font-size: var(--page-font-size);
+}
+
+table.markdownTable td, table.markdownTable th, table.fieldtable dt {
+    border: 1px solid var(--separator-color);
+    padding: var(--spacing-small) var(--spacing-medium);
+}
+
+table.fieldtable th {
+    font-size: var(--page-font-size);
+    font-weight: 600;
+    background-image: none;
+    background-color: var(--tablehead-background);
+    color: var(--tablehead-foreground);
+    border-bottom: 1px solid var(--separator-color);
+}
+
+.fieldtable td.fieldtype, .fieldtable td.fieldname {
+    border-bottom: 1px solid var(--separator-color);
+    border-right: 1px solid var(--separator-color);
+}
+
+.fieldtable td.fielddoc {
+    border-bottom: 1px solid var(--separator-color);
+}
+
+.memberdecls td.glow, .fieldtable tr.glow {
+    background-color: var(--primary-light-color);
+    box-shadow: 0 0 15px var(--primary-lighter-color);
+}
+
+table.memberdecls {
+    display: block;
+    overflow-x: auto;
+    overflow-y: hidden;
+}
+
+
+/*
+ Horizontal Rule
+ */
+
+hr {
+    margin-top: var(--spacing-large);
+    margin-bottom: var(--spacing-large);
+    border-top:1px solid var(--separator-color);
+}
+
+.contents hr {
+    box-shadow: var(--content-maxwidth) 0 0 0 var(--separator-color), calc(0px - var(--content-maxwidth)) 0 0 0 var(--separator-color);
+}
+
+.contents img {
+    max-width: 100%;
+}
+
+/*
+ Directories
+ */
+div.directory {
+    border-top: 1px solid var(--separator-color);
+    border-bottom: 1px solid var(--separator-color);
+    width: auto;
+}
+
+table.directory {
+    font-family: var(--font-family);
+    font-size: var(--page-font-size);
+    font-weight: normal;
+}
+
+.directory td.entry {
+    padding: var(--spacing-small);
+    display: flex;
+    align-items: center;
+}
+
+.directory tr.even {
+    background-color: var(--odd-color);
+}
+
+.icona {
+    width: auto;
+    height: auto;
+    margin: 0 var(--spacing-small);
+}
+
+.icon {
+    background: var(--primary-color);
+    width: 18px;
+    height: 18px;
+    line-height: 18px;
+}
+
+.iconfopen, .icondoc, .iconfclosed {
+    background-position: center;
+    margin-bottom: 0;
+}
+
+.icondoc {
+    filter: saturate(0.2);
+}
+
+@media screen and (max-width: 767px) {
+    div.directory {
+        margin-left: calc(0px - var(--spacing-medium));
+        margin-right: calc(0px - var(--spacing-medium));
+    }
+}
+
+@media (prefers-color-scheme: dark) {
+    html:not(.light-mode) .iconfopen, html:not(.light-mode) .iconfclosed {
+        filter: hue-rotate(180deg) invert();
+    }
+}
+
+html.dark-mode .iconfopen, html.dark-mode .iconfclosed {
+    filter: hue-rotate(180deg) invert();
+}
+
+/*
+ Class list
+ */
+
+.classindex dl.odd {
+    background: var(--odd-color);
+    border-radius: var(--border-radius-small);
+}
+
+@media screen and (max-width: 767px) {
+    .classindex {
+        margin: 0 calc(0px - var(--spacing-small));
+    }
+}
+
+/*
+  Footer and nav-path
+ */
+
+#nav-path {
+    margin-bottom: -1px;
+    width: 100%;
+}
+
+#nav-path ul {
+    background-image: none;
+    background: var(--page-background-color);
+    border: none;
+    border-top: 1px solid var(--separator-color);
+    border-bottom: 1px solid var(--separator-color);
+    font-size: var(--navigation-font-size);
+}
+
+img.footer {
+    width: 60px;
+}
+
+.navpath li.footer {
+    color: var(--page-secondary-foreground-color);
+}
+
+address.footer {
+    margin-bottom: var(--spacing-large);
+}
+
+#nav-path li.navelem {
+    background-image: none;
+    display: flex;
+    align-items: center;
+}
+
+.navpath li.navelem a {
+    text-shadow: none;
+    display: inline-block;
+    color: var(--primary-color) !important;
+}
+
+.navpath li.navelem b {
+    color: var(--primary-dark-color);
+    font-weight: 500;
+}
+
+li.navelem {
+    padding: 0;
+    margin-left: -8px;
+}
+
+li.navelem:first-child {
+    margin-left: var(--spacing-large);
+}
+
+li.navelem:first-child:before {
+    display: none;
+}
+
+#nav-path li.navelem:after {
+    content: '';
+    border: 5px solid var(--page-background-color);
+    border-bottom-color: transparent;
+    border-right-color: transparent;
+    border-top-color: transparent;
+    transform: scaleY(4.2);
+    z-index: 10;
+    margin-left: 6px;
+}
+
+#nav-path li.navelem:before {
+    content: '';
+    border: 5px solid var(--separator-color);
+    border-bottom-color: transparent;
+    border-right-color: transparent;
+    border-top-color: transparent;
+    transform: scaleY(3.2);
+    margin-right: var(--spacing-small);
+}
+
+.navpath li.navelem a:hover {
+    color: var(--primary-color);
+}
+
+/*
+  Optional Dark mode toggle button
+*/
+
+doxygen-awesome-dark-mode-toggle {
+    display: inline-block;
+    margin: 0 0 0 var(--spacing-small);
+    padding: 0;
+    width: var(--searchbar-height);
+    height: var(--searchbar-height);
+    background: none;
+    border: none;
+    font-size: 23px;
+    border-radius: var(--border-radius-medium);
+    vertical-align: middle;
+    text-align: center;
+    line-height: var(--searchbar-height);
+}
+
+doxygen-awesome-dark-mode-toggle:hover {
+    background: var(--separator-color);
+}
+
+doxygen-awesome-dark-mode-toggle:after {
+    content: var(--darkmode-toggle-button-icon)
+}
diff --git a/docs/css/doxygen-awesome-css/img/screenshot.png b/docs/css/doxygen-awesome-css/img/screenshot.png
new file mode 100644 (file)
index 0000000..c65033f
Binary files /dev/null and b/docs/css/doxygen-awesome-css/img/screenshot.png differ
diff --git a/docs/css/doxygen-awesome-css/img/theme-variations.drawio.svg b/docs/css/doxygen-awesome-css/img/theme-variations.drawio.svg
new file mode 100644 (file)
index 0000000..c6b395f
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1001px" height="401px" viewBox="-0.5 -0.5 1001 401" content="&lt;mxfile host=&quot;drawio-plugin&quot; modified=&quot;2021-03-17T15:33:31.636Z&quot; agent=&quot;5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36&quot; etag=&quot;RyKBBCdKCVcXAhIW2RaO&quot; version=&quot;13.7.9&quot; type=&quot;embed&quot;&gt;&lt;diagram id=&quot;6E4AiNPWWr3a8GvC3Ypl&quot; name=&quot;Page-1&quot;&gt;1VlNc5swEP01nkkPZRACAcfYsdNL24Mz07NiFGAqkEeWY6e/vgIkAxbUJJh4Chkinj7Qvt2VXpQZXGTHR463yXcWETpz7Og4gw8zxwlCWz4L4K0CPM+tgJinUQWBGlinf4gCVb94n0Zk12ooGKMi3bbBDctzshEtDHPODu1mL4y2v7rFMTGA9QZTE/2VRiJRZnl2jX8jaZzoLwNb1WRYN1bALsEROzQguJzBBWdMVKXsuCC04E7zUvVb9dSeJsZJLgZ18Koer5jutXGWfJ/jHZG/nhKSETVT8abNF+QoB58nIqMSALKIaRrnsryRnyVcAq+Ei1QSdq8qsjSKiu7zQ5IKst7iTTHWQUaHxDjb5xGJ1FgvLBfK5XJ26l19vKxPKV0wyng5Gbi6L27VroHb5SVxkxLFUjFHcmxAiqJHwjIi+Jtsomt931JEqYiFgXLgofY/gKpN0vC9djRWIRefBq+9IgvKMT1OQoaTDJ/EksTtcFNPuYGf9Qh2NwUNA12dt00DoXcFCwcYWAeJ3RNGjXjsIAL1MHEji13D4oWM32K6owzfCc5+k0YaLMt7LCW6NgwsDwJ0uvxWUriuFfjAD139NFJEjmAhD4HT1ZEwPrD80HehF5TPcDzXjsH1UyooecZconc/8GsaY5GyfFbkgCTKXhPMN8mXca44W6celsuH1Wrq2OxxwRj2oMHeWu6+BnnXZWvlF/dYtgbHJXCQ5csNHOgf+CmBaW6+K7nzk5LZOSc42vB9tt2NpPYaFMqktxAyEv/iUgkt2LrQeNJ8Mx7LdP0HSWBiklQtLCLEcQH0Qwhs6LYlAziPQscMQxtYurMbOL6OsSalZ45AKBhPadC9QBqMmsKvvd/kLCdnuawgLRApeREfl4d2Wx46PfLu/fsasoIQeR7Q3nPe6zkZ6E2/BahDCk7hOWBmg+G1yaSh6uUBUwtPJ5zCywaPXR39HmZuJBU1vTfVisM5aWlFnQ6OfaYV+5LBEIt1UgK3g2D7GgQDg+Ba4swcRIsl61m+oLgo3anFUYnFW0igD0VoJXLq7cnt2F2uE7Cm4P4kXfP+KO3hZLDsgQhaOsLLPaSD0wlEEOhQ5dOooA9QaqEWpUGLUhe0E79DjN9IBQHzb/L/WgZd23MAXFyybyaDTAXrFMeYahn/+jOnhZ1DjzM73fmpZ5w9Z5nnW0R5XeeMUzrCcgYcctZHoSOPOeVrfc5d1jX+WQCXfwE=&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><rect x="177.5" y="380" width="135" height="20" rx="3" ry="3" fill="#fafafa" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 133px; height: 1px; padding-top: 390px; margin-left: 179px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 15px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">1. Base Theme</div></div></div></foreignObject><text x="245" y="395" fill="#000000" font-family="Helvetica" font-size="15px" text-anchor="middle" font-weight="bold">1. Base Theme</text></switch></g><rect x="0" y="0" width="490" height="350" fill="#ffffff" stroke="#000000" pointer-events="all"/><rect x="198.53" y="44.87" width="219.66" height="271.8" fill="#ffffff" stroke="#e3e3e3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 181px; margin-left: 200px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Content</div></div></div></foreignObject><text x="308" y="184" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Content</text></switch></g><rect x="0" y="0" width="490" height="44.87" fill="#deedff" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 488px; height: 1px; padding-top: 22px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Titlebar (Navigation + Search)</div></div></div></foreignObject><text x="245" y="26" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Titlebar (Navigation + Search)</text></switch></g><rect x="0" y="44.87" width="126.73" height="271.8" fill="#f7f7f7" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 125px; height: 1px; padding-top: 181px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Sidebar (Navigation)</div></div></div></foreignObject><text x="63" y="184" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Sidebar (Navigation)</text></switch></g><rect x="0" y="316.67" width="490" height="33.33" fill="#ffffff" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 488px; height: 1px; padding-top: 333px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Footer (Breadcrumbs)</div></div></div></foreignObject><text x="245" y="337" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Footer (Breadcrumbs)</text></switch></g><rect x="371.72" y="14.87" width="101.38" height="16.67" rx="2.5" ry="2.5" fill="#ffffff" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 99px; height: 1px; padding-top: 23px; margin-left: 373px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Search</div></div></div></foreignObject><text x="422" y="27" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Search</text></switch></g><rect x="16.9" y="14.87" width="33.79" height="16.67" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 32px; height: 1px; padding-top: 23px; margin-left: 19px;"><div style="box-sizing: border-box; font-size: 0; text-align: left; "><div style="display: inline-block; font-size: 20px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Title</div></div></div></foreignObject><text x="19" y="29" fill="#000000" font-family="Helvetica" font-size="20px">Tit...</text></switch></g><rect x="510" y="0" width="490" height="350" fill="#ffffff" stroke="#000000" pointer-events="all"/><rect x="708.53" y="16.67" width="219.66" height="300" fill="#ffffff" stroke="#e3e3e3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 167px; margin-left: 710px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Content</div></div></div></foreignObject><text x="818" y="170" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Content</text></switch></g><rect x="510" y="0" width="126.72" height="350" fill="#f7f7f7" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 125px; height: 1px; padding-top: 175px; margin-left: 511px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Sidebar <br />(Title + Navigation)</div></div></div></foreignObject><text x="573" y="179" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Sidebar...</text></switch></g><rect x="636.72" y="316.67" width="363.28" height="33.33" fill="#ffffff" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 361px; height: 1px; padding-top: 333px; margin-left: 638px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Footer (Breadcrumbs)</div></div></div></foreignObject><text x="818" y="337" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Footer (Breadcrumbs)</text></switch></g><rect x="522.67" y="41.67" width="101.38" height="16.67" rx="2.5" ry="2.5" fill="#ffffff" stroke="#000000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 99px; height: 1px; padding-top: 50px; margin-left: 524px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Search</div></div></div></foreignObject><text x="573" y="54" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">Search</text></switch></g><rect x="522.67" y="11.67" width="33.79" height="16.67" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 32px; height: 1px; padding-top: 20px; margin-left: 525px;"><div style="box-sizing: border-box; font-size: 0; text-align: left; "><div style="display: inline-block; font-size: 20px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">Title</div></div></div></foreignObject><text x="525" y="26" fill="#000000" font-family="Helvetica" font-size="20px">Tit...</text></switch></g><rect x="666.25" y="380" width="177.5" height="20" rx="3" ry="3" fill="#ffffff" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 176px; height: 1px; padding-top: 390px; margin-left: 667px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; "><div style="display: inline-block; font-size: 15px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">2. Sidebar-Only Theme</div></div></div></foreignObject><text x="755" y="395" fill="#000000" font-family="Helvetica" font-size="15px" text-anchor="middle" font-weight="bold">2. Sidebar-Only Theme</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://desk.draw.io/support/solutions/articles/16000042487" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg>\r
diff --git a/docs/css/doxygen-awesome-css/include/MyLibrary/example.hpp b/docs/css/doxygen-awesome-css/include/MyLibrary/example.hpp
new file mode 100644 (file)
index 0000000..76f9088
--- /dev/null
@@ -0,0 +1,98 @@
+#pragma once
+#include <string>
+
+namespace MyLibrary {
+
+enum Color { red, green, blue };
+
+/**
+ * Example class to demonstrate the features of the custom CSS.
+ *
+ * @author jothepro
+ *
+ */
+class Example {
+public:
+    /**
+     * @brief brief summary
+     *
+     * doxygen test documentation
+     *
+     * @param test this is the only parameter of this test function. It does nothing!
+     *
+     * # Supported elements
+     *
+     * These elements have been tested with the custom CSS.
+     *
+     *
+     * ## Lists
+     *
+     * - element 1
+     * - element 2
+     *
+     * 1. element 1
+     *    ```
+     *    code in lists
+     *    ```
+     * 2. element 2
+     *
+     * ## Quotes
+     *
+     * > This is an **awesome** design...
+     * >
+     * > ...do you agree?
+     * *- jothepro*
+     *
+     * ## Code block
+     *
+     * ```
+     * code within md fences (```)
+     * ```
+     *
+     * @code{.cpp}
+     * // code within @code block
+     * if(true) {
+     *    auto example = std::make_shared<Example>(5);
+     *    example->test("test");
+     * }
+     * 
+     * @endcode
+     *
+     *     // code within indented code block
+     *     auto test = std::shared_ptr<Example(5);
+     *
+     *
+     * Inline `code` elements in a text. Lorem Ipsum set dolor. This also works within multiline text and does not break the `layout`.
+     *
+     *
+     * ## special hints
+     *
+     * @warning this is a warning only for demonstration purposes
+     *
+     * @note this is a note to show that notes work. They can also include `code`:
+     * @code{.c}
+     * void this_looks_awesome();
+     * @endcode
+     *
+     * @bug this css has no bugs, it is perfect... NOT!
+     *
+     * @deprecated None of this will be deprecated, because it's beautiful!
+     *
+     * @invariant This is an invariant
+     *
+     * @pre This is a precondition
+     *
+     *
+     *
+     */
+    std::string test(const std::string& test);
+
+    virtual int virtualfunc() = 0;
+
+    static bool staticfunc();
+
+
+};
+
+}
+
diff --git a/docs/css/doxygen-awesome-css/include/MyLibrary/subclass-example.hpp b/docs/css/doxygen-awesome-css/include/MyLibrary/subclass-example.hpp
new file mode 100644 (file)
index 0000000..dce8bdd
--- /dev/null
@@ -0,0 +1,26 @@
+#pragma once
+#include <string>
+#include "example.hpp"
+#include <iostream>
+
+namespace MyLibrary {
+
+    class SubclassExample : public Example {
+    public:
+
+        /**
+         * @bug second bug
+         * @return
+         */
+        int virtualfunc() override;
+
+        std::shared_ptr<std::string> super_long_function_with_lots_of_parameters(std::shared_ptr<std::string>& text, std::shared_ptr<std::string>& text2) {
+            if(true) {
+                std::cout << "this even has some code." << std::endl;
+            }
+        }
+
+    };
+
+}
+
diff --git a/docs/css/doxygen-awesome-css/logo.drawio.svg b/docs/css/doxygen-awesome-css/logo.drawio.svg
new file mode 100644 (file)
index 0000000..a506ee0
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="61px" height="74px" viewBox="-0.5 -0.5 61 74" content="&lt;mxfile host=&quot;drawio-plugin&quot; modified=&quot;2021-03-16T23:58:23.462Z&quot; agent=&quot;5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36&quot; version=&quot;13.7.9&quot; etag=&quot;JoeaGLJ54FcERO7YrWLQ&quot; type=&quot;embed&quot;&gt;&lt;diagram id=&quot;JMB9aH8b_oZ7EWDuqJgx&quot; name=&quot;Page-1&quot;&gt;7VdNc5swEP01HDsjkGPDsSVJe+lMZnzoWYENaAwsI8ux6a+vCCtA4KSu62kmSS+M9LT7tB9P0uDxuDx8VaLOv2MKhRew9ODxay8Igigy3xZoCOC8AzIl0w7yB2AtfwKBjNCdTGHrGGrEQsvaBROsKki0gwmlcO+aPWDh7lqLDGbAOhHFHP0hU513aHjFBvwbyCy3O/uMVkphjQnY5iLF/QjiNx6PFaLuRuUhhqKtna1L53f7zGofmIJKn+RAcTyKYkfJUWC6sdlmCnc1mYHScDhWY3Fvzdk8Br/PzCgCsAStGmNCRJy2JDH4pIV8VMG+edS4rCcZcjMDSu+ZVP3fpwpV+rnVh5ndF5hsPP4l16VhvPbN8AErTWI0re7mMRaonpw5Y8tlHBvcsNzKwnpttVDaslZYgcXIhj3NFW56LS1bbrM44l6m4Wq5MLhxzEDfgZKmAKDWtUhklRFNgqVM7LYb0Enu8I9j9dkVC80KtgS6Lb3fGnYVgXSm/1Ez2fFu7oeTYA/CuIUWU1AILR9d/mN9pR3uUJqde7F88leOWhYLl2GLO5UAOY2FP+GxMm3c6CwNlXlKY9oompFZ3Rps59EOkuw8BoH2BTtNs8EfaZbUdYZkXQGuXhDgR9DYRBycXURj00D+UmMT2ktJLnr9B8HG0IzFcPkHYfUe3oPZqfOjMEiDs1+KEw5n9P/+/1f3f/gq1394lt7erqQ+0HVvpsPPRWc+/KHxm18=&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><path d="M 13 57 L 13.01 57.01 L 15.87 50.14 L 18.37 43.14 L 20.91 36.15 L 23.67 29.25 L 26.4 22.33 Q 30 13 33.71 22.28 L 33.55 22.22 L 35.48 26.91 L 37.49 31.64 L 39.48 36.36 L 41.2 40.97 L 43.05 45.63" fill="none" stroke="#010508" stroke-opacity="0.1" stroke-width="6" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 47.51 56.77 L 47.65 56.93 L 45.43 54.91 L 43.41 53.11 L 41.43 51.35 L 39.63 49.8 L 37.48 47.86 L 37.39 47.64 L 39.79 47.17 L 41.9 45.98 L 44.24 45.37 L 46.48 44.52 L 48.62 43.4 L 48.54 43.39 L 48.58 46.09 L 48.04 48.74 L 48.04 51.43 L 47.8 54.1 L 47.51 56.77 Z Z" fill-opacity="0.1" fill="#010508" stroke="#010508" stroke-opacity="0.1" stroke-width="6" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 10 43 L 9.94 42.88 L 12.16 41.98 L 14.31 40.96 L 16.51 40.01 L 18.62 38.89 L 20.88 38.1 Q 30 34 40 34 L 40 33.75 L 42 33.83 L 44 33.8 L 46 33.79 L 48 34.05 L 50 34" fill="none" stroke="#010508" stroke-opacity="0.1" stroke-width="7" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 10 54 L 9.97 53.99 L 12.69 47.07 L 15.43 40.16 L 18.07 33.21 L 20.65 26.24 L 23.4 19.33 Q 27 10 30.71 19.28 L 30.66 19.26 L 32.46 23.91 L 34.55 28.66 L 36.26 33.27 L 38.35 38.03 L 40.05 42.63" fill="none" stroke="#1982d2" stroke-width="6" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 44.51 53.77 L 44.56 53.83 L 42.48 51.97 L 40.5 50.21 L 38.48 48.41 L 36.41 46.56 L 34.48 44.86 L 34.55 45.02 L 36.72 44 L 39 43.24 L 41.21 42.28 L 43.48 41.51 L 45.62 40.4 L 45.78 40.42 L 45.51 43.09 L 45.01 45.74 L 44.87 48.42 L 44.94 51.12 L 44.51 53.77 Z Z" fill="#1982d2" stroke="#1982d2" stroke-width="6" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/><path d="M 7 40 L 7.02 40.05 L 9.28 39.25 L 11.33 38 L 13.48 36.96 L 15.73 36.14 L 17.88 35.1 Q 27 31 37 31 L 37 30.79 L 39 31.11 L 41 30.85 L 43 30.78 L 45 30.89 L 47 31" fill="none" stroke="#1982d2" stroke-width="8" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="stroke"/></g></svg>
\ No newline at end of file
diff --git a/docs/internal-api.md b/docs/internal-api.md
new file mode 100644 (file)
index 0000000..18dd15b
--- /dev/null
@@ -0,0 +1,37 @@
+# Internal documentation of LWNode.js
+
+These flags and variables are for LWNode.js core development usage only. Do not use them in your own applications.
+
+## CLI
+
+### Flags
+
+#### `--internal-log`
+
+If the `--internal-log` flag is specified or the `LWNODE_INTERNAL_LOG` environment variable is set to 1, LWNode will print internal logs in release build.
+
+#### `--trace-call[=[-]trace id[,<trace id>]]`
+
+If the `--trace-call` flag is specified or the `LWNODE_TRACE_CALL` environment variable is set to trace ids, LWNode will print trace call logs in debug build. Setting trace id with `-` will negate printing trace logs for the specific id.
+
+```shell
+--trace-call=COMMON,ISOLATE
+
+# or
+
+export LWNODE_TRACE_CALL=COMMON,ISOLATE
+```
+
+### Environment variables
+
+#### `LWNODE_INTERNAL_LOG`
+
+Refer to the description above.
+
+#### `LWNODE_TRACE_CALL`
+
+Refer to the description above.
+
+#### `LWNODE_RUNNING_ON_TESTS`
+
+If the `LWNODE_RUNNING_ON_TESTS` environment variable is set to 1, LWNode will ignore comparing error messages in detail while using `assert.throw` and similars. This is used as default when using `tools/test.py`. Please refer to https://github.sec.samsung.net/lws/node-escargot/issues/1002 for more information.
diff --git a/docs/spec.md b/docs/spec.md
new file mode 100644 (file)
index 0000000..3ed5100
--- /dev/null
@@ -0,0 +1,68 @@
+# Lightweight Node.js Specification
+
+* Forked version: 14.14
+
+* Node.js APIs
+  - Supported Features
+    - [Assertion](https://nodejs.org/dist/latest-v14.x/docs/api/assert.html)
+    - [Buffer](https://nodejs.org/dist/latest-v14.x/docs/api/buffer.html)
+    - [C/C++ addons with Node-API](https://nodejs.org/dist/latest-v14.x/docs/api/n-api.html)
+    - [Console](https://nodejs.org/dist/latest-v14.x/docs/api/console.html)
+    - [Crypto](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html)
+    - [DNS](https://nodejs.org/dist/latest-v14.x/docs/api/dns.html)
+    - [Errors](https://nodejs.org/dist/latest-v14.x/docs/api/errors.html)
+    - [Events](https://nodejs.org/dist/latest-v14.x/docs/api/events.html)
+    - [File system](https://nodejs.org/dist/latest-v14.x/docs/api/fs.html)
+    - [Globals](https://nodejs.org/dist/latest-v14.x/docs/api/globals.html)
+    - [HTTP](https://nodejs.org/dist/latest-v14.x/docs/api/http.html)
+    - [HTTPS](https://nodejs.org/dist/latest-v14.x/docs/api/https.html)
+    - [Modules: CommonJS modules](https://nodejs.org/dist/latest-v14.x/docs/api/modules.html)
+    - [Net](https://nodejs.org/dist/latest-v14.x/docs/api/net.html)
+    - [OS](https://nodejs.org/dist/latest-v14.x/docs/api/os.html)
+    - [Path](https://nodejs.org/dist/latest-v14.x/docs/api/path.html)
+    - [Process](https://nodejs.org/dist/latest-v14.x/docs/api/process.html)
+    - [Query strings](https://nodejs.org/dist/latest-v14.x/docs/api/querystring.html)
+    - [Stream](https://nodejs.org/dist/latest-v14.x/docs/api/stream.html)
+    - [String decoder](https://nodejs.org/dist/latest-v14.x/docs/api/string_decoder.html)
+    - [Timers](https://nodejs.org/dist/latest-v14.x/docs/api/timers.html)
+    - [TLS/SSL](https://nodejs.org/dist/latest-v14.x/docs/api/tls.html)
+    - [UDP/datagram](https://nodejs.org/dist/latest-v14.x/docs/api/dgram.html)
+    - [URL](https://nodejs.org/dist/latest-v14.x/docs/api/url.html)
+    - [Utilities](https://nodejs.org/dist/latest-v14.x/docs/api/util.html)
+    - [Zlib](https://nodejs.org/dist/latest-v14.x/docs/api/zlib.html)
+  - Supported (Possibly) but Not Opened Features
+    - Experimental
+      - [Async hooks](https://nodejs.org/dist/latest-v14.x/docs/api/async_hooks.html)
+      - [Modules: ECMAScript modules](https://nodejs.org/dist/latest-v14.x/docs/api/esm.html)
+      - [Modules: `module` API](https://nodejs.org/dist/latest-v14.x/docs/api/module.html)
+      - [Modules: Packages](https://nodejs.org/dist/latest-v14.x/docs/api/packages.html)
+    - Deprecated
+      - [Domain](https://nodejs.org/dist/latest-v14.x/docs/api/domain.html)
+      - [Punycode](https://nodejs.org/dist/latest-v14.x/docs/api/punycode.html)
+    - [Command-line options](https://nodejs.org/dist/latest-v14.x/docs/api/cli.html)
+    - [Child processes](https://nodejs.org/dist/latest-v14.x/docs/api/child_process.html)
+    - [Cluster](https://nodejs.org/dist/latest-v14.x/docs/api/cluster.html)
+    - [HTTP/2](https://nodejs.org/dist/latest-v14.x/docs/api/http2.html)
+    - [Internationalization](https://nodejs.org/dist/latest-v14.x/docs/api/intl.html)
+    - [Readline](https://nodejs.org/dist/latest-v14.x/docs/api/readline.html)
+    - [REPL](https://nodejs.org/dist/latest-v14.x/docs/api/repl.html)
+    - [TTY](https://nodejs.org/dist/latest-v14.x/docs/api/tty.html)
+  - Unsupported Features
+    - Experimental
+      - [WASI](https://nodejs.org/dist/latest-v14.x/docs/api/wasi.html)
+      - [Policies](https://nodejs.org/dist/latest-v14.x/docs/api/policy.html)
+      - [Trace events](https://nodejs.org/dist/latest-v14.x/docs/api/tracing.html)
+    - [C++ addons](https://nodejs.org/dist/latest-v14.x/docs/api/addons.html)
+    - [C++ embedder API](https://nodejs.org/dist/latest-v14.x/docs/api/embedding.html)
+    - [Debugger](https://nodejs.org/dist/latest-v14.x/docs/api/debugger.html)
+    - [Deprecated APIs](https://nodejs.org/dist/latest-v14.x/docs/api/deprecations.html)
+    - [Worker threads](https://nodejs.org/dist/latest-v14.x/docs/api/worker_threads.html)
+    - [Diagnostics Channel](https://nodejs.org/dist/latest-v14.x/docs/api/diagnostics_channel.html)
+    - [Inspector](https://nodejs.org/dist/latest-v14.x/docs/api/inspector.html)
+    - [Report](https://nodejs.org/dist/latest-v14.x/docs/api/report.html)
+    - [V8](https://nodejs.org/dist/latest-v14.x/docs/api/v8.html)
+    - [VM](https://nodejs.org/dist/latest-v14.x/docs/api/vm.html)
+    - [Performance hooks](https://nodejs.org/dist/latest-v14.x/docs/api/perf_hooks.html)
+
+* ECMAScript
+  * [node.green](https://node.green/) provides an overview over supported ECMAScript features in our target version of Node.js, `v14.14`.
index 08ef18240925bae4651fe7466316ef7e0c4daeaa..9248a2f1eadfd61de9f7b6c18f57e0ea0a7bf33a 100644 (file)
@@ -573,6 +573,13 @@ function compareExceptionKey(actual, expected, key, message, keys, fn) {
   }
 }
 
+// @lwnode
+function canIgnoreErrorMessage() {
+  const useEscargot = process.config.variables.javascript_engine == "escargot";
+  const isRunningOnTests = !!process.env["LWNODE_RUNNING_ON_TESTS"];
+  return useEscargot && isRunningOnTests;
+}
+
 function expectedException(actual, expected, message, fn) {
   let generatedMessage = false;
   let throwError = false;
@@ -619,6 +626,9 @@ function expectedException(actual, expected, message, fn) {
             RegExpPrototypeTest(expected[key], actual[key])) {
           continue;
         }
+        if (key == 'message' && canIgnoreErrorMessage()) {
+          continue;
+        }
         compareExceptionKey(actual, expected, key, message, keys, fn);
       }
       return;
index b8bec1e5200df91a8bfc2688c30c2235b4f7d4c9..d05f0bc61ae2bb63df0b1cd34bde75ec5331510c 100644 (file)
@@ -467,6 +467,16 @@ function fromString(string, encoding) {
     if (string.length === 0)
       return new FastBuffer();
   }
+
+  // @lwnode
+  // if the given string with latin1 or ascii encoding is not
+  // being handled as one byte string in JS engine, we newly create it.
+  if (ops == encodingOps.latin1 || ops == encodingOps.ascii) {
+    if (process.lwnode.checkIfHandledAsOneByteString(string) == false) {
+      return fromStringFast(`${string}`, ops);
+    }
+  }
+
   return fromStringFast(string, ops);
 }
 
index d5715aa9f8c666e4222812dc9f051b732d3252e8..8ae84f4aaec37bf4f7fdb4bcb3563c2f618b5d46 100644 (file)
@@ -102,6 +102,11 @@ const internalBindingWhitelist = new SafeSet([
   'zlib'
 ]);
 
+// @lwnode
+const userModuleBlacklist = [
+  'v8',
+];
+
 // Set up process.binding() and process._linkedBinding().
 {
   const bindingObj = ObjectCreate(null);
@@ -168,7 +173,10 @@ class NativeModule {
   constructor(id) {
     this.filename = `${id}.js`;
     this.id = id;
-    this.canBeRequiredByUsers = !id.startsWith('internal/');
+    // this.canBeRequiredByUsers = !id.startsWith('internal/');
+    // @lwnode
+    this.canBeRequiredByUsers =
+      !id.startsWith("internal/") && !userModuleBlacklist.includes(id);
 
     // The CJS exports object of the module.
     this.exports = {};
index 284add2f3dc3e834b1ba3047049ea93c32f6114a..c9a9caa8298f2d9cd899ffe1c19c64589e4f99f3 100644 (file)
@@ -63,6 +63,11 @@ function createProcessEntry(binding) {
         return binding.MemSnapshot.apply(null, args);
       }
     },
+    checkIfHandledAsOneByteString: (...args) => {
+      if (binding.checkIfHandledAsOneByteString) {
+        return binding.checkIfHandledAsOneByteString.apply(null, args);
+      }
+    },
     isReloadScriptEnabled: () => {
       return !!binding.CreateReloadableSourceFromFile;
     },
index 5ab8701bf6b1833e5d8cf9f56a8fd7fc0a6889f6..a49bb17df5f031d7c403727bb9b4911daf3129b4 100755 (executable)
 ROOT_PATH=out/cctest
 
 ./tools/gyp/gyp ./lwnode/code/escargotshim/test/cctest.gyp --depth=. -f ninja \
-  --generator-output=$ROOT_PATH -Dbuild_asan=1 -Dbuild_mode=debug \
+  --generator-output=$ROOT_PATH -Dasan=1 -Dbuild_mode=debug \
   -Descargot_lib_type=static_lib -Dtarget_arch=x64 -Dtarget_os=linux \
-  -Denable_experimental=true -Descargot_threading=1
+  -Denable_experimental=true -Descargot_threading=1 -Dinclude_node_bindings=false \
+  -Descargot_debugger=false
 
 ninja -v -C $ROOT_PATH/out/Debug cctest
 
diff --git a/lwnode/build-modules.sh b/lwnode/build-modules.sh
new file mode 100755 (executable)
index 0000000..f51787a
--- /dev/null
@@ -0,0 +1,96 @@
+#!/bin/bash
+# Copyright (c) 2022-present Samsung Electronics Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+TARGET_OS="linux"
+
+PROJECT_ROOT_PATH=$PWD
+MODULES_ROOT_PATH=$PROJECT_ROOT_PATH/lwnode/modules
+BUILD_OUT_ROOT_PATH=$PROJECT_ROOT_PATH/out/modules
+LWNODE_INCLUDES_PATH="$PROJECT_ROOT_PATH/src;$PROJECT_ROOT_PATH/lwnode/code/escargotshim/include"
+
+fancy_echo() {
+  local BOLD="\033[1m"
+  local GREEN="\033[1;32m"
+  local CLEAR="\033[0m"
+  echo -e ""
+  echo -e ${GREEN}$1$2${CLEAR}
+}
+
+error_echo() {
+  local BOLD="\033[1m"
+  local RED="\033[1;31m"
+  local CLEAR="\033[0m"
+  echo -e ""
+  echo -e ${RED}$1$2${CLEAR}
+}
+
+usage() {
+  echo "Usage: build-modules.sh <modules-list> [options]"
+  echo "
+   options:
+    --os)       target os (linux/tizen)
+    "
+  echo "example) build-modules.sh hello-world,device-api --os=tizen
+       "
+}
+
+find_and_build_modules() {
+  local module_list=($(echo $1 | tr "," "\n"))
+
+  for module in "${module_list[@]}"; do
+    if [ -d "$MODULES_ROOT_PATH/$module" ]; then
+      build_module $module
+    else
+      error_echo "Cannot find module: $module"
+    fi
+  done
+}
+
+build_module() {
+  fancy_echo "build [$1]"
+
+  local out_path=$BUILD_OUT_ROOT_PATH/$TARGET_OS/$1
+  local module_path=$MODULES_ROOT_PATH/$1
+  mkdir -p $out_path
+
+  cmake $module_path -B$out_path -H$module_path -DLWNODE_INCLUDES=$LWNODE_INCLUDES_PATH \
+    -G Ninja
+  ninja -C $out_path
+}
+
+if [[ -z $1 ]] || [[ $1 == -* ]]; then
+  usage
+  exit 1
+fi
+
+MODULES_LIST=$1
+shift
+
+while [[ $# -gt 0 ]]; do
+  case "$1" in
+  --os=*)
+    TARGET_OS="${1#*=}"
+    ;;
+  *)
+    echo "Unknown option $1"
+    exit -1
+    ;;
+  esac
+
+  shift
+done
+
+fancy_echo "target os: $TARGET_OS"
+find_and_build_modules $MODULES_LIST
index 0e9c682f88399096aa80a6d8c9ef007fe42fe412..8e808e9a56cfcf6c607ec00c87b4e56f718a046b 100755 (executable)
@@ -19,7 +19,10 @@ set -e
 ROOT_PATH=./out/sample
 
 gyp ./lwnode/code/escargotshim/sample/sample.gyp --depth=. -f ninja \
-  --generator-output=$ROOT_PATH -Dbuild_asan=1 -Dbuild_mode=debug \
-  -Descargot_lib_type=static_lib
+  --generator-output=$ROOT_PATH \
+  -Descargot_lib_type=static_lib -Dtarget_arch=x64 -Dtarget_os=linux \
+  -Dbuild_mode=debug \
+  -Descargot_threading=1 \
+  -Dinclude_node_bindings=false
 
 ninja -v -C $ROOT_PATH/out/Debug sample
index f7e074e5b09d29c6a8050194ccb7b901bfe00044..8ee6d9076baf06d0ab7aee1658ea31abe049c07d 100755 (executable)
@@ -4,7 +4,7 @@
     'target_os%': 'none',  # configure with --tizen
     'build_mode%': 'release',
     'build_host%': '<(OS)',
-    'build_asan%': '0',
+    'asan%': '0',
   },
   'target_defaults': {
     'defines': [ 'LWNODE=1' ],
@@ -57,7 +57,7 @@
           ],
         },
       }],
-      ['build_asan==1', {
+      ['asan==1', {
         'cflags+':    [ '-fsanitize=address', '-fno-omit-frame-pointer', '-fno-common', '-D_FORTIFY_SOURCE=2' ],
         'cflags_cc+': [ '-fsanitize=address', '-fno-omit-frame-pointer', '-fno-common', '-D_FORTIFY_SOURCE=2' ],
         'cflags!': [ '-fomit-frame-pointer' ],
index ee7f7ee1e2127edb1ee57730a2c9dd891c43a030..dabf7dca792b7fa2971a2dc48edccde2e1970b3e 100644 (file)
@@ -136,7 +136,7 @@ IF (ESCARGOT_LIBICU_SUPPORT)
 ENDIF()
 
 IF (ESCARGOT_USE_CUSTOM_LOGGING)
-    SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DESCARGOT_USE_CUSTOM_LOGGING)
+    SET (ESCARGOT_DEFINITIONS ${ESCARGOT_DEFINITIONS} -DENABLE_CUSTOM_LOGGING)
 ELSEIF (${ESCARGOT_HOST} STREQUAL "tizen_obs")
     PKG_CHECK_MODULES (DLOG REQUIRED dlog)
     SET (ESCARGOT_LIBRARIES ${ESCARGOT_LIBRARIES} ${DLOG_LIBRARIES})
index 5359820e1f25d54b12ddbf10a2a68b47c779f122..f6574fdf1c9344c774942e2f9a48f5c1a74a65b6 100644 (file)
@@ -148,7 +148,7 @@ ENDIF()
 IF (${ESCARGOT_OUTPUT} MATCHES "shell")
     ADD_EXECUTABLE (${ESCARGOT_TARGET} ${ESCARGOT_SRC_LIST})
 
-    TARGET_LINK_LIBRARIES (${ESCARGOT_TARGET} ${ESCARGOT_LIBRARIES} ${ESCARGOT_LDFLAGS} ${LDFLAGS_FROM_ENV})
+    TARGET_LINK_LIBRARIES (${ESCARGOT_TARGET} PRIVATE ${ESCARGOT_LIBRARIES} ${ESCARGOT_LDFLAGS} ${LDFLAGS_FROM_ENV})
     TARGET_INCLUDE_DIRECTORIES (${ESCARGOT_TARGET} PRIVATE ${ESCARGOT_INCDIRS})
     TARGET_COMPILE_DEFINITIONS (${ESCARGOT_TARGET} PRIVATE ${ESCARGOT_DEFINITIONS})
     TARGET_COMPILE_OPTIONS (${ESCARGOT_TARGET} PRIVATE ${ESCARGOT_CXXFLAGS} ${CXXFLAGS_FROM_ENV} ${PROFILER_FLAGS} ${DEBUGGER_FLAGS})
@@ -156,24 +156,24 @@ IF (${ESCARGOT_OUTPUT} MATCHES "shell")
 ELSEIF (${ESCARGOT_OUTPUT} STREQUAL "shared_lib")
     ADD_LIBRARY (${ESCARGOT_TARGET} SHARED ${ESCARGOT_SRC_LIST})
 
-    TARGET_LINK_LIBRARIES (${ESCARGOT_TARGET} ${ESCARGOT_LIBRARIES} ${ESCARGOT_LDFLAGS} ${LDFLAGS_FROM_ENV})
+    TARGET_LINK_LIBRARIES (${ESCARGOT_TARGET} PUBLIC ${ESCARGOT_LIBRARIES} ${ESCARGOT_LDFLAGS} ${LDFLAGS_FROM_ENV})
     TARGET_INCLUDE_DIRECTORIES (${ESCARGOT_TARGET} PRIVATE ${ESCARGOT_INCDIRS})
     TARGET_COMPILE_DEFINITIONS (${ESCARGOT_TARGET} PRIVATE ${ESCARGOT_DEFINITIONS})
-    TARGET_COMPILE_OPTIONS (${ESCARGOT_TARGET} PRIVATE ${ESCARGOT_CXXFLAGS} ${CXXFLAGS_FROM_ENV})
+    TARGET_COMPILE_OPTIONS (${ESCARGOT_TARGET} PRIVATE ${ESCARGOT_CXXFLAGS} ${DEBUGGER_FLAGS} ${CXXFLAGS_FROM_ENV})
 
 ELSEIF (${ESCARGOT_OUTPUT} STREQUAL "static_lib")
     ADD_LIBRARY (${ESCARGOT_TARGET} STATIC ${ESCARGOT_SRC_LIST})
 
-    TARGET_LINK_LIBRARIES (${ESCARGOT_TARGET} ${ESCARGOT_LIBRARIES} ${ESCARGOT_LDFLAGS} ${LDFLAGS_FROM_ENV})
+    TARGET_LINK_LIBRARIES (${ESCARGOT_TARGET} PUBLIC ${ESCARGOT_LIBRARIES} ${ESCARGOT_LDFLAGS} ${LDFLAGS_FROM_ENV})
     TARGET_INCLUDE_DIRECTORIES (${ESCARGOT_TARGET} PRIVATE ${ESCARGOT_INCDIRS})
     TARGET_COMPILE_DEFINITIONS (${ESCARGOT_TARGET} PRIVATE ${ESCARGOT_DEFINITIONS})
-    TARGET_COMPILE_OPTIONS (${ESCARGOT_TARGET} PRIVATE ${ESCARGOT_CXXFLAGS} ${CXXFLAGS_FROM_ENV})
+    TARGET_COMPILE_OPTIONS (${ESCARGOT_TARGET} PRIVATE ${ESCARGOT_CXXFLAGS} ${DEBUGGER_FLAGS} ${CXXFLAGS_FROM_ENV})
 
 ELSEIF (${ESCARGOT_OUTPUT} STREQUAL "cctest")
     ADD_EXECUTABLE (${ESCARGOT_CCTEST_TARGET} ${ESCARGOT_SRC_LIST})
 
-    TARGET_LINK_LIBRARIES (${ESCARGOT_CCTEST_TARGET} ${ESCARGOT_LIBRARIES} ${ESCARGOT_LDFLAGS} ${LDFLAGS_FROM_ENV} gtest)
+    TARGET_LINK_LIBRARIES (${ESCARGOT_CCTEST_TARGET} PRIVATE ${ESCARGOT_LIBRARIES} ${ESCARGOT_LDFLAGS} ${LDFLAGS_FROM_ENV} gtest)
     TARGET_INCLUDE_DIRECTORIES (${ESCARGOT_CCTEST_TARGET} PRIVATE ${ESCARGOT_INCDIRS})
     TARGET_COMPILE_DEFINITIONS (${ESCARGOT_CCTEST_TARGET} PRIVATE ${ESCARGOT_DEFINITIONS})
-    TARGET_COMPILE_OPTIONS (${ESCARGOT_CCTEST_TARGET} PRIVATE ${ESCARGOT_CXXFLAGS} -I${ESCARGOT_ROOT}/third_party/googletest/googletest/include/ ${CXXFLAGS_FROM_ENV})
+    TARGET_COMPILE_OPTIONS (${ESCARGOT_CCTEST_TARGET} PRIVATE ${ESCARGOT_CXXFLAGS} ${DEBUGGER_FLAGS} -I${ESCARGOT_ROOT}/third_party/googletest/googletest/include/ ${CXXFLAGS_FROM_ENV})
 ENDIF()
index 91a1d87f73bf49201ed9eafde6d1191b98771f1e..8fac1dba9289e1d08196ac50ae099ce0e6498d00 100755 (executable)
@@ -234,6 +234,7 @@ if (f.type == Type::B) { puts("failed in msvc."); }
 #include <unordered_set>
 #include <vector>
 #include <random>
+#include <queue>
 
 #if defined(COMPILER_MSVC)
 #include <stddef.h>
@@ -260,6 +261,10 @@ typedef unsigned char LChar;
 #include "RuntimeICUBinder.h"
 #include "ICUPolyfill.h"
 #else
+
+#if defined(OS_WINDOWS_UWP)
+#include <icu.h>
+#else
 #include <unicode/locid.h>
 #include <unicode/uchar.h>
 #include <unicode/ustring.h>
@@ -293,6 +298,8 @@ void vzone_getOffset3(VZone* zone, UDate date, UBool local, int32_t& rawOffset,
                       int32_t& dstOffset, UErrorCode& ec);
 int32_t vzone_getRawOffset(VZone* zone);
 }
+#endif // !defined(OS_WINDOWS_UWP)
+
 #endif
 
 #else
@@ -324,6 +331,14 @@ typedef int32_t UChar32;
 #define UCHAR_MAX_VALUE 0x10ffff
 #endif
 
+#if defined(ENABLE_INTL) && !defined(OS_WINDOWS_UWP)
+#define ENABLE_INTL_DISPLAYNAMES
+#define ENABLE_INTL_NUMBERFORMAT
+#define ENABLE_INTL_PLURALRULES
+#define ENABLE_INTL_RELATIVETIMEFORMAT
+#define ENABLE_INTL_LISTFORMAT
+#endif
+
 #ifndef TRUE
 #define TRUE 1
 #endif
@@ -332,7 +347,7 @@ typedef int32_t UChar32;
 #define FALSE 0
 #endif
 
-#ifdef ESCARGOT_USE_CUSTOM_LOGGING
+#ifdef ENABLE_CUSTOM_LOGGING
 // use customized logging
 #include <stdarg.h>
 namespace Escargot {
@@ -503,10 +518,6 @@ typedef uint16_t LexicalBlockIndex;
 #define REGEXP_CACHE_SIZE_MAX 64
 #endif
 
-#ifndef ROPE_STRING_MIN_LENGTH
-#define ROPE_STRING_MIN_LENGTH 24
-#endif
-
 #include "EscargotInfo.h"
 #include "heap/Heap.h"
 #include "util/Util.h"
index 759802eca894eaf63113defc2fad692fa07ca1fc..47070637613ac62baabbdc6e6bb82cc19df1a54d 100644 (file)
@@ -183,7 +183,7 @@ public:
         m_platform->deallocateThreadLocalCustomData();
     }
 
-#ifdef ESCARGOT_USE_CUSTOM_LOGGING
+#ifdef ENABLE_CUSTOM_LOGGING
     virtual void customInfoLogger(const char* format, va_list arg) override
     {
         m_platform->customInfoLogger(format, arg);
@@ -503,7 +503,7 @@ void PersistentValueRefMap::clear()
 
 StringRef* StringRef::createFromASCII(const char* s, size_t len)
 {
-    return toRef(new ASCIIString(s, len));
+    return toRef(String::fromASCII(s, len));
 }
 
 StringRef* StringRef::createFromUTF8(const char* s, size_t len, bool maybeASCII)
@@ -518,7 +518,7 @@ StringRef* StringRef::createFromUTF16(const char16_t* s, size_t len)
 
 StringRef* StringRef::createFromLatin1(const unsigned char* s, size_t len)
 {
-    return toRef(new Latin1String(s, len));
+    return toRef(String::fromLatin1(s, len));
 }
 
 StringRef* StringRef::createExternalFromASCII(const char* s, size_t len)
@@ -946,10 +946,11 @@ bool BigIntRef::isNegative()
 }
 
 Evaluator::StackTraceData::StackTraceData()
-    : src(toRef(String::emptyString))
+    : srcName(toRef(String::emptyString))
     , sourceCode(toRef(String::emptyString))
     , loc(SIZE_MAX, SIZE_MAX, SIZE_MAX)
     , functionName(toRef(String::emptyString))
+    , callee(nullptr)
     , isFunction(false)
     , isConstructor(false)
     , isAssociatedWithJavaScriptCode(false)
@@ -966,7 +967,7 @@ Evaluator::EvaluatorResult::EvaluatorResult()
 Evaluator::EvaluatorResult::EvaluatorResult(const EvaluatorResult& src)
     : result(src.result)
     , error(src.error)
-    , stackTraceData(src.stackTraceData)
+    , stackTrace(src.stackTrace)
 {
 }
 
@@ -974,14 +975,14 @@ const Evaluator::EvaluatorResult& Evaluator::EvaluatorResult::operator=(Evaluato
 {
     result = src.result;
     error = src.error;
-    stackTraceData = src.stackTraceData;
+    stackTrace = src.stackTrace;
     return *this;
 }
 
 Evaluator::EvaluatorResult::EvaluatorResult(EvaluatorResult&& src)
     : result(src.result)
     , error(src.error)
-    , stackTraceData(std::move(src.stackTraceData))
+    , stackTrace(std::move(src.stackTrace))
 {
     src.result = ValueRef::createUndefined();
     src.error = nullptr;
@@ -1003,20 +1004,23 @@ static Evaluator::EvaluatorResult toEvaluatorResultRef(SandBox::SandBoxResult& r
     r.result = toRef(result.result);
 
     if (!result.error.isEmpty()) {
-        new (&r.stackTraceData) GCManagedVector<Evaluator::StackTraceData>(result.stackTraceData.size());
-        for (size_t i = 0; i < result.stackTraceData.size(); i++) {
+        new (&r.stackTrace) GCManagedVector<Evaluator::StackTraceData>(result.stackTrace.size());
+        for (size_t i = 0; i < result.stackTrace.size(); i++) {
             Evaluator::StackTraceData t;
-            t.src = toRef(result.stackTraceData[i].src);
-            t.sourceCode = toRef(result.stackTraceData[i].sourceCode);
-            t.loc.index = result.stackTraceData[i].loc.index;
-            t.loc.line = result.stackTraceData[i].loc.line;
-            t.loc.column = result.stackTraceData[i].loc.column;
-            t.functionName = toRef(result.stackTraceData[i].functionName);
-            t.isFunction = result.stackTraceData[i].isFunction;
-            t.isConstructor = result.stackTraceData[i].isConstructor;
-            t.isAssociatedWithJavaScriptCode = result.stackTraceData[i].isAssociatedWithJavaScriptCode;
-            t.isEval = result.stackTraceData[i].isEval;
-            r.stackTraceData[i] = t;
+            t.srcName = toRef(result.stackTrace[i].srcName);
+            t.sourceCode = toRef(result.stackTrace[i].sourceCode);
+            t.loc.index = result.stackTrace[i].loc.index;
+            t.loc.line = result.stackTrace[i].loc.line;
+            t.loc.column = result.stackTrace[i].loc.column;
+            t.functionName = toRef(result.stackTrace[i].functionName);
+            if (result.stackTrace[i].callee) {
+                t.callee = toRef(result.stackTrace[i].callee.value());
+            }
+            t.isFunction = result.stackTrace[i].isFunction;
+            t.isConstructor = result.stackTrace[i].isConstructor;
+            t.isAssociatedWithJavaScriptCode = result.stackTrace[i].isAssociatedWithJavaScriptCode;
+            t.isEval = result.stackTrace[i].isEval;
+            r.stackTrace[i] = t;
         }
     }
 
@@ -1072,6 +1076,11 @@ COMPILE_ASSERT((int)VMInstanceRef::PromiseHookType::Resolve == (int)VMInstance::
 COMPILE_ASSERT((int)VMInstanceRef::PromiseHookType::Before == (int)VMInstance::PromiseHookType::Before, "");
 COMPILE_ASSERT((int)VMInstanceRef::PromiseHookType::After == (int)VMInstance::PromiseHookType::After, "");
 
+COMPILE_ASSERT((int)VMInstanceRef::PromiseRejectEvent::PromiseRejectWithNoHandler == (int)VMInstance::PromiseRejectEvent::PromiseRejectWithNoHandler, "");
+COMPILE_ASSERT((int)VMInstanceRef::PromiseRejectEvent::PromiseHandlerAddedAfterReject == (int)VMInstance::PromiseRejectEvent::PromiseHandlerAddedAfterReject, "");
+COMPILE_ASSERT((int)VMInstanceRef::PromiseRejectEvent::PromiseRejectAfterResolved == (int)VMInstance::PromiseRejectEvent::PromiseRejectAfterResolved, "");
+COMPILE_ASSERT((int)VMInstanceRef::PromiseRejectEvent::PromiseResolveAfterResolved == (int)VMInstance::PromiseRejectEvent::PromiseResolveAfterResolved, "");
+
 PersistentRefHolder<VMInstanceRef> VMInstanceRef::create(const char* locale, const char* timezone, const char* baseCacheDir)
 {
     return PersistentRefHolder<VMInstanceRef>(toRef(new VMInstance(locale, timezone, baseCacheDir)));
@@ -1115,6 +1124,20 @@ void VMInstanceRef::unregisterPromiseHook()
     toImpl(this)->unregisterPromiseHook();
 }
 
+void VMInstanceRef::registerPromiseRejectCallback(PromiseRejectCallback rejectCallback)
+{
+    toImpl(this)->registerPromiseRejectCallback([](ExecutionState& state, PromiseObject* promise, const Value& value, VMInstance::PromiseRejectEvent event, void* callback) -> void {
+        ASSERT(!!callback);
+        (reinterpret_cast<PromiseRejectCallback>(callback))(toRef(&state), toRef(promise), toRef(value), (PromiseRejectEvent)(event));
+    },
+                                                (void*)rejectCallback);
+}
+
+void VMInstanceRef::unregisterPromiseRejectCallback()
+{
+    toImpl(this)->unregisterPromiseRejectCallback();
+}
+
 void VMInstanceRef::enterIdleMode()
 {
     toImpl(this)->enterIdleMode();
@@ -1144,6 +1167,315 @@ Evaluator::EvaluatorResult VMInstanceRef::executePendingJob()
     return toEvaluatorResultRef(result);
 }
 
+#ifdef ESCARGOT_DEBUGGER
+
+StringRef* DebuggerOperationsRef::BreakpointOperations::eval(StringRef* sourceCode, bool& isError)
+{
+    ExecutionState* state = toImpl(m_executionState);
+    Debugger* debugger = state->context()->debugger();
+
+    if (debugger == nullptr) {
+        isError = true;
+
+        return StringRef::createFromASCII("Debugger is not available");
+    }
+
+    isError = false;
+
+    String* result;
+
+    debugger->setStopState(ESCARGOT_DEBUGGER_IN_EVAL_MODE);
+
+    try {
+        Value asValue(toImpl(sourceCode));
+        Value evalResult(Value::ForceUninitialized);
+        evalResult = state->context()->globalObject()->evalLocal(*state, asValue, state->thisValue(), reinterpret_cast<ByteCodeBlock*>(weakCodeRef())->m_codeBlock, true);
+        result = evalResult.toStringWithoutException(*state);
+    } catch (const Value& val) {
+        result = val.toStringWithoutException(*state);
+
+        isError = true;
+    }
+
+    debugger->setStopState(ESCARGOT_DEBUGGER_IN_WAIT_MODE);
+    return toRef(result);
+}
+
+void DebuggerOperationsRef::BreakpointOperations::getStackTrace(DebuggerOperationsRef::DebuggerStackTraceDataVector& outStackTrace)
+{
+    ExecutionState* state = toImpl(m_executionState);
+    SandBox::StackTraceDataVector stackTraceDataVector;
+
+    bool hasSavedStackTrace = SandBox::createStackTrace(stackTraceDataVector, *state, true);
+    ByteCodeLOCDataMap locMap;
+    size_t size = stackTraceDataVector.size();
+
+    outStackTrace.clear();
+
+    for (uint32_t i = 0; i < size; i++) {
+        if (reinterpret_cast<size_t>(stackTraceDataVector[i].loc.actualCodeBlock) != SIZE_MAX) {
+            ByteCodeBlock* byteCodeBlock = stackTraceDataVector[i].loc.actualCodeBlock;
+            size_t line, column;
+
+            if (stackTraceDataVector[i].loc.index == SIZE_MAX) {
+                size_t byteCodePosition = stackTraceDataVector[i].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)stackTraceDataVector[i].loc.line;
+                column = (uint32_t)stackTraceDataVector[i].loc.column;
+            }
+
+            outStackTrace.push_back(DebuggerStackTraceData(reinterpret_cast<WeakCodeRef*>(byteCodeBlock), line, column, stackTraceDataVector[i].executionStateDepth));
+        }
+    }
+
+    for (auto iter = locMap.begin(); iter != locMap.end(); iter++) {
+        delete iter->second;
+    }
+
+    if (hasSavedStackTrace) {
+        Debugger* debugger = state->context()->debugger();
+
+        for (auto iter = debugger->activeSavedStackTrace()->begin(); iter != debugger->activeSavedStackTrace()->end(); iter++) {
+            outStackTrace.push_back(DebuggerStackTraceData(reinterpret_cast<WeakCodeRef*>(iter->byteCodeBlock), iter->line, iter->column, SIZE_MAX));
+        }
+    }
+}
+
+void DebuggerOperationsRef::BreakpointOperations::getLexicalScopeChain(uint32_t stateIndex, DebuggerOperationsRef::LexicalScopeChainVector& outLexicalScopeChain)
+{
+    outLexicalScopeChain.clear();
+
+    ExecutionState* state = toImpl(m_executionState);
+
+    while (stateIndex > 0) {
+        state = state->parent();
+        stateIndex--;
+
+        if (state == nullptr) {
+            return;
+        }
+    }
+
+    LexicalEnvironment* lexEnv = state->lexicalEnvironment();
+
+    while (lexEnv) {
+        EnvironmentRecord* record = lexEnv->record();
+        ScopeType type;
+
+        if (record->isGlobalEnvironmentRecord()) {
+            type = GLOBAL_ENVIRONMENT;
+        } else if (record->isDeclarativeEnvironmentRecord()) {
+            DeclarativeEnvironmentRecord* declarativeRecord = record->asDeclarativeEnvironmentRecord();
+            if (declarativeRecord->isFunctionEnvironmentRecord()) {
+                type = FUNCTION_ENVIRONMENT;
+            } else if (record->isModuleEnvironmentRecord()) {
+                type = MODULE_ENVIRONMENT;
+            } else {
+                type = DECLARATIVE_ENVIRONMENT;
+            }
+        } else if (record->isObjectEnvironmentRecord()) {
+            type = OBJECT_ENVIRONMENT;
+        } else {
+            type = UNKNOWN_ENVIRONMENT;
+        }
+
+        outLexicalScopeChain.push_back(type);
+        lexEnv = lexEnv->outerEnvironment();
+    }
+}
+
+StringRef* DebuggerOperationsRef::getFunctionName(WeakCodeRef* weakCodeRef)
+{
+    ByteCodeBlock* byteCode = reinterpret_cast<ByteCodeBlock*>(weakCodeRef);
+
+    return toRef(byteCode->codeBlock()->functionName().string());
+}
+
+bool DebuggerOperationsRef::updateBreakpoint(WeakCodeRef* weakCodeRef, uint32_t offset, bool enable)
+{
+    ByteCodeBlock* byteCode = reinterpret_cast<ByteCodeBlock*>(weakCodeRef);
+
+    ByteCode* breakpoint = (ByteCode*)(byteCode->m_code.data() + offset);
+
+#if defined(COMPILER_GCC) || defined(COMPILER_CLANG)
+    if (enable) {
+        if (breakpoint->m_opcodeInAddress != g_opcodeTable.m_addressTable[BreakpointDisabledOpcode]) {
+            return false;
+        }
+        breakpoint->m_opcodeInAddress = g_opcodeTable.m_addressTable[BreakpointEnabledOpcode];
+    } else {
+        if (breakpoint->m_opcodeInAddress != g_opcodeTable.m_addressTable[BreakpointEnabledOpcode]) {
+            return false;
+        }
+        breakpoint->m_opcodeInAddress = g_opcodeTable.m_addressTable[BreakpointDisabledOpcode];
+    }
+#else
+    if (enable) {
+        if (breakpoint->m_opcode != BreakpointDisabledOpcode) {
+            return false;
+        }
+        breakpoint->m_opcode = BreakpointEnabledOpcode;
+    } else {
+        if (breakpoint->m_opcode != BreakpointEnabledOpcode) {
+            return false;
+        }
+        breakpoint->m_opcode = BreakpointDisabledOpcode;
+    }
+#endif
+
+    return true;
+}
+
+class DebuggerC : public Debugger {
+public:
+    virtual void parseCompleted(String* source, String* srcName, String* error = nullptr) override;
+    virtual void stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state) override;
+    virtual void byteCodeReleaseNotification(ByteCodeBlock* byteCodeBlock) override;
+    virtual void exceptionCaught(String* message, SavedStackTraceDataVector& exceptionTrace) override;
+    virtual void consoleOut(String* output) override;
+    virtual String* getClientSource(String** sourceName) override;
+    virtual bool getWaitBeforeExitClient() override;
+
+    DebuggerC(DebuggerOperationsRef::DebuggerClient* debuggerClient, Context* context)
+        : m_debuggerClient(debuggerClient)
+    {
+        enable(context);
+    }
+
+protected:
+    virtual bool processEvents(ExecutionState* state, Optional<ByteCodeBlock*> byteCodeBlock, bool isBlockingRequest = true) override;
+
+private:
+    DebuggerOperationsRef::DebuggerClient* m_debuggerClient;
+};
+
+void DebuggerC::parseCompleted(String* source, String* srcName, String* error)
+{
+    if (error != nullptr) {
+        m_debuggerClient->parseError(toRef(source), toRef(srcName), toRef(error));
+        return;
+    }
+
+    size_t breakpointLocationsSize = m_breakpointLocationsVector.size();
+
+    for (size_t i = 0; i < breakpointLocationsSize; i++) {
+        InterpretedCodeBlock* codeBlock = reinterpret_cast<InterpretedCodeBlock*>(m_breakpointLocationsVector[i]->weakCodeRef);
+
+        m_breakpointLocationsVector[i]->weakCodeRef = reinterpret_cast<Debugger::WeakCodeRef*>(codeBlock->byteCodeBlock());
+    }
+
+    // Same structure, but the definition is duplicated.
+    std::vector<DebuggerOperationsRef::BreakpointLocationsInfo*>* info = reinterpret_cast<std::vector<DebuggerOperationsRef::BreakpointLocationsInfo*>*>(&m_breakpointLocationsVector);
+
+    m_debuggerClient->parseCompleted(toRef(source), toRef(srcName), *info);
+}
+
+static LexicalEnvironment* getFunctionLexEnv(ExecutionState* state)
+{
+    LexicalEnvironment* lexEnv = state->lexicalEnvironment();
+
+    while (lexEnv) {
+        EnvironmentRecord* record = lexEnv->record();
+
+        if (record->isDeclarativeEnvironmentRecord()
+            && record->asDeclarativeEnvironmentRecord()->isFunctionEnvironmentRecord()) {
+            return lexEnv;
+        }
+
+        lexEnv = lexEnv->outerEnvironment();
+    }
+    return nullptr;
+}
+
+void DebuggerC::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state)
+{
+    DebuggerOperationsRef::BreakpointOperations operations(reinterpret_cast<DebuggerOperationsRef::WeakCodeRef*>(byteCodeBlock), toRef(state), offset);
+
+    switch (m_debuggerClient->stopAtBreakpoint(operations)) {
+    case DebuggerOperationsRef::Continue: {
+        m_stopState = nullptr;
+        break;
+    }
+    case DebuggerOperationsRef::Step: {
+        m_stopState = ESCARGOT_DEBUGGER_ALWAYS_STOP;
+        break;
+    }
+    case DebuggerOperationsRef::Next: {
+        m_stopState = state;
+        break;
+    }
+    case DebuggerOperationsRef::Finish: {
+        LexicalEnvironment* lexEnv = getFunctionLexEnv(state);
+
+        if (!lexEnv) {
+            m_stopState = nullptr;
+            break;
+        }
+
+        ExecutionState* stopState = state->parent();
+
+        while (stopState && getFunctionLexEnv(stopState) == lexEnv) {
+            stopState = stopState->parent();
+        }
+
+        m_stopState = stopState;
+        break;
+    }
+    }
+}
+
+void DebuggerC::byteCodeReleaseNotification(ByteCodeBlock* byteCodeBlock)
+{
+    m_debuggerClient->codeReleased(reinterpret_cast<DebuggerOperationsRef::WeakCodeRef*>(byteCodeBlock));
+}
+
+void DebuggerC::exceptionCaught(String* message, SavedStackTraceDataVector& exceptionTrace)
+{
+    UNUSED_PARAMETER(message);
+    UNUSED_PARAMETER(exceptionTrace);
+}
+
+void DebuggerC::consoleOut(String* output)
+{
+    UNUSED_PARAMETER(output);
+}
+
+String* DebuggerC::getClientSource(String** sourceName)
+{
+    UNUSED_PARAMETER(sourceName);
+
+    return nullptr;
+}
+
+bool DebuggerC::getWaitBeforeExitClient()
+{
+    return false;
+}
+
+bool DebuggerC::processEvents(ExecutionState* state, Optional<ByteCodeBlock*> byteCodeBlock, bool isBlockingRequest)
+{
+    UNUSED_PARAMETER(state);
+    UNUSED_PARAMETER(byteCodeBlock);
+    UNUSED_PARAMETER(isBlockingRequest);
+
+    return false;
+}
+
+#endif /* ESCARGOT_DEBUGGER */
+
 PersistentRefHolder<ContextRef> ContextRef::create(VMInstanceRef* vminstanceref)
 {
     VMInstance* vminstance = toImpl(vminstanceref);
@@ -1383,7 +1715,7 @@ public:
 
     virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override
     {
-        Value PV = P.toPlainValue(state);
+        Value PV = P.toPlainValue();
         if (!PV.isSymbol()) {
             auto result = m_getOwnPropetyCallback(toRef(&state), toRef(this), toRef(PV));
             if (result.m_value.hasValue()) {
@@ -1396,7 +1728,7 @@ public:
     {
         // Only value type supported
         if (desc.isValuePresent()) {
-            Value PV = P.toPlainValue(state);
+            Value PV = P.toPlainValue();
             if (!PV.isSymbol() && m_defineOwnPropertyCallback(toRef(&state), toRef(this), toRef(PV), toRef(desc.value()))) {
                 return true;
             }
@@ -1405,11 +1737,11 @@ public:
     }
     virtual bool deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override
     {
-        Value PV = P.toPlainValue(state);
+        Value PV = P.toPlainValue();
         if (!PV.isSymbol()) {
-            auto result = m_getOwnPropetyCallback(toRef(&state), toRef(this), toRef(P.toPlainValue(state)));
+            auto result = m_getOwnPropetyCallback(toRef(&state), toRef(this), toRef(P.toPlainValue()));
             if (result.m_value.hasValue()) {
-                return m_deleteOwnPropertyCallback(toRef(&state), toRef(this), toRef(P.toPlainValue(state)));
+                return m_deleteOwnPropertyCallback(toRef(&state), toRef(this), toRef(P.toPlainValue()));
             }
         }
         return Object::deleteOwnProperty(state, P);
@@ -1723,7 +2055,7 @@ void ObjectRef::enumerateObjectOwnProperties(ExecutionStateRef* state, const std
     toImpl(this)->enumeration(*toImpl(state), [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
         const std::function<bool(ExecutionStateRef * state, ValueRef * propertyName, bool isWritable, bool isEnumerable, bool isConfigurable)>* cb
             = (const std::function<bool(ExecutionStateRef * state, ValueRef * propertyName, bool isWritable, bool isEnumerable, bool isConfigurable)>*)data;
-        return (*cb)(toRef(&state), toRef(name.toPlainValue(state)), desc.isWritable(), desc.isEnumerable(), desc.isConfigurable());
+        return (*cb)(toRef(&state), toRef(name.toPlainValue()), desc.isWritable(), desc.isEnumerable(), desc.isConfigurable());
     },
                               (void*)&cb, shouldSkipSymbolKey);
 }
@@ -2131,10 +2463,28 @@ FunctionObjectRef* FunctionObjectRef::create(ExecutionStateRef* stateRef, Atomic
         newArgv[i] = toImpl(argumentNameArray[i]);
     }
 
-    auto functionSource = FunctionObject::createFunctionSourceFromScriptSource(state, toImpl(functionName), argumentCount, newArgv, toImpl(body), false, false, false, false);
+    auto functionSource = FunctionObject::createFunctionScript(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);
+
+    return toRef(result);
+}
+
+FunctionObjectRef* FunctionObjectRef::create(ExecutionStateRef* stateRef, StringRef* sourceName, AtomicStringRef* functionName, size_t argumentCount, ValueRef** argumentNameArray, ValueRef* body)
+{
+    ASSERT(toImpl(sourceName));
+
+    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::createFunctionScript(state, toImpl(functionName), argumentCount, newArgv, toImpl(body), false, false, false, false, false, toImpl(sourceName));
 
     Object* proto = state.context()->globalObject()->functionPrototype();
-    ScriptFunctionObject* result = new ScriptFunctionObject(state, proto, functionSource.codeBlock, functionSource.outerEnvironment, true, false, false);
+    ScriptFunctionObject* result = new ScriptFunctionObject(state, proto, functionSource.codeBlock, functionSource.outerEnvironment, true, false);
 
     return toRef(result);
 }
@@ -2180,6 +2530,11 @@ void FunctionObjectRef::markFunctionNeedsSlowVirtualIdentifierOperation()
     }
 }
 
+bool FunctionObjectRef::setName(AtomicStringRef* name)
+{
+    return toImpl(this)->setName(toImpl(name));
+}
+
 GlobalObjectRef* ContextRef::globalObject()
 {
     Context* ctx = toImpl(this);
@@ -2210,10 +2565,26 @@ void ContextRef::throwException(ValueRef* exceptionValue)
     toImpl(this)->throwException(s, toImpl(exceptionValue));
 }
 
-bool ContextRef::initDebugger(const char* options)
+bool ContextRef::initDebugger(DebuggerOperationsRef::DebuggerClient* debuggerClient)
+{
+#ifdef ESCARGOT_DEBUGGER
+    Context* context = toImpl(this);
+
+    if (debuggerClient == nullptr || context->debuggerEnabled()) {
+        return false;
+    }
+
+    new DebuggerC(debuggerClient, context);
+    return true;
+#else /* !ESCARGOT_DEBUGGER */
+    return false;
+#endif /* ESCARGOT_DEBUGGER */
+}
+
+bool ContextRef::initDebuggerRemote(const char* options)
 {
 #ifdef ESCARGOT_DEBUGGER
-    return toImpl(this)->initDebugger(options);
+    return toImpl(this)->initDebuggerRemote(options);
 #else /* !ESCARGOT_DEBUGGER */
     return false;
 #endif /* ESCARGOT_DEBUGGER */
@@ -2222,7 +2593,16 @@ bool ContextRef::initDebugger(const char* options)
 bool ContextRef::isDebuggerRunning()
 {
 #ifdef ESCARGOT_DEBUGGER
-    return !!toImpl(this)->debugger() && toImpl(this)->debugger()->enabled();
+    return toImpl(this)->debuggerEnabled();
+#else /* !ESCARGOT_DEBUGGER */
+    return false;
+#endif /* ESCARGOT_DEBUGGER */
+}
+
+bool ContextRef::isWaitBeforeExit()
+{
+#ifdef ESCARGOT_DEBUGGER
+    return isDebuggerRunning() && toImpl(this)->debugger()->getWaitBeforeExitClient();
 #else /* !ESCARGOT_DEBUGGER */
     return false;
 #endif /* ESCARGOT_DEBUGGER */
@@ -2236,6 +2616,20 @@ void ContextRef::printDebugger(StringRef* output)
 #endif /* ESCARGOT_DEBUGGER */
 }
 
+void ContextRef::pumpDebuggerEvents()
+{
+#ifdef ESCARGOT_DEBUGGER
+    toImpl(this)->pumpDebuggerEvents();
+#endif /* ESCARGOT_DEBUGGER */
+}
+
+void ContextRef::setAsAlwaysStopState()
+{
+#ifdef ESCARGOT_DEBUGGER
+    toImpl(this)->setAsAlwaysStopState();
+#endif /* ESCARGOT_DEBUGGER */
+}
+
 StringRef* ContextRef::getClientSource(StringRef** sourceName)
 {
 #ifdef ESCARGOT_DEBUGGER
@@ -2351,18 +2745,18 @@ void ExecutionStateRef::throwException(ValueRef* value)
     imp->throwException(toImpl(value));
 }
 
-GCManagedVector<Evaluator::StackTraceData> ExecutionStateRef::computeStackTraceData()
+GCManagedVector<Evaluator::StackTraceData> ExecutionStateRef::computeStackTrace()
 {
     ExecutionState* state = toImpl(this);
 
-    SandBox::StackTraceDataVector stackTraceData;
-    SandBox::createStackTraceData(stackTraceData, *state);
+    SandBox::StackTraceDataVector stackTraceDataVector;
+    SandBox::createStackTrace(stackTraceDataVector, *state);
 
-    GCManagedVector<Evaluator::StackTraceData> result(stackTraceData.size());
+    GCManagedVector<Evaluator::StackTraceData> result(stackTraceDataVector.size());
     ByteCodeLOCDataMap locMap;
-    for (size_t i = 0; i < stackTraceData.size(); i++) {
-        if ((size_t)stackTraceData[i].second.loc.index == SIZE_MAX && (size_t)stackTraceData[i].second.loc.actualCodeBlock != SIZE_MAX) {
-            ByteCodeBlock* byteCodeBlock = stackTraceData[i].second.loc.actualCodeBlock;
+    for (size_t i = 0; i < stackTraceDataVector.size(); i++) {
+        if (stackTraceDataVector[i].loc.index == SIZE_MAX && reinterpret_cast<size_t>(stackTraceDataVector[i].loc.actualCodeBlock) != SIZE_MAX) {
+            ByteCodeBlock* byteCodeBlock = stackTraceDataVector[i].loc.actualCodeBlock;
 
             ByteCodeLOCData* locData;
             auto iterMap = locMap.find(byteCodeBlock);
@@ -2374,23 +2768,27 @@ GCManagedVector<Evaluator::StackTraceData> ExecutionStateRef::computeStackTraceD
             }
 
             InterpretedCodeBlock* codeBlock = byteCodeBlock->codeBlock();
-            size_t byteCodePosition = stackTraceData[i].second.loc.byteCodePosition;
-            stackTraceData[i].second.loc = byteCodeBlock->computeNodeLOCFromByteCode(state->context(), byteCodePosition, byteCodeBlock->m_codeBlock, locData);
-            stackTraceData[i].second.src = codeBlock->script()->srcName();
-            stackTraceData[i].second.sourceCode = codeBlock->script()->sourceCode();
+            size_t byteCodePosition = stackTraceDataVector[i].loc.byteCodePosition;
+            stackTraceDataVector[i].loc = byteCodeBlock->computeNodeLOCFromByteCode(state->context(), byteCodePosition, byteCodeBlock->m_codeBlock, locData);
+
+            stackTraceDataVector[i].srcName = codeBlock->script()->srcName();
+            stackTraceDataVector[i].sourceCode = codeBlock->script()->sourceCode();
         }
 
         Evaluator::StackTraceData t;
-        t.src = toRef(stackTraceData[i].second.src);
-        t.sourceCode = toRef(stackTraceData[i].second.sourceCode);
-        t.loc.index = stackTraceData[i].second.loc.index;
-        t.loc.line = stackTraceData[i].second.loc.line;
-        t.loc.column = stackTraceData[i].second.loc.column;
-        t.functionName = toRef(stackTraceData[i].second.functionName);
-        t.isFunction = stackTraceData[i].second.isFunction;
-        t.isConstructor = stackTraceData[i].second.isConstructor;
-        t.isAssociatedWithJavaScriptCode = stackTraceData[i].second.isAssociatedWithJavaScriptCode;
-        t.isEval = stackTraceData[i].second.isEval;
+        t.srcName = toRef(stackTraceDataVector[i].srcName);
+        t.sourceCode = toRef(stackTraceDataVector[i].sourceCode);
+        t.loc.index = stackTraceDataVector[i].loc.index;
+        t.loc.line = stackTraceDataVector[i].loc.line;
+        t.loc.column = stackTraceDataVector[i].loc.column;
+        t.functionName = toRef(stackTraceDataVector[i].functionName);
+        if (stackTraceDataVector[i].callee) {
+            t.callee = toRef(stackTraceDataVector[i].callee.value());
+        }
+        t.isFunction = stackTraceDataVector[i].isFunction;
+        t.isConstructor = stackTraceDataVector[i].isConstructor;
+        t.isAssociatedWithJavaScriptCode = stackTraceDataVector[i].isAssociatedWithJavaScriptCode;
+        t.isEval = stackTraceDataVector[i].isEval;
         result[i] = t;
     }
     for (auto iter = locMap.begin(); iter != locMap.end(); iter++) {
@@ -3261,6 +3659,16 @@ void PromiseObjectRef::reject(ExecutionStateRef* state, ValueRef* reason)
     toImpl(this)->reject(*toImpl(state), toImpl(reason));
 }
 
+bool PromiseObjectRef::hasResolveHandlers()
+{
+    return toImpl(this)->hasResolveHandlers();
+}
+
+bool PromiseObjectRef::hasRejectHandlers()
+{
+    return toImpl(this)->hasRejectHandlers();
+}
+
 ProxyObjectRef* ProxyObjectRef::create(ExecutionStateRef* state, ObjectRef* target, ObjectRef* handler)
 {
     return toRef(ProxyObject::createProxy(*toImpl(state), toImpl(target), toImpl(handler)));
@@ -3565,16 +3973,26 @@ ObjectTemplateRef* ObjectTemplateRef::create()
     return toRef(new ObjectTemplate());
 }
 
-void ObjectTemplateRef::setNamedPropertyHandler(const ObjectTemplateNamedPropertyHandlerData& data)
+void ObjectTemplateRef::setNamedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data)
 {
     toImpl(this)->setNamedPropertyHandler(data);
 }
 
+void ObjectTemplateRef::setIndexedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data)
+{
+    toImpl(this)->setIndexedPropertyHandler(data);
+}
+
 void ObjectTemplateRef::removeNamedPropertyHandler()
 {
     toImpl(this)->removeNamedPropertyHandler();
 }
 
+void ObjectTemplateRef::removeIndexedPropertyHandler()
+{
+    toImpl(this)->removeIndexedPropertyHandler();
+}
+
 OptionalRef<FunctionTemplateRef> ObjectTemplateRef::constructor()
 {
     if (toImpl(this)->constructor()) {
@@ -3719,6 +4137,39 @@ ValueRef* ScriptRef::moduleEvaluationError()
     return toRef(toImpl(this)->moduleEvaluationError());
 }
 
+ScriptRef::ModuleStatus ScriptRef::moduleStatus()
+{
+    auto md = toImpl(this)->moduleData();
+    if (md->m_evaluationError) {
+        return ModuleStatus::Errored;
+    }
+    switch (md->m_status) {
+    case Script::ModuleData::Unlinked:
+        return ModuleStatus::Uninstantiated;
+    case Script::ModuleData::Linking:
+        return ModuleStatus::Instantiating;
+    case Script::ModuleData::Linked:
+        return ModuleStatus::Instantiated;
+    case Script::ModuleData::Evaluating:
+        return ModuleStatus::Evaluating;
+    case Script::ModuleData::Evaluated:
+        return ModuleStatus::Evaluated;
+    }
+
+    ASSERT_NOT_REACHED();
+    return ModuleStatus::Errored;
+}
+
+ValueRef* ScriptRef::moduleInstantiate(ExecutionStateRef* state)
+{
+    return toRef(toImpl(this)->moduleInstantiate(*toImpl(state)));
+}
+
+ValueRef* ScriptRef::moduleEvaluate(ExecutionStateRef* state)
+{
+    return toRef(toImpl(this)->moduleEvaluate(*toImpl(state)));
+}
+
 PlatformRef::LoadModuleResult::LoadModuleResult(ScriptRef* result)
     : script(result)
     , errorMessage(StringRef::emptyString())
@@ -3733,6 +4184,15 @@ PlatformRef::LoadModuleResult::LoadModuleResult(ErrorObjectRef::Code errorCode,
 {
 }
 
+bool PlatformRef::isCustomLoggingEnabled()
+{
+#if defined(ENABLE_CUSTOM_LOGGING)
+    return true;
+#else
+    return false;
+#endif
+}
+
 bool SerializerRef::serializeInto(ValueRef* value, std::ostringstream& output)
 {
     return Serializer::serializeInto(toImpl(value), output);
@@ -3753,6 +4213,15 @@ ValueRef* SerializerRef::deserializeFrom(ContextRef* context, std::istringstream
     return toRef(result.result);
 }
 
+bool WASMOperationsRef::isWASMOperationsEnabled()
+{
+#if defined(ENABLE_WASM)
+    return true;
+#else
+    return false;
+#endif
+}
+
 #if defined(ENABLE_WASM)
 ValueRef* WASMOperationsRef::copyStableBufferBytes(ExecutionStateRef* state, ValueRef* source)
 {
@@ -3772,6 +4241,33 @@ void WASMOperationsRef::collectHeap()
 {
     WASMOperations::collectHeap();
 }
+#else
+ValueRef* WASMOperationsRef::copyStableBufferBytes(ExecutionStateRef* state, ValueRef* source)
+{
+    ESCARGOT_LOG_ERROR("If you want to use this function, you should enable WASM");
+    RELEASE_ASSERT_NOT_REACHED();
+    return nullptr;
+}
+
+ObjectRef* WASMOperationsRef::asyncCompileModule(ExecutionStateRef* state, ValueRef* source)
+{
+    ESCARGOT_LOG_ERROR("If you want to use this function, you should enable WASM");
+    RELEASE_ASSERT_NOT_REACHED();
+    return nullptr;
+}
+
+ObjectRef* WASMOperationsRef::instantiatePromiseOfModuleWithImportObject(ExecutionStateRef* state, PromiseObjectRef* promiseOfModule, ValueRef* importObj)
+{
+    ESCARGOT_LOG_ERROR("If you want to use this function, you should enable WASM");
+    RELEASE_ASSERT_NOT_REACHED();
+    return nullptr;
+}
+
+void WASMOperationsRef::collectHeap()
+{
+    ESCARGOT_LOG_ERROR("If you want to use this function, you should enable WASM");
+    RELEASE_ASSERT_NOT_REACHED();
+}
 #endif
 
 } // namespace Escargot
index 8b92c20ef8a97abcdad6fa5641f7429576b6ba53..6a3d6a9bc4b149bc3acab1fa6f3ef8e451f43281 100644 (file)
@@ -545,10 +545,11 @@ public:
     };
 
     struct ESCARGOT_EXPORT StackTraceData {
-        StringRef* src;
+        StringRef* srcName;
         StringRef* sourceCode;
         LOC loc;
         StringRef* functionName;
+        OptionalRef<FunctionObjectRef> callee;
         bool isFunction;
         bool isConstructor;
         bool isAssociatedWithJavaScriptCode;
@@ -571,7 +572,7 @@ public:
 
         ValueRef* result;
         OptionalRef<ValueRef> error;
-        GCManagedVector<StackTraceData> stackTraceData;
+        GCManagedVector<StackTraceData> stackTrace;
     };
 
     template <typename... Args, typename F>
@@ -617,7 +618,7 @@ public:
 
     void throwException(ValueRef* value);
 
-    GCManagedVector<Evaluator::StackTraceData> computeStackTraceData();
+    GCManagedVector<Evaluator::StackTraceData> computeStackTrace();
 
     ContextRef* context();
 
@@ -646,11 +647,22 @@ public:
         After
     };
 
+    enum PromiseRejectEvent {
+        PromiseRejectWithNoHandler = 0,
+        PromiseHandlerAddedAfterReject = 1,
+        PromiseRejectAfterResolved = 2,
+        PromiseResolveAfterResolved = 3,
+    };
+
     typedef void (*PromiseHook)(ExecutionStateRef* state, PromiseHookType type, PromiseObjectRef* promise, ValueRef* parent);
+    typedef void (*PromiseRejectCallback)(ExecutionStateRef* state, PromiseObjectRef* promise, ValueRef* value, PromiseRejectEvent event);
 
     // Register PromiseHook (PromiseHook is used by third party app)
     void registerPromiseHook(PromiseHook promiseHook);
     void unregisterPromiseHook();
+    // Register a callback to call if this promise is rejected, but it does not have a reject handler
+    void registerPromiseRejectCallback(PromiseRejectCallback);
+    void unregisterPromiseRejectCallback();
 
     // this function enforce do gc,
     // remove every compiled bytecodes,
@@ -679,6 +691,121 @@ public:
     Evaluator::EvaluatorResult executePendingJob();
 };
 
+class ESCARGOT_EXPORT DebuggerOperationsRef {
+public:
+    class WeakCodeRef;
+
+    struct BreakpointLocation {
+        BreakpointLocation(uint32_t line, uint32_t offset)
+            : line(line)
+            , offset(offset)
+        {
+        }
+
+        uint32_t line;
+        uint32_t offset;
+    };
+
+    typedef std::vector<BreakpointLocation> BreakpointLocationVector;
+
+    struct BreakpointLocationsInfo {
+        BreakpointLocationsInfo(WeakCodeRef* weakCodeRef)
+            : weakCodeRef(weakCodeRef)
+        {
+        }
+
+        // The codeRef is a unique id which is not garbage collected
+        // to avoid keeping script / function code in the memory.
+        WeakCodeRef* weakCodeRef;
+        BreakpointLocationVector breakpointLocations;
+    };
+
+    struct DebuggerStackTraceData {
+        DebuggerStackTraceData(WeakCodeRef* weakCodeRef, size_t line, size_t column, size_t depth)
+            : weakCodeRef(weakCodeRef)
+            , line(line)
+            , column(column)
+            , depth(depth)
+        {
+        }
+
+        WeakCodeRef* weakCodeRef;
+        size_t line;
+        size_t column;
+        size_t depth;
+    };
+
+    typedef std::vector<DebuggerStackTraceData> DebuggerStackTraceDataVector;
+
+    enum ScopeType {
+        UNKNOWN_ENVIRONMENT,
+        GLOBAL_ENVIRONMENT,
+        FUNCTION_ENVIRONMENT,
+        DECLARATIVE_ENVIRONMENT,
+        OBJECT_ENVIRONMENT,
+        MODULE_ENVIRONMENT,
+    };
+
+    typedef std::vector<ScopeType> LexicalScopeChainVector;
+
+    class ESCARGOT_EXPORT BreakpointOperations {
+        friend class DebuggerC;
+
+    public:
+        WeakCodeRef* weakCodeRef()
+        {
+            return m_weakCodeRef;
+        }
+
+        ExecutionStateRef* executionState()
+        {
+            return m_executionState;
+        }
+
+        uint32_t offset()
+        {
+            return m_offset;
+        }
+
+        StringRef* eval(StringRef* sourceCode, bool& isError);
+        void getStackTrace(DebuggerStackTraceDataVector& outStackTrace);
+        void getLexicalScopeChain(uint32_t stateIndex, LexicalScopeChainVector& outLexicalScopeChain);
+
+    private:
+        BreakpointOperations(WeakCodeRef* weakCodeRef, ExecutionStateRef* executionState, uint32_t offset)
+            : m_weakCodeRef(weakCodeRef)
+            , m_executionState(executionState)
+            , m_offset(offset)
+        {
+        }
+
+        WeakCodeRef* m_weakCodeRef;
+        ExecutionStateRef* m_executionState;
+        uint32_t m_offset;
+    };
+
+    enum ResumeBreakpointOperation {
+        Continue,
+        Step,
+        Next,
+        Finish,
+    };
+
+    // Base class for debugger callbacks
+    class DebuggerClient {
+    public:
+        virtual void parseCompleted(StringRef* source, StringRef* srcName, std::vector<DebuggerOperationsRef::BreakpointLocationsInfo*>& breakpointLocationsVector) = 0;
+        virtual void parseError(StringRef* source, StringRef* srcName, StringRef* error) = 0;
+        virtual void codeReleased(WeakCodeRef* weakCodeRef) = 0;
+
+        virtual ResumeBreakpointOperation stopAtBreakpoint(BreakpointOperations& operations) = 0;
+    };
+
+    static StringRef* getFunctionName(WeakCodeRef* weakCodeRef);
+    // Returns true, if the breakpoint status is changed from enabled to disabled or vica versa
+    static bool updateBreakpoint(WeakCodeRef* weakCodeRef, uint32_t offset, bool enable);
+};
+
 class ESCARGOT_EXPORT ContextRef {
 public:
     static PersistentRefHolder<ContextRef> create(VMInstanceRef* vmInstance);
@@ -695,9 +822,15 @@ public:
 
     void throwException(ValueRef* exceptionValue); // if you use this function without Evaluator, your program will crash :(
 
-    bool initDebugger(const char* options);
+    bool initDebugger(DebuggerOperationsRef::DebuggerClient* debuggerClient);
+    // available options(separator is ';')
+    // "--port=6501", default for TCP debugger
+    bool initDebuggerRemote(const char* options);
     bool isDebuggerRunning();
+    bool isWaitBeforeExit();
     void printDebugger(StringRef* output);
+    void pumpDebuggerEvents();
+    void setAsAlwaysStopState();
     StringRef* getClientSource(StringRef** sourceName);
 
     typedef OptionalRef<ValueRef> (*VirtualIdentifierCallback)(ExecutionStateRef* state, ValueRef* name);
@@ -1036,7 +1169,7 @@ public:
     void operator delete[](void* obj) = delete;
 
 private:
-    friend class ObjectWithNamedPropertyHandler;
+    friend class ObjectWithPropertyHandler;
     ObjectPropertyDescriptorRef(void* src);
 
     void* m_privateData;
@@ -1331,7 +1464,10 @@ public:
 
     static FunctionObjectRef* create(ExecutionStateRef* state, NativeFunctionInfo info);
     static FunctionObjectRef* createBuiltinFunction(ExecutionStateRef* state, NativeFunctionInfo info); // protoype of builtin function is non-writable
+
+    // dynamically create a function from source string
     static FunctionObjectRef* create(ExecutionStateRef* state, AtomicStringRef* functionName, size_t argumentCount, ValueRef** argumentNameArray, ValueRef* body);
+    static FunctionObjectRef* create(ExecutionStateRef* state, StringRef* sourceName, 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
@@ -1343,6 +1479,9 @@ public:
 
     bool isConstructor();
     void markFunctionNeedsSlowVirtualIdentifierOperation();
+
+    // set function name is allowed only for native function or dynamically created function except class constructor
+    bool setName(AtomicStringRef* name);
 };
 
 class ESCARGOT_EXPORT IteratorObjectRef : public ObjectRef {
@@ -1633,6 +1772,9 @@ public:
     ObjectRef* then(ExecutionStateRef* state, ValueRef* onFulfilled, ValueRef* onRejected);
     void fulfill(ExecutionStateRef* state, ValueRef* value);
     void reject(ExecutionStateRef* state, ValueRef* reason);
+
+    bool hasResolveHandlers();
+    bool hasRejectHandlers();
 };
 
 class ESCARGOT_EXPORT ProxyObjectRef : public ObjectRef {
@@ -1728,45 +1870,53 @@ public:
     void* instanceExtraData();
 };
 
-typedef OptionalRef<ValueRef> (*TemplateNamedPropertyHandlerGetterCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
+typedef OptionalRef<ValueRef> (*PropertyHandlerGetterCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
 // if intercepted you may returns non-empty value.
 // the returned value will be use futuer operation(you can return true, or false)
-typedef OptionalRef<ValueRef> (*TemplateNamedPropertyHandlerSetterCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, ValueRef* value);
-enum TemplatePropertyAttribute {
-    TemplatePropertyAttributeNotExist = 1 << 0,
-    TemplatePropertyAttributeExist = 1 << 1,
-    TemplatePropertyAttributeWritable = 1 << 2,
-    TemplatePropertyAttributeEnumerable = 1 << 3,
-    TemplatePropertyAttributeConfigurable = 1 << 4,
-};
-typedef TemplatePropertyAttribute (*TemplateNamedPropertyHandlerQueryCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
+typedef OptionalRef<ValueRef> (*PropertyHandlerSetterCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, ValueRef* value);
+enum class ObjectTemplatePropertyAttribute : uint8_t {
+    PropertyAttributeNotExist = 1 << 0,
+    PropertyAttributeExist = 1 << 1,
+    PropertyAttributeWritable = 1 << 2,
+    PropertyAttributeEnumerable = 1 << 3,
+    PropertyAttributeConfigurable = 1 << 4,
+};
+inline bool operator&(ObjectTemplatePropertyAttribute a, ObjectTemplatePropertyAttribute b)
+{
+    return static_cast<uint8_t>(a) & static_cast<uint8_t>(b);
+}
+inline ObjectTemplatePropertyAttribute operator|(ObjectTemplatePropertyAttribute a, ObjectTemplatePropertyAttribute b)
+{
+    return static_cast<ObjectTemplatePropertyAttribute>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
+}
+typedef ObjectTemplatePropertyAttribute (*PropertyHandlerQueryCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
 // if intercepted you may returns non-empty value.
 // the returned value will be use futuer operation(you can return true, or false)
-typedef OptionalRef<ValueRef> (*TemplateNamedPropertyHandlerDeleteCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
-typedef ValueVectorRef* (*TemplateNamedPropertyHandlerEnumerationCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data);
+typedef OptionalRef<ValueRef> (*PropertyHandlerDeleteCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
+typedef ValueVectorRef* (*PropertyHandlerEnumerationCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data);
 // if intercepted you may returns non-empty value.
 // the returned value will be use futuer operation(you can return true, or false)
-typedef OptionalRef<ValueRef> (*TemplateNamedPropertyHandlerDefineOwnPropertyCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, const ObjectPropertyDescriptorRef& desc);
-typedef OptionalRef<ValueRef> (*TemplateNamedPropertyHandlerGetPropertyDescriptorCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
-
-struct ESCARGOT_EXPORT ObjectTemplateNamedPropertyHandlerData {
-    TemplateNamedPropertyHandlerGetterCallback getter;
-    TemplateNamedPropertyHandlerSetterCallback setter;
-    TemplateNamedPropertyHandlerQueryCallback query;
-    TemplateNamedPropertyHandlerDeleteCallback deleter;
-    TemplateNamedPropertyHandlerEnumerationCallback enumerator;
-    TemplateNamedPropertyHandlerDefineOwnPropertyCallback definer;
-    TemplateNamedPropertyHandlerGetPropertyDescriptorCallback descriptor;
-    void* data;
-
-    ObjectTemplateNamedPropertyHandlerData(
-        TemplateNamedPropertyHandlerGetterCallback getter = nullptr,
-        TemplateNamedPropertyHandlerSetterCallback setter = nullptr,
-        TemplateNamedPropertyHandlerQueryCallback query = nullptr,
-        TemplateNamedPropertyHandlerDeleteCallback deleter = nullptr,
-        TemplateNamedPropertyHandlerEnumerationCallback enumerator = nullptr,
-        TemplateNamedPropertyHandlerDefineOwnPropertyCallback definer = nullptr,
-        TemplateNamedPropertyHandlerGetPropertyDescriptorCallback descriptor = nullptr,
+typedef OptionalRef<ValueRef> (*PropertyHandlerDefineOwnPropertyCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, const ObjectPropertyDescriptorRef& desc);
+typedef OptionalRef<ValueRef> (*PropertyHandlerGetPropertyDescriptorCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
+
+struct ESCARGOT_EXPORT ObjectTemplatePropertyHandlerConfiguration {
+    PropertyHandlerGetterCallback getter;
+    PropertyHandlerSetterCallback setter;
+    PropertyHandlerQueryCallback query;
+    PropertyHandlerDeleteCallback deleter;
+    PropertyHandlerEnumerationCallback enumerator;
+    PropertyHandlerDefineOwnPropertyCallback definer;
+    PropertyHandlerGetPropertyDescriptorCallback descriptor;
+    void* data; // this data member is guaranteed to be kept in GC heap
+
+    ObjectTemplatePropertyHandlerConfiguration(
+        PropertyHandlerGetterCallback getter = nullptr,
+        PropertyHandlerSetterCallback setter = nullptr,
+        PropertyHandlerQueryCallback query = nullptr,
+        PropertyHandlerDeleteCallback deleter = nullptr,
+        PropertyHandlerEnumerationCallback enumerator = nullptr,
+        PropertyHandlerDefineOwnPropertyCallback definer = nullptr,
+        PropertyHandlerGetPropertyDescriptorCallback descriptor = nullptr,
         void* data = nullptr)
         : getter(getter)
         , setter(setter)
@@ -1790,8 +1940,10 @@ public:
 class ESCARGOT_EXPORT ObjectTemplateRef : public TemplateRef {
 public:
     static ObjectTemplateRef* create();
-    void setNamedPropertyHandler(const ObjectTemplateNamedPropertyHandlerData& data);
+    void setNamedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data);
+    void setIndexedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data);
     void removeNamedPropertyHandler();
+    void removeIndexedPropertyHandler();
 
     // returns function template if object template is instance template of function template
     OptionalRef<FunctionTemplateRef> constructor();
@@ -1857,6 +2009,17 @@ public:
     ObjectRef* moduleNamespace(ExecutionStateRef* state);
     bool wasThereErrorOnModuleEvaluation();
     ValueRef* moduleEvaluationError();
+    enum ModuleStatus {
+        Uninstantiated,
+        Instantiating,
+        Instantiated,
+        Evaluating,
+        Evaluated,
+        Errored
+    };
+    ModuleStatus moduleStatus();
+    ValueRef* moduleInstantiate(ExecutionStateRef* state);
+    ValueRef* moduleEvaluate(ExecutionStateRef* state);
 };
 
 class ESCARGOT_EXPORT PlatformRef {
@@ -1926,7 +2089,8 @@ public:
         // do nothing
     }
 
-#ifdef ESCARGOT_USE_CUSTOM_LOGGING
+    // you can use these functions only if you enabled custom logging
+    static bool isCustomLoggingEnabled();
     // default custom logger
     virtual void customInfoLogger(const char* format, va_list arg)
     {
@@ -1937,20 +2101,19 @@ public:
     {
         vfprintf(stderr, format, arg);
     }
-#endif
 
     void* threadLocalCustomData();
 };
 
-#if defined(ENABLE_WASM)
 class ESCARGOT_EXPORT WASMOperationsRef {
 public:
+    // you can use these functions only if you enabled WASM
+    static bool isWASMOperationsEnabled();
     static ValueRef* copyStableBufferBytes(ExecutionStateRef* state, ValueRef* source);
     static ObjectRef* asyncCompileModule(ExecutionStateRef* state, ValueRef* source);
     static ObjectRef* instantiatePromiseOfModuleWithImportObject(ExecutionStateRef* state, PromiseObjectRef* promiseOfModule, ValueRef* importObj);
     static void collectHeap();
 };
-#endif
 
 } // namespace Escargot
 
index 4965259aaf746f6e9cbf1fca26d32619a93fb99e..160cfe1d69160ff99873ef05a3b25e2201752c48 100644 (file)
@@ -412,7 +412,7 @@ static Value builtinArrayJoin(ExecutionState& state, Value thisValue, size_t arg
                     int64_t index;
                     Data* e = (Data*)data;
                     int64_t* ret = &e->ret;
-                    Value key = name.toPlainValue(state);
+                    Value key = name.toPlainValue();
                     index = key.toNumber(state);
                     if ((uint64_t)index != Value::InvalidIndexValue) {
                         if (self->get(state, name).value(state, self).isUndefined()) {
index 041852c04ba65d0814114cffb00e5343a9ee7a1e..45299a479fa75fd2c9a4591a0da9b5bce3c32286 100644 (file)
@@ -31,7 +31,7 @@ static Value builtinAsyncFunction(ExecutionState& state, Value thisValue, size_t
 {
     size_t argumentVectorCount = argc > 1 ? argc - 1 : 0;
     Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString);
-    auto functionSource = FunctionObject::createFunctionSourceFromScriptSource(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, false, true, false);
+    auto functionSource = FunctionObject::createFunctionScript(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, false, true, false);
 
     // Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
     if (!newTarget.hasValue()) {
index 1921b5ac36bd9878b3b4a7af59cc477d9df767e6..d68fb9baac5d3206e33f6053143e1c6bca3dd682 100644 (file)
@@ -31,7 +31,7 @@ static Value builtinAsyncGeneratorFunction(ExecutionState& state, Value thisValu
 {
     size_t argumentVectorCount = argc > 1 ? argc - 1 : 0;
     Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString);
-    auto functionSource = FunctionObject::createFunctionSourceFromScriptSource(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, true, true, false);
+    auto functionSource = FunctionObject::createFunctionScript(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, true, true, false);
 
     // Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
     if (!newTarget.hasValue()) {
index 88a283499d741573c752d2860d36ef1b95561d6e..8a89d957d5dd5e24424a9d4b8b65e28314a531a9 100644 (file)
@@ -74,10 +74,11 @@ static size_t validateAtomicAccess(ExecutionState& state, TypedArrayObject* type
     return (static_cast<size_t>(accessIndex) * elementSize) + offset;
 }
 
-template <typename T, typename ArgType = int64_t>
-static T atomicOperation(volatile uint8_t* rawStart, ArgType value, AtomicBinaryOps op)
+template <typename T>
+static T atomicOperation(volatile uint8_t* rawStart, int64_t v, AtomicBinaryOps op)
 {
-    T returnValue;
+    T returnValue = 0;
+    T value = static_cast<T>(v);
 #if defined(HAVE_BUILTIN_ATOMIC_FUNCTIONS)
     volatile T* ptr = reinterpret_cast<volatile T*>(rawStart);
     switch (op) {
@@ -88,8 +89,7 @@ static T atomicOperation(volatile uint8_t* rawStart, ArgType value, AtomicBinary
         returnValue = __atomic_fetch_and(ptr, value, __ATOMIC_SEQ_CST);
         break;
     case AtomicBinaryOps::EXCH: {
-        T v = value;
-        __atomic_exchange(ptr, &v, &returnValue, __ATOMIC_SEQ_CST);
+        __atomic_exchange(ptr, &value, &returnValue, __ATOMIC_SEQ_CST);
     } break;
     case AtomicBinaryOps::OR:
         returnValue = __atomic_fetch_or(ptr, value, __ATOMIC_SEQ_CST);
@@ -139,46 +139,26 @@ static Value getModifySetValueInBuffer(ExecutionState& state, ArrayBuffer* buffe
     ASSERT(indexedPosition + elemSize <= buffer->byteLength());
     uint8_t* rawStart = const_cast<uint8_t*>(buffer->data()) + indexedPosition;
 
-    if (v2.isInt32()) {
-        switch (type) {
-        case TypedArrayType::Int8:
-            return Value(atomicOperation<int8_t>(rawStart, v2.asInt32(), op));
-        case TypedArrayType::Int16:
-            return Value(atomicOperation<int16_t>(rawStart, v2.asInt32(), op));
-        case TypedArrayType::Int32:
-            return Value(atomicOperation<int32_t>(rawStart, v2.asInt32(), op));
-        case TypedArrayType::Uint8:
-            return Value(atomicOperation<uint8_t>(rawStart, v2.asInt32(), op));
-        case TypedArrayType::Uint16:
-            return Value(atomicOperation<uint16_t>(rawStart, v2.asInt32(), op));
-        case TypedArrayType::Uint32:
-            return Value(atomicOperation<uint32_t>(rawStart, v2.asInt32(), op));
-        default:
-            ASSERT(TypedArrayType::Uint8Clamped == type);
-            return Value(atomicOperation<uint8_t>(rawStart, v2.asInt32(), op));
-        }
-    }
-
     switch (type) {
     case TypedArrayType::Int8:
-        return Value(atomicOperation<int8_t, int64_t>(rawStart, v2.asNumber(), op));
+        return Value(atomicOperation<int8_t>(rawStart, v2.asNumber(), op));
     case TypedArrayType::Int16:
-        return Value(atomicOperation<int16_t, int64_t>(rawStart, v2.asNumber(), op));
+        return Value(atomicOperation<int16_t>(rawStart, v2.asNumber(), op));
     case TypedArrayType::Int32:
-        return Value(atomicOperation<int32_t, int64_t>(rawStart, v2.asNumber(), op));
+        return Value(atomicOperation<int32_t>(rawStart, v2.asNumber(), op));
     case TypedArrayType::Uint8:
-        return Value(atomicOperation<uint8_t, int64_t>(rawStart, v2.asNumber(), op));
+        return Value(atomicOperation<uint8_t>(rawStart, v2.asNumber(), op));
     case TypedArrayType::Uint16:
-        return Value(atomicOperation<uint16_t, int64_t>(rawStart, v2.asNumber(), op));
+        return Value(atomicOperation<uint16_t>(rawStart, v2.asNumber(), op));
     case TypedArrayType::Uint32:
-        return Value(atomicOperation<uint32_t, int64_t>(rawStart, v2.asNumber(), op));
+        return Value(atomicOperation<uint32_t>(rawStart, v2.asNumber(), op));
     case TypedArrayType::Uint8Clamped:
-        return Value(atomicOperation<uint8_t, int64_t>(rawStart, v2.asNumber(), op));
+        return Value(atomicOperation<uint8_t>(rawStart, v2.asNumber(), op));
     case TypedArrayType::BigInt64:
-        return new BigInt(atomicOperation<int64_t, int64_t>(rawStart, v2.asBigInt()->toInt64(), op));
+        return new BigInt(atomicOperation<int64_t>(rawStart, v2.asBigInt()->toInt64(), op));
     default:
         ASSERT(TypedArrayType::BigUint64 == type);
-        return new BigInt(atomicOperation<uint64_t, uint64_t>(rawStart, v2.asBigInt()->toUint64(), op));
+        return new BigInt(atomicOperation<uint64_t>(rawStart, v2.asBigInt()->toUint64(), op));
     }
 }
 
@@ -299,14 +279,6 @@ static Value builtinAtomicsExchange(ExecutionState& state, Value thisValue, size
     return atomicReadModifyWrite(state, argv[0], argv[1], argv[2], AtomicBinaryOps::EXCH);
 }
 
-#if defined(HAVE_BUILTIN_ATOMIC_FUNCTIONS)
-template <typename T>
-void atomicLoad(uint8_t* rawStart, uint8_t* rawBytes)
-{
-    __atomic_load(reinterpret_cast<T*>(rawStart), reinterpret_cast<T*>(rawBytes), __ATOMIC_SEQ_CST);
-}
-#endif
-
 static Value builtinAtomicsLoad(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
 {
     ArrayBuffer* buffer = validateIntegerTypedArray(state, argv[0]);
@@ -314,44 +286,7 @@ static Value builtinAtomicsLoad(ExecutionState& state, Value thisValue, size_t a
     size_t indexedPosition = validateAtomicAccess(state, TA, argv[1]);
     TypedArrayType type = TA->typedArrayType();
 
-#if defined(HAVE_BUILTIN_ATOMIC_FUNCTIONS)
-    uint8_t* rawStart = buffer->data() + indexedPosition;
-    uint8_t* rawBytes = ALLOCA(8, uint8_t, state);
-    switch (type) {
-    case TypedArrayType::Int8:
-        atomicLoad<int8_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::Int16:
-        atomicLoad<int16_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::Int32:
-        atomicLoad<int32_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::Uint8:
-        atomicLoad<uint8_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::Uint16:
-        atomicLoad<uint16_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::Uint32:
-        atomicLoad<uint32_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::Uint8Clamped:
-        atomicLoad<uint8_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::BigInt64:
-        atomicLoad<int64_t>(rawStart, rawBytes);
-        break;
-    default:
-        ASSERT(TypedArrayType::BigUint64 == type);
-        atomicLoad<uint64_t>(rawStart, rawBytes);
-        break;
-    }
-    return TypedArrayHelper::rawBytesToNumber(state, type, rawBytes);
-#else
-    std::lock_guard<SpinLock> guard(Global::atomicsLock());
     return buffer->getValueFromBuffer(state, indexedPosition, type);
-#endif
 }
 
 static Value builtinAtomicsOr(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@@ -359,14 +294,6 @@ static Value builtinAtomicsOr(ExecutionState& state, Value thisValue, size_t arg
     return atomicReadModifyWrite(state, argv[0], argv[1], argv[2], AtomicBinaryOps::OR);
 }
 
-#if defined(HAVE_BUILTIN_ATOMIC_FUNCTIONS)
-template <typename T>
-void atomicStore(uint8_t* rawStart, uint8_t* rawBytes)
-{
-    __atomic_store(reinterpret_cast<T*>(rawStart), reinterpret_cast<T*>(rawBytes), __ATOMIC_SEQ_CST);
-}
-#endif
-
 static Value builtinAtomicsStore(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
 {
     ArrayBuffer* buffer = validateIntegerTypedArray(state, argv[0]);
@@ -382,47 +309,8 @@ static Value builtinAtomicsStore(ExecutionState& state, Value thisValue, size_t
         v = Value(value.toInteger(state));
     }
 
-#if defined(HAVE_BUILTIN_ATOMIC_FUNCTIONS)
-    uint8_t* rawStart = buffer->data() + indexedPosition;
-    uint8_t* rawBytes = ALLOCA(8, uint8_t, state);
-    TypedArrayHelper::numberToRawBytes(state, type, v, rawBytes);
-
-    switch (type) {
-    case TypedArrayType::Int8:
-        atomicStore<int8_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::Int16:
-        atomicStore<int16_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::Int32:
-        atomicStore<int32_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::Uint8:
-        atomicStore<uint8_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::Uint16:
-        atomicStore<uint16_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::Uint32:
-        atomicStore<uint32_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::Uint8Clamped:
-        atomicStore<uint8_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::BigInt64:
-        atomicStore<int64_t>(rawStart, rawBytes);
-        break;
-    default:
-        ASSERT(TypedArrayType::BigUint64 == type);
-        atomicStore<uint64_t>(rawStart, rawBytes);
-        break;
-    }
-    return v;
-#else
-    std::lock_guard<SpinLock> guard(Global::atomicsLock());
     buffer->setValueInBuffer(state, indexedPosition, type, v);
     return v;
-#endif
 }
 
 static Value builtinAtomicsSub(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@@ -482,28 +370,9 @@ static Value builtinAtomicsWait(ExecutionState& state, Value thisValue, size_t a
     WL->m_mutex.lock();
     // 14. Let elementType be the Element Type value in Table 63 for arrayTypeName.
     // 15. Let w be ! GetValueFromBuffer(buffer, indexedPosition, elementType, true, SeqCst).
+    ASSERT(arrayTypeName == TypedArrayType::Int32 || arrayTypeName == TypedArrayType::BigInt64);
     Value w(Value::ForceUninitialized);
-#if defined(HAVE_BUILTIN_ATOMIC_FUNCTIONS)
-    uint8_t* rawStart = buffer->data() + indexedPosition;
-    uint8_t* rawBytes = ALLOCA(8, uint8_t, state);
-    switch (arrayTypeName) {
-    case TypedArrayType::Int32:
-        atomicLoad<int32_t>(rawStart, rawBytes);
-        break;
-    case TypedArrayType::BigInt64:
-        atomicLoad<int64_t>(rawStart, rawBytes);
-        break;
-    default:
-        RELEASE_ASSERT_NOT_REACHED();
-        break;
-    }
-    w = TypedArrayHelper::rawBytesToNumber(state, arrayTypeName, rawBytes);
-#else
-    {
-        std::lock_guard<SpinLock> guard(Global::atomicsLock());
-        w = buffer->getValueFromBuffer(state, indexedPosition, arrayTypeName);
-    }
-#endif
+    w = buffer->getValueFromBuffer(state, indexedPosition, arrayTypeName);
     // 16. If v ≠ w, then
     if (!v.equalsTo(state, w)) {
         // a. Perform LeaveCriticalSection(WL).
@@ -595,7 +464,7 @@ static Value builtinAtomicsNotify(ExecutionState& state, Value thisValue, size_t
 
 static Value builtinAtomicsIsLockFree(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
 {
-    auto size = argv[0].toInteger(state);
+    const auto size = argv[0].toInteger(state);
 #if defined(HAVE_BUILTIN_ATOMIC_FUNCTIONS)
     if (size == 1 || size == 2 || size == 4 || size == 8) {
         return Value(true);
index 73ac0e601b6ad0db690868b8e128f891ca6e650d..adc89e24586bf396b65fed3854d7f6cf1622cef5 100644 (file)
@@ -163,7 +163,7 @@ static Value builtinBigIntToLocaleString(ExecutionState& state, Value thisValue,
 {
     RESOLVE_THIS_BINDING_TO_BIGINT(thisObject, BigInt, toLocaleString);
 
-#if defined(ENABLE_ICU) && defined(ENABLE_INTL)
+#if defined(ENABLE_ICU) && defined(ENABLE_INTL_NUMBERFORMAT)
     Value locales = argc > 0 ? argv[0] : Value();
     Value options = argc > 1 ? argv[1] : Value();
     Object* numberFormat = IntlNumberFormat::create(state, state.context(), locales, options);
index d5761b689c9f962fcd5a64316095070bf2ee3ccb..14a53e6d55044134037685b4fb5714819cc68499 100644 (file)
@@ -47,7 +47,7 @@ static Value builtinFunctionConstructor(ExecutionState& state, Value thisValue,
 
     size_t argumentVectorCount = argc > 1 ? argc - 1 : 0;
     Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString);
-    auto functionSource = FunctionObject::createFunctionSourceFromScriptSource(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, false, false, false);
+    auto functionSource = FunctionObject::createFunctionScript(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, false, false, false);
 
     // Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
     if (!newTarget.hasValue()) {
@@ -57,7 +57,7 @@ static Value builtinFunctionConstructor(ExecutionState& state, Value thisValue,
         return constructorRealm->globalObject()->functionPrototype();
     });
 
-    ScriptFunctionObject* result = new ScriptFunctionObject(state, proto, functionSource.codeBlock, functionSource.outerEnvironment, true, false, false);
+    ScriptFunctionObject* result = new ScriptFunctionObject(state, proto, functionSource.codeBlock, functionSource.outerEnvironment, true, false);
 
     return result;
 }
index 8f2dc5388c1b7f38b09b8aeb86d48965dc3abccf..c91dd1fa6bb8b64f0d7b3be4501c9280d8f2f037 100644 (file)
@@ -31,7 +31,7 @@ static Value builtinGeneratorFunction(ExecutionState& state, Value thisValue, si
 {
     size_t argumentVectorCount = argc > 1 ? argc - 1 : 0;
     Value sourceValue = argc >= 1 ? argv[argc - 1] : Value(String::emptyString);
-    auto functionSource = FunctionObject::createFunctionSourceFromScriptSource(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, true, false, false);
+    auto functionSource = FunctionObject::createFunctionScript(state, state.context()->staticStrings().anonymous, argumentVectorCount, argv, sourceValue, false, true, false, false);
 
     // Let proto be ? GetPrototypeFromConstructor(newTarget, fallbackProto).
     if (!newTarget.hasValue()) {
index 38b7fe93de53f499e799e91382c925d5750fb6e3..9091e5db02a4f20f6b00607fba92f5bf766ba77f 100644 (file)
@@ -315,6 +315,7 @@ static Value builtinIntlDateTimeFormatSupportedLocalesOf(ExecutionState& state,
     return Intl::supportedLocales(state, availableLocales, requestedLocales, options);
 }
 
+#if defined(ENABLE_INTL_NUMBERFORMAT)
 static Value builtinIntlNumberFormatFormat(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
 {
     FunctionObject* callee = state.resolveCallee();
@@ -440,7 +441,9 @@ static Value builtinIntlNumberFormatSupportedLocalesOf(ExecutionState& state, Va
     // Return the result of calling the SupportedLocales abstract operation (defined in 9.2.8) with arguments availableLocales, requestedLocales, and options.
     return Intl::supportedLocales(state, availableLocales, requestedLocales, options);
 }
+#endif
 
+#if defined(ENABLE_INTL_PLURALRULES)
 static Value builtinIntlPluralRulesConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
 {
     // If NewTarget is undefined, throw a TypeError exception.
@@ -560,6 +563,7 @@ static Value builtinIntlPluralRulesSupportedLocalesOf(ExecutionState& state, Val
     // Return the result of calling the SupportedLocales abstract operation (defined in 9.2.8) with arguments availableLocales, requestedLocales, and options.
     return Intl::supportedLocales(state, availableLocales, requestedLocales, options);
 }
+#endif
 
 static Value builtinIntlLocaleConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
 {
@@ -896,6 +900,7 @@ static Value builtinIntlLocaleTimeZonesGetter(ExecutionState& state, Value thisV
     return thisValue.asObject()->asIntlLocaleObject()->timeZones(state);
 }
 
+#if defined(ENABLE_INTL_RELATIVETIMEFORMAT)
 static Value builtinIntlRelativeTimeFormatConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
 {
     // If NewTarget is undefined, throw a TypeError exception.
@@ -986,7 +991,9 @@ static Value builtinIntlRelativeTimeFormatFormatToParts(ExecutionState& state, V
     // Return ? FormatRelativeTimeToParts(relativeTimeFormat, value, unit).
     return thisValue.asObject()->asIntlRelativeTimeFormatObject()->formatToParts(state, value, unit);
 }
+#endif
 
+#if defined(ENABLE_INTL_DISPLAYNAMES)
 static Value builtinIntlDisplayNamesConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
 {
     // https://402.ecma-international.org/8.0/#sec-Intl.DisplayNames
@@ -1029,7 +1036,9 @@ static Value builtinIntlDisplayNamesResolvedOptions(ExecutionState& state, Value
     options->defineOwnPropertyThrowsException(state, ObjectPropertyName(staticStrings.lazyLanguageDisplay()), ObjectPropertyDescriptor(r->languageDisplay(), ObjectPropertyDescriptor::AllPresent));
     return options;
 }
+#endif
 
+#if defined(ENABLE_INTL_LISTFORMAT)
 static Value builtinIntlListFormatConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
 {
     // If NewTarget is undefined, throw a TypeError exception.
@@ -1097,6 +1106,7 @@ static Value builtinIntlListFormatFormatToParts(ExecutionState& state, Value thi
     IntlListFormatObject* r = thisValue.asObject()->asIntlListFormatObject();
     return r->formatToParts(state, argv[0]);
 }
+#endif
 
 static Value builtinIntlGetCanonicalLocales(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
 {
@@ -1162,6 +1172,7 @@ void GlobalObject::installIntl(ExecutionState& state)
     m_intlDateTimeFormat->defineOwnProperty(state, state.context()->staticStrings().supportedLocalesOf,
                                             ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->supportedLocalesOf, builtinIntlDateTimeFormatSupportedLocalesOf, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent)));
 
+#if defined(ENABLE_INTL_NUMBERFORMAT)
     m_intlNumberFormat = new NativeFunctionObject(state, NativeFunctionInfo(strings->NumberFormat, builtinIntlNumberFormatConstructor, 0), NativeFunctionObject::__ForBuiltinConstructor__);
     m_intlNumberFormat->setGlobalIntrinsicObject(state);
     m_intlNumberFormatPrototype = m_intlNumberFormat->getFunctionPrototype(state).asObject();
@@ -1185,7 +1196,9 @@ void GlobalObject::installIntl(ExecutionState& state)
 
     m_intlNumberFormat->defineOwnProperty(state, state.context()->staticStrings().supportedLocalesOf,
                                           ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->supportedLocalesOf, builtinIntlNumberFormatSupportedLocalesOf, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::WritablePresent)));
+#endif
 
+#if defined(ENABLE_INTL_PLURALRULES)
     m_intlPluralRules = new NativeFunctionObject(state, NativeFunctionInfo(strings->PluralRules, builtinIntlPluralRulesConstructor, 0), NativeFunctionObject::__ForBuiltinConstructor__);
     m_intlPluralRules->setGlobalIntrinsicObject(state);
 
@@ -1203,7 +1216,7 @@ void GlobalObject::installIntl(ExecutionState& state)
 
     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)));
-
+#endif
 
     m_intlLocale = new NativeFunctionObject(state, NativeFunctionInfo(strings->Locale, builtinIntlLocaleConstructor, 1), NativeFunctionObject::__ForBuiltinConstructor__);
     m_intlLocale->setGlobalIntrinsicObject(state);
@@ -1342,6 +1355,7 @@ void GlobalObject::installIntl(ExecutionState& state)
         m_intlLocalePrototype->defineOwnProperty(state, ObjectPropertyName(state, strings->lazyTimeZones()), desc);
     }
 
+#if defined(ENABLE_INTL_RELATIVETIMEFORMAT)
     m_intlRelativeTimeFormat = new NativeFunctionObject(state, NativeFunctionInfo(strings->RelativeTimeFormat, builtinIntlRelativeTimeFormatConstructor, 0), NativeFunctionObject::__ForBuiltinConstructor__);
     m_intlRelativeTimeFormat->setGlobalIntrinsicObject(state);
 
@@ -1362,7 +1376,9 @@ 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)));
+#endif
 
+#if defined(ENABLE_INTL_DISPLAYNAMES)
     m_intlDisplayNames = new NativeFunctionObject(state, NativeFunctionInfo(strings->DisplayNames, builtinIntlDisplayNamesConstructor, 2), NativeFunctionObject::__ForBuiltinConstructor__);
     m_intlDisplayNames->setGlobalIntrinsicObject(state);
 
@@ -1377,7 +1393,9 @@ void GlobalObject::installIntl(ExecutionState& state)
 
     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)));
+#endif
 
+#if defined(ENABLE_INTL_LISTFORMAT)
     m_intlListFormat = new NativeFunctionObject(state, NativeFunctionInfo(strings->ListFormat, builtinIntlListFormatConstructor, 0), NativeFunctionObject::__ForBuiltinConstructor__);
     m_intlListFormat->setGlobalIntrinsicObject(state);
 
@@ -1401,31 +1419,35 @@ void GlobalObject::installIntl(ExecutionState& state)
 
     m_intl->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag),
                                              ObjectPropertyDescriptor(Value(state.context()->staticStrings().Intl.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
+#endif
 
     m_intl->defineOwnProperty(state, ObjectPropertyName(strings->Collator),
                               ObjectPropertyDescriptor(m_intlCollator, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
 
     m_intl->defineOwnProperty(state, ObjectPropertyName(strings->DateTimeFormat),
                               ObjectPropertyDescriptor(m_intlDateTimeFormat, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
-
+#if defined(ENABLE_INTL_NUMBERFORMAT)
     m_intl->defineOwnProperty(state, ObjectPropertyName(strings->NumberFormat),
                               ObjectPropertyDescriptor(m_intlNumberFormat, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
-
+#endif
+#if defined(ENABLE_INTL_PLURALRULES)
     m_intl->defineOwnProperty(state, ObjectPropertyName(strings->PluralRules),
                               ObjectPropertyDescriptor(m_intlPluralRules, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
-
+#endif
     m_intl->defineOwnProperty(state, ObjectPropertyName(strings->Locale),
                               ObjectPropertyDescriptor(m_intlLocale, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
-
+#if defined(ENABLE_INTL_RELATIVETIMEFORMAT)
     m_intl->defineOwnProperty(state, ObjectPropertyName(strings->RelativeTimeFormat),
                               ObjectPropertyDescriptor(m_intlRelativeTimeFormat, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
-
+#endif
+#if defined(ENABLE_INTL_DISPLAYNAMES)
     m_intl->defineOwnProperty(state, ObjectPropertyName(strings->DisplayNames),
                               ObjectPropertyDescriptor(m_intlDisplayNames, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
-
+#endif
+#if defined(ENABLE_INTL_LISTFORMAT)
     m_intl->defineOwnProperty(state, ObjectPropertyName(strings->ListFormat),
                               ObjectPropertyDescriptor(m_intlListFormat, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
-
+#endif
     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)));
index 9036522c04d6cf3aba5c90bf5418867df9fadfe6..d7bdb74fbc7d35fd88920aa5edd0ec07d903b608 100644 (file)
@@ -116,16 +116,17 @@ static Value parseJSONWorker(ExecutionState& state, rapidjson::GenericValue<JSON
             const char16_t* chars = (const char16_t*)value.GetString();
             unsigned len = value.GetStringLength();
             if (isAllLatin1(chars, len)) {
-                return new Latin1String(chars, len);
+                return String::fromLatin1(chars, len);
             } else {
                 return new UTF16String(chars, len);
             }
         } else {
             const char* valueAsString = (const char*)value.GetString();
-            if (isAllASCII(valueAsString, strlen(valueAsString))) {
-                return new ASCIIString(valueAsString);
+            size_t len = strlen(valueAsString);
+            if (isAllASCII(valueAsString, len)) {
+                return String::fromASCII(valueAsString, len);
             } else {
-                return new UTF16String(utf8StringToUTF16String(valueAsString, strlen(valueAsString)));
+                return new UTF16String(utf8StringToUTF16String(valueAsString, len));
             }
         }
     } else if (value.IsArray()) {
@@ -279,7 +280,7 @@ static Value builtinJSONParse(ExecutionState& state, Value thisValue, size_t arg
                     }
                 }
             }
-            Value arguments[] = { name.toPlainValue(state), val };
+            Value arguments[] = { name.toPlainValue(), val };
             return Object::call(state, reviver, holder, 2, arguments);
         };
         return Walk(root, ObjectPropertyName(state, String::emptyString));
@@ -643,7 +644,7 @@ static Value builtinJSONStringify(ExecutionState& state, Value thisValue, size_t
 
             std::vector<Value::ValueIndex> indexes;
             arrObject->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& P, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
-                Value::ValueIndex idx = P.toPlainValue(state).toNumber(state);
+                Value::ValueIndex idx = P.toPlainValue().toNumber(state);
                 if (idx != Value::InvalidIndexValue) {
                     std::vector<Value::ValueIndex>* indexes = (std::vector<Value::ValueIndex>*)data;
                     indexes->push_back(idx);
index e30939888909c199727a3ebe2c36a0c31d3dfec7..f8fe9e173d579aa730df73b8a105f61f4c4f98d4 100644 (file)
@@ -133,7 +133,8 @@ static Value builtinNumberToFixed(ExecutionState& state, Value thisValue, size_t
     char buffer[NUMBER_TO_STRING_BUFFER_LENGTH];
     double_conversion::StringBuilder builder(buffer, NUMBER_TO_STRING_BUFFER_LENGTH);
     double_conversion::DoubleToStringConverter::EcmaScriptConverter().ToFixed(number, digit, &builder);
-    return Value(new ASCIIString(builder.Finalize()));
+    auto len = builder.position();
+    return Value(String::fromASCII(builder.Finalize(), len));
 }
 
 static Value builtinNumberToExponential(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@@ -174,7 +175,8 @@ static Value builtinNumberToExponential(ExecutionState& state, Value thisValue,
     } else {
         double_conversion::DoubleToStringConverter::EcmaScriptConverter().ToExponential(number, digit, &builder);
     }
-    return Value(new ASCIIString(builder.Finalize()));
+    auto len = builder.position();
+    return Value(String::fromASCII(builder.Finalize(), len));
 }
 
 static Value builtinNumberToPrecision(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@@ -215,7 +217,8 @@ static Value builtinNumberToPrecision(ExecutionState& state, Value thisValue, si
     char buffer[NUMBER_TO_STRING_BUFFER_LENGTH];
     double_conversion::StringBuilder builder(buffer, NUMBER_TO_STRING_BUFFER_LENGTH);
     double_conversion::DoubleToStringConverter::EcmaScriptConverter().ToPrecision(number, p, &builder);
-    return Value(new ASCIIString(builder.Finalize()));
+    auto len = builder.position();
+    return Value(String::fromASCII(builder.Finalize(), len));
 }
 
 static Value builtinNumberToString(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
@@ -255,12 +258,12 @@ static Value builtinNumberToString(ExecutionState& state, Value thisValue, size_
         } else {
             itoa(static_cast<int64_t>(number), buffer, radix);
         }
-        return new ASCIIString(buffer);
+        return String::fromASCII(buffer, strlen(buffer));
     } else {
         ASSERT(Value(number).isDouble());
         NumberObject::RadixBuffer s;
         const char* str = NumberObject::toStringWithRadix(state, s, number, radix);
-        return new ASCIIString(str);
+        return String::fromASCII(str, strlen(str));
     }
 }
 
@@ -271,7 +274,7 @@ static Value builtinNumberToLocaleString(ExecutionState& state, Value thisValue,
         ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, ErrorObject::Messages::GlobalObject_ThisNotNumber);
     }
 
-#if defined(ENABLE_ICU) && defined(ENABLE_INTL)
+#if defined(ENABLE_ICU) && defined(ENABLE_INTL_NUMBERFORMAT)
     Value locales = argc > 0 ? argv[0] : Value();
     Value options = argc > 1 ? argv[1] : Value();
     Object* numberFormat = IntlNumberFormat::create(state, state.context(), locales, options);
index 0c339ecbfd58a554e7bdc5659455670381019a99..1f1f44c0dd52ce7cec09a6dddfbe38ad1d7ce94e 100644 (file)
@@ -107,7 +107,9 @@ static Value builtinRegExpExec(ExecutionState& state, Value thisValue, size_t ar
         int e = result.m_matchResults[0][0].m_end;
         if (option & RegExpObject::Option::Unicode) {
             char16_t utfRes = str->charAt(e);
-            size_t eUTF = str->find(new ASCIIString((const char*)&utfRes), 0);
+            const char* buf = reinterpret_cast<const char*>(&utfRes);
+            size_t len = strlen(buf);
+            size_t eUTF = str->find(buf, len, 0);
             if (eUTF >= str->length()) {
                 e = str->length();
             } else if ((int)eUTF > e || e == (int)str->length()) {
index 75355b767ccbb1ffb417fffe47c5ab4b16283874..ac8dc78424194fc53e21f9c0c58dab10c572cde3 100644 (file)
@@ -87,6 +87,25 @@ static Value builtinSharedArrayBufferGrowableGetter(ExecutionState& state, Value
     return Value(obj->isResizableArrayBuffer());
 }
 
+static Value builtinSharedArrayBufferGrow(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
+{
+    RESOLVE_THIS_BINDING_TO_SHAREDARRAYBUFFER(O, SharedArrayBuffer, grow);
+
+    if (!O->isResizableArrayBuffer()) {
+        ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, state.context()->staticStrings().SharedArrayBuffer.string(), true, state.context()->staticStrings().grow.string(), "SharedArrayBuffer is not a growable buffer");
+    }
+
+    // Let newByteLength to ? ToIntegerOrInfinity(newLength).
+    auto newByteLength = argv[0].toInteger(state);
+
+    if ((newByteLength < O->byteLength()) || (newByteLength > O->maxByteLength())) {
+        ErrorObject::throwBuiltinError(state, ErrorObject::RangeError, state.context()->staticStrings().SharedArrayBuffer.string(), true, state.context()->staticStrings().grow.string(), ErrorObject::Messages::GlobalObject_FirstArgumentInvalidLength);
+    }
+
+    O->backingStore()->resize(static_cast<size_t>(newByteLength));
+    return Value();
+}
+
 // https://262.ecma-international.org/#sec-sharedarraybuffer.prototype.slice
 static Value builtinSharedArrayBufferSlice(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
 {
@@ -166,6 +185,8 @@ void GlobalObject::installSharedArrayBuffer(ExecutionState& state)
         m_sharedArrayBufferPrototype->defineOwnProperty(state, ObjectPropertyName(strings->growable), growableDesc);
     }
 
+    m_sharedArrayBufferPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->grow),
+                                                                   ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->grow, builtinSharedArrayBufferGrow, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
 
     m_sharedArrayBufferPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->slice),
                                                                    ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->slice, builtinSharedArrayBufferSlice, 2, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
index db663507bd6924494cc2f673bed8b10180ba0128..2407a3f3f24769be540394cd345942f777055f80 100644 (file)
@@ -175,9 +175,7 @@ static Value builtinStringSubstring(ExecutionState& state, Value thisValue, size
         ASSERT(from <= to);
         if (to - from == 1) {
             char16_t c = str->charAt(from);
-            if (c < ESCARGOT_ASCII_TABLE_MAX) {
-                return state.context()->staticStrings().asciiTable[c].string();
-            }
+            return state.context()->staticStrings().charCodeToString(c);
         }
         return str->substring(from, to);
     }
@@ -793,17 +791,11 @@ static Value builtinStringCharCodeAt(ExecutionState& state, Value thisValue, siz
     RESOLVE_THIS_BINDING_TO_STRING(str, String, charCodeAt);
     int position = argv[0].toInteger(state);
     Value ret;
-    const auto& data = str->bufferAccessData();
-    if (position < 0 || position >= (int)data.length)
+    size_t length = str->length();
+    if (position < 0 || position >= (int)length)
         ret = Value(std::numeric_limits<double>::quiet_NaN());
     else {
-        char16_t c;
-        if (data.has8BitContent) {
-            c = ((LChar*)data.buffer)[position];
-        } else {
-            c = ((char16_t*)data.buffer)[position];
-        }
-        ret = Value(c);
+        ret = Value(str->charAt(position));
     }
     return ret;
 }
@@ -814,29 +806,17 @@ static Value builtinStringCodePointAt(ExecutionState& state, Value thisValue, si
     RESOLVE_THIS_BINDING_TO_STRING(str, String, codePointAt);
     int position = argv[0].toInteger(state);
     Value ret;
-    const auto& data = str->bufferAccessData();
-    const int size = (int)data.length;
+    size_t length = str->length();
+    const int size = (int)length;
     if (position < 0 || position >= size)
         return Value();
 
-    char16_t first;
-    if (data.has8BitContent) {
-        first = ((LChar*)data.buffer)[position];
-    } else {
-        first = ((char16_t*)data.buffer)[position];
-    }
-
+    char16_t first = str->charAt(position);
     if (first < 0xD800 || first > 0xDBFF || (position + 1) == size) {
         return Value(first);
     }
 
-    char16_t second;
-    if (data.has8BitContent) {
-        second = ((LChar*)data.buffer)[position + 1];
-    } else {
-        second = ((char16_t*)data.buffer)[position + 1];
-    }
-
+    char16_t second = str->charAt(position + 1);
     if (second < 0xDC00 || second > 0xDFFF) {
         return Value(first);
     }
@@ -854,20 +834,10 @@ static Value builtinStringCharAt(ExecutionState& state, Value thisValue, size_t
         position = argv[0].toInteger(state);
     }
 
-    const auto& accessData = str->bufferAccessData();
-
-    if (LIKELY(0 <= position && position < (int64_t)accessData.length)) {
-        char16_t c;
-        if (accessData.has8BitContent) {
-            c = ((LChar*)accessData.buffer)[position];
-        } else {
-            c = ((char16_t*)accessData.buffer)[position];
-        }
-        if (LIKELY(c < ESCARGOT_ASCII_TABLE_MAX)) {
-            return state.context()->staticStrings().asciiTable[c].string();
-        } else {
-            return String::fromCharCode(c);
-        }
+    const auto length = str->length();
+    if (LIKELY(0 <= position && position < (int64_t)length)) {
+        char16_t c = str->charAt(position);
+        return state.context()->staticStrings().charCodeToString(c);
     } else {
         return String::emptyString;
     }
@@ -877,9 +847,7 @@ static Value builtinStringFromCharCode(ExecutionState& state, Value thisValue, s
 {
     if (argc == 1) {
         char16_t c = argv[0].toUint32(state) & 0xFFFF;
-        if (c < ESCARGOT_ASCII_TABLE_MAX)
-            return state.context()->staticStrings().asciiTable[c].string();
-        return String::fromCharCode(c);
+        return state.context()->staticStrings().charCodeToString(c);
     }
 
     StringBuilder builder;
@@ -972,20 +940,32 @@ static Value builtinStringToLowerCase(ExecutionState& state, Value thisValue, si
 {
     RESOLVE_THIS_BINDING_TO_STRING(str, String, toLowerCase);
     if (str->has8BitContent()) {
-        Latin1StringData newStr;
         size_t len = str->length();
-        newStr.resizeWithUninitializedValues(len);
-        const LChar* buf = str->characters8();
+        const LChar* from = str->characters8();
+        LChar* dest;
+        Latin1StringData newStr;
+        if (len <= LATIN1_LARGE_INLINE_BUFFER_MAX_SIZE) {
+            dest = static_cast<LChar*>(alloca(len));
+        } else {
+            newStr.resizeWithUninitializedValues(len);
+            dest = newStr.data();
+        }
+
         for (size_t i = 0; i < len; i++) {
 #if defined(ENABLE_ICU)
-            char32_t u2 = u_tolower(buf[i]);
+            char32_t u2 = u_tolower(from[i]);
 #else
-            char32_t u2 = tolower(buf[i]);
+            char32_t u2 = tolower(from[i]);
 #endif
             ASSERT(u2 < 256);
-            newStr[i] = u2;
+            dest[i] = u2;
+        }
+
+        if (len <= LATIN1_LARGE_INLINE_BUFFER_MAX_SIZE) {
+            return String::fromLatin1(dest, len);
+        } else {
+            return new Latin1String(std::move(newStr));
         }
-        return new Latin1String(std::move(newStr));
     }
 
 #if defined(ENABLE_ICU)
@@ -1531,7 +1511,7 @@ static Value builtinStringAt(ExecutionState& state, Value thisValue, size_t argc
     if (relativeStart < 0 || relativeStart >= len) {
         return Value();
     }
-    return String::fromCharCode(str->charAt(relativeStart));
+    return state.context()->staticStrings().charCodeToString(str->charAt(relativeStart));
 }
 
 #define DEFINE_STRING_ADDITIONAL_HTML_FUNCTION(fnName, P0, P1, P2)                                                                    \
index 6ffdf5d3312cb0f5bf323ea6bc3bc2b84a6f9c03..e0a3cbbc3631c71a79f02681a55d80a6dc08328a 100644 (file)
 #ifdef ESCARGOT_DEBUGGER
 namespace Escargot {
 
-void Debugger::sendType(uint8_t type)
+void Debugger::enable(Context* context)
+{
+    ASSERT(m_context == nullptr);
+    m_context = context;
+    m_context->initDebugger(this);
+}
+
+void Debugger::disable()
+{
+    ASSERT(m_context != nullptr);
+    m_context->removeDebugger();
+    m_context = nullptr;
+}
+
+void DebuggerRemote::sendType(uint8_t type)
 {
     send(type, nullptr, 0);
 }
 
-void Debugger::sendSubtype(uint8_t type, uint8_t subType)
+void DebuggerRemote::sendSubtype(uint8_t type, uint8_t subType)
 {
     send(type, &subType, 1);
 }
 
-void Debugger::sendString(uint8_t type, String* string)
+void DebuggerRemote::sendString(uint8_t type, String* string)
 {
     size_t length = string->length();
 
@@ -75,44 +89,95 @@ void Debugger::sendString(uint8_t type, String* string)
     send(type + 2 + 1, chars, length * 2);
 }
 
-void Debugger::sendPointer(uint8_t type, const void* ptr)
+void DebuggerRemote::sendPointer(uint8_t type, const void* ptr)
 {
     // The pointer itself is sent, not the data pointed by it
     send(type, (void*)&ptr, sizeof(void*));
 }
 
-void Debugger::sendFunctionInfo(InterpretedCodeBlock* codeBlock)
+void DebuggerRemote::parseCompleted(String* source, String* srcName, String* error)
 {
-    char* byteCodeStart = codeBlock->byteCodeBlock()->m_code.data();
-    uint32_t startLine = (uint32_t)codeBlock->functionStart().line;
-    uint32_t startColumn = (uint32_t)(codeBlock->functionStart().column + 1);
-    FunctionInfo functionInfo;
+    if (!enabled()) {
+        return;
+    }
 
-    memcpy(&functionInfo.byteCodeStart, (void*)&byteCodeStart, sizeof(char*));
-    memcpy(&functionInfo.startLine, &startLine, sizeof(uint32_t));
-    memcpy(&functionInfo.startColumn, &startColumn, sizeof(uint32_t));
+    sendString(ESCARGOT_MESSAGE_SOURCE_8BIT, source);
 
-    send(ESCARGOT_MESSAGE_FUNCTION_PTR, (void*)&functionInfo, sizeof(FunctionInfo));
-}
+    if (!enabled()) {
+        return;
+    }
 
-void Debugger::sendBreakpointLocations(std::vector<Debugger::BreakpointLocation>& locations)
-{
-    const size_t maxPacketLength = (ESCARGOT_DEBUGGER_MAX_MESSAGE_LENGTH - 1) / sizeof(BreakpointLocation);
-    BreakpointLocation* ptr = locations.data();
-    size_t length = locations.size();
+    sendString(ESCARGOT_MESSAGE_FILE_NAME_8BIT, srcName);
 
-    while (length > maxPacketLength) {
-        if (!send(ESCARGOT_MESSAGE_BREAKPOINT_LOCATION, ptr, maxPacketLength * sizeof(BreakpointLocation))) {
+    if (!enabled()) {
+        return;
+    }
+
+    if (error != nullptr) {
+        sendType(ESCARGOT_MESSAGE_PARSE_ERROR);
+
+        if (enabled()) {
+            sendString(ESCARGOT_MESSAGE_STRING_8BIT, error);
+        }
+        return;
+    }
+
+    size_t breakpointLocationsSize = m_breakpointLocationsVector.size();
+
+    for (size_t i = 0; i < breakpointLocationsSize; i++) {
+        /* Send breakpoint locations. */
+        const size_t maxPacketLength = (ESCARGOT_DEBUGGER_MAX_MESSAGE_LENGTH - 1) / sizeof(BreakpointLocation);
+        BreakpointLocation* ptr = m_breakpointLocationsVector[i]->breakpointLocations.data();
+        size_t length = m_breakpointLocationsVector[i]->breakpointLocations.size();
+
+        while (length > maxPacketLength) {
+            if (!send(ESCARGOT_MESSAGE_BREAKPOINT_LOCATION, ptr, maxPacketLength * sizeof(BreakpointLocation))) {
+                return;
+            }
+            ptr += maxPacketLength;
+            length -= maxPacketLength;
+        }
+
+        if (!send(ESCARGOT_MESSAGE_BREAKPOINT_LOCATION, ptr, length * sizeof(BreakpointLocation))) {
+            return;
+        }
+
+        InterpretedCodeBlock* codeBlock = reinterpret_cast<InterpretedCodeBlock*>(m_breakpointLocationsVector[i]->weakCodeRef);
+        String* functionName = codeBlock->functionName().string();
+
+        /* Send function name. */
+        if (functionName->length() > 0) {
+            StringView* functionNameView = new StringView(functionName);
+            sendString(ESCARGOT_MESSAGE_FUNCTION_NAME_8BIT, functionNameView);
+
+            if (!enabled()) {
+                return;
+            }
+        }
+
+        /* Send function info. */
+        char* byteCodeStart = codeBlock->byteCodeBlock()->m_code.data();
+        uint32_t startLine = (uint32_t)codeBlock->functionStart().line;
+        uint32_t startColumn = (uint32_t)(codeBlock->functionStart().column + 1);
+        FunctionInfo functionInfo;
+
+        memcpy(&functionInfo.byteCodeStart, (void*)&byteCodeStart, sizeof(char*));
+        memcpy(&functionInfo.startLine, &startLine, sizeof(uint32_t));
+        memcpy(&functionInfo.startColumn, &startColumn, sizeof(uint32_t));
+
+        if (!send(ESCARGOT_MESSAGE_FUNCTION_PTR, (void*)&functionInfo, sizeof(FunctionInfo))) {
             return;
         }
-        ptr += maxPacketLength;
-        length -= maxPacketLength;
     }
 
-    send(ESCARGOT_MESSAGE_BREAKPOINT_LOCATION, ptr, length * sizeof(BreakpointLocation));
+    sendType(ESCARGOT_MESSAGE_PARSE_DONE);
+
+    if (enabled() && pendingWait()) {
+        waitForResolvingPendingBreakpoints();
+    }
 }
 
-void Debugger::sendBacktraceInfo(uint8_t type, ByteCodeBlock* byteCodeBlock, uint32_t line, uint32_t column, uint32_t executionStateDepth)
+void DebuggerRemote::sendBacktraceInfo(uint8_t type, ByteCodeBlock* byteCodeBlock, uint32_t line, uint32_t column, uint32_t executionStateDepth)
 {
     BacktraceInfo backtraceInfo;
 
@@ -125,7 +190,7 @@ void Debugger::sendBacktraceInfo(uint8_t type, ByteCodeBlock* byteCodeBlock, uin
     send(type, &backtraceInfo, sizeof(BacktraceInfo));
 }
 
-void Debugger::sendVariableObjectInfo(uint8_t subType, Object* object)
+void DebuggerRemote::sendVariableObjectInfo(uint8_t subType, Object* object)
 {
     /* Maximum UINT32_MAX number of objects are stored. */
     uint32_t size = (uint32_t)m_activeObjects.size();
@@ -141,19 +206,19 @@ void Debugger::sendVariableObjectInfo(uint8_t subType, Object* object)
         m_activeObjects.pushBack(object);
     }
 
-    Debugger::VariableObjectInfo variableObjectInfo;
+    VariableObjectInfo variableObjectInfo;
 
     variableObjectInfo.subType = subType;
     memcpy(&variableObjectInfo.index, &index, sizeof(uint32_t));
-    send(Debugger::ESCARGOT_MESSAGE_VARIABLE, &variableObjectInfo, sizeof(VariableObjectInfo));
+    send(ESCARGOT_MESSAGE_VARIABLE, &variableObjectInfo, sizeof(VariableObjectInfo));
 }
 
-void Debugger::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state)
+void DebuggerRemote::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state)
 {
     if (m_stopState == ESCARGOT_DEBUGGER_IN_EVAL_MODE) {
-        m_delay = (uint8_t)(m_delay - 1);
+        m_delay--;
         if (m_delay == 0) {
-            processIncomingMessages(state, byteCodeBlock);
+            processEvents(state, byteCodeBlock);
         }
         return;
     }
@@ -173,21 +238,81 @@ void Debugger::stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, E
     ASSERT(m_activeObjects.size() == 0);
     m_stopState = ESCARGOT_DEBUGGER_IN_WAIT_MODE;
 
-    while (processIncomingMessages(state, byteCodeBlock))
+    while (processEvents(state, byteCodeBlock))
         ;
 
     m_activeObjects.clear();
     m_delay = ESCARGOT_DEBUGGER_MESSAGE_PROCESS_DELAY;
 }
 
-void Debugger::releaseFunction(const void* ptr)
+void DebuggerRemote::byteCodeReleaseNotification(ByteCodeBlock* byteCodeBlock)
 {
     // All messages which involves this pointer should be ignored until the confirmation arrives.
-    m_releasedFunctions.push_back(reinterpret_cast<uintptr_t>(ptr));
-    sendPointer(ESCARGOT_MESSAGE_RELEASE_FUNCTION, ptr);
+    if (enabled()) {
+        m_releasedFunctions.push_back(reinterpret_cast<uintptr_t>(byteCodeBlock));
+        sendPointer(ESCARGOT_MESSAGE_RELEASE_FUNCTION, byteCodeBlock);
+    }
+}
+
+void DebuggerRemote::exceptionCaught(String* message, SavedStackTraceDataVector& exceptionTrace)
+{
+    if (!enabled()) {
+        return;
+    }
+
+    sendType(ESCARGOT_MESSAGE_EXCEPTION);
+
+    if (!enabled()) {
+        return;
+    }
+
+    sendString(ESCARGOT_MESSAGE_STRING_8BIT, message);
+
+    size_t size = exceptionTrace.size();
+    for (size_t i = 0; i < size && enabled(); i++) {
+        sendBacktraceInfo(ESCARGOT_MESSAGE_EXCEPTION_BACKTRACE, exceptionTrace[i].byteCodeBlock, exceptionTrace[i].line, exceptionTrace[i].column, UINT32_MAX);
+    }
 }
 
-bool Debugger::doEval(ExecutionState* state, ByteCodeBlock* byteCodeBlock, uint8_t* buffer, size_t length)
+void DebuggerRemote::consoleOut(String* output)
+{
+    if (enabled()) {
+        sendType(ESCARGOT_MESSAGE_PRINT);
+
+        if (enabled()) {
+            sendString(ESCARGOT_MESSAGE_STRING_8BIT, output);
+        }
+    }
+}
+
+String* DebuggerRemote::getClientSource(String** sourceName)
+{
+    if (!enabled()) {
+        return nullptr;
+    }
+
+    sendType(ESCARGOT_DEBUGGER_WAIT_FOR_SOURCE);
+    while (processEvents(nullptr, nullptr))
+        ;
+
+    if (sourceName) {
+        *sourceName = m_clientSourceName;
+    }
+    String* sourceData = m_clientSourceData;
+    m_clientSourceName = nullptr;
+    m_clientSourceData = nullptr;
+    return sourceData;
+}
+
+bool DebuggerRemote::getWaitBeforeExitClient()
+{
+    sendType(ESCARGOT_DEBUGGER_WAIT_FOR_WAIT_EXIT);
+    while (processEvents(nullptr, nullptr))
+        ;
+    return this->m_exitClient;
+}
+
+bool DebuggerRemote::doEval(ExecutionState* state, Optional<ByteCodeBlock*> byteCodeBlock, uint8_t* buffer, size_t length)
 {
     uint8_t type = (uint8_t)(buffer[0] + 1);
     uint32_t size;
@@ -229,9 +354,9 @@ bool Debugger::doEval(ExecutionState* state, ByteCodeBlock* byteCodeBlock, uint8
     }
 
     String* str;
-    if (type == ESCARGOT_MESSAGE_EVAL_8BIT) {
+    if (type == ESCARGOT_MESSAGE_EVAL_8BIT || type == ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_8BIT) {
         str = new Latin1String(data, size);
-    } else if (type == ESCARGOT_MESSAGE_EVAL_16BIT) {
+    } else if (type == ESCARGOT_MESSAGE_EVAL_16BIT || type == ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_16BIT) {
         str = new UTF16String((char16_t*)data, size / 2);
     } else if (type == ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT) {
         char* sourceNameSrc = (char*)memchr(data, '\0', size);
@@ -259,12 +384,17 @@ bool Debugger::doEval(ExecutionState* state, ByteCodeBlock* byteCodeBlock, uint8
         return false;
     }
 
-    type = ESCARGOT_MESSAGE_EVAL_RESULT_8BIT;
     m_stopState = ESCARGOT_DEBUGGER_IN_EVAL_MODE;
 
     try {
         Value asValue(str);
-        Value result(state->context()->globalObject()->evalLocal(*state, asValue, Value(Value::Undefined), byteCodeBlock->m_codeBlock, true));
+        Value result(Value::ForceUninitialized);
+        if (type == ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_8BIT || type == ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_16BIT) {
+            result = state->context()->globalObject()->eval(*state, asValue);
+        } else {
+            result = state->context()->globalObject()->evalLocal(*state, asValue, state->thisValue(), byteCodeBlock->m_codeBlock, true);
+        }
+        type = ESCARGOT_MESSAGE_EVAL_RESULT_8BIT;
         str = result.toStringWithoutException(*state);
     } catch (const Value& val) {
         type = ESCARGOT_MESSAGE_EVAL_FAILED_8BIT;
@@ -286,23 +416,23 @@ error:
     return false;
 }
 
-void Debugger::getBacktrace(ExecutionState* state, uint32_t minDepth, uint32_t maxDepth, bool getTotal)
+void DebuggerRemote::getBacktrace(ExecutionState* state, uint32_t minDepth, uint32_t maxDepth, bool getTotal)
 {
     SandBox::StackTraceDataVector stackTraceData;
 
-    bool hasSavedStackTrace = SandBox::createStackTraceData(stackTraceData, *state, true);
+    bool hasSavedStackTrace = SandBox::createStackTrace(stackTraceData, *state, true);
 
     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) {
+        if ((size_t)stackTraceData[i].loc.actualCodeBlock != SIZE_MAX) {
             total++;
         }
     }
 
     if (hasSavedStackTrace) {
-        total += (uint32_t)m_activeSavedStackTrace->size();
+        total += (uint32_t)activeSavedStackTrace()->size();
     }
 
     if (getTotal && !send(ESCARGOT_MESSAGE_BACKTRACE_TOTAL, &total, sizeof(uint32_t))) {
@@ -321,16 +451,16 @@ void Debugger::getBacktrace(ExecutionState* state, uint32_t minDepth, uint32_t m
     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 ((size_t)stackTraceData[i].loc.actualCodeBlock != SIZE_MAX) {
             if (++counter <= minDepth) {
                 continue;
             }
 
-            ByteCodeBlock* byteCodeBlock = stackTraceData[i].second.loc.actualCodeBlock;
+            ByteCodeBlock* byteCodeBlock = stackTraceData[i].loc.actualCodeBlock;
             uint32_t line, column;
 
-            if ((size_t)stackTraceData[i].second.loc.index == SIZE_MAX) {
-                size_t byteCodePosition = stackTraceData[i].second.loc.byteCodePosition;
+            if ((size_t)stackTraceData[i].loc.index == SIZE_MAX) {
+                size_t byteCodePosition = stackTraceData[i].loc.byteCodePosition;
 
                 ByteCodeLOCData* locData;
                 auto iterMap = locMap.find(byteCodeBlock);
@@ -345,11 +475,11 @@ void Debugger::getBacktrace(ExecutionState* state, uint32_t minDepth, uint32_t m
                 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;
+                line = (uint32_t)stackTraceData[i].loc.line;
+                column = (uint32_t)stackTraceData[i].loc.column;
             }
 
-            sendBacktraceInfo(ESCARGOT_MESSAGE_BACKTRACE, byteCodeBlock, line, column, (uint32_t)stackTraceData[i].second.executionStateDepth);
+            sendBacktraceInfo(ESCARGOT_MESSAGE_BACKTRACE, byteCodeBlock, line, column, (uint32_t)stackTraceData[i].executionStateDepth);
 
             if (!enabled()) {
                 return;
@@ -362,8 +492,8 @@ void Debugger::getBacktrace(ExecutionState* state, uint32_t minDepth, uint32_t m
     }
 
     if (hasSavedStackTrace) {
-        SavedStackTraceData* savedStackTracePtr = m_activeSavedStackTrace->begin();
-        SavedStackTraceData* savedStackTraceEnd = m_activeSavedStackTrace->end();
+        SavedStackTraceData* savedStackTracePtr = activeSavedStackTrace()->begin();
+        SavedStackTraceData* savedStackTraceEnd = activeSavedStackTrace()->end();
 
         while (counter < maxDepth && savedStackTracePtr < savedStackTraceEnd) {
             if (++counter <= minDepth) {
@@ -378,7 +508,7 @@ void Debugger::getBacktrace(ExecutionState* state, uint32_t minDepth, uint32_t m
     sendType(ESCARGOT_MESSAGE_BACKTRACE_END);
 }
 
-void Debugger::getScopeChain(ExecutionState* state, uint32_t stateIndex)
+void DebuggerRemote::getScopeChain(ExecutionState* state, uint32_t stateIndex)
 {
     const size_t maxMessageLength = ESCARGOT_DEBUGGER_MAX_MESSAGE_LENGTH - 1;
     uint8_t buffer[maxMessageLength];
@@ -431,32 +561,32 @@ void Debugger::getScopeChain(ExecutionState* state, uint32_t stateIndex)
     send(ESCARGOT_MESSAGE_SCOPE_CHAIN_END, buffer, nextScope);
 }
 
-static void sendProperty(Debugger* debugger, ExecutionState* state, AtomicString name, Value value)
+static void sendProperty(DebuggerRemote* debugger, ExecutionState* state, AtomicString name, Value value)
 {
-    uint8_t type = Debugger::ESCARGOT_VARIABLE_UNDEFINED;
+    uint8_t type = DebuggerRemote::ESCARGOT_VARIABLE_UNDEFINED;
     StringView* valueView = nullptr;
 
     if (value.isNull()) {
-        type = Debugger::ESCARGOT_VARIABLE_NULL;
+        type = DebuggerRemote::ESCARGOT_VARIABLE_NULL;
     } else if (value.isTrue()) {
-        type = Debugger::ESCARGOT_VARIABLE_TRUE;
+        type = DebuggerRemote::ESCARGOT_VARIABLE_TRUE;
     } else if (value.isFalse()) {
-        type = Debugger::ESCARGOT_VARIABLE_FALSE;
+        type = DebuggerRemote::ESCARGOT_VARIABLE_FALSE;
     } else if (value.isNumber()) {
-        type = Debugger::ESCARGOT_VARIABLE_NUMBER;
+        type = DebuggerRemote::ESCARGOT_VARIABLE_NUMBER;
 
         String* valueString = value.toString(*state);
         valueView = new StringView(valueString);
     } else if (value.isString() || value.isSymbol() || value.isBigInt()) {
         String* valueString;
         if (value.isString()) {
-            type = Debugger::ESCARGOT_VARIABLE_STRING;
+            type = DebuggerRemote::ESCARGOT_VARIABLE_STRING;
             valueString = value.asString();
         } else if (value.isBigInt()) {
-            type = Debugger::ESCARGOT_VARIABLE_BIGINT;
+            type = DebuggerRemote::ESCARGOT_VARIABLE_BIGINT;
             valueString = value.asBigInt()->toString();
         } else {
-            type = Debugger::ESCARGOT_VARIABLE_SYMBOL;
+            type = DebuggerRemote::ESCARGOT_VARIABLE_SYMBOL;
             Symbol* symbol = value.asSymbol();
 
             valueString = String::emptyString;
@@ -467,65 +597,65 @@ static void sendProperty(Debugger* debugger, ExecutionState* state, AtomicString
         size_t valueLength = valueString->length();
 
         if (valueLength >= ESCARGOT_DEBUGGER_MAX_VARIABLE_LENGTH) {
-            type |= Debugger::ESCARGOT_VARIABLE_LONG_VALUE;
+            type |= DebuggerRemote::ESCARGOT_VARIABLE_LONG_VALUE;
             valueLength = ESCARGOT_DEBUGGER_MAX_VARIABLE_LENGTH;
         }
 
         valueView = new StringView(valueString, 0, valueLength);
     } else if (value.isFunction()) {
-        type = Debugger::ESCARGOT_VARIABLE_FUNCTION;
+        type = DebuggerRemote::ESCARGOT_VARIABLE_FUNCTION;
     } else if (value.isObject()) {
-        type = Debugger::ESCARGOT_VARIABLE_OBJECT;
+        type = DebuggerRemote::ESCARGOT_VARIABLE_OBJECT;
 
         Object* valueObject = value.asObject();
 
         if (valueObject->isArrayObject()) {
-            type = Debugger::ESCARGOT_VARIABLE_ARRAY;
+            type = DebuggerRemote::ESCARGOT_VARIABLE_ARRAY;
         }
     }
 
     size_t nameLength = name.string()->length();
 
     if (nameLength > ESCARGOT_DEBUGGER_MAX_VARIABLE_LENGTH) {
-        type |= Debugger::ESCARGOT_VARIABLE_LONG_NAME;
+        type |= DebuggerRemote::ESCARGOT_VARIABLE_LONG_NAME;
         nameLength = ESCARGOT_DEBUGGER_MAX_VARIABLE_LENGTH;
     }
 
-    if ((type & Debugger::ESCARGOT_VARIABLE_TYPE_MASK) < Debugger::ESCARGOT_VARIABLE_OBJECT) {
-        debugger->sendSubtype(Debugger::ESCARGOT_MESSAGE_VARIABLE, type);
+    if ((type & DebuggerRemote::ESCARGOT_VARIABLE_TYPE_MASK) < DebuggerRemote::ESCARGOT_VARIABLE_OBJECT) {
+        debugger->sendSubtype(DebuggerRemote::ESCARGOT_MESSAGE_VARIABLE, type);
     } else {
         debugger->sendVariableObjectInfo(type, value.asObject());
     }
 
-    if (debugger->enabled()) {
+    if (debugger->connected()) {
         StringView* nameView = new StringView(name.string(), 0, nameLength);
-        debugger->sendString(Debugger::ESCARGOT_MESSAGE_STRING_8BIT, nameView);
+        debugger->sendString(DebuggerRemote::ESCARGOT_MESSAGE_STRING_8BIT, nameView);
     }
 
-    if (valueView && debugger->enabled()) {
-        debugger->sendString(Debugger::ESCARGOT_MESSAGE_STRING_8BIT, valueView);
+    if (valueView && debugger->connected()) {
+        debugger->sendString(DebuggerRemote::ESCARGOT_MESSAGE_STRING_8BIT, valueView);
     }
 }
 
-static void sendUnaccessibleProperty(Debugger* debugger, AtomicString name)
+static void sendUnaccessibleProperty(DebuggerRemote* debugger, AtomicString name)
 {
-    uint8_t type = Debugger::ESCARGOT_VARIABLE_UNACCESSIBLE;
+    uint8_t type = DebuggerRemote::ESCARGOT_VARIABLE_UNACCESSIBLE;
     size_t nameLength = name.string()->length();
 
     if (nameLength > ESCARGOT_DEBUGGER_MAX_VARIABLE_LENGTH) {
-        type |= Debugger::ESCARGOT_VARIABLE_LONG_NAME;
+        type |= DebuggerRemote::ESCARGOT_VARIABLE_LONG_NAME;
         nameLength = ESCARGOT_DEBUGGER_MAX_VARIABLE_LENGTH;
     }
 
-    debugger->sendSubtype(Debugger::ESCARGOT_MESSAGE_VARIABLE, type);
+    debugger->sendSubtype(DebuggerRemote::ESCARGOT_MESSAGE_VARIABLE, type);
 
-    if (debugger->enabled()) {
+    if (debugger->connected()) {
         StringView* nameView = new StringView(name.string(), 0, nameLength);
-        debugger->sendString(Debugger::ESCARGOT_MESSAGE_STRING_8BIT, nameView);
+        debugger->sendString(DebuggerRemote::ESCARGOT_MESSAGE_STRING_8BIT, nameView);
     }
 }
 
-static void sendObjectProperties(Debugger* debugger, ExecutionState* state, Object* object)
+static void sendObjectProperties(DebuggerRemote* debugger, ExecutionState* state, Object* object)
 {
     Object::OwnPropertyKeyVector keys = object->ownPropertyKeys(*state);
     size_t size = keys.size();
@@ -544,7 +674,7 @@ static void sendObjectProperties(Debugger* debugger, ExecutionState* state, Obje
     }
 }
 
-static void sendRecordProperties(Debugger* debugger, ExecutionState* state, IdentifierRecordVector& identifiers, EnvironmentRecord* record)
+static void sendRecordProperties(DebuggerRemote* debugger, ExecutionState* state, IdentifierRecordVector& identifiers, EnvironmentRecord* record)
 {
     size_t size = identifiers.size();
 
@@ -561,7 +691,7 @@ static void sendRecordProperties(Debugger* debugger, ExecutionState* state, Iden
     }
 }
 
-static void sendRecordProperties(Debugger* debugger, ExecutionState* state, const ModuleEnvironmentRecord::ModuleBindingRecordVector& bindings, ModuleEnvironmentRecord* record)
+static void sendRecordProperties(DebuggerRemote* debugger, ExecutionState* state, const ModuleEnvironmentRecord::ModuleBindingRecordVector& bindings, ModuleEnvironmentRecord* record)
 {
     size_t size = bindings.size();
 
@@ -578,7 +708,7 @@ static void sendRecordProperties(Debugger* debugger, ExecutionState* state, cons
     }
 }
 
-void Debugger::getScopeVariables(ExecutionState* state, uint32_t stateIndex, uint32_t index)
+void DebuggerRemote::getScopeVariables(ExecutionState* state, uint32_t stateIndex, uint32_t index)
 {
     while (stateIndex > 0) {
         state = state->parent();
@@ -645,27 +775,45 @@ static LexicalEnvironment* getFunctionLexEnv(ExecutionState* state)
     return nullptr;
 }
 
-bool Debugger::processIncomingMessages(ExecutionState* state, ByteCodeBlock* byteCodeBlock)
+bool DebuggerRemote::processEvents(ExecutionState* state, Optional<ByteCodeBlock*> byteCodeBlock, bool isBlockingRequest)
 {
     uint8_t buffer[ESCARGOT_DEBUGGER_MAX_MESSAGE_LENGTH];
     size_t length;
 
-    while (receive(buffer, length)) {
+    while (true) {
+        if (isBlockingRequest) {
+            if (!receive(buffer, length)) {
+                break;
+            }
+        } else {
+            if (isThereAnyEvent()) {
+                if (!receive(buffer, length)) {
+                    break;
+                }
+            } else {
+                return false;
+            }
+        }
         switch (buffer[0]) {
         case ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT_START:
         case ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT_START: {
-            if ((length <= 1 + sizeof(uint32_t) || state != nullptr || byteCodeBlock != nullptr)) {
+            if ((length <= 1 + sizeof(uint32_t) || state != nullptr || byteCodeBlock)) {
                 break;
             }
 
             return doEval(state, byteCodeBlock, buffer, length);
         }
         case ESCARGOT_DEBUGGER_THERE_WAS_NO_SOURCE: {
-            if (length != 1 || state != nullptr || byteCodeBlock != nullptr) {
+            if (length != 1 || state != nullptr || byteCodeBlock) {
                 break;
             }
             return false;
         }
+        case ESCARGOT_DEBUGGER_WAIT_BEFORE_EXIT: {
+            m_exitClient = buffer[1];
+            return false;
+        }
+
         case ESCARGOT_MESSAGE_FUNCTION_RELEASED: {
             if (length != 1 + sizeof(uintptr_t)) {
                 break;
@@ -776,9 +924,17 @@ bool Debugger::processIncomingMessages(ExecutionState* state, ByteCodeBlock* byt
             if ((length <= 1 + sizeof(uint32_t)) || m_stopState != ESCARGOT_DEBUGGER_IN_WAIT_MODE) {
                 break;
             }
-
+            ASSERT(byteCodeBlock.hasValue());
             return doEval(state, byteCodeBlock, buffer, length);
         }
+        case ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_8BIT_START:
+        case ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_16BIT_START: {
+            if ((length <= 1 + sizeof(uint32_t)) || (m_stopState != ESCARGOT_DEBUGGER_IN_WAIT_MODE && m_stopState != ESCARGOT_DEBUGGER_ALWAYS_STOP)) {
+                break;
+            }
+            ASSERT(!byteCodeBlock.hasValue());
+            return doEval(state, nullptr, buffer, length);
+        }
         case ESCARGOT_MESSAGE_GET_BACKTRACE: {
             if ((length != 1 + sizeof(uint32_t) + sizeof(uint32_t) + 1) || m_stopState != ESCARGOT_DEBUGGER_IN_WAIT_MODE) {
                 break;
@@ -854,12 +1010,12 @@ bool Debugger::processIncomingMessages(ExecutionState* state, ByteCodeBlock* byt
     return enabled();
 }
 
-void Debugger::waitForResolvingPendingBreakpoints()
+void DebuggerRemote::waitForResolvingPendingBreakpoints()
 {
     m_waitForResume = true;
-    sendType(Debugger::ESCARGOT_DEBUGGER_WAITING_AFTER_PENDING);
+    sendType(ESCARGOT_DEBUGGER_WAITING_AFTER_PENDING);
     while (m_waitForResume) {
-        processIncomingMessages(nullptr, nullptr);
+        processEvents(nullptr, nullptr);
 
         if (!enabled()) {
             break;
@@ -867,25 +1023,25 @@ void Debugger::waitForResolvingPendingBreakpoints()
     }
 }
 
-Debugger::SavedStackTraceDataVector* Debugger::saveStackTrace(ExecutionState& state)
+DebuggerRemote::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);
+    bool hasSavedStackTrace = SandBox::createStackTrace(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;
+        if ((size_t)stackTraceData[i].loc.actualCodeBlock != SIZE_MAX) {
+            ByteCodeBlock* byteCodeBlock = stackTraceData[i].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;
+            if ((size_t)stackTraceData[i].loc.index == SIZE_MAX) {
+                size_t byteCodePosition = stackTraceData[i].loc.byteCodePosition;
 
                 ByteCodeLOCData* locData;
                 auto iterMap = locMap.find(byteCodeBlock);
@@ -901,8 +1057,8 @@ Debugger::SavedStackTraceDataVector* Debugger::saveStackTrace(ExecutionState& st
                 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;
+                line = (uint32_t)stackTraceData[i].loc.line;
+                column = (uint32_t)stackTraceData[i].loc.column;
             }
 
             savedStackTrace->push_back(SavedStackTraceData(byteCodeBlock, line, column));
@@ -928,53 +1084,45 @@ Debugger::SavedStackTraceDataVector* Debugger::saveStackTrace(ExecutionState& st
     return savedStackTrace;
 }
 
-Debugger* createDebugger(const char* options, bool* debuggerEnabled)
+void Debugger::pumpDebuggerEvents(ExecutionState* state)
 {
-    Debugger* debugger = new DebuggerTcp();
+    while (processEvents(state, nullptr, false))
+        ;
+}
 
-    if (debugger->init(options)) {
-        union {
-            uint16_t u16Value;
-            uint8_t u8Value;
-        } endian;
+void DebuggerRemote::init(const char*, Context*)
+{
+    union {
+        uint16_t u16Value;
+        uint8_t u8Value;
+    } endian;
 
-        endian.u16Value = 1;
+    endian.u16Value = 1;
 
-        Debugger::MessageVersion version;
-        version.littleEndian = (endian.u8Value == 1);
+    MessageVersion version;
+    version.littleEndian = (endian.u8Value == 1);
 
-        uint32_t debuggerVersion = ESCARGOT_DEBUGGER_VERSION;
-        memcpy(version.version, &debuggerVersion, sizeof(uint32_t));
+    uint32_t debuggerVersion = ESCARGOT_DEBUGGER_VERSION;
+    memcpy(version.version, &debuggerVersion, sizeof(uint32_t));
 
-        if (debugger->send(Debugger::ESCARGOT_MESSAGE_VERSION, &version, sizeof(version))) {
-            Debugger::MessageConfiguration configuration;
+    if (!send(ESCARGOT_MESSAGE_VERSION, &version, sizeof(version))) {
+        return;
+    }
 
-            configuration.maxMessageSize = ESCARGOT_DEBUGGER_MAX_MESSAGE_LENGTH;
-            configuration.pointerSize = (uint8_t)sizeof(void*);
+    MessageConfiguration configuration;
 
-            debugger->send(Debugger::ESCARGOT_MESSAGE_CONFIGURATION, &configuration, sizeof(configuration));
-        }
+    configuration.maxMessageSize = ESCARGOT_DEBUGGER_MAX_MESSAGE_LENGTH;
+    configuration.pointerSize = (uint8_t)sizeof(void*);
 
-        if (debugger->enabled()) {
-            *debuggerEnabled = true;
-            debugger->m_debuggerEnabled = debuggerEnabled;
-        }
-    }
-    return debugger;
+    send(ESCARGOT_MESSAGE_CONFIGURATION, &configuration, sizeof(configuration));
 }
 
-String* Debugger::getClientSource(String** sourceName)
+void Debugger::createDebuggerRemote(const char* options, Context* context)
 {
-    sendType(Debugger::ESCARGOT_DEBUGGER_WAIT_FOR_SOURCE);
-    while (processIncomingMessages(nullptr, nullptr))
-        ;
-    if (sourceName) {
-        *sourceName = m_clientSourceName;
-    }
-    String* sourceData = m_clientSourceData;
-    m_clientSourceName = nullptr;
-    m_clientSourceData = nullptr;
-    return sourceData;
+    DebuggerRemote* debugger = new DebuggerTcp();
+
+    debugger->init(options, context);
 }
+
 } // namespace Escargot
 #endif /* ESCARGOT_DEBUGGER */
index be824cbad1c1b5a3e100b064c7287afa2a6df96b..6139d3289ee170e470aa3445f65bc801b25329ec 100644 (file)
@@ -37,6 +37,7 @@ namespace Escargot {
 #define ESCARGOT_DEBUGGER_NO_STACK_TRACE_RESTORE (reinterpret_cast<ExecutionState*>(0x1))
 #define ESCARGOT_DEBUGGER_MAX_VARIABLE_LENGTH 128
 
+class Context;
 class Object;
 class String;
 class ExecutionState;
@@ -44,8 +45,169 @@ class ByteCodeBlock;
 class InterpretedCodeBlock;
 
 class Debugger : public gc {
-    friend Debugger* createDebugger(const char* options, bool* debuggerEnabled);
+public:
+    // The following code is the sam as in EscargotPublic.h
+    class WeakCodeRef;
+
+    struct BreakpointLocation {
+        BreakpointLocation(uint32_t line, uint32_t offset)
+            : line(line)
+            , offset(offset)
+        {
+        }
+
+        uint32_t line;
+        uint32_t offset;
+    };
+
+    typedef std::vector<BreakpointLocation> BreakpointLocationVector;
+
+    struct BreakpointLocationsInfo {
+        BreakpointLocationsInfo(WeakCodeRef* weakCodeRef)
+            : weakCodeRef(weakCodeRef)
+        {
+        }
+
+        // The codeRef is a unique id which is not garbage collected
+        // to avoid keeping script / function code in the memory.
+        WeakCodeRef* weakCodeRef;
+        BreakpointLocationVector breakpointLocations;
+    };
+
+    // End of the code from EscargotPublic.h
+
+    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<SavedStackTraceData, GCUtil::gc_malloc_allocator<SavedStackTraceData>> SavedStackTraceDataVector;
+
+    bool inDebuggingCodeMode() const
+    {
+        return m_inDebuggingCodeMode;
+    }
+
+    void setInDebuggingCodeMode(bool mode)
+    {
+        m_inDebuggingCodeMode = mode;
+    }
+
+    void appendBreakpointLocations(BreakpointLocationsInfo* breakpointLocations)
+    {
+        m_breakpointLocationsVector.push_back(breakpointLocations);
+    }
+
+    void clearParsingData()
+    {
+        m_breakpointLocationsVector.clear();
+    }
+
+    void setActiveSavedStackTrace(ExecutionState* state, SavedStackTraceDataVector* trace)
+    {
+        m_activeSavedStackTraceExecutionState = state;
+        m_activeSavedStackTrace = trace;
+    }
+
+    ExecutionState* activeSavedStackTraceExecutionState()
+    {
+        return m_activeSavedStackTraceExecutionState;
+    }
+
+    SavedStackTraceDataVector* activeSavedStackTrace()
+    {
+        return m_activeSavedStackTrace;
+    }
+
+    inline void processDisabledBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state)
+    {
+        if (m_stopState != ESCARGOT_DEBUGGER_ALWAYS_STOP && m_stopState != state) {
+            m_delay--;
+            if (m_delay == 0) {
+                processEvents(state, byteCodeBlock);
+            }
+        }
+
+        if (m_stopState == ESCARGOT_DEBUGGER_ALWAYS_STOP || m_stopState == state) {
+            stopAtBreakpoint(byteCodeBlock, offset, state);
+        }
+    }
+
+    static inline void updateStopState(Debugger* debugger, ExecutionState* state, ExecutionState* newState)
+    {
+        if (debugger != nullptr && debugger->m_stopState == state) {
+            // Stop at the next breakpoint if a "next" operation targets the current function
+            debugger->m_stopState = newState;
+        }
+    }
+
+    void setStopState(ExecutionState* stopState)
+    {
+        m_stopState = stopState;
+    }
+
+    static void createDebuggerRemote(const char* options, Context* context);
+
+    virtual void parseCompleted(String* source, String* srcName, String* error = nullptr) = 0;
+    virtual void stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state) = 0;
+    virtual void byteCodeReleaseNotification(ByteCodeBlock* byteCodeBlock) = 0;
+    virtual void exceptionCaught(String* message, SavedStackTraceDataVector& exceptionTrace) = 0;
+    virtual void consoleOut(String* output) = 0;
+    virtual String* getClientSource(String** sourceName) = 0;
+    virtual bool getWaitBeforeExitClient() = 0;
+    virtual bool skipSourceCode(String* srcName) const
+    {
+        return false;
+    }
+
+    static SavedStackTraceDataVector* saveStackTrace(ExecutionState& state);
+
+    void pumpDebuggerEvents(ExecutionState* state);
+
+protected:
+    Debugger()
+        : m_delay(ESCARGOT_DEBUGGER_MESSAGE_PROCESS_DELAY)
+        , m_stopState(ESCARGOT_DEBUGGER_ALWAYS_STOP)
+        , m_context(nullptr)
+        , m_activeSavedStackTraceExecutionState(nullptr)
+        , m_activeSavedStackTrace(nullptr)
+        , m_inDebuggingCodeMode(false)
+    {
+    }
+
+    bool enabled()
+    {
+        return m_context != nullptr;
+    }
+
+    void enable(Context* context);
+    void disable();
+
+    virtual bool processEvents(ExecutionState* state, Optional<ByteCodeBlock*> byteCodeBlock, bool isBlockingRequest = true) = 0;
+
+    uint32_t m_delay;
+    ExecutionState* m_stopState;
+    std::vector<BreakpointLocationsInfo*> m_breakpointLocationsVector;
+
+private:
+    Context* m_context;
+    ExecutionState* m_activeSavedStackTraceExecutionState;
+    SavedStackTraceDataVector* m_activeSavedStackTrace;
+
+    // represent that every created InterpretedCodeBlock and its ByteCode should be marked with debugging feature
+    // ByteCode should contain debugging code (breakpoint)
+    bool m_inDebuggingCodeMode;
+};
+
+class DebuggerRemote : public Debugger {
 public:
     // Messages sent by Escargot to the debugger client
     enum {
@@ -100,6 +262,7 @@ public:
         ESCARGOT_MESSAGE_EXCEPTION_BACKTRACE = 42,
         ESCARGOT_DEBUGGER_WAIT_FOR_SOURCE = 43,
         ESCARGOT_DEBUGGER_WAITING_AFTER_PENDING = 44,
+        ESCARGOT_DEBUGGER_WAIT_FOR_WAIT_EXIT = 45,
     };
 
     // Messages sent by the debugger client to Escargot
@@ -115,18 +278,24 @@ public:
         ESCARGOT_MESSAGE_EVAL_8BIT = 7,
         ESCARGOT_MESSAGE_EVAL_16BIT_START = 8,
         ESCARGOT_MESSAGE_EVAL_16BIT = 9,
-        ESCARGOT_MESSAGE_GET_BACKTRACE = 10,
-        ESCARGOT_MESSAGE_GET_SCOPE_CHAIN = 11,
-        ESCARGOT_MESSAGE_GET_SCOPE_VARIABLES = 12,
-        ESCARGOT_MESSAGE_GET_OBJECT = 13,
         // These four must be in the same order.
-        ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT_START = 14,
-        ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT = 15,
-        ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT_START = 16,
-        ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT = 17,
-        ESCARGOT_DEBUGGER_THERE_WAS_NO_SOURCE = 18,
-        ESCARGOT_DEBUGGER_PENDING_CONFIG = 19,
-        ESCARGOT_DEBUGGER_PENDING_RESUME = 20,
+        ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_8BIT_START = 10,
+        ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_8BIT = 11,
+        ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_16BIT_START = 12,
+        ESCARGOT_MESSAGE_EVAL_WITHOUT_STOP_16BIT = 13,
+        ESCARGOT_MESSAGE_GET_BACKTRACE = 14,
+        ESCARGOT_MESSAGE_GET_SCOPE_CHAIN = 15,
+        ESCARGOT_MESSAGE_GET_SCOPE_VARIABLES = 16,
+        ESCARGOT_MESSAGE_GET_OBJECT = 17,
+        // These four must be in the same order.
+        ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT_START = 18,
+        ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT = 19,
+        ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT_START = 20,
+        ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT = 21,
+        ESCARGOT_DEBUGGER_THERE_WAS_NO_SOURCE = 22,
+        ESCARGOT_DEBUGGER_PENDING_CONFIG = 23,
+        ESCARGOT_DEBUGGER_PENDING_RESUME = 24,
+        ESCARGOT_DEBUGGER_WAIT_BEFORE_EXIT = 25,
     };
 
     // Environment record types
@@ -160,129 +329,51 @@ public:
         ESCARGOT_VARIABLE_LONG_VALUE = 0x80,
     };
 
-    struct BreakpointLocation {
-        BreakpointLocation(uint32_t line, uint32_t offset)
-            : line(line)
-            , offset(offset)
-        {
-        }
-
-        uint32_t line;
-        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<SavedStackTraceData, GCUtil::gc_malloc_allocator<SavedStackTraceData>> SavedStackTraceDataVector;
-
-    bool enabled()
-    {
-        return m_enabled;
-    }
-
-    bool parsingEnabled()
-    {
-        return m_parsingEnabled;
-    }
-
-    void setParsingEnabled(bool value)
-    {
-        m_parsingEnabled = value;
-    }
-
-    bool pendingWait(void)
+    inline bool pendingWait(void)
     {
         return m_pendingWait;
     }
 
-    inline void processDisabledBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state)
+    inline bool connected(void)
     {
-        if (m_stopState != ESCARGOT_DEBUGGER_ALWAYS_STOP && m_stopState != state) {
-            m_delay = (uint8_t)(m_delay - 1);
-            if (m_delay == 0) {
-                processIncomingMessages(state, byteCodeBlock);
-            }
-        }
-
-        if (m_stopState == ESCARGOT_DEBUGGER_ALWAYS_STOP || m_stopState == state) {
-            stopAtBreakpoint(byteCodeBlock, offset, state);
-        }
-    }
-
-    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) {
-            // Stop at the next breakpoint if a "next" operation targets the current function
-            debugger->m_stopState = newState;
-        }
+        return enabled();
     }
 
     void sendType(uint8_t type);
     void sendSubtype(uint8_t type, uint8_t subType);
     void sendString(uint8_t type, String* string);
     void sendPointer(uint8_t type, const void* ptr);
-    void sendFunctionInfo(InterpretedCodeBlock* codeBlock);
-    void sendBreakpointLocations(std::vector<Debugger::BreakpointLocation>& locations);
+
+    virtual void init(const char* options, Context* context) = 0;
+    virtual void parseCompleted(String* source, String* srcName, String* error = nullptr) override;
+    virtual void stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state) override;
+    virtual void byteCodeReleaseNotification(ByteCodeBlock* byteCodeBlock) override;
+    virtual void exceptionCaught(String* message, SavedStackTraceDataVector& exceptionTrace) override;
+    virtual void consoleOut(String* output) override;
+    virtual String* getClientSource(String** sourceName) override;
+    virtual bool getWaitBeforeExitClient() override;
+
     void sendBacktraceInfo(uint8_t type, ByteCodeBlock* byteCodeBlock, uint32_t line, uint32_t column, uint32_t executionStateDepth);
     void sendVariableObjectInfo(uint8_t subType, Object* object);
-    void stopAtBreakpoint(ByteCodeBlock* byteCodeBlock, uint32_t offset, ExecutionState* state);
-    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)
+    DebuggerRemote()
+        : m_exitClient(false)
         , m_pendingWait(false)
         , m_waitForResume(false)
-        , m_stopState(ESCARGOT_DEBUGGER_ALWAYS_STOP)
         , m_clientSourceData(nullptr)
         , m_clientSourceName(nullptr)
-        , m_activeSavedStackTraceExecutionState(nullptr)
-        , m_activeSavedStackTrace(nullptr)
     {
     }
 
-    virtual bool init(const char* options) = 0;
+    virtual bool processEvents(ExecutionState* state, Optional<ByteCodeBlock*> byteCodeBlock, bool isBlockingRequest = true) override;
+
     virtual bool send(uint8_t type, const void* buffer, size_t length) = 0;
     virtual bool receive(uint8_t* buffer, size_t& length) = 0;
+    virtual bool isThereAnyEvent() = 0;
     virtual void close(void) = 0;
 
-    bool m_enabled;
-    bool m_parsingEnabled;
-    bool* m_debuggerEnabled;
-
 private:
     // Packed structure definitions to reduce network traffic
 
@@ -320,25 +411,21 @@ private:
     };
 
     uint32_t appendToActiveObjects(Object* object);
-    bool doEval(ExecutionState* state, ByteCodeBlock* byteCodeBlock, uint8_t* buffer, size_t length);
+    bool doEval(ExecutionState* state, Optional<ByteCodeBlock*> byteCodeBlock, uint8_t* buffer, size_t length);
     void getBacktrace(ExecutionState* state, uint32_t minDepth, uint32_t maxDepth, bool getTotal);
     void getScopeChain(ExecutionState* state, uint32_t stateIndex);
     void getScopeVariables(ExecutionState* state, uint32_t stateIndex, uint32_t index);
-    bool processIncomingMessages(ExecutionState* state, ByteCodeBlock* byteCodeBlock);
 
-    uint8_t m_delay;
+    bool m_exitClient : 1;
     bool m_pendingWait : 1;
     bool m_waitForResume : 1;
-    ExecutionState* m_stopState;
     String* m_clientSourceData;
     String* m_clientSourceName;
+
     Vector<uintptr_t, GCUtil::gc_malloc_atomic_allocator<uintptr_t>> m_releasedFunctions;
     Vector<Object*, GCUtil::gc_malloc_allocator<Object*>> m_activeObjects;
-    ExecutionState* m_activeSavedStackTraceExecutionState;
-    SavedStackTraceDataVector* m_activeSavedStackTrace;
 };
 
-Debugger* createDebugger(const char* options, bool* debuggerEnabled);
 } // namespace Escargot
 #endif /* ESCARGOT_DEBUGGER */
 
index 39de349ada264949a578db79417889463afa1da8..769c8c315c8d3e1f4a272744f173449eca6fd386 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "Escargot.h"
 #include "DebuggerTcp.h"
+#include "runtime/String.h" // for split function
 
 #ifdef ESCARGOT_DEBUGGER
 namespace Escargot {
@@ -39,6 +40,7 @@ typedef SSIZE_T ssize_t;
 #include <arpa/inet.h>
 #include <fcntl.h>
 #include <sys/socket.h>
+#include <sys/poll.h>
 #include <unistd.h>
 
 /* On *nix the EWOULDBLOCK errno value can be returned for non-blocking operations */
@@ -301,9 +303,32 @@ static bool webSocketHandshake(EscargotSocket socket)
     return tcpSend(socket, responseSuffix, sizeof(responseSuffix) - 1);
 }
 
-bool DebuggerTcp::init(const char*)
+void DebuggerTcp::init(const char* options, Context* context)
 {
     uint16_t port = 6501;
+    int timeout = -1;
+
+    if (options) {
+        auto v = split(options, ';');
+        const char portOption[] = "--port=";
+        const char acceptTimeoutOption[] = "--accept-timeout=";
+        const char skipOption[] = "--skip=";
+        for (size_t i = 0; i < v.size(); i++) {
+            const std::string& s = v[i];
+            if (s.find(portOption) == 0) {
+                int i = std::atoi(s.data() + sizeof(portOption) - 1);
+                if (i > 0 && i <= 65535) {
+                    port = i;
+                }
+            } else if (s.find(acceptTimeoutOption) == 0) {
+                timeout = std::atoi(s.data() + sizeof(acceptTimeoutOption) - 1);
+            } else if (s.find(skipOption) == 0) {
+                const char* skipStr = const_cast<const char*>(s.data() + sizeof(skipOption) - 1);
+                size_t skipLen = strlen(skipStr);
+                m_skipSourceName = String::fromASCII(skipStr, skipLen);
+            }
+        }
+    }
 
     ASSERT(enabled() == false);
 
@@ -311,23 +336,45 @@ bool DebuggerTcp::init(const char*)
     WSADATA wsaData;
     int wsa_init_status = WSAStartup(MAKEWORD(2, 2), &wsaData);
     if (wsa_init_status != NO_ERROR) {
-        return false;
+        return;
     }
 #endif /* WIN32*/
 
     EscargotSocket serverSocket = socket(AF_INET, SOCK_STREAM, 0);
     if (m_socket == ESCARGOT_INVALID_SOCKET) {
-        return false;
+        return;
     }
 
     if (!tcpConfigureSocket(serverSocket, port)) {
         int error = tcpGetErrno();
         tcpCloseSocket(serverSocket);
         tcpLogError(error);
-        return false;
+        return;
     }
 
-    printf("Waiting for client connection\n");
+    ESCARGOT_LOG_INFO("Waiting for client connection 0.0.0.0:%hd\n", port);
+
+    struct pollfd fd[1];
+    fd[0].fd = serverSocket;
+    fd[0].events = POLLIN;
+    while (true) {
+        int rc = poll(fd, 1, 0);
+
+        if (rc != 0) {
+            break;
+        }
+
+        usleep(10 * 1000); // 10ms
+        if (timeout == -1) {
+            continue;
+        }
+        timeout -= 10;
+        if (timeout < 0) {
+            ESCARGOT_LOG_ERROR("Waiting for client connection error: timeout reached\n");
+            tcpCloseSocket(serverSocket);
+            return;
+        }
+    }
 
     sockaddr_in addr;
     socklen_t sinSize = sizeof(sockaddr_in);
@@ -338,7 +385,7 @@ bool DebuggerTcp::init(const char*)
 
     if (m_socket == ESCARGOT_INVALID_SOCKET) {
         tcpLogError(tcpGetErrno());
-        return false;
+        return;
     }
 
 #ifdef WIN32
@@ -347,35 +394,46 @@ bool DebuggerTcp::init(const char*)
     /* Set non-blocking mode. */
     if (ioctlsocket(m_socket, FIONBIO, &nonblockingEnabled) != NO_ERROR) {
         tcpCloseSocket(m_socket);
-        return false;
+        return;
     }
 #else /* !WIN32 */
     int socketFlags = fcntl(m_socket, F_GETFL, 0);
 
     if (socketFlags < 0) {
         tcpCloseSocket(m_socket);
-        return false;
+        return;
     }
 
     /* Set non-blocking mode. */
     if (fcntl(m_socket, F_SETFL, socketFlags | O_NONBLOCK) == -1) {
         tcpCloseSocket(m_socket);
-        return false;
+        return;
     }
 #endif /* WIN32 */
 
-    printf("Connected from: %s\n", inet_ntoa(addr.sin_addr));
+    ESCARGOT_LOG_INFO("Connected from: %s\n", inet_ntoa(addr.sin_addr));
 
     if (!webSocketHandshake(m_socket)) {
         tcpCloseSocket(m_socket);
-        return false;
+        return;
     }
 
-    m_enabled = true;
-    m_parsingEnabled = true;
     m_receiveBufferFill = 0;
     m_messageLength = 0;
-    return true;
+
+    enable(context);
+
+    return DebuggerRemote::init(nullptr, context);
+}
+
+bool DebuggerTcp::skipSourceCode(String* srcName) const
+{
+    ASSERT(!!srcName);
+    if (!m_skipSourceName || m_skipSourceName->length() == 0 || srcName->length() == 0) {
+        return false;
+    }
+
+    return srcName->contains(m_skipSourceName);
 }
 
 #define ESCARGOT_DEBUGGER_WEBSOCKET_FIN_BIT 0x80
@@ -405,6 +463,26 @@ bool DebuggerTcp::send(uint8_t type, const void* buffer, size_t length)
     return false;
 }
 
+bool DebuggerTcp::isThereAnyEvent()
+{
+    // if there is remained receive buffer data,
+    // user should call receive function again
+    if (m_receiveBufferFill) {
+        return true;
+    }
+
+    struct pollfd fd[1];
+    fd[0].fd = m_socket;
+    fd[0].events = POLLIN;
+    int rc = poll(fd, 1, 0);
+
+    if (rc == 0) {
+        return false;
+    }
+
+    return true;
+}
+
 bool DebuggerTcp::receive(uint8_t* buffer, size_t& length)
 {
     size_t receivedLength;
@@ -489,8 +567,7 @@ void DebuggerTcp::close(void)
 {
     if (enabled()) {
         tcpCloseSocket(m_socket);
-        m_enabled = false;
-        *m_debuggerEnabled = false;
+        disable();
     }
 }
 } // namespace Escargot
index 7cbc7cbcefc1bdd859c3e0bee4625eaff853ccb2..b9ea0ae0f11258c00e70d9ad0b25c182c80bdae9 100644 (file)
@@ -32,24 +32,29 @@ typedef SOCKET EscargotSocket;
 typedef int EscargotSocket;
 #endif /* WIN32 */
 
-class DebuggerTcp : public Debugger {
+class DebuggerTcp : public DebuggerRemote {
 public:
     DebuggerTcp()
         : m_socket(0)
         , m_receiveBuffer{}
         , m_receiveBufferFill(0)
         , m_messageLength(0)
+        , m_skipSourceName(nullptr)
     {
     }
 
+    virtual void init(const char* options, Context* context) override;
+
+    virtual bool skipSourceCode(String* srcName) const override;
+
     static void computeSha1(const uint8_t* source1, size_t source1Length,
                             const uint8_t* source2, size_t source2Length,
                             uint8_t destination[20]);
 
 protected:
-    virtual bool init(const char* options) override;
     virtual bool send(uint8_t type, const void* buffer, size_t length) override;
     virtual bool receive(uint8_t* buffer, size_t& length) override;
+    virtual bool isThereAnyEvent() override;
     virtual void close(void) override;
 
 private:
@@ -59,6 +64,9 @@ private:
     uint8_t m_receiveBuffer[2 + sizeof(uint32_t) + ESCARGOT_DEBUGGER_MAX_MESSAGE_LENGTH];
     uint8_t m_receiveBufferFill;
     uint8_t m_messageLength;
+
+    // skip generating debugging bytecode for source code whose name contains m_skipSourceName
+    String* m_skipSourceName;
 };
 } // namespace Escargot
 #endif /* ESCARGOT_DEBUGGER */
index 091b17af57c7598d7b016524d1b235256700a2e8..364c10e48f81fc3e7edf11f9cba3817f0deb1df5 100644 (file)
@@ -351,6 +351,18 @@ GetObjectInlineCacheData* CustomAllocator<GetObjectInlineCacheData>::allocate(si
 {
     // Un-comment this to use default allocator
     // return (Value*)GC_MALLOC(sizeof(GetObjectInlineCacheData) * GC_n);
+    // typed calloc test
+    /*
+    static MAY_THREAD_LOCAL bool typeInited = false;
+    static MAY_THREAD_LOCAL GC_descr descr;
+    if (!typeInited) {
+        GC_word obj_bitmap[GC_BITMAP_SIZE(GetObjectInlineCacheData)] = { 0 };
+        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(GetObjectInlineCacheData, m_cachedhiddenClassChain));
+        descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(GetObjectInlineCacheData));
+        typeInited = true;
+    }
+    return (GetObjectInlineCacheData*)GC_CALLOC_EXPLICITLY_TYPED(GC_n, sizeof(GetObjectInlineCacheData), descr);
+    */
     int kind = s_gcKinds[HeapObjectKind::GetObjectInlineCacheDataVectorKind];
     size_t size = sizeof(GetObjectInlineCacheData) * GC_n;
 
index bd88650cadd39a34b692d98fb7659be36d498d4f..cd28c63ee6bdfa8f3ac38f08c5831cd4d04f090a 100644 (file)
@@ -118,8 +118,8 @@ static void clearByteCodeBlock(ByteCodeBlock* self)
 {
 #ifdef ESCARGOT_DEBUGGER
     Debugger* debugger = self->m_codeBlock->context()->debugger();
-    if (debugger && debugger->enabled()) {
-        debugger->releaseFunction(self->m_code.data());
+    if (debugger != nullptr) {
+        debugger->byteCodeReleaseNotification(self);
     }
 #endif
     self->m_code.clear();
@@ -202,6 +202,7 @@ ExtendedNodeLOC ByteCodeBlock::computeNodeLOCFromByteCode(Context* c, size_t cod
         }
     }
 
+    ASSERT(index >= cb->functionStart().index);
     size_t indexRelatedWithScript = index;
     index -= cb->functionStart().index;
 
index 1082a73def2b6ac6f90a8f2438b2a0142306e68b..0e2af167a69fe16c18c7d9ff22bdc8d95f0451f9 100644 (file)
@@ -1037,6 +1037,9 @@ public:
         , m_loadRegisterIndex(loadRegisterIndex)
         , m_propertyName(propertyName)
         , m_presentAttribute(presentAttribute)
+        , m_missCount(0)
+        , m_inlineCachedStructureBefore(nullptr)
+        , m_inlineCachedStructureAfter(nullptr)
     {
     }
 
@@ -1044,8 +1047,11 @@ public:
     ByteCodeRegisterIndex m_loadRegisterIndex : REGISTER_INDEX_IN_BIT;
     AtomicString m_propertyName;
     ObjectPropertyDescriptor::PresentAttribute m_presentAttribute : 8;
-#ifndef NDEBUG
+    size_t m_missCount : 4;
+    ObjectStructure* m_inlineCachedStructureBefore;
+    ObjectStructure* m_inlineCachedStructureAfter;
 
+#ifndef NDEBUG
     void dump()
     {
         printf("object define own property with name r%u.%s <- r%u", m_objectRegisterIndex, m_propertyName.string()->toUTF8StringData().data(), m_loadRegisterIndex);
@@ -1053,7 +1059,7 @@ public:
 #endif
 };
 
-BYTECODE_SIZE_CHECK_IN_32BIT(ObjectDefineOwnPropertyWithNameOperation, sizeof(size_t) * 4);
+BYTECODE_SIZE_CHECK_IN_32BIT(ObjectDefineOwnPropertyWithNameOperation, sizeof(size_t) * 6);
 
 #define ARRAY_DEFINE_OPERATION_MERGE_COUNT 8
 
@@ -1120,6 +1126,7 @@ struct GetObjectInlineCacheData {
     {
         m_cachedhiddenClassChain = nullptr;
         m_cachedhiddenClassChainLength = 0;
+        m_isPlainDataProperty = false;
         m_cachedIndex = 0;
     }
 
@@ -1127,8 +1134,12 @@ struct GetObjectInlineCacheData {
         ObjectStructure** m_cachedhiddenClassChain;
         ObjectStructure* m_cachedhiddenClass;
     };
-    size_t m_cachedhiddenClassChainLength;
-    size_t m_cachedIndex;
+    bool m_isPlainDataProperty : 1;
+    // 15bits of storage is enough
+    // inlineCacheProtoTraverseMaxCount is so small
+    uint16_t m_cachedhiddenClassChainLength : 15;
+    static constexpr size_t inlineCacheCachedIndexMax = std::numeric_limits<uint16_t>::max();
+    uint16_t m_cachedIndex : 16;
 };
 
 typedef Vector<GetObjectInlineCacheData, CustomAllocator<GetObjectInlineCacheData>, ComputeReservedCapacityFunctionWithLog2<>> GetObjectInlineCacheDataVector;
@@ -1150,6 +1161,7 @@ public:
     GetObjectPreComputedCase(const ByteCodeLOC& loc, const size_t objectRegisterIndex, const size_t storeRegisterIndex, ObjectStructurePropertyName propertyName)
         : ByteCode(Opcode::GetObjectPreComputedCaseOpcode, loc)
         , m_isLength(propertyName.plainString()->equals("length"))
+        , m_inlineCacheProtoTraverseMaxIndex(0)
         , m_cacheMissCount(0)
         , m_inlineCache(nullptr)
         , m_objectRegisterIndex(objectRegisterIndex)
@@ -1158,8 +1170,11 @@ public:
     {
     }
 
+    static constexpr size_t inlineCacheProtoTraverseMaxCount = 12;
+
     bool m_isLength : 1;
-    uint16_t m_cacheMissCount : 16;
+    unsigned char m_inlineCacheProtoTraverseMaxIndex : 8;
+    size_t m_cacheMissCount : 16;
     GetObjectInlineCache* m_inlineCache;
 
     ByteCodeRegisterIndex m_objectRegisterIndex;
@@ -2530,13 +2545,17 @@ public:
 
 class ObjectDefineGetterSetter : public ByteCode {
 public:
-    ObjectDefineGetterSetter(const ByteCodeLOC& loc, size_t objectRegisterIndex, size_t objectPropertyNameRegisterIndex, size_t objectPropertyValueRegisterIndex, ObjectPropertyDescriptor::PresentAttribute presentAttribute, bool isGetter)
+    ObjectDefineGetterSetter(const ByteCodeLOC& loc, size_t objectRegisterIndex, size_t objectPropertyNameRegisterIndex, size_t objectPropertyValueRegisterIndex, ObjectPropertyDescriptor::PresentAttribute presentAttribute, bool isGetter, bool isPrecomputed)
         : ByteCode(Opcode::ObjectDefineGetterSetterOpcode, loc)
         , m_objectRegisterIndex(objectRegisterIndex)
         , m_objectPropertyNameRegisterIndex(objectPropertyNameRegisterIndex)
         , m_objectPropertyValueRegisterIndex(objectPropertyValueRegisterIndex)
         , m_presentAttribute(presentAttribute)
         , m_isGetter(isGetter)
+        , m_isPrecomputed(isPrecomputed)
+        , m_missCount(0)
+        , m_inlineCachedStructureBefore(nullptr)
+        , m_inlineCachedStructureAfter(nullptr)
     {
     }
 
@@ -2545,6 +2564,10 @@ public:
     ByteCodeRegisterIndex m_objectPropertyValueRegisterIndex : REGISTER_INDEX_IN_BIT;
     ObjectPropertyDescriptor::PresentAttribute m_presentAttribute : 8;
     bool m_isGetter : 1; // other case, this is setter
+    bool m_isPrecomputed : 1;
+    size_t m_missCount : 4;
+    ObjectStructure* m_inlineCachedStructureBefore;
+    ObjectStructure* m_inlineCachedStructureAfter;
 
 #ifndef NDEBUG
     void dump()
@@ -2558,7 +2581,7 @@ public:
 #endif
 };
 
-BYTECODE_SIZE_CHECK_IN_32BIT(ObjectDefineGetterSetter, sizeof(size_t) * 3);
+BYTECODE_SIZE_CHECK_IN_32BIT(ObjectDefineGetterSetter, sizeof(size_t) * 5);
 
 class BindingRestElement : public ByteCode {
 public:
index f82d1b6bd4e0f6a5150c1c0aea753c595a186fc1..14d2a77f955698018ad4c68b3ccbf4eadd3272ab 100644 (file)
@@ -95,32 +95,29 @@ void ByteCodeGenerateContext::morphJumpPositionIntoComplexCase(ByteCodeBlock* cb
 }
 
 #ifdef ESCARGOT_DEBUGGER
-size_t ByteCodeGenerateContext::calculateBreakpointLineOffset(size_t index, ExtendedNodeLOC sourceElementStart)
+void ByteCodeGenerateContext::calculateBreakpointLocation(size_t index, ExtendedNodeLOC sourceElementStart)
 {
-    StringView src = m_codeBlock->src();
-    size_t lastLineOffset = m_breakpointContext->m_lastBreakpointLineOffset;
-    index -= sourceElementStart.index;
-
-    // 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;
-    }
+    ASSERT(index >= sourceElementStart.index);
+    const size_t indexOffset = index - sourceElementStart.index;
+    size_t lineOffset = m_breakpointContext->m_lastBreakpointLineOffset;
+    ASSERT(indexOffset >= m_breakpointContext->m_lastBreakpointIndexOffset);
 
-    for (size_t i = m_breakpointContext->m_lastBreakpointIndexOffset; i < index; i++) {
+    // calculate the current breakpoint's location based on the last breakpoint's location
+    StringView src = m_codeBlock->src();
+    for (size_t i = m_breakpointContext->m_lastBreakpointIndexOffset; i < indexOffset; i++) {
         char16_t c = src.charAt(i);
         if (EscargotLexer::isLineTerminator(c)) {
             // skip \r\n
-            if (UNLIKELY(c == 13 && (i + 1 < index) && src.charAt(i + 1) == 10)) {
+            if (UNLIKELY(c == 13 && (i + 1 < indexOffset) && src.charAt(i + 1) == 10)) {
                 i++;
             }
-            lastLineOffset++;
+            lineOffset++;
         }
     }
 
-    m_breakpointContext->m_lastBreakpointIndexOffset = index;
-
-    return lastLineOffset;
+    // cache the current breakpoint's calculated location (offset)
+    m_breakpointContext->m_lastBreakpointIndexOffset = indexOffset;
+    m_breakpointContext->m_lastBreakpointLineOffset = lineOffset;
 }
 
 void ByteCodeGenerateContext::insertBreakpoint(size_t index, Node* node)
@@ -128,24 +125,52 @@ void ByteCodeGenerateContext::insertBreakpoint(size_t index, Node* node)
     ASSERT(m_breakpointContext != nullptr);
     ASSERT(index != SIZE_MAX);
 
+    // do not insert any breakpoint for unmarked code
+    if (UNLIKELY(!m_codeBlock->markDebugging())) {
+        return;
+    }
+
+    // dynamically generated code should not insert any debugging code
+    ASSERT(!m_codeBlock->hasDynamicSourceCode());
+
+    // handle eval code
+    // insert one break point only at the start with line 1
+    if (UNLIKELY(m_isEvalCode)) {
+        if (m_breakpointContext->m_breakpointLocations->breakpointLocations.size() == 0) {
+            insertBreakpointAt(1, node);
+        }
+        return;
+    }
+
+    // previous breakpoint's line offset
+    size_t lastLineOffset = m_breakpointContext->m_lastBreakpointLineOffset;
     ExtendedNodeLOC sourceElementStart = m_codeBlock->functionStart();
-    size_t lastLineOffset = calculateBreakpointLineOffset(index, sourceElementStart);
+    calculateBreakpointLocation(index, sourceElementStart);
 
-    if (lastLineOffset != m_breakpointContext->m_lastBreakpointLineOffset) {
-        ASSERT(lastLineOffset > m_breakpointContext->m_lastBreakpointLineOffset);
-        m_breakpointContext->m_lastBreakpointLineOffset = lastLineOffset;
-        insertBreakpointAt(lastLineOffset + sourceElementStart.line, node);
+    // insert a breakpoint if its the first breakpoint insertion or
+    // there was no breakpoint insertion with the same lineoffset
+    if ((m_breakpointContext->m_breakpointLocations->breakpointLocations.size() == 0) || (lastLineOffset != m_breakpointContext->m_lastBreakpointLineOffset)) {
+        ASSERT(lastLineOffset <= m_breakpointContext->m_lastBreakpointLineOffset);
+        insertBreakpointAt(m_breakpointContext->m_lastBreakpointLineOffset + sourceElementStart.line, node);
     }
 }
 
 void ByteCodeGenerateContext::insertBreakpointAt(size_t line, Node* 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);
-    }
+    m_breakpointContext->m_breakpointLocations->breakpointLocations.push_back(Debugger::BreakpointLocation(line, (uint32_t)m_byteCodeBlock->currentCodeSize()));
+    m_byteCodeBlock->pushCode(BreakpointDisabled(ByteCodeLOC(node->loc().index)), this, node);
 }
 
+ByteCodeBreakpointContext::ByteCodeBreakpointContext(Debugger* debugger, InterpretedCodeBlock* codeBlock)
+    : m_lastBreakpointLineOffset(0)
+    , m_lastBreakpointIndexOffset(0)
+    , m_breakpointLocations()
+{
+    m_breakpointLocations = new Debugger::BreakpointLocationsInfo(reinterpret_cast<Debugger::WeakCodeRef*>(codeBlock));
+    if (debugger && codeBlock->markDebugging()) {
+        debugger->appendBreakpointLocations(m_breakpointLocations);
+    }
+}
 #endif /* ESCARGOT_DEBUGGER */
 
 #define ASSIGN_STACKINDEX_IF_NEEDED(registerIndex, stackBase, stackBaseWillBe, stackVariableSize)                         \
@@ -190,19 +215,13 @@ ByteCodeBlock* ByteCodeGenerator::generateByteCode(Context* context, Interpreted
     ByteCodeGenerateContext ctx(codeBlock, block, codeBlock->isGlobalScope(), codeBlock->isEvalCode(), inWithFromRuntime || codeBlock->inWith(), nData);
 
 #ifdef ESCARGOT_DEBUGGER
-    ByteCodeBreakpointContext breakpointContext(context->debugger() && context->debugger()->parsingEnabled());
+    ByteCodeBreakpointContext breakpointContext(context->debugger(), codeBlock);
     ctx.m_breakpointContext = &breakpointContext;
 #endif /* ESCARGOT_DEBUGGER */
 
     // generate bytecode
     ast->generateStatementByteCode(block, &ctx);
 
-#ifdef 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());
         memcpy(block->m_numeralLiteralData.data(), nData->data(), sizeof(Value) * nData->size());
@@ -266,7 +285,7 @@ void ByteCodeGenerator::collectByteCodeLOCData(Context* context, InterpretedCode
     ctx.m_locData = locData;
 
 #ifdef ESCARGOT_DEBUGGER
-    ByteCodeBreakpointContext breakpointContext(context->debugger() && context->debugger()->parsingEnabled());
+    ByteCodeBreakpointContext breakpointContext(context->debugger(), codeBlock);
     ctx.m_breakpointContext = &breakpointContext;
 #endif /* ESCARGOT_DEBUGGER */
 
@@ -800,7 +819,11 @@ void ByteCodeGenerator::printByteCode(Context* context, ByteCodeBlock* block)
             b++;
         }
 
-        for (size_t i = 0; i < codeBlock->identifierInfos().size(); i++) {
+        size_t localStart = 0;
+        if (codeBlock->isFunctionExpression() && !codeBlock->isFunctionNameSaveOnHeap()) {
+            localStart = 1;
+        }
+        for (size_t i = localStart; i < codeBlock->identifierInfos().size(); i++) {
             if (codeBlock->identifierInfos()[i].m_needToAllocateOnStack) {
                 auto name = codeBlock->identifierInfos()[i].m_name.string()->toNonGCUTF8StringData();
                 if (i == 0 && codeBlock->isFunctionExpression()) {
index ab3a412321d198301a98415dc5cf806605b42e89..ac32dad79bc14a18ccf75b367af3344ee44f6097 100644 (file)
@@ -35,8 +35,7 @@ class InterpretedCodeBlock;
 
 struct ClassContextInformation {
     ClassContextInformation()
-        : m_thisExpressionIndex(REGULAR_REGISTER_LIMIT)
-        , m_constructorIndex(SIZE_MAX)
+        : m_constructorIndex(SIZE_MAX)
         , m_prototypeIndex(SIZE_MAX)
         , m_superIndex(SIZE_MAX)
         , m_name()
@@ -44,7 +43,6 @@ struct ClassContextInformation {
     {
     }
 
-    size_t m_thisExpressionIndex;
     size_t m_constructorIndex;
     size_t m_prototypeIndex;
     size_t m_superIndex;
@@ -54,17 +52,12 @@ struct ClassContextInformation {
 
 #ifdef ESCARGOT_DEBUGGER
 struct ByteCodeBreakpointContext {
+    size_t m_lastBreakpointLineOffset; // cache breakpoint's calculated line offset
+    size_t m_lastBreakpointIndexOffset; // cache breakpoint's calculated index offset
+    Debugger::BreakpointLocationsInfo* m_breakpointLocations;
     bool m_parsingEnabled;
-    size_t m_lastBreakpointLineOffset;
-    size_t m_lastBreakpointIndexOffset;
-    std::vector<Debugger::BreakpointLocation> m_breakpointLocations;
-
-    ByteCodeBreakpointContext(bool parsingEnabled)
-        : m_parsingEnabled(parsingEnabled)
-        , m_lastBreakpointLineOffset(0)
-        , m_lastBreakpointIndexOffset(0)
-    {
-    }
+
+    ByteCodeBreakpointContext(Debugger* debugger, InterpretedCodeBlock* codeBlock);
 };
 #endif /* ESCARGOT_DEBUGGER */
 
@@ -94,8 +87,6 @@ struct ByteCodeGenerateContext {
         , m_positionToContinue(0)
         , m_complexJumpBreakIgnoreCount(0)
         , m_complexJumpContinueIgnoreCount(0)
-        , m_complexJumpLabelledBreakIgnoreCount(0)
-        , m_complexJumpLabelledContinueIgnoreCount(0)
         , m_lexicalBlockIndex(0)
         , m_openedNonBlockEnvCount(0)
         , m_classInfo()
@@ -130,10 +121,8 @@ struct ByteCodeGenerateContext {
         , m_lexicallyDeclaredNames(contextBefore.m_lexicallyDeclaredNames)
         , m_positionToContinue(contextBefore.m_positionToContinue)
         , m_recursiveStatementStack(contextBefore.m_recursiveStatementStack)
-        , m_complexJumpBreakIgnoreCount(contextBefore.m_complexJumpBreakIgnoreCount)
-        , m_complexJumpContinueIgnoreCount(contextBefore.m_complexJumpContinueIgnoreCount)
-        , m_complexJumpLabelledBreakIgnoreCount(contextBefore.m_complexJumpLabelledBreakIgnoreCount)
-        , m_complexJumpLabelledContinueIgnoreCount(contextBefore.m_complexJumpLabelledContinueIgnoreCount)
+        , m_complexJumpBreakIgnoreCount(contextBefore.m_recursiveStatementStack.size())
+        , m_complexJumpContinueIgnoreCount(m_complexJumpBreakIgnoreCount)
         , m_lexicalBlockIndex(contextBefore.m_lexicalBlockIndex)
         , m_openedNonBlockEnvCount(contextBefore.m_openedNonBlockEnvCount)
         , m_classInfo(contextBefore.m_classInfo)
@@ -142,6 +131,7 @@ struct ByteCodeGenerateContext {
         , m_breakpointContext(contextBefore.m_breakpointContext)
 #endif /* ESCARGOT_DEBUGGER */
     {
+        ASSERT(m_complexJumpBreakIgnoreCount == m_complexJumpContinueIgnoreCount);
     }
 
     ~ByteCodeGenerateContext()
@@ -209,16 +199,16 @@ struct ByteCodeGenerateContext {
 
         for (unsigned i = 0; i < m_labelledBreakStatmentPositions.size(); i++) {
             if (m_labelledBreakStatmentPositions[i].second > (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_labelledBreakStatmentPositions[i].second) == m_complexCaseStatementPositions.end()) {
-                if (tryCatchWithBlockStatementCount() - m_complexJumpLabelledBreakIgnoreCount > 0) {
-                    m_complexCaseStatementPositions.insert(std::make_pair(m_labelledBreakStatmentPositions[i].second, tryCatchWithBlockStatementCount() - m_complexJumpLabelledBreakIgnoreCount));
+                if (tryCatchWithBlockStatementCount() > 0) {
+                    m_complexCaseStatementPositions.insert(std::make_pair(m_labelledBreakStatmentPositions[i].second, tryCatchWithBlockStatementCount()));
                 }
             }
         }
 
         for (unsigned i = 0; i < m_labelledContinueStatmentPositions.size(); i++) {
             if (m_labelledContinueStatmentPositions[i].second > (unsigned long)frontlimit && m_complexCaseStatementPositions.find(m_labelledContinueStatmentPositions[i].second) == m_complexCaseStatementPositions.end()) {
-                if (tryCatchWithBlockStatementCount() - m_complexJumpLabelledContinueIgnoreCount > 0) {
-                    m_complexCaseStatementPositions.insert(std::make_pair(m_labelledContinueStatmentPositions[i].second, tryCatchWithBlockStatementCount() - m_complexJumpLabelledContinueIgnoreCount));
+                if (tryCatchWithBlockStatementCount() > 0) {
+                    m_complexCaseStatementPositions.insert(std::make_pair(m_labelledContinueStatmentPositions[i].second, tryCatchWithBlockStatementCount()));
                 }
             }
         }
@@ -321,7 +311,7 @@ struct ByteCodeGenerateContext {
     }
 
 #ifdef ESCARGOT_DEBUGGER
-    size_t calculateBreakpointLineOffset(size_t index, ExtendedNodeLOC sourceElementStart);
+    void calculateBreakpointLocation(size_t index, ExtendedNodeLOC sourceElementStart);
     void insertBreakpoint(size_t index, Node* node);
     void insertBreakpointAt(size_t line, Node* node);
 #endif /* ESCARGOT_DEBUGGER */
@@ -370,8 +360,6 @@ struct ByteCodeGenerateContext {
     std::vector<std::pair<RecursiveStatementKind, size_t>> m_recursiveStatementStack;
     int m_complexJumpBreakIgnoreCount;
     int m_complexJumpContinueIgnoreCount;
-    int m_complexJumpLabelledBreakIgnoreCount;
-    int m_complexJumpLabelledContinueIgnoreCount;
     size_t m_lexicalBlockIndex;
     size_t m_openedNonBlockEnvCount;
     ClassContextInformation m_classInfo;
index baf16844172ac1637a2b1b40322f5b7afb452f94..e4474dcef88df86de6c6798ea67a7c20a97fa611 100644 (file)
@@ -483,7 +483,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
             const Value& willBeObject = registerFile[code->m_objectRegisterIndex];
             const Value& property = registerFile[code->m_propertyRegisterIndex];
             PointerValue* v;
-            if (LIKELY(willBeObject.isObject() && (v = willBeObject.asPointerValue())->isArrayObject())) {
+            if (LIKELY(willBeObject.isObject() && (v = willBeObject.asPointerValue())->hasArrayObjectTag())) {
                 ArrayObject* arr = (ArrayObject*)v;
                 if (LIKELY(arr->isFastModeArray())) {
                     uint32_t idx = property.tryToUseAsIndexProperty(*state);
@@ -506,7 +506,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
             SetObjectOperation* code = (SetObjectOperation*)programCounter;
             const Value& willBeObject = registerFile[code->m_objectRegisterIndex];
             const Value& property = registerFile[code->m_propertyRegisterIndex];
-            if (LIKELY(willBeObject.isObject() && (willBeObject.asPointerValue())->isArrayObject())) {
+            if (LIKELY(willBeObject.isObject() && (willBeObject.asPointerValue())->hasArrayObjectTag())) {
                 ArrayObject* arr = willBeObject.asObject()->asArrayObject();
                 uint32_t idx = property.tryToUseAsIndexProperty(*state);
                 if (LIKELY(arr->isFastModeArray())) {
@@ -533,14 +533,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
             :
         {
             GetObjectPreComputedCase* code = (GetObjectPreComputedCase*)programCounter;
-            const Value& willBeObject = registerFile[code->m_objectRegisterIndex];
-            Object* obj;
-            if (LIKELY(willBeObject.isObject())) {
-                obj = willBeObject.asObject();
-            } else {
-                obj = fastToObject(*state, willBeObject);
-            }
-            registerFile[code->m_storeRegisterIndex] = getObjectPrecomputedCaseOperation(*state, obj, willBeObject, code, byteCodeBlock);
+            getObjectPrecomputedCaseOperation(*state, code, registerFile, byteCodeBlock);
             ADD_PROGRAM_COUNTER(GetObjectPreComputedCase);
             NEXT_INSTRUCTION();
         }
@@ -919,7 +912,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
             :
         {
             ObjectDefineOwnPropertyWithNameOperation* code = (ObjectDefineOwnPropertyWithNameOperation*)programCounter;
-            objectDefineOwnPropertyWithNameOperation(*state, code, registerFile);
+            objectDefineOwnPropertyWithNameOperation(*state, code, byteCodeBlock, registerFile);
             ADD_PROGRAM_COUNTER(ObjectDefineOwnPropertyWithNameOperation);
             NEXT_INSTRUCTION();
         }
@@ -1146,8 +1139,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
             :
         {
             CreateEnumerateObject* code = (CreateEnumerateObject*)programCounter;
-            auto data = createEnumerateObject(*state, registerFile[code->m_objectRegisterIndex].toObject(*state), code->m_isDestruction);
-            registerFile[code->m_dataRegisterIndex] = Value((PointerValue*)data);
+            createEnumerateObject(*state, code, registerFile);
             ADD_PROGRAM_COUNTER(CreateEnumerateObject);
             NEXT_INSTRUCTION();
         }
@@ -1258,7 +1250,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
             :
         {
             ObjectDefineGetterSetter* code = (ObjectDefineGetterSetter*)programCounter;
-            defineObjectGetterSetter(*state, code, registerFile);
+            defineObjectGetterSetter(*state, code, byteCodeBlock, registerFile);
             ADD_PROGRAM_COUNTER(ObjectDefineGetterSetter);
             NEXT_INSTRUCTION();
         }
@@ -1402,7 +1394,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
         {
 #ifdef ESCARGOT_DEBUGGER
             Debugger* debugger = state->context()->debugger();
-            if (debugger && debugger->enabled()) {
+            if (debugger != nullptr) {
                 debugger->processDisabledBreakpoint(byteCodeBlock, (uint32_t)(programCounter - (size_t)codeBuffer), state);
             }
 #endif /* ESCARGOT_DEBUGGER */
@@ -1416,7 +1408,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState* state, ByteCodeBlock* byteC
         {
 #ifdef ESCARGOT_DEBUGGER
             Debugger* debugger = state->context()->debugger();
-            if (debugger && debugger->enabled()) {
+            if (debugger != nullptr) {
                 debugger->stopAtBreakpoint(byteCodeBlock, (uint32_t)(programCounter - (size_t)codeBuffer), state);
             }
 #endif /* ESCARGOT_DEBUGGER */
@@ -2050,92 +2042,131 @@ NEVER_INLINE bool ByteCodeInterpreter::abstractLeftIsLessThanEqualRightSlowCase(
     }
 }
 
-ALWAYS_INLINE Value ByteCodeInterpreter::getObjectPrecomputedCaseOperation(ExecutionState& state, Object* obj, const Value& receiver, GetObjectPreComputedCase* code, ByteCodeBlock* block)
+ALWAYS_INLINE void ByteCodeInterpreter::getObjectPrecomputedCaseOperation(ExecutionState& state, GetObjectPreComputedCase* code, Value* registerFile, ByteCodeBlock* block)
 {
-    Object* orgObj = obj;
+    const Value& receiver = registerFile[code->m_objectRegisterIndex];
+    Object* obj;
+    if (LIKELY(receiver.isObject())) {
+        obj = receiver.asObject();
+    } else {
+        obj = fastToObject(state, receiver);
+    }
+
     if (LIKELY(code->m_inlineCache != nullptr)) {
-        auto inlineCache = code->m_inlineCache;
+        GetObjectInlineCache* const inlineCache = code->m_inlineCache;
         const size_t cacheFillCount = inlineCache->m_cache.size();
-        GetObjectInlineCacheData* cacheData = inlineCache->m_cache.data();
-        unsigned currentCacheIndex = 0;
-    TestCache:
-        for (; currentCacheIndex < cacheFillCount; currentCacheIndex++) {
-            const GetObjectInlineCacheData& data = cacheData[currentCacheIndex];
-            const size_t cSiz = data.m_cachedhiddenClassChainLength - 1;
-            if (cSiz) {
-                obj = orgObj;
-                ObjectStructure** cachedHiddenClassChain = data.m_cachedhiddenClassChain;
-                size_t cachedIndex = data.m_cachedIndex;
-                for (size_t i = 0; i < cSiz; i++) {
-                    if (cachedHiddenClassChain[i] != obj->structure()) {
-                        currentCacheIndex++;
-                        goto TestCache;
-                    }
-                    Object* protoObject = obj->Object::getPrototypeObject(state);
-                    if (protoObject != nullptr) {
-                        obj = protoObject;
+        GetObjectInlineCacheData* const cacheData = inlineCache->m_cache.data();
+
+        // simple case
+        if (!code->m_inlineCacheProtoTraverseMaxIndex) {
+            ObjectStructure* const objStructure = obj->structure();
+            for (unsigned currentCacheIndex = 0; currentCacheIndex < cacheFillCount; currentCacheIndex++) {
+                const GetObjectInlineCacheData& data = cacheData[currentCacheIndex];
+                if (data.m_cachedhiddenClass == objStructure) {
+                    const auto& cachedIndex = data.m_cachedIndex;
+                    // this is possible. but super rare
+                    // so not cached for performance
+                    ASSERT(cachedIndex != GetObjectInlineCacheData::inlineCacheCachedIndexMax);
+                    if (LIKELY(data.m_isPlainDataProperty)) {
+                        registerFile[code->m_storeRegisterIndex] = obj->m_values[cachedIndex];
                     } else {
-                        currentCacheIndex++;
-                        goto TestCache;
+                        registerFile[code->m_storeRegisterIndex] = obj->getOwnNonPlainDataPropertyUtilForObject(state, cachedIndex, receiver);
                     }
+                    return;
                 }
+            }
+        } else {
+            if (getObjectPrecomputedCaseOperationSlowCase(state, obj, receiver, code, cacheData, cacheFillCount, registerFile, block)) {
+                return;
+            }
+        }
+    }
 
-                if (LIKELY(cachedHiddenClassChain[cSiz] == obj->structure())) {
-                    if (LIKELY(data.m_cachedIndex != SIZE_MAX)) {
-                        return obj->getOwnPropertyUtilForObject(state, data.m_cachedIndex, receiver);
-                    } else {
-                        return Value();
-                    }
+    getObjectPrecomputedCaseOperationCacheMiss(state, obj, receiver, code, registerFile, block);
+}
+
+NEVER_INLINE bool ByteCodeInterpreter::getObjectPrecomputedCaseOperationSlowCase(ExecutionState& state, Object* obj, const Value& receiver, GetObjectPreComputedCase* code,
+                                                                                 GetObjectInlineCacheData* cacheData,
+                                                                                 const size_t& cacheFillCount,
+                                                                                 Value* registerFile,
+                                                                                 ByteCodeBlock* block)
+{
+    Object* objChain[GetObjectPreComputedCase::inlineCacheProtoTraverseMaxCount];
+    ObjectStructure* objStructures[GetObjectPreComputedCase::inlineCacheProtoTraverseMaxCount];
+    const auto& maxIndex = code->m_inlineCacheProtoTraverseMaxIndex;
+    size_t fillCount;
+    for (fillCount = 0; fillCount <= maxIndex && obj; fillCount++) {
+        objChain[fillCount] = obj;
+        objStructures[fillCount] = obj->structure();
+        obj = obj->Object::getPrototypeObject(state);
+    }
+
+    for (unsigned currentCacheIndex = 0; currentCacheIndex < cacheFillCount; currentCacheIndex++) {
+        const GetObjectInlineCacheData& data = cacheData[currentCacheIndex];
+        const size_t& cSiz = data.m_cachedhiddenClassChainLength;
+        if (cSiz <= fillCount) {
+            bool ok = true;
+            for (size_t i = 0; i < cSiz; i++) {
+                if (objStructures[i] != data.m_cachedhiddenClassChain[i]) {
+                    ok = false;
+                    break;
                 }
-            } else {
-                if (LIKELY(data.m_cachedhiddenClass == orgObj->structure())) {
-                    if (LIKELY(data.m_cachedIndex != SIZE_MAX)) {
-                        return orgObj->getOwnPropertyUtilForObject(state, data.m_cachedIndex, receiver);
+            }
+            if (ok) {
+                const auto& cachedIndex = data.m_cachedIndex;
+                if (LIKELY(cachedIndex != GetObjectInlineCacheData::inlineCacheCachedIndexMax)) {
+                    if (LIKELY(data.m_isPlainDataProperty)) {
+                        registerFile[code->m_storeRegisterIndex] = objChain[cSiz - 1]->m_values[cachedIndex];
                     } else {
-                        return Value();
+                        registerFile[code->m_storeRegisterIndex] = objChain[cSiz - 1]->getOwnNonPlainDataPropertyUtilForObject(state, cachedIndex, receiver);
                     }
+                } else {
+                    registerFile[code->m_storeRegisterIndex] = Value();
                 }
+                return true;
             }
         }
     }
-
-    return getObjectPrecomputedCaseOperationCacheMiss(state, orgObj, receiver, code, block);
+    return false;
 }
 
-NEVER_INLINE Value ByteCodeInterpreter::getObjectPrecomputedCaseOperationCacheMiss(ExecutionState& state, Object* obj, const Value& receiver, GetObjectPreComputedCase* code, ByteCodeBlock* block)
+NEVER_INLINE void ByteCodeInterpreter::getObjectPrecomputedCaseOperationCacheMiss(ExecutionState& state, Object* obj, const Value& receiver, GetObjectPreComputedCase* code, Value* registerFile, ByteCodeBlock* block)
 {
     if (code->m_isLength && obj->isArrayObject()) {
-        return Value(obj->asArrayObject()->arrayLength(state));
+        registerFile[code->m_storeRegisterIndex] = Value(obj->asArrayObject()->arrayLength(state));
+        return;
     }
 
 #if defined(ESCARGOT_SMALL_CONFIG)
-    return obj->get(state, ObjectPropertyName(state, code->m_propertyName)).value(state, receiver);
+    registerFile[code->m_storeRegisterIndex] = obj->get(state, ObjectPropertyName(state, code->m_propertyName)).value(state, receiver);
+    return;
 #endif
 
-    const int maxCacheMissCount = 16;
-    const int minCacheFillCount = 3;
-    const size_t maxCacheCount = 6;
+    const size_t maxCacheMissCount = 32;
+    const size_t minCacheFillCount = 4;
+    const size_t maxCacheCount = 24;
 
     // cache miss.
     if (code->m_cacheMissCount > maxCacheMissCount) {
-        return obj->get(state, ObjectPropertyName(state, code->m_propertyName)).value(state, receiver);
+        registerFile[code->m_storeRegisterIndex] = obj->get(state, ObjectPropertyName(state, code->m_propertyName)).value(state, receiver);
+        return;
     }
 
     code->m_cacheMissCount++;
     if (code->m_cacheMissCount <= minCacheFillCount) {
-        return obj->get(state, ObjectPropertyName(state, code->m_propertyName)).value(state, receiver);
+        registerFile[code->m_storeRegisterIndex] = obj->get(state, ObjectPropertyName(state, code->m_propertyName)).value(state, receiver);
+        return;
     }
 
     if (UNLIKELY(!obj->isInlineCacheable())) {
         code->m_cacheMissCount = maxCacheMissCount + 1;
-        return obj->get(state, ObjectPropertyName(state, code->m_propertyName)).value(state, receiver);
+        registerFile[code->m_storeRegisterIndex] = obj->get(state, ObjectPropertyName(state, code->m_propertyName)).value(state, receiver);
+        return;
     }
 
     if (UNLIKELY(code->m_cacheMissCount == maxCacheMissCount)) {
-        if (code->m_inlineCache) {
-            code->m_inlineCache->m_cache.clear();
-        }
-        return obj->get(state, ObjectPropertyName(state, code->m_propertyName)).value(state, receiver);
+        registerFile[code->m_storeRegisterIndex] = obj->get(state, ObjectPropertyName(state, code->m_propertyName)).value(state, receiver);
+        return;
     }
 
     auto& currentCodeSizeTotal = state.context()->vmInstance()->compiledByteCodeSize();
@@ -2148,18 +2179,20 @@ NEVER_INLINE Value ByteCodeInterpreter::getObjectPrecomputedCaseOperationCacheMi
     }
 
     auto inlineCache = code->m_inlineCache;
+    Object* orgObj = obj;
 
     if (inlineCache->m_cache.size() > maxCacheCount) {
-        return obj->get(state, ObjectPropertyName(state, code->m_propertyName)).value(state, receiver);
+        for (size_t i = inlineCache->m_cache.size() - 1; i > 0; i--) {
+            inlineCache->m_cache[i] = inlineCache->m_cache[i - 1];
+        }
+    } else {
+        inlineCache->m_cache.insert(0, GetObjectInlineCacheData());
+        block->m_inlineCacheDataSize += sizeof(GetObjectInlineCacheData);
+        currentCodeSizeTotal += sizeof(GetObjectInlineCacheData);
     }
 
-    Object* orgObj = obj;
-    inlineCache->m_cache.insert(0, GetObjectInlineCacheData());
-    block->m_inlineCacheDataSize += sizeof(GetObjectInlineCacheData);
-    currentCodeSizeTotal += sizeof(GetObjectInlineCacheData);
-
     auto& newItem = inlineCache->m_cache[0];
-    VectorWithInlineStorage<24, ObjectStructure*, std::allocator<ObjectStructure*>> cachedhiddenClassChain;
+    VectorWithInlineStorage<GetObjectPreComputedCase::inlineCacheProtoTraverseMaxCount, ObjectStructure*, std::allocator<ObjectStructure*>> cachedhiddenClassChain;
 
     while (true) {
         auto s = obj->structure();
@@ -2167,24 +2200,38 @@ NEVER_INLINE Value ByteCodeInterpreter::getObjectPrecomputedCaseOperationCacheMi
         auto result = s->findProperty(code->m_propertyName);
 
         if (result.first != SIZE_MAX) {
+            if (UNLIKELY(result.first > GetObjectInlineCacheData::inlineCacheCachedIndexMax)) {
+                goto GiveUp;
+            }
             newItem.m_cachedIndex = result.first;
+            newItem.m_isPlainDataProperty = result.second->m_descriptor.isPlainDataProperty();
             break;
         }
 
         obj = obj->Object::getPrototypeObject(state);
 
         if (!obj) {
-            newItem.m_cachedIndex = SIZE_MAX;
+            newItem.m_cachedIndex = GetObjectInlineCacheData::inlineCacheCachedIndexMax;
             break;
         }
 
         if (UNLIKELY(!obj->isInlineCacheable())) {
-            inlineCache->m_cache.clear();
-            code->m_cacheMissCount = maxCacheMissCount + 1;
-            return obj->get(state, ObjectPropertyName(state, code->m_propertyName)).value(state, receiver);
+            goto GiveUp;
         }
     }
 
+    if (UNLIKELY(cachedhiddenClassChain.size() > GetObjectPreComputedCase::inlineCacheProtoTraverseMaxCount)) {
+        goto GiveUp;
+    }
+
+    // this is possible. but super rare
+    // so this case is not cached for performance
+    if (UNLIKELY(cachedhiddenClassChain.size() == 1 && newItem.m_cachedIndex == GetObjectInlineCacheData::inlineCacheCachedIndexMax)) {
+        goto GiveUp;
+    }
+
+    code->m_inlineCacheProtoTraverseMaxIndex = std::max(cachedhiddenClassChain.size() - 1, (size_t)code->m_inlineCacheProtoTraverseMaxIndex);
+
     newItem.m_cachedhiddenClassChainLength = cachedhiddenClassChain.size();
     if (newItem.m_cachedhiddenClassChainLength == 1) {
         newItem.m_cachedhiddenClass = cachedhiddenClassChain[0];
@@ -2195,11 +2242,23 @@ NEVER_INLINE Value ByteCodeInterpreter::getObjectPrecomputedCaseOperationCacheMi
         memcpy(newItem.m_cachedhiddenClassChain, cachedhiddenClassChain.data(), sizeof(ObjectStructure*) * cachedhiddenClassChain.size());
     }
 
-    if (newItem.m_cachedIndex != SIZE_MAX) {
-        return obj->getOwnPropertyUtilForObject(state, newItem.m_cachedIndex, receiver);
+    if (newItem.m_cachedIndex != GetObjectInlineCacheData::inlineCacheCachedIndexMax) {
+        if (newItem.m_isPlainDataProperty) {
+            registerFile[code->m_storeRegisterIndex] = obj->m_values[newItem.m_cachedIndex];
+        } else {
+            registerFile[code->m_storeRegisterIndex] = obj->getOwnNonPlainDataPropertyUtilForObject(state, newItem.m_cachedIndex, receiver);
+        }
+        return;
     } else {
-        return Value();
+        registerFile[code->m_storeRegisterIndex] = Value();
+        return;
     }
+
+GiveUp:
+    inlineCache->m_cache.clear();
+    code->m_inlineCache = nullptr;
+    code->m_cacheMissCount = maxCacheMissCount + 1;
+    registerFile[code->m_storeRegisterIndex] = orgObj->get(state, ObjectPropertyName(state, code->m_propertyName)).value(state, receiver);
 }
 
 ALWAYS_INLINE void ByteCodeInterpreter::setObjectPreComputedCaseOperation(ExecutionState& state, const Value& willBeObject, const Value& value, SetObjectPreComputedCase* code, ByteCodeBlock* block)
@@ -2257,9 +2316,13 @@ ALWAYS_INLINE void ByteCodeInterpreter::setObjectPreComputedCaseOperation(Execut
 
 NEVER_INLINE void ByteCodeInterpreter::setObjectPreComputedCaseOperationCacheMiss(ExecutionState& state, Object* originalObject, const Value& willBeObject, const Value& value, SetObjectPreComputedCase* code, ByteCodeBlock* block)
 {
-    if (code->m_isLength && originalObject->isArrayObject() && originalObject->asArrayObject()->isFastModeArray()) {
-        if (!originalObject->asArrayObject()->setArrayLength(state, value) && state.inStrictMode()) {
-            ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, code->m_propertyName.toExceptionString(), false, String::emptyString, ErrorObject::Messages::DefineProperty_NotWritable);
+    if (code->m_isLength && originalObject->isArrayObject()) {
+        if (LIKELY(originalObject->asArrayObject()->isFastModeArray())) {
+            if (!originalObject->asArrayObject()->setArrayLength(state, value) && state.inStrictMode()) {
+                ErrorObject::throwBuiltinError(state, ErrorObject::Code::TypeError, code->m_propertyName.toExceptionString(), false, String::emptyString, ErrorObject::Messages::DefineProperty_NotWritable);
+            }
+        } else {
+            originalObject->setThrowsExceptionWhenStrictMode(state, ObjectPropertyName(state, code->m_propertyName), value, willBeObject);
         }
         return;
     }
@@ -2545,7 +2608,7 @@ NEVER_INLINE void ByteCodeInterpreter::createFunctionOperation(ExecutionState& s
     } else if (cb->isObjectMethod() || cb->isClassMethod() || cb->isClassStaticMethod()) {
         registerFile[code->m_registerIndex] = new ScriptClassMethodFunctionObject(state, proto, cb, outerLexicalEnvironment, registerFile[code->m_homeObjectRegisterIndex].asObject());
     } else {
-        registerFile[code->m_registerIndex] = new ScriptFunctionObject(state, proto, cb, outerLexicalEnvironment, true, false, false);
+        registerFile[code->m_registerIndex] = new ScriptFunctionObject(state, proto, cb, outerLexicalEnvironment, true, false);
     }
 }
 
@@ -2600,7 +2663,7 @@ NEVER_INLINE Value ByteCodeInterpreter::tryOperation(ExecutionState*& state, siz
         newState->ensureRareData()->m_controlFlowRecord = state->rareData()->m_controlFlowRecord;
     }
 
-    SandBox::StackTraceDataVector stackTraceData;
+    SandBox::StackTraceDataVector stackTraceDataVector;
 
     if (LIKELY(!code->m_isCatchResumeProcess && !code->m_isFinallyResumeProcess)) {
         try {
@@ -2649,11 +2712,11 @@ NEVER_INLINE Value ByteCodeInterpreter::tryOperation(ExecutionState*& state, siz
                 ESCARGOT_LOG_ERROR("%s\n", builder.finalize()->toUTF8StringData().data());
             }
 #endif
-            stackTraceData = std::move(newState->context()->vmInstance()->currentSandBox()->stackTraceData());
+            stackTraceDataVector = std::move(newState->context()->vmInstance()->currentSandBox()->stackTraceDataVector());
             if (!code->m_hasCatch) {
                 newState->rareData()->m_controlFlowRecord->back() = new ControlFlowRecord(ControlFlowRecord::NeedsThrow, val);
             } else {
-                stackTraceData.clear();
+                stackTraceDataVector.clear();
                 registerFile[code->m_catchedValueRegisterIndex] = val;
                 try {
                     ExecutionStateVariableChanger<void (*)(ExecutionState&, bool)> changer(*state, [](ExecutionState& state, bool in) {
@@ -2664,7 +2727,7 @@ NEVER_INLINE Value ByteCodeInterpreter::tryOperation(ExecutionState*& state, siz
                         return Value();
                     }
                 } catch (const Value& val) {
-                    stackTraceData = newState->context()->vmInstance()->currentSandBox()->stackTraceData();
+                    stackTraceDataVector = newState->context()->vmInstance()->currentSandBox()->stackTraceDataVector();
                     newState->rareData()->m_controlFlowRecord->back() = new ControlFlowRecord(ControlFlowRecord::NeedsThrow, val);
                 }
             }
@@ -2737,7 +2800,7 @@ NEVER_INLINE Value ByteCodeInterpreter::tryOperation(ExecutionState*& state, siz
                 return Value(Value::EmptyValue);
             }
         } else if (record->reason() == ControlFlowRecord::NeedsThrow) {
-            state->context()->vmInstance()->currentSandBox()->rethrowPreviouslyCaughtException(*state, record->value(), stackTraceData);
+            state->context()->vmInstance()->currentSandBox()->rethrowPreviouslyCaughtException(*state, record->value(), stackTraceDataVector);
             ASSERT_NOT_REACHED();
             // never get here. but I add return statement for removing compile warning
             return Value(Value::EmptyValue);
@@ -2821,7 +2884,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, true);
+                auto functionSource = FunctionObject::createFunctionScript(state, state.context()->staticStrings().constructor, 1, &argv[0], argv[1], true, false, false, false, true);
                 functionSource.codeBlock->setAsClassConstructor();
                 constructor = new ScriptClassConstructorFunctionObject(state, constructorParent.asObject(),
                                                                        functionSource.codeBlock, functionSource.outerEnvironment, proto,
@@ -2829,7 +2892,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, true);
+                auto functionSource = FunctionObject::createFunctionScript(state, state.context()->staticStrings().constructor, 1, &argv[0], argv[1], true, false, false, true, true);
                 functionSource.codeBlock->setAsClassConstructor();
                 functionSource.codeBlock->setAsDerivedClassConstructor();
                 constructor = new ScriptClassConstructorFunctionObject(state, constructorParent.asObject(),
@@ -3484,22 +3547,25 @@ NEVER_INLINE void ByteCodeInterpreter::spreadFunctionArguments(ExecutionState& s
     }
 }
 
-NEVER_INLINE EnumerateObject* ByteCodeInterpreter::createEnumerateObject(ExecutionState& state, Object* obj, bool isDestruction)
+NEVER_INLINE void ByteCodeInterpreter::createEnumerateObject(ExecutionState& state, CreateEnumerateObject* code, Value* registerFile)
 {
+    Object* obj = registerFile[code->m_objectRegisterIndex].toObject(state);
+    bool isDestruction = code->m_isDestruction;
+
     EnumerateObject* enumObj;
     if (isDestruction) {
         enumObj = new EnumerateObjectWithDestruction(state, obj);
     } else {
         enumObj = new EnumerateObjectWithIteration(state, obj);
     }
-
-    return enumObj;
+    registerFile[code->m_dataRegisterIndex] = Value((PointerValue*)enumObj);
 }
 
 NEVER_INLINE void ByteCodeInterpreter::checkLastEnumerateKey(ExecutionState& state, CheckLastEnumerateKey* code, char* codeBuffer, size_t& programCounter, Value* registerFile)
 {
     EnumerateObject* data = (EnumerateObject*)registerFile[code->m_registerIndex].asPointerValue();
     if (data->checkLastEnumerateKey(state)) {
+        delete data;
         programCounter = jumpTo(codeBuffer, code->m_exitPosition);
     } else {
         ADD_PROGRAM_COUNTER(CheckLastEnumerateKey);
@@ -3673,17 +3739,43 @@ NEVER_INLINE void ByteCodeInterpreter::objectDefineOwnPropertyOperation(Executio
     willBeObject.asObject()->defineOwnProperty(state, ObjectPropertyName(state, propertyStringOrSymbol), ObjectPropertyDescriptor(value, code->m_presentAttribute));
 }
 
-NEVER_INLINE void ByteCodeInterpreter::objectDefineOwnPropertyWithNameOperation(ExecutionState& state, ObjectDefineOwnPropertyWithNameOperation* code, Value* registerFile)
+NEVER_INLINE void ByteCodeInterpreter::objectDefineOwnPropertyWithNameOperation(ExecutionState& state, ObjectDefineOwnPropertyWithNameOperation* code, ByteCodeBlock* byteCodeBlock, Value* registerFile)
 {
-    const Value& willBeObject = registerFile[code->m_objectRegisterIndex];
+    Object* object = registerFile[code->m_objectRegisterIndex].asObject();
+    const Value& v = registerFile[code->m_loadRegisterIndex];
     // http://www.ecma-international.org/ecma-262/6.0/#sec-__proto__-property-names-in-object-initializers
-    if (!willBeObject.asObject()->isScriptClassConstructorPrototypeObject() && (code->m_propertyName == state.context()->staticStrings().__proto__)) {
-        const Value& v = registerFile[code->m_loadRegisterIndex];
+    if (!object->isScriptClassConstructorPrototypeObject() && (code->m_propertyName == state.context()->staticStrings().__proto__)) {
         if (v.isObject() || v.isNull()) {
-            willBeObject.asObject()->setPrototype(state, v);
+            object->setPrototype(state, v);
         }
     } else {
-        willBeObject.asObject()->defineOwnProperty(state, ObjectPropertyName(code->m_propertyName), ObjectPropertyDescriptor(registerFile[code->m_loadRegisterIndex], code->m_presentAttribute));
+        const size_t minCacheFillCount = 2;
+        if (object->structure() == code->m_inlineCachedStructureBefore) {
+            object->m_values.push_back(v, code->m_inlineCachedStructureAfter->propertyCount());
+            object->m_structure = code->m_inlineCachedStructureAfter;
+        } else if (code->m_missCount > minCacheFillCount) {
+            // cache miss
+            object->defineOwnProperty(state, ObjectPropertyName(code->m_propertyName), ObjectPropertyDescriptor(v, code->m_presentAttribute));
+        } else {
+            code->m_missCount++;
+            // should we fill cache?
+            if (minCacheFillCount == code->m_missCount) {
+                // try to fill cache
+                auto oldStructure = object->structure();
+                object->defineOwnProperty(state, ObjectPropertyName(code->m_propertyName), ObjectPropertyDescriptor(v, code->m_presentAttribute));
+                auto newStructure = object->structure();
+                if (object->isInlineCacheable() && oldStructure != newStructure) {
+                    byteCodeBlock->m_otherLiteralData.push_back(oldStructure);
+                    byteCodeBlock->m_otherLiteralData.push_back(newStructure);
+                    code->m_inlineCachedStructureBefore = oldStructure;
+                    code->m_inlineCachedStructureAfter = newStructure;
+                } else {
+                    // failed to cache
+                }
+            } else {
+                object->defineOwnProperty(state, ObjectPropertyName(code->m_propertyName), ObjectPropertyDescriptor(v, code->m_presentAttribute));
+            }
+        }
     }
 }
 
@@ -3799,7 +3891,7 @@ NEVER_INLINE void ByteCodeInterpreter::createSpreadArrayObject(ExecutionState& s
     registerFile[code->m_registerIndex] = spreadArray;
 }
 
-NEVER_INLINE void ByteCodeInterpreter::defineObjectGetterSetter(ExecutionState& state, ObjectDefineGetterSetter* code, Value* registerFile)
+static void defineObjectGetterSetterOperation(ExecutionState& state, ObjectDefineGetterSetter* code, ByteCodeBlock* byteCodeBlock, Value* registerFile, Object* object)
 {
     FunctionObject* fn = registerFile[code->m_objectPropertyValueRegisterIndex].asFunction();
     Value pName = code->m_objectPropertyNameRegisterIndex == REGISTER_LIMIT ? fn->codeBlock()->functionName().string() : registerFile[code->m_objectPropertyNameRegisterIndex];
@@ -3817,10 +3909,47 @@ NEVER_INLINE void ByteCodeInterpreter::defineObjectGetterSetter(ExecutionState&
         gs = new (alloca(sizeof(JSGetterSetter))) JSGetterSetter(Value(Value::EmptyValue), registerFile[code->m_objectPropertyValueRegisterIndex].asFunction());
     }
     ObjectPropertyDescriptor desc(*gs, code->m_presentAttribute);
-    Object* object = registerFile[code->m_objectRegisterIndex].toObject(state);
     object->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, pName), desc);
 }
 
+NEVER_INLINE void ByteCodeInterpreter::defineObjectGetterSetter(ExecutionState& state, ObjectDefineGetterSetter* code, ByteCodeBlock* byteCodeBlock, Value* registerFile)
+{
+    Object* object = registerFile[code->m_objectRegisterIndex].toObject(state);
+    const size_t minCacheFillCount = 2;
+    if (object->structure() == code->m_inlineCachedStructureBefore) {
+        JSGetterSetter* gs;
+        if (code->m_isGetter) {
+            gs = new JSGetterSetter(registerFile[code->m_objectPropertyValueRegisterIndex].asFunction(), Value(Value::EmptyValue));
+        } else {
+            gs = new JSGetterSetter(Value(Value::EmptyValue), registerFile[code->m_objectPropertyValueRegisterIndex].asFunction());
+        }
+        object->m_values.push_back(Value(gs), code->m_inlineCachedStructureAfter->propertyCount());
+        object->m_structure = code->m_inlineCachedStructureAfter;
+    } else if (code->m_missCount > minCacheFillCount) {
+        // cache miss
+        defineObjectGetterSetterOperation(state, code, byteCodeBlock, registerFile, object);
+    } else {
+        code->m_missCount++;
+        // should we fill cache?
+        if (minCacheFillCount == code->m_missCount && code->m_isPrecomputed) {
+            // try to fill cache
+            auto oldStructure = object->structure();
+            defineObjectGetterSetterOperation(state, code, byteCodeBlock, registerFile, object);
+            auto newStructure = object->structure();
+            if (object->isInlineCacheable() && oldStructure != newStructure) {
+                byteCodeBlock->m_otherLiteralData.push_back(oldStructure);
+                byteCodeBlock->m_otherLiteralData.push_back(newStructure);
+                code->m_inlineCachedStructureBefore = oldStructure;
+                code->m_inlineCachedStructureAfter = newStructure;
+            } else {
+                // failed to cache
+            }
+        } else {
+            defineObjectGetterSetterOperation(state, code, byteCodeBlock, registerFile, object);
+        }
+    }
+}
+
 ALWAYS_INLINE Value ByteCodeInterpreter::incrementOperation(ExecutionState& state, const Value& value)
 {
     if (LIKELY(value.isInt32())) {
index f644331967bfb67a52f555d9e0042eee40d8832d..ef9168af9584eccfb5ee5e97731b79d0094eb002 100644 (file)
@@ -33,6 +33,7 @@ class LexicalEnvironment;
 class GetObjectPreComputedCase;
 class SetObjectPreComputedCase;
 struct GetObjectInlineCache;
+struct GetObjectInlineCacheData;
 struct SetObjectInlineCache;
 struct GlobalVariableAccessCacheItem;
 class InitializeGlobalVariable;
@@ -67,6 +68,7 @@ class EnumerateObject;
 class CheckLastEnumerateKey;
 class TaggedTemplateOperation;
 class MarkEnumerateKey;
+class CreateEnumerateObject;
 
 class ByteCodeInterpreter {
 public:
@@ -110,8 +112,10 @@ private:
     static bool abstractLeftIsLessThanEqualRightSlowCase(ExecutionState& state, const Value& left, const Value& right, bool switched);
     static bool abstractLeftIsLessThanEqualRight(ExecutionState& state, const Value& left, const Value& right, bool switched);
 
-    static Value getObjectPrecomputedCaseOperation(ExecutionState& state, Object* obj, const Value& receiver, GetObjectPreComputedCase* code, ByteCodeBlock* block);
-    static Value getObjectPrecomputedCaseOperationCacheMiss(ExecutionState& state, Object* obj, const Value& receiver, GetObjectPreComputedCase* code, ByteCodeBlock* block);
+    static void getObjectPrecomputedCaseOperation(ExecutionState& state, GetObjectPreComputedCase* code, Value* registerFile, ByteCodeBlock* block);
+    static bool getObjectPrecomputedCaseOperationSlowCase(ExecutionState& state, Object* obj, const Value& receiver, GetObjectPreComputedCase* code, GetObjectInlineCacheData* cacheData,
+                                                          const size_t& cacheFillCount, Value* registerFile, ByteCodeBlock* block);
+    static void getObjectPrecomputedCaseOperationCacheMiss(ExecutionState& state, Object* obj, const Value& receiver, GetObjectPreComputedCase* code, Value* registerFile, ByteCodeBlock* block);
     static void setObjectPreComputedCaseOperation(ExecutionState& state, const Value& willBeObject, const Value& value, SetObjectPreComputedCase* code, ByteCodeBlock* block);
     static void setObjectPreComputedCaseOperationCacheMiss(ExecutionState& state, Object* obj, const Value& willBeObject, const Value& value, SetObjectPreComputedCase* code, ByteCodeBlock* block);
 
@@ -137,7 +141,7 @@ private:
     static void callFunctionComplexCase(ExecutionState& state, CallFunctionComplexCase* code, Value* registerFile, ByteCodeBlock* byteCodeBlock);
     static void spreadFunctionArguments(ExecutionState& state, const Value* argv, const size_t argc, ValueVector& argVector);
 
-    static EnumerateObject* createEnumerateObject(ExecutionState& state, Object* obj, bool isDestruction);
+    static void createEnumerateObject(ExecutionState& state, CreateEnumerateObject* code, Value* registerFile);
     static void checkLastEnumerateKey(ExecutionState& state, CheckLastEnumerateKey* code, char* codeBuffer, size_t& programCounter, Value* registerFile);
     static void markEnumerateKey(ExecutionState& state, MarkEnumerateKey* code, Value* registerFile);
 
@@ -149,11 +153,11 @@ private:
     static void metaPropertyOperation(ExecutionState& state, MetaPropertyOperation* code, ByteCodeBlock* byteCodeBlock, Value* registerFile);
 
     static void objectDefineOwnPropertyOperation(ExecutionState& state, ObjectDefineOwnPropertyOperation* code, Value* registerFile);
-    static void objectDefineOwnPropertyWithNameOperation(ExecutionState& state, ObjectDefineOwnPropertyWithNameOperation* code, Value* registerFile);
+    static void objectDefineOwnPropertyWithNameOperation(ExecutionState& state, ObjectDefineOwnPropertyWithNameOperation* code, ByteCodeBlock* byteCodeBlock, Value* registerFile);
     static void arrayDefineOwnPropertyOperation(ExecutionState& state, ArrayDefineOwnPropertyOperation* code, Value* registerFile);
     static void arrayDefineOwnPropertyBySpreadElementOperation(ExecutionState& state, ArrayDefineOwnPropertyBySpreadElementOperation* code, Value* registerFile);
     static void createSpreadArrayObject(ExecutionState& state, CreateSpreadArrayObject* code, Value* registerFile);
-    static void defineObjectGetterSetter(ExecutionState& state, ObjectDefineGetterSetter* code, Value* registerFile);
+    static void defineObjectGetterSetter(ExecutionState& state, ObjectDefineGetterSetter* code, ByteCodeBlock* byteCodeBlock, Value* registerFile);
     static Value incrementOperation(ExecutionState& state, const Value& value);
     static Value incrementOperationSlowCase(ExecutionState& state, const Value& value);
     static Value decrementOperation(ExecutionState& state, const Value& value);
index f48f1eb2168d86d744100019d12a0bcbe262fa5c..7c4a390b8bb988f4bfb7f1164f0f37929f4f1393 100644 (file)
@@ -2167,6 +2167,12 @@ String* Intl::icuNumberFieldToString(ExecutionState& state, int32_t fieldName, d
         return state.context()->staticStrings().lazyExponentMinusSign().string();
     case UNUM_EXPONENT_FIELD:
         return state.context()->staticStrings().lazyExponentInteger().string();
+#ifndef UNUM_MEASURE_UNIT_FIELD
+#define UNUM_MEASURE_UNIT_FIELD (UNUM_SIGN_FIELD + 1)
+#endif
+#ifndef UNUM_COMPACT_FIELD
+#define UNUM_COMPACT_FIELD (UNUM_SIGN_FIELD + 2)
+#endif
     case UNUM_MEASURE_UNIT_FIELD:
         return state.context()->staticStrings().lazyUnit().string();
     case UNUM_COMPACT_FIELD:
index 0c6af5d705aaa6e54d44172fa2fb1827e4d63e62..c0b888eb4077ba97bc8be083b0841ef17615b004 100644 (file)
@@ -182,8 +182,9 @@ static void toDateTimeOptionsTest(ExecutionState& state, Value options, AtomicSt
 
 static String* defaultTimeZone(ExecutionState& state)
 {
-    // ensure timezone
-    state.context()->vmInstance()->timezone();
+#if !defined(OS_WINDOWS_UWP)
+    state.context()->vmInstance()->ensureTimezone();
+#endif
     return String::fromUTF8(state.context()->vmInstance()->timezoneID().data(), state.context()->vmInstance()->timezoneID().length());
 }
 
index 0b1b32236b622445d26ceac2ed0132aefeecabfc..c99bfaa295a339592d69f1736cd29af06409f980 100644 (file)
@@ -26,6 +26,8 @@
 #include "Intl.h"
 #include "IntlDisplayNames.h"
 
+#if defined(ENABLE_INTL_DISPLAYNAMES)
+
 namespace Escargot {
 
 IntlDisplayNamesObject::IntlDisplayNamesObject(ExecutionState& state, Object* proto, Value locales, Value options)
@@ -367,3 +369,4 @@ Value IntlDisplayNamesObject::of(ExecutionState& state, const Value& codeInput)
 
 } // namespace Escargot
 #endif
+#endif
index a3579c07b855bca8afe170f924af892450a1626e..1b46ea64b5e09ce6baa703414df60b58deea6e04 100644 (file)
@@ -1,4 +1,4 @@
-#if defined(ENABLE_ICU) && defined(ENABLE_INTL)
+#if defined(ENABLE_ICU) && defined(ENABLE_INTL) && defined(ENABLE_INTL_DISPLAYNAMES)
 /*
  * Copyright (c) 2021-present Samsung Electronics Co., Ltd
  *
index a8dbfae4383e741255df1448e5a6dd1017141e08..8de08f40f3283a4386af9c52cbef860b87623f73 100644 (file)
@@ -29,6 +29,8 @@
 #include "Intl.h"
 #include "IntlListFormat.h"
 
+#if defined(ENABLE_INTL_LISTFORMAT)
+
 namespace Escargot {
 
 IntlListFormatObject::IntlListFormatObject(ExecutionState& state, Object* proto, Value locales, Value options)
@@ -306,3 +308,4 @@ Value IntlListFormatObject::formatToParts(ExecutionState& state, const Value& li
 
 } // namespace Escargot
 #endif
+#endif
index 0bb67c5c2e18453da294d8dcde6ec177eb5fe9d6..0ebf7ac7119dd22a680de9a77a1fb8f571e96c98 100644 (file)
@@ -1,4 +1,4 @@
-#if defined(ENABLE_ICU) && defined(ENABLE_INTL)
+#if defined(ENABLE_ICU) && defined(ENABLE_INTL) && defined(ENABLE_INTL_LISTFORMAT)
 /*
  * Copyright (c) 2021-present Samsung Electronics Co., Ltd
  *
index d05d7cadcdfb7fff499f9e204777a876d6928e4e..0e5b1ffb716e860e4a6a62b2cf83360ab4e00793 100644 (file)
@@ -52,6 +52,8 @@
 #include "Intl.h"
 #include "IntlNumberFormat.h"
 
+#if defined(ENABLE_INTL_NUMBERFORMAT)
+
 namespace Escargot {
 
 static const char* const intlNumberFormatRelevantExtensionKeys[1] = { "nu" };
@@ -910,3 +912,4 @@ ArrayObject* IntlNumberFormat::formatToParts(ExecutionState& state, Object* numb
 
 } // namespace Escargot
 #endif
+#endif
index 37fb84166fb34248eb1f2b6678d25ff8fc5ff088..6502e6423ba84f73da5ca4eb4566f7c6d9792d95 100644 (file)
@@ -1,4 +1,4 @@
-#if defined(ENABLE_ICU) && defined(ENABLE_INTL)
+#if defined(ENABLE_ICU) && defined(ENABLE_INTL) && defined(ENABLE_INTL_NUMBERFORMAT)
 /*
  * Copyright (c) 2019-present Samsung Electronics Co., Ltd
  *
index 55617402123e1db22ddda5ec92d99d977e15afce..813ff828ebd37be97ffb86932ccfbd1769115489 100644 (file)
@@ -26,6 +26,8 @@
 #include "Intl.h"
 #include "IntlPluralRules.h"
 
+#if defined(ENABLE_INTL_PLURALRULES)
+
 namespace Escargot {
 
 static double getNumberOption(ExecutionState& state, Optional<Object*> options, String* property, double minimum, double maximum, double fallback)
@@ -221,3 +223,4 @@ String* IntlPluralRulesObject::resolvePlural(double number)
 
 } // namespace Escargot
 #endif
+#endif
index 99cb8eb286b221cc6d64112ba6d2b16f1c752df8..00f52a5781b4ea57f67cd6f197849341f6c4a8f8 100644 (file)
@@ -1,4 +1,4 @@
-#if defined(ENABLE_ICU) && defined(ENABLE_INTL)
+#if defined(ENABLE_ICU) && defined(ENABLE_INTL) && defined(ENABLE_INTL_PLURALRULES)
 /*
  * Copyright (c) 2020-present Samsung Electronics Co., Ltd
  *
index a4619fad0ef4cb14d839ceaed61b154633280bd0..2c5fa3be1b7790cb9259f339f5fb397a8259d707 100644 (file)
@@ -28,6 +28,8 @@
 #include "Intl.h"
 #include "IntlRelativeTimeFormat.h"
 
+#if defined(ENABLE_INTL_RELATIVETIMEFORMAT)
+
 namespace Escargot {
 
 static const char* const intlRelativeTimeFormatRelevantExtensionKeys[1] = { "nu" };
@@ -350,3 +352,4 @@ ArrayObject* IntlRelativeTimeFormatObject::formatToParts(ExecutionState& state,
 
 } // namespace Escargot
 #endif
+#endif
index 91dc6ecb666b15e070f32caf5cf46c3707ed903a..4891b8a5e13e36c6eab41396b9efe0864f292339 100644 (file)
@@ -1,4 +1,4 @@
-#if defined(ENABLE_ICU) && defined(ENABLE_INTL)
+#if defined(ENABLE_ICU) && defined(ENABLE_INTL) && defined(ENABLE_INTL_RELATIVETIMEFORMAT)
 /*
  * Copyright (c) 2020-present Samsung Electronics Co., Ltd
  *
index 32fc1ef6117a558cf07975095c9e9dcdc8bfe163..57f52d49c5c84d9d8cf00ec902f0f53835152ad7 100644 (file)
@@ -214,6 +214,10 @@ InterpretedCodeBlock::InterpretedCodeBlock(Context* ctx, Script* script, StringV
     , m_allowSuperCall(false)
     , m_allowSuperProperty(false)
     , m_allowArguments(false)
+    , m_hasDynamicSourceCode(false)
+#ifdef ESCARGOT_DEBUGGER
+    , m_markDebugging(ctx->inDebuggingCodeMode())
+#endif
 #ifndef NDEBUG
     , m_scopeContext(scopeCtx)
 #endif
@@ -270,6 +274,10 @@ InterpretedCodeBlock::InterpretedCodeBlock(Context* ctx, Script* script, StringV
     , m_allowSuperCall(false)
     , m_allowSuperProperty(false)
     , m_allowArguments(false)
+    , m_hasDynamicSourceCode(false)
+#ifdef ESCARGOT_DEBUGGER
+    , m_markDebugging(ctx->inDebuggingCodeMode())
+#endif
 #ifndef NDEBUG
     , m_scopeContext(scopeCtx)
 #endif
@@ -326,6 +334,10 @@ InterpretedCodeBlock::InterpretedCodeBlock(Context* ctx, Script* script)
     , m_allowSuperCall(false)
     , m_allowSuperProperty(false)
     , m_allowArguments(false)
+    , m_hasDynamicSourceCode(false)
+#ifdef ESCARGOT_DEBUGGER
+    , m_markDebugging(ctx->inDebuggingCodeMode())
+#endif
 #ifndef NDEBUG
     , m_scopeContext(nullptr)
 #endif
index d4e53802bed9b30d007b8014ca8a6a7014b6b6f4..228c8877aa39b5f2826305723184d0e92b861a49 100644 (file)
@@ -72,6 +72,7 @@ public:
 
     virtual uint16_t functionLength() const = 0;
     virtual AtomicString functionName() const = 0;
+    virtual void setFunctionName(AtomicString name) = 0;
 
     virtual bool isNativeCodeBlock() const
     {
@@ -146,6 +147,11 @@ public:
         return m_functionName;
     }
 
+    virtual void setFunctionName(AtomicString name) override
+    {
+        m_functionName = name;
+    }
+
     bool isNativeConstructor() const
     {
         return m_isNativeConstructor;
@@ -291,10 +297,6 @@ public:
 
     typedef TightVector<IdentifierInfo, GCUtil::gc_malloc_atomic_allocator<IdentifierInfo>> IdentifierInfoVector;
 
-    static InterpretedCodeBlock* createInterpretedCodeBlock(Context* ctx, Script* script, StringView src, ASTScopeContext* scopeCtx, bool isEvalCode, bool isEvalCodeInFunction);
-    static InterpretedCodeBlock* createInterpretedCodeBlock(Context* ctx, Script* script, StringView src, ASTScopeContext* scopeCtx, InterpretedCodeBlock* parentBlock, bool isEvalCode, bool isEvalCodeInFunction);
-    static InterpretedCodeBlock* createInterpretedCodeBlock(Context* ctx, Script* script, bool needRareData = false);
-
     void* operator new(size_t size);
     void* operator new[](size_t size) = delete;
 
@@ -313,6 +315,13 @@ public:
         return m_functionName;
     }
 
+    virtual void setFunctionName(AtomicString name) override
+    {
+        // set function name is allowed only for dynamically created function except class constructor
+        ASSERT(m_hasDynamicSourceCode && !m_isClassConstructor);
+        m_functionName = name;
+    }
+
     virtual bool hasRareData() const
     {
         return false;
@@ -631,6 +640,23 @@ public:
         return m_allowArguments;
     }
 
+    bool hasDynamicSourceCode() const
+    {
+        return m_hasDynamicSourceCode;
+    }
+
+    void setDynamicSourceCode()
+    {
+        m_hasDynamicSourceCode = true;
+    }
+
+#ifdef ESCARGOT_DEBUGGER
+    bool markDebugging() const
+    {
+        return m_markDebugging;
+    }
+#endif
+
     bool isFunctionNameSaveOnHeap() const
     {
         return m_isFunctionNameSaveOnHeap;
@@ -874,6 +900,12 @@ protected:
     bool m_allowSuperCall : 1;
     bool m_allowSuperProperty : 1;
     bool m_allowArguments : 1;
+    // represent if its source code is created dynamically by createFunctionScript
+    bool m_hasDynamicSourceCode : 1;
+#ifdef ESCARGOT_DEBUGGER
+    // mark that this InterpretedCodeBlock should generate debugging bytecode (breakpoint)
+    bool m_markDebugging : 1;
+#endif
 
 #ifndef NDEBUG
     ASTScopeContext* m_scopeContext;
@@ -886,6 +918,10 @@ protected:
     // empty CodeBlock (for CodeCache loading)
     InterpretedCodeBlock(Context* ctx, Script* script);
 
+    static InterpretedCodeBlock* createInterpretedCodeBlock(Context* ctx, Script* script, StringView src, ASTScopeContext* scopeCtx, bool isEvalCode, bool isEvalCodeInFunction);
+    static InterpretedCodeBlock* createInterpretedCodeBlock(Context* ctx, Script* script, StringView src, ASTScopeContext* scopeCtx, InterpretedCodeBlock* parentBlock, bool isEvalCode, bool isEvalCodeInFunction);
+    static InterpretedCodeBlock* createInterpretedCodeBlock(Context* ctx, Script* script, bool needRareData = false);
+
     void recordGlobalParsingInfo(ASTScopeContext* scopeCtx, bool isEvalCode, bool isEvalCodeInFunction);
     void recordFunctionParsingInfo(ASTScopeContext* scopeCtxm, bool isEvalCode, bool isEvalCodeInFunction);
 
index 2bb89e3ba31dcd229df237ef9435e80d25d6f28d..6a2ec3d4e0426e196668f6f39c5ade79d916e58e 100644 (file)
@@ -480,18 +480,48 @@ StringView Scanner::ScannerResult::relatedSource(const StringView& source)
 
 Value Scanner::ScannerResult::valueStringLiteralToValue(Scanner* scannerInstance)
 {
-    if (this->type == Token::KeywordToken) {
-        return keywordToString(scannerInstance->escargotContext, this->valueKeywordKind).string();
-    }
+    ASSERT(this->type == Token::StringLiteralToken);
 
-    if (this->hasAllocatedString) {
+    if (UNLIKELY(this->hasAllocatedString)) {
         if (!this->valueStringLiteralData.m_stringIfNewlyAllocated) {
             constructStringLiteral(scannerInstance);
         }
         return this->valueStringLiteralData.m_stringIfNewlyAllocated;
     }
 
-    return new StringView(scannerInstance->sourceAsNormalView, this->valueStringLiteralData.m_start, this->valueStringLiteralData.m_end);
+    // check if string is one of typeof strings
+    // we only consider the most common cases which are undefined, object, function
+    size_t start = this->valueStringLiteralData.m_start;
+    size_t end = this->valueStringLiteralData.m_end;
+    size_t length = end - start;
+    if (length > 5 && length < 10) {
+        ParserStringView str(scannerInstance->source, start, end);
+        switch (str.bufferedCharAt(0)) {
+        case 'o': {
+            if (length == 6 && str.equalsSameLength("object", 1)) {
+                return scannerInstance->escargotContext->staticStrings().object.string();
+            }
+            break;
+        }
+        case 'f': {
+            if (length == 8 && str.equalsSameLength("function", 1)) {
+                return scannerInstance->escargotContext->staticStrings().function.string();
+            }
+            break;
+        }
+        case 'u': {
+            if (length == 9 && str.equalsSameLength("undefined", 1)) {
+                return scannerInstance->escargotContext->staticStrings().undefined.string();
+            }
+            break;
+        }
+        default: {
+            return new StringView(scannerInstance->sourceAsNormalView, start, end);
+        }
+        }
+    }
+
+    return new StringView(scannerInstance->sourceAsNormalView, start, end);
 }
 
 ParserStringView Scanner::ScannerResult::valueStringLiteral(Scanner* scannerInstance)
@@ -663,7 +693,7 @@ void Scanner::ScannerResult::constructStringLiteral(Scanner* scannerInstance)
 
     String* newStr;
     if (isEveryCharLatin1) {
-        newStr = new Latin1String(stringUTF16.data(), stringUTF16.length());
+        newStr = String::fromLatin1(stringUTF16.data(), stringUTF16.length());
     } else {
         newStr = new UTF16String(stringUTF16.data(), stringUTF16.length());
     }
@@ -1894,7 +1924,7 @@ String* Scanner::scanRegExpFlags()
     }
 
     if (isAllASCII(flags.data(), flags.length())) {
-        return new ASCIIString(flags.data(), flags.length());
+        return String::fromLatin1(flags.data(), flags.length());
     }
 
     return new UTF16String(flags.data(), flags.length());
index a29e1ad08a3d2096e93eaba845582205004fb1ec..10c7eaa419bf3e9dd17258cad4bc82742e4db340 100644 (file)
@@ -442,6 +442,7 @@ public:
             , lineStart(0)
             , start(0)
             , end(0)
+            , valueKeywordKind(NotKeyword)
         {
         }
 
index 253cc51fe7df3518aa930de8977c2152349e42f4..742e6a1251e51e41ba8eaa75ca58432c5a88c5ad 100644 (file)
@@ -73,15 +73,15 @@ public:
         }
 
         const auto& data = m_bufferData;
-        if (data.has8BitContent) {
+        if (LIKELY(data.has8BitContent)) {
             for (size_t i = 0; i < srcLen; i++) {
-                if (src[i] != ((const LChar*)data.buffer)[i]) {
+                if (src[i] != data.bufferAs8Bit[i]) {
                     return false;
                 }
             }
         } else {
             for (size_t i = 0; i < srcLen; i++) {
-                if (src[i] != ((const char16_t*)data.buffer)[i]) {
+                if (src[i] != data.bufferAs16Bit[i]) {
                     return false;
                 }
             }
@@ -90,6 +90,18 @@ public:
         return true;
     }
 
+    ALWAYS_INLINE bool equalsSameLength(const char* str, size_t compareStartAt = 0) const
+    {
+        ASSERT(strlen(str) == length());
+
+        const auto& data = m_bufferData;
+        if (LIKELY(data.has8BitContent)) {
+            return memcmp(data.bufferAs8Bit + compareStartAt, str + compareStartAt, data.length - compareStartAt) == 0;
+        } else {
+            return equals16Bit(data.bufferAs16Bit + compareStartAt, str + compareStartAt, data.length - compareStartAt);
+        }
+    }
+
     template <const size_t srcLen>
     bool operator!=(const char (&src)[srcLen]) const
     {
@@ -103,7 +115,7 @@ public:
         ret.resizeWithUninitializedValues(len);
 
         for (size_t i = 0; i < len; i++) {
-            ret[i] = charAt(i);
+            ret[i] = bufferedCharAt(i);
         }
 
         return ret;
@@ -122,13 +134,13 @@ public:
     virtual const LChar* characters8() const override
     {
         ASSERT(has8BitContent());
-        return (LChar*)m_bufferData.buffer;
+        return reinterpret_cast<const LChar*>(m_bufferData.bufferAs8Bit);
     }
 
     virtual const char16_t* characters16() const override
     {
         ASSERT(!has8BitContent());
-        return (const char16_t*)m_bufferData.buffer;
+        return reinterpret_cast<const char16_t*>(m_bufferData.bufferAs16Bit);
     }
 
     virtual bool isStringView() override
@@ -138,10 +150,10 @@ public:
 
     char16_t bufferedCharAt(const size_t idx) const
     {
-        if (m_bufferData.has8BitContent) {
-            return ((const LChar*)m_bufferData.buffer)[idx];
+        if (LIKELY(m_bufferData.has8BitContent)) {
+            return m_bufferData.bufferAs8Bit[idx];
         } else {
-            return ((const char16_t*)m_bufferData.buffer)[idx];
+            return m_bufferData.bufferAs16Bit[idx];
         }
     }
 
@@ -154,11 +166,23 @@ protected:
         m_bufferData.has8BitContent = srcData.has8BitContent;
         m_bufferData.length = end - start;
         if (srcData.has8BitContent) {
-            m_bufferData.buffer = ((LChar*)srcData.buffer) + start;
+            m_bufferData.bufferAs8Bit = srcData.bufferAs8Bit + start;
         } else {
-            m_bufferData.buffer = ((char16_t*)srcData.buffer) + start;
+            m_bufferData.bufferAs16Bit = srcData.bufferAs16Bit + start;
         }
     }
+
+    bool equals16Bit(const char16_t* c1, const char* c2, size_t len) const
+    {
+        while (len > 0) {
+            if (*c1++ != *c2++) {
+                return false;
+            }
+            len--;
+        }
+
+        return true;
+    }
 };
 
 } // namespace Escargot
index f165bf2cdd517049f76769f014bab18a62a0aa8c..a78741a712f8541a41b0d611b40f852a0b1d9c43 100644 (file)
@@ -57,7 +57,7 @@ void* Script::operator new(size_t size)
 bool Script::isExecuted()
 {
     if (isModule()) {
-        return m_moduleData->m_status != ModuleData::ModuleStatus::Unlinked;
+        return m_moduleData->m_status >= ModuleData::ModuleStatus::Evaluating;
     }
     return m_topCodeBlock->byteCodeBlock() == nullptr;
 }
@@ -107,6 +107,32 @@ String* Script::moduleRequest(size_t i)
     return m_moduleData->m_requestedModules[i];
 }
 
+Value Script::moduleInstantiate(ExecutionState& state)
+{
+    ASSERT(isModule());
+    if (!moduleData()->m_didCallLoadedCallback) {
+        Global::platform()->didLoadModule(context(), nullptr, this);
+        moduleData()->m_didCallLoadedCallback = true;
+    }
+
+    auto result = moduleLinking(state);
+    if (result.gotException) {
+        throw result.value;
+    }
+    return result.value;
+}
+
+Value Script::moduleEvaluate(ExecutionState& state)
+{
+    ASSERT(isModule());
+
+    auto result = moduleEvaluation(state);
+    if (result.gotException) {
+        throw result.value;
+    }
+    return result.value;
+}
+
 AtomicStringVector Script::exportedNames(ExecutionState& state, std::vector<Script*>& exportStarSet)
 {
     // Let module be this Source Text Module Record.
@@ -334,7 +360,7 @@ Value Script::execute(ExecutionState& state, bool isExecuteOnEvalFunction, bool
         if (result.gotException) {
             throw result.value;
         }
-        result = moduleEvaluate(state);
+        result = moduleEvaluation(state);
         if (result.gotException) {
             throw result.value;
         }
@@ -688,16 +714,7 @@ Script::ModuleExecutionResult Script::innerModuleLinking(ExecutionState& state,
         // Assert: requiredModule.[[Status]] is either "linking", "linked", or "evaluated".
         ASSERT(requiredModule->moduleData()->m_status == ModuleData::Linking || requiredModule->moduleData()->m_status == ModuleData::Linked || requiredModule->moduleData()->m_status == ModuleData::Evaluated);
         // Assert: requiredModule.[[Status]] is "linking" if and only if requiredModule is in stack.
-        if (requiredModule->moduleData()->m_status == ModuleData::Linking) {
-            bool onStack = false;
-            for (size_t j = 0; j < stack.size(); j++) {
-                if (stack[j] == requiredModule) {
-                    onStack = true;
-                    break;
-                }
-            }
-            ASSERT(onStack);
-        }
+        // this assert is removed. because some users want to instantiate their module on onLoadModule
 
         // If requiredModule.[[Status]] is "linking", then
         if (requiredModule->moduleData()->m_status == ModuleData::Linking) {
@@ -738,7 +755,7 @@ Script::ModuleExecutionResult Script::innerModuleLinking(ExecutionState& state,
     return Script::ModuleExecutionResult(false, Value(index));
 }
 
-Script::ModuleExecutionResult Script::moduleEvaluate(ExecutionState& state)
+Script::ModuleExecutionResult Script::moduleEvaluation(ExecutionState& state)
 {
     // + https://tc39.es/proposal-top-level-await/#sec-moduleevaluation
 
index a8a3598b8685d6e7d0d52abe31be68eb92372ace..9534044bf2ab98e900c69466bc023513c5ce7887 100644 (file)
@@ -153,6 +153,8 @@ public:
         , m_topCodeBlock(nullptr)
         , m_moduleData(moduleData)
     {
+        // srcName and sourceCode should have valid string (empty string for no name)
+        ASSERT(!!srcName && !!sourceCode);
     }
 
     void* operator new(size_t size);
@@ -189,6 +191,9 @@ public:
     size_t moduleRequestsLength();
     String* moduleRequest(size_t i);
 
+    Value moduleInstantiate(ExecutionState& state);
+    Value moduleEvaluate(ExecutionState& state);
+
     bool isExecuted();
     bool wasThereErrorOnModuleEvaluation();
     Value moduleEvaluationError();
@@ -253,7 +258,7 @@ private:
     ModuleExecutionResult innerModuleLinking(ExecutionState& state, std::vector<Script*>& stack, uint32_t index);
 
     // https://tc39.es/ecma262/#sec-moduleevaluation
-    ModuleExecutionResult moduleEvaluate(ExecutionState& state);
+    ModuleExecutionResult moduleEvaluation(ExecutionState& state);
 
     // https://tc39.es/ecma262/#sec-innermoduleevaluation
     ModuleExecutionResult innerModuleEvaluation(ExecutionState& state, std::vector<Script*>& stack, uint32_t index);
index 5bc4eb8a0671e7f1f9b8aa0cd31f3a046dca3681..746531bc2faf230b34fc5ffbafba67bb188491fc 100644 (file)
@@ -418,7 +418,7 @@ ScriptParser::InitializeScriptResult ScriptParser::initializeScript(String* sour
 {
     ASSERT(m_context->astAllocator().isInitialized());
 #ifdef ESCARGOT_DEBUGGER
-    if (LIKELY(needByteCodeGeneration) && m_context->debugger() != nullptr && m_context->debugger()->enabled()) {
+    if (LIKELY(needByteCodeGeneration) && m_context->debuggerEnabled() && !m_context->debugger()->skipSourceCode(srcName)) {
         return initializeScriptWithDebugger(source, srcName, parentCodeBlock, isModule, isEvalMode, isEvalCodeInFunction, inWithOperation, strictFromOutside, allowSuperCall, allowSuperProperty, allowNewTarget);
     }
 #endif /* ESCARGOT_DEBUGGER */
@@ -504,11 +504,9 @@ void ScriptParser::generateFunctionByteCode(ExecutionState& state, InterpretedCo
 {
 #ifdef ESCARGOT_DEBUGGER
     // When the debugger is enabled, lazy compilation is disabled, so the functions are compiled
-    // during parsing, and this function is never called. However, implicit class constructors
-    // has no source code, and still compiled later. These functions are ignored by the debugger.
-    if (m_context->debugger() != nullptr) {
-        m_context->debugger()->setParsingEnabled(false);
-    }
+    // during parsing, and this function is never called. However, implicit class constructors and dynamically generated functions
+    // are still compiled later. These functions are ignored by the debugger.
+    ASSERT(!m_context->debuggerEnabled() || !m_context->inDebuggingCodeMode());
 #endif /* ESCARGOT_DEBUGGER */
 
     GC_disable();
@@ -535,12 +533,6 @@ void ScriptParser::generateFunctionByteCode(ExecutionState& state, InterpretedCo
     // reset ASTAllocator
     m_context->astAllocator().reset();
     GC_enable();
-
-#ifdef ESCARGOT_DEBUGGER
-    if (m_context->debugger() != nullptr) {
-        m_context->debugger()->setParsingEnabled(true);
-    }
-#endif /* ESCARGOT_DEBUGGER */
 }
 
 #ifdef ESCARGOT_DEBUGGER
@@ -561,18 +553,6 @@ void ScriptParser::recursivelyGenerateChildrenByteCode(InterpretedCodeBlock* par
         FunctionNode* functionNode = esprima::parseSingleFunction(m_context, codeBlock, SIZE_MAX);
         codeBlock->m_byteCodeBlock = ByteCodeGenerator::generateByteCode(m_context, codeBlock, functionNode);
 
-        if (m_context->debugger() != nullptr && m_context->debugger()->enabled()) {
-            String* functionName = codeBlock->functionName().string();
-            if (functionName->length() > 0) {
-                StringView* functionNameView = new StringView(functionName);
-                m_context->debugger()->sendString(Debugger::ESCARGOT_MESSAGE_FUNCTION_NAME_8BIT, functionNameView);
-            }
-
-            if (m_context->debugger()->enabled()) {
-                m_context->debugger()->sendFunctionInfo(codeBlock);
-            }
-        }
-
         m_context->astAllocator().reset();
     }
 
@@ -584,6 +564,9 @@ void ScriptParser::recursivelyGenerateChildrenByteCode(InterpretedCodeBlock* par
 ScriptParser::InitializeScriptResult ScriptParser::initializeScriptWithDebugger(String* source, String* srcName, InterpretedCodeBlock* parentCodeBlock, bool isModule, bool isEvalMode, bool isEvalCodeInFunction, bool inWithOperation, bool strictFromOutside, bool allowSuperCall, bool allowSuperProperty, bool allowNewTarget)
 {
     GC_disable();
+    if (m_context->debuggerEnabled()) {
+        m_context->debugger()->setInDebuggingCodeMode(true);
+    }
 
     bool inWith = (parentCodeBlock ? parentCodeBlock->inWith() : false) || inWithOperation;
     bool allowSC = (parentCodeBlock ? parentCodeBlock->allowSuperCall() : false) || allowSuperCall;
@@ -601,14 +584,6 @@ ScriptParser::InitializeScriptResult ScriptParser::initializeScriptWithDebugger(
 
         programNode = esprima::parseProgram(m_context, sourceView, outerClassInfo, isModule, strictFromOutside, inWith, SIZE_MAX, allowSC, allowSP, allowNewTarget, allowArguments);
 
-        if (m_context->debugger() != nullptr && m_context->debugger()->enabled()) {
-            m_context->debugger()->sendString(Debugger::ESCARGOT_MESSAGE_SOURCE_8BIT, source);
-
-            if (m_context->debugger()->enabled()) {
-                m_context->debugger()->sendString(Debugger::ESCARGOT_MESSAGE_FILE_NAME_8BIT, srcName);
-            }
-        }
-
         script = new Script(srcName, source, programNode->moduleData(), !parentCodeBlock);
         if (parentCodeBlock) {
             programNode->scopeContext()->m_hasEval = parentCodeBlock->hasEval();
@@ -629,10 +604,10 @@ ScriptParser::InitializeScriptResult ScriptParser::initializeScriptWithDebugger(
         // reset ASTAllocator
         m_context->astAllocator().reset();
 
-        if (m_context->debugger() != nullptr && m_context->debugger()->enabled()) {
-            m_context->debugger()->sendType(Debugger::ESCARGOT_MESSAGE_PARSE_ERROR);
-            StringView* errorView = new StringView(orgError->message, 0, orgError->message->length());
-            m_context->debugger()->sendString(Debugger::ESCARGOT_MESSAGE_STRING_8BIT, errorView);
+        if (m_context->debuggerEnabled()) {
+            m_context->debugger()->parseCompleted(source, srcName, orgError->message);
+            m_context->debugger()->clearParsingData();
+            m_context->debugger()->setInDebuggingCodeMode(false);
         }
 
         GC_enable();
@@ -658,19 +633,16 @@ ScriptParser::InitializeScriptResult ScriptParser::initializeScriptWithDebugger(
     // Generate ByteCode
     topCodeBlock->m_byteCodeBlock = ByteCodeGenerator::generateByteCode(m_context, topCodeBlock, programNode, inWith);
 
-    if (m_context->debugger() != nullptr && m_context->debugger()->enabled()) {
-        m_context->debugger()->sendFunctionInfo(topCodeBlock);
-    }
-
     // reset ASTAllocator
     m_context->astAllocator().reset();
 
-    if (m_context->debugger() != nullptr && m_context->debugger()->enabled()) {
+    Debugger* debugger = m_context->debugger();
+    if (debugger != nullptr) {
         recursivelyGenerateChildrenByteCode(topCodeBlock);
-        m_context->debugger()->sendType(Debugger::ESCARGOT_MESSAGE_PARSE_DONE);
-        if (m_context->debugger()->pendingWait()) {
-            m_context->debugger()->waitForResolvingPendingBreakpoints();
-        }
+
+        debugger->parseCompleted(source, srcName);
+        debugger->clearParsingData();
+        debugger->setInDebuggingCodeMode(false);
     }
 
     GC_enable();
index 5da9a89d932fc94ed4f5793ea659bad5ec09e186..61a66a56246ccb1abb8f7efe95417a5d26e709d8 100644 (file)
@@ -77,7 +77,7 @@ public:
         if (blk->usesArgumentsObject() && !codeBlock->m_codeBlock->isArrowFunctionExpression()) {
             codeBlock->pushCode(EnsureArgumentsObject(ByteCodeLOC(m_loc.index)), context, this);
         }
-        codeBlock->pushCode(CreateFunction(ByteCodeLOC(m_loc.index), dstIndex, context->m_classInfo.m_thisExpressionIndex, blk), context, this);
+        codeBlock->pushCode(CreateFunction(ByteCodeLOC(m_loc.index), dstIndex, REGULAR_REGISTER_LIMIT, blk), context, this);
     }
 
 private:
index 4e141ade45b387e4d3e57537505df599210482f7..7fe50f7ba3f300cdbe2d8a8a56bc96e60f8680c8 100644 (file)
@@ -158,7 +158,7 @@ public:
             ByteCodeRegisterIndex startIndex = args.first;
             context->giveUpRegister();
             codeBlock->pushCode(CallFunctionComplexCase(ByteCodeLOC(m_loc.index), CallFunctionComplexCase::MayBuiltinEval, context->m_isWithScope, args.second,
-                                                        isOptional, context->m_classInfo.m_thisExpressionIndex, evalIndex, startIndex, dstRegister, m_arguments.size()),
+                                                        isOptional, REGULAR_REGISTER_LIMIT, evalIndex, startIndex, dstRegister, m_arguments.size()),
                                 context, this);
             return;
         }
index b3dd6fc2df123b1f9e4437a62da9a7fd693a784a..c9c4603949eaeddb41291670aab2d7d2f9c3f036 100644 (file)
@@ -254,10 +254,10 @@ public:
                     codeBlock->pushCode(ObjectDefineOwnPropertyOperation(ByteCodeLOC(m_loc.index), destIndex, propertyIndex, valueIndex, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent), true), context, this);
                 }
             } else if (p->kind() == ClassElementNode::Kind::Get) {
-                codeBlock->pushCode(ObjectDefineGetterSetter(ByteCodeLOC(m_loc.index), destIndex, propertyIndex, valueIndex, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::NonEnumerablePresent), true), context, this);
+                codeBlock->pushCode(ObjectDefineGetterSetter(ByteCodeLOC(m_loc.index), destIndex, propertyIndex, valueIndex, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::NonEnumerablePresent), true, hasKeyName), context, this);
             } else {
                 ASSERT(p->kind() == ClassElementNode::Kind::Set);
-                codeBlock->pushCode(ObjectDefineGetterSetter(ByteCodeLOC(m_loc.index), destIndex, propertyIndex, valueIndex, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::NonEnumerablePresent), false), context, this);
+                codeBlock->pushCode(ObjectDefineGetterSetter(ByteCodeLOC(m_loc.index), destIndex, propertyIndex, valueIndex, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::NonEnumerablePresent), false, hasKeyName), context, this);
             }
 
             if (propertyIndex != SIZE_MAX) {
index 4db1cf39b38020e48ab9cfb11f631dff1f4faf83..9b619777639d08980f2d93d26bb2147a9683335b 100644 (file)
@@ -112,8 +112,11 @@ public:
                 newContext.giveUpRegister();
             }
 
+            // we should increase this count here.
+            // because the block was created after newContext creation
             if (bi->m_shouldAllocateEnvironment) {
                 newContext.m_complexJumpContinueIgnoreCount++;
+                newContext.m_complexJumpBreakIgnoreCount++;
             }
         }
 
index b109b08521befb2f4df95a66393dac99aa9b75fa..0273784176c80ca1a0f7a384a0b42bd38beaec07 100644 (file)
@@ -44,7 +44,7 @@ public:
             size_t homeObjectIndex = blk->isClassStaticMethod() ? context->m_classInfo.m_constructorIndex : context->m_classInfo.m_prototypeIndex;
             codeBlock->pushCode(CreateFunction(ByteCodeLOC(m_loc.index), dstIndex, homeObjectIndex, blk), context, this);
         } else {
-            codeBlock->pushCode(CreateFunction(ByteCodeLOC(m_loc.index), dstIndex, context->m_classInfo.m_thisExpressionIndex, blk), context, this);
+            codeBlock->pushCode(CreateFunction(ByteCodeLOC(m_loc.index), dstIndex, REGULAR_REGISTER_LIMIT, blk), context, this);
         }
 
         codeBlock->m_shouldClearStack = true;
index a93c04fcf8c892fb2b240f99d303e148317276a7..b92cf1961c78e462b620ac8904901967bd757d9f 100644 (file)
@@ -75,10 +75,10 @@ public:
                         codeBlock->pushCode(ObjectDefineOwnPropertyOperation(ByteCodeLOC(m_loc.index), objIndex, propertyIndex, valueIndex, ObjectPropertyDescriptor::AllPresent, hasFunctionOnRightSide | hasClassOnRightSide), context, this);
                     }
                 } else if (p->kind() == PropertyNode::Kind::Get) {
-                    codeBlock->pushCode(ObjectDefineGetterSetter(ByteCodeLOC(m_loc.index), objIndex, propertyIndex, valueIndex, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::EnumerablePresent), true), context, this);
+                    codeBlock->pushCode(ObjectDefineGetterSetter(ByteCodeLOC(m_loc.index), objIndex, propertyIndex, valueIndex, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::EnumerablePresent), true, hasKeyName), context, this);
                 } else {
                     ASSERT(p->kind() == PropertyNode::Kind::Set);
-                    codeBlock->pushCode(ObjectDefineGetterSetter(ByteCodeLOC(m_loc.index), objIndex, propertyIndex, valueIndex, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::EnumerablePresent), false), context, this);
+                    codeBlock->pushCode(ObjectDefineGetterSetter(ByteCodeLOC(m_loc.index), objIndex, propertyIndex, valueIndex, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent | ObjectPropertyDescriptor::EnumerablePresent), false, hasKeyName), context, this);
                 }
 
                 if (!hasKeyName) {
index 660f8182c4e9a02f59cf66064d61730a58fecffa..032b4901e2dfa45ffbfc3130d470b967f06d6a91 100644 (file)
@@ -53,12 +53,9 @@ public:
         codeBlock->finalizeLexicalBlock(context, blockContext);
 
 #ifdef ESCARGOT_DEBUGGER
-        if (context->m_breakpointContext->m_breakpointLocations.size() == 0) {
-            if (context->m_isEvalCode) {
-                context->insertBreakpointAt(1, this);
-            } else {
-                insertBreakpoint(context);
-            }
+        if (context->m_breakpointContext->m_breakpointLocations->breakpointLocations.size() == 0) {
+            // add a break point for empty global code (including eval code)
+            insertBreakpoint(context);
         }
 #endif /* ESCARGOT_DEBUGGER */
         codeBlock->pushCode(End(ByteCodeLOC(SIZE_MAX), 0), context, this);
index be34e8c34d11facd7382f769576fc5d8444feaae..30c4e8d689d961c094208f0dd268e92c4dac14bc 100644 (file)
@@ -36,22 +36,14 @@ public:
     virtual void generateStatementByteCode(ByteCodeBlock* codeBlock, ByteCodeGenerateContext* context) override
     {
 #ifdef ESCARGOT_DEBUGGER
-        if (context->m_breakpointContext->m_breakpointLocations.size() == 0 && context->m_breakpointContext->m_parsingEnabled) {
-            ASSERT(context->m_breakpointContext->m_lastBreakpointLineOffset == 0);
-            ASSERT(context->m_breakpointContext->m_breakpointLocations.size() == 0);
-
+        if (codeBlock->codeBlock()->markDebugging()) {
             InterpretedCodeBlock* interpretedCodeBlock = context->m_codeBlock;
-
             if (interpretedCodeBlock->hasRareData() && interpretedCodeBlock->rareData()->m_debuggerLineStart != SIZE_MAX) {
                 ASSERT(interpretedCodeBlock->isOneExpressionOnlyVirtualArrowFunctionExpression());
                 context->insertBreakpointAt(interpretedCodeBlock->rareData()->m_debuggerLineStart, this);
             } else {
-                ExtendedNodeLOC sourceElementStart = context->m_codeBlock->functionStart();
-                size_t lastLineOffset = context->calculateBreakpointLineOffset(m_loc.index, sourceElementStart);
-                context->insertBreakpointAt(lastLineOffset + sourceElementStart.line, this);
+                insertBreakpoint(context);
             }
-        } else {
-            insertBreakpoint(context);
         }
 #endif /* ESCARGOT_DEBUGGER */
 
index 2c03e4de94bf0057f25ac24b5d4f88ece5129d1c..937db01519f49717944e86421fc2fee32628d9ac 100644 (file)
@@ -34,7 +34,7 @@ public:
     virtual ASTNodeType type() override { return ASTNodeType::ThisExpression; }
     virtual ByteCodeRegisterIndex getRegister(ByteCodeBlock* codeBlock, ByteCodeGenerateContext* context) override
     {
-        if (UNLIKELY(context->m_classInfo.m_thisExpressionIndex != REGULAR_REGISTER_LIMIT || codeBlock->m_codeBlock->isClassConstructor())) {
+        if (UNLIKELY(codeBlock->m_codeBlock->isClassConstructor())) {
             return context->getRegister();
         }
         context->pushRegister(REGULAR_REGISTER_LIMIT);
@@ -43,10 +43,6 @@ public:
 
     virtual void generateExpressionByteCode(ByteCodeBlock* codeBlock, ByteCodeGenerateContext* context, ByteCodeRegisterIndex dstRegister) override
     {
-        if (UNLIKELY(context->m_classInfo.m_thisExpressionIndex != REGULAR_REGISTER_LIMIT)) {
-            codeBlock->pushCode(Move(ByteCodeLOC(m_loc.index), context->m_classInfo.m_thisExpressionIndex, dstRegister), context, this);
-            return;
-        }
         if (UNLIKELY(codeBlock->m_codeBlock->needsToLoadThisBindingFromEnvironment())) {
             codeBlock->pushCode(LoadThisBinding(ByteCodeLOC(m_loc.index), dstRegister), context, this);
             return;
index 3f55c01d80e42ed3b9e0832be325aa27a821b61c..6d0d3561bfeab0ff48f83e9d2e7b4562bf71471a 100644 (file)
@@ -312,7 +312,7 @@ public:
         this->currentScopeContext = ctx;
         this->lastUsingName = AtomicString();
 #ifdef ESCARGOT_DEBUGGER
-        if (this->escargotContext->debugger() && this->escargotContext->debugger()->enabled()) {
+        if (this->escargotContext->debuggerEnabled()) {
             ctx->m_hasEval = true;
         }
 #endif /* ESCARGOT_DEBUGGER */
index 7bfa1a784229118677d32ddb9c26d6f6b3510106..029743f0a331b2494bafb48d3f0d2c1561772f52 100644 (file)
@@ -47,24 +47,6 @@ static void ArgumentsObjectNativeSetter(ExecutionState& state, Object* self, con
     targetRecord->setHeapValueByIndex(state, info.m_indexForIndexedStorage, setterInputData);
 }
 
-void* ArgumentsObject::operator new(size_t size)
-{
-    static MAY_THREAD_LOCAL bool typeInited = false;
-    static MAY_THREAD_LOCAL GC_descr descr;
-    if (!typeInited) {
-        GC_word obj_bitmap[GC_BITMAP_SIZE(ArgumentsObject)] = { 0 };
-        Object::fillGCDescriptor(obj_bitmap);
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ArgumentsObject, m_targetRecord));
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ArgumentsObject, m_sourceFunctionObject));
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ArgumentsObject, m_parameterMap));
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ArgumentsObject, m_modifiedArguments));
-        descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(ArgumentsObject));
-        typeInited = true;
-    }
-    return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
-}
-
-
 ArgumentsObject::ArgumentsObject(ExecutionState& state, Object* proto, ScriptFunctionObject* sourceFunctionObject, size_t argc, Value* argv, FunctionEnvironmentRecord* environmentRecordWillArgumentsObjectBeLocatedIn, bool isMapped)
     : Object(state, proto, ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 3)
     , m_targetRecord(environmentRecordWillArgumentsObjectBeLocatedIn->isFunctionEnvironmentRecordOnStack() ? nullptr : environmentRecordWillArgumentsObjectBeLocatedIn)
index fa00151e292332c4e68221eaa8086426960282d3..635bde6776d7132ae46a81eb3ad37ef6e47624b5 100644 (file)
@@ -42,12 +42,12 @@ public:
     virtual bool set(ExecutionState& state, const ObjectPropertyName& propertyName, const Value& v, const Value& receiver) override;
     virtual bool setIndexedProperty(ExecutionState& state, const Value& property, const Value& value, const Value& receiver) override;
 
-    virtual bool isInlineCacheable() override
+    virtual bool isArgumentsObject() const override
     {
-        return false;
+        return true;
     }
 
-    virtual bool isArgumentsObject() const override
+    virtual bool hasOwnEnumeration() const override
     {
         return true;
     }
@@ -57,9 +57,6 @@ public:
         return m_sourceFunctionObject;
     }
 
-    void* operator new(size_t size);
-    void* operator new[](size_t size) = delete;
-
 private:
     FunctionEnvironmentRecord* m_targetRecord;
     ScriptFunctionObject* m_sourceFunctionObject;
diff --git a/lwnode/code/escargotshim/deps/escargot/src/runtime/ArrayBuffer.cpp b/lwnode/code/escargotshim/deps/escargot/src/runtime/ArrayBuffer.cpp
deleted file mode 100644 (file)
index 8795b90..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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/VMInstance.h"
-#include "runtime/BackingStore.h"
-#include "runtime/ArrayBuffer.h"
-#include "runtime/TypedArrayInlines.h"
-#include "runtime/ArrayBufferObject.h"
-#include "runtime/SharedArrayBufferObject.h"
-
-namespace Escargot {
-
-unsigned TypedArrayHelper::elementSizeTable[11] = { 1, 2, 4, 1, 2, 4, 1, 4, 8, 8, 8 };
-
-ArrayBuffer::ArrayBuffer(ExecutionState& state, Object* proto)
-    : Object(state, proto, ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER)
-{
-}
-
-// $24.1.1.6
-Value ArrayBuffer::getValueFromBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, bool isLittleEndian)
-{
-    // If isLittleEndian is not present, set isLittleEndian to either true or false.
-    ASSERT(byteLength());
-    size_t elemSize = TypedArrayHelper::elementSize(type);
-    ASSERT(byteindex + elemSize <= byteLength());
-    uint8_t* rawStart = data() + byteindex;
-    if (LIKELY(isLittleEndian)) {
-        return TypedArrayHelper::rawBytesToNumber(state, type, rawStart);
-    } else {
-        uint8_t* rawBytes = ALLOCA(8, uint8_t, state);
-        for (size_t i = 0; i < elemSize; i++) {
-            rawBytes[elemSize - i - 1] = rawStart[i];
-        }
-        return TypedArrayHelper::rawBytesToNumber(state, type, rawBytes);
-    }
-}
-
-// $24.1.1.8
-void ArrayBuffer::setValueInBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, const Value& val, bool isLittleEndian)
-{
-    // If isLittleEndian is not present, set isLittleEndian to either true or false.
-    ASSERT(byteLength());
-    size_t elemSize = TypedArrayHelper::elementSize(type);
-    ASSERT(byteindex + elemSize <= byteLength());
-    uint8_t* rawStart = data() + byteindex;
-    uint8_t* rawBytes = ALLOCA(8, uint8_t, state);
-    TypedArrayHelper::numberToRawBytes(state, type, val, rawBytes);
-    if (LIKELY(isLittleEndian)) {
-        memcpy(rawStart, rawBytes, elemSize);
-    } else {
-        for (size_t i = 0; i < elemSize; i++) {
-            rawStart[i] = rawBytes[elemSize - i - 1];
-        }
-    }
-}
-} // namespace Escargot
index adaf3ec0733f974de39281f9a20a44a9e2123528..cce5da0afb65f0db7fd44c9feeae3258d235c03c 100644 (file)
@@ -40,18 +40,25 @@ enum class TypedArrayType : unsigned {
 };
 
 class ArrayBuffer : public Object {
-    friend void initializeCustomAllocators();
-
 public:
     static const uint64_t maxArrayBufferSize = 210000000;
 
-    explicit ArrayBuffer(ExecutionState& state, Object* proto);
+    explicit ArrayBuffer(ExecutionState& state, Object* proto)
+        : Object(state, proto, ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER)
+    {
+    }
 
     virtual bool isArrayBuffer() const override
     {
         return true;
     }
 
+    // pure virtual function to ensure that ArrayBuffer instance never created
+    // all these pure virtual functions guarantee thread-safe operations
+    virtual void fillData(const uint8_t* newData, size_t length) = 0;
+    virtual Value getValueFromBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, bool isLittleEndian = true) = 0;
+    virtual void setValueInBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, const Value& val, bool isLittleEndian = true) = 0;
+
     Optional<BackingStore*> backingStore()
     {
         return m_backingStore;
@@ -79,12 +86,6 @@ public:
         return m_backingStore->maxByteLength();
     }
 
-    // $24.1.1.6
-    Value getValueFromBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, bool isLittleEndian = true);
-
-    // $24.1.1.8
-    void setValueInBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, const Value& val, bool isLittleEndian = true);
-
     ALWAYS_INLINE bool isDetachedBuffer()
     {
         return (data() == nullptr);
@@ -105,12 +106,6 @@ public:
         }
     }
 
-    void fillData(const uint8_t* newData, size_t length)
-    {
-        ASSERT(!isDetachedBuffer());
-        memcpy(data(), newData, length);
-    }
-
     void* operator new(size_t size) = delete;
     void* operator new[](size_t size) = delete;
 
index 8c0dbe1df84e2ca7cf32033e0b08a39dd5f10f47..338d79ee9a56fb8c06fc8f9774455eb593df8465 100644 (file)
@@ -25,6 +25,8 @@
 
 namespace Escargot {
 
+unsigned TypedArrayHelper::elementSizeTable[11] = { 1, 2, 4, 1, 2, 4, 1, 4, 8, 8, 8 };
+
 ArrayBufferObject* ArrayBufferObject::allocateArrayBuffer(ExecutionState& state, Object* constructor, uint64_t byteLength, Optional<uint64_t> maxByteLength)
 {
     // https://www.ecma-international.org/ecma-262/10.0/#sec-allocatearraybuffer
@@ -149,4 +151,40 @@ void* ArrayBufferObject::operator new(size_t size)
     return CustomAllocator<ArrayBufferObject>().allocate(1);
 #endif
 }
+
+Value ArrayBufferObject::getValueFromBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, bool isLittleEndian)
+{
+    // If isLittleEndian is not present, set isLittleEndian to either true or false.
+    ASSERT(byteLength());
+    size_t elemSize = TypedArrayHelper::elementSize(type);
+    ASSERT(byteindex + elemSize <= byteLength());
+    uint8_t* rawStart = data() + byteindex;
+    if (LIKELY(isLittleEndian)) {
+        return TypedArrayHelper::rawBytesToNumber(state, type, rawStart);
+    } else {
+        uint8_t* rawBytes = ALLOCA(8, uint8_t, state);
+        for (size_t i = 0; i < elemSize; i++) {
+            rawBytes[elemSize - i - 1] = rawStart[i];
+        }
+        return TypedArrayHelper::rawBytesToNumber(state, type, rawBytes);
+    }
+}
+
+void ArrayBufferObject::setValueInBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, const Value& val, bool isLittleEndian)
+{
+    // If isLittleEndian is not present, set isLittleEndian to either true or false.
+    ASSERT(byteLength());
+    size_t elemSize = TypedArrayHelper::elementSize(type);
+    ASSERT(byteindex + elemSize <= byteLength());
+    uint8_t* rawStart = data() + byteindex;
+    uint8_t* rawBytes = ALLOCA(8, uint8_t, state);
+    TypedArrayHelper::numberToRawBytes(state, type, val, rawBytes);
+    if (LIKELY(isLittleEndian)) {
+        memcpy(rawStart, rawBytes, elemSize);
+    } else {
+        for (size_t i = 0; i < elemSize; i++) {
+            rawStart[i] = rawBytes[elemSize - i - 1];
+        }
+    }
+}
 } // namespace Escargot
index b34b08a03f8d1c85cc8efdd1e0290130082b829b..c1fb0a9d2bb135e88fd7e547fa925159ecdb9375 100644 (file)
@@ -40,11 +40,20 @@ public:
     void attachBuffer(BackingStore* backingStore);
     void detachArrayBuffer();
 
-    virtual bool isArrayBufferObject() const
+    virtual bool isArrayBufferObject() const override
     {
         return true;
     }
 
+    virtual void fillData(const uint8_t* newData, size_t length) override
+    {
+        ASSERT(!isDetachedBuffer());
+        memcpy(data(), newData, length);
+    }
+
+    virtual Value getValueFromBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, bool isLittleEndian = true) override;
+    virtual void setValueInBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, const Value& val, bool isLittleEndian = true) override;
+
     void* operator new(size_t size);
     void* operator new[](size_t size) = delete;
 };
index e72107f3c4bc28d4432339bc140999fea6568d48..9c4eff4f3b5ab8bdadf66838a054149e10eee8dc 100644 (file)
@@ -385,8 +385,9 @@ bool ArrayObject::setArrayLength(ExecutionState& state, const uint32_t newLength
                 bool hasRD = hasRareData();
 #if defined(ESCARGOT_64) && defined(ESCARGOT_USE_32BIT_IN_64BIT)
                 m_fastModeData.resizeWithUninitializedValues(oldLength, newLength);
-                for (size_t i = oldLength; i < newLength; i++) {
-                    m_fastModeData[i] = EncodedSmallValue(EncodedSmallValue::EmptyValue);
+
+                if (oldLength < newLength) {
+                    memset(static_cast<void*>(m_fastModeData.data() + oldLength), 0, sizeof(ObjectPropertyValue) * (newLength - oldLength));
                 }
 #else
                 size_t oldCapacity = hasRD ? (size_t)rareData()->m_arrayObjectFastModeBufferCapacity : 0;
@@ -394,8 +395,8 @@ bool ArrayObject::setArrayLength(ExecutionState& state, const uint32_t newLength
                     if (newLength > oldCapacity) {
                         m_fastModeData = (EncodedValue*)GC_REALLOC(m_fastModeData, sizeof(EncodedValue) * newLength);
 
-                        for (size_t i = oldLength; i < newLength; i++) {
-                            m_fastModeData[i] = EncodedValue(EncodedValue::EmptyValue);
+                        if (oldLength < newLength) {
+                            memset(static_cast<void*>(m_fastModeData + oldLength), 0, sizeof(ObjectPropertyValue) * (newLength - oldLength));
                         }
 
                     } else {
@@ -404,8 +405,8 @@ bool ArrayObject::setArrayLength(ExecutionState& state, const uint32_t newLength
                 } else {
                     m_fastModeData = (EncodedValue*)GC_REALLOC(m_fastModeData, sizeof(EncodedValue) * newLength);
 
-                    for (size_t i = oldLength; i < newLength; i++) {
-                        m_fastModeData[i] = EncodedValue(EncodedValue::EmptyValue);
+                    if (oldLength < newLength) {
+                        memset(static_cast<void*>(m_fastModeData + oldLength), 0, sizeof(ObjectPropertyValue) * (newLength - oldLength));
                     }
                 }
 #endif
@@ -432,8 +433,9 @@ bool ArrayObject::setArrayLength(ExecutionState& state, const uint32_t newLength
                     }
                     m_fastModeData.resizeWithUninitializedValues(oldLength, newCapacity);
 
-                    for (size_t i = oldLength; i < newLength; i++) {
-                        m_fastModeData[i] = EncodedSmallValue(EncodedSmallValue::EmptyValue);
+
+                    if (oldLength < newLength) {
+                        memset(static_cast<void*>(m_fastModeData.data() + oldLength), 0, sizeof(ObjectPropertyValue) * (newLength - oldLength));
                     }
 
                     rd->m_arrayObjectFastModeBufferCapacity = newCapacity;
@@ -441,9 +443,10 @@ bool ArrayObject::setArrayLength(ExecutionState& state, const uint32_t newLength
                         rd->m_arrayObjectFastModeBufferExpandCount++;
                     }
                 } else {
-                    for (size_t i = oldLength; i < newLength; i++) {
-                        m_fastModeData[i] = EncodedSmallValue(EncodedSmallValue::EmptyValue);
+                    if (oldLength < newLength) {
+                        memset(static_cast<void*>(m_fastModeData.data() + oldLength), 0, sizeof(ObjectPropertyValue) * (newLength - oldLength));
                     }
+
                     rd->m_arrayObjectFastModeBufferCapacity = oldCapacity;
                 }
 #else
@@ -462,8 +465,8 @@ bool ArrayObject::setArrayLength(ExecutionState& state, const uint32_t newLength
                     GC_FREE(m_fastModeData);
                     m_fastModeData = newFastModeData;
 
-                    for (size_t i = oldLength; i < newLength; i++) {
-                        m_fastModeData[i] = EncodedValue(EncodedValue::EmptyValue);
+                    if (oldLength < newLength) {
+                        memset(static_cast<void*>(m_fastModeData + oldLength), 0, sizeof(ObjectPropertyValue) * (newLength - oldLength));
                     }
 
                     rd->m_arrayObjectFastModeBufferCapacity = newCapacity;
@@ -471,8 +474,8 @@ bool ArrayObject::setArrayLength(ExecutionState& state, const uint32_t newLength
                         rd->m_arrayObjectFastModeBufferExpandCount++;
                     }
                 } else {
-                    for (size_t i = oldLength; i < newLength; i++) {
-                        m_fastModeData[i] = EncodedValue(EncodedValue::EmptyValue);
+                    if (oldLength < newLength) {
+                        memset(static_cast<void*>(m_fastModeData + oldLength), 0, sizeof(ObjectPropertyValue) * (newLength - oldLength));
                     }
                     rd->m_arrayObjectFastModeBufferCapacity = oldCapacity;
                 }
@@ -597,6 +600,11 @@ bool ArrayObject::preventExtensions(ExecutionState& state)
     return Object::preventExtensions(state);
 }
 
+uint64_t ArrayObject::length(ExecutionState& state)
+{
+    return arrayLength(state);
+}
+
 ArrayIteratorObject::ArrayIteratorObject(ExecutionState& state, Object* a, Type type)
     : IteratorObject(state, state.context()->globalObject()->arrayIteratorPrototype())
     , m_array(a)
index bd1c87527d431d110bdeb3d1ec50f7d26b4ebf20..15b4beb892d78fe9ffe1623e481a94adcee90226 100644 (file)
@@ -51,9 +51,9 @@ public:
 
     static ArrayObject* createSpreadArray(ExecutionState& state);
 
-    virtual bool isInlineCacheable() override
+    virtual bool hasOwnEnumeration() const override
     {
-        return false;
+        return true;
     }
 
     virtual ObjectHasPropertyResult hasProperty(ExecutionState& state, const ObjectPropertyName& P) override;
@@ -72,6 +72,7 @@ public:
     virtual ObjectHasPropertyResult hasIndexedProperty(ExecutionState& state, const Value& propertyName) override;
     virtual bool setIndexedProperty(ExecutionState& state, const Value& property, const Value& value, const Value& receiver) override;
     virtual bool preventExtensions(ExecutionState&) override;
+    virtual uint64_t length(ExecutionState& state) override;
 
     // Use custom allocator for Array object (for Badtime)
     void* operator new(size_t size);
index e6124422334b2c51b3e57444d4157135429001af..24e2b725d399760e6f3808cdfacba25de828090f 100644 (file)
@@ -73,11 +73,6 @@ AtomicString::AtomicString(AtomicStringMap* map, const char16_t* src, size_t len
     init(map, src, len);
 }
 
-AtomicString::AtomicString(ExecutionState& ec, String* name)
-{
-    init(ec.context()->m_atomicStringMap, name);
-}
-
 class ASCIIStringOnStack : public String {
 public:
     ASCIIStringOnStack(const char* str, size_t len)
@@ -127,11 +122,11 @@ void AtomicString::init(AtomicStringMap* map, const char* src, size_t len, bool
 
     auto iter = map->find(&stringForSearch);
     if (map->end() == iter) {
-        ASCIIString* newStr;
+        String* newStr;
         if (fromExternalMemory) {
             newStr = new ASCIIStringFromExternalMemory(src, len);
         } else {
-            newStr = new ASCIIString(src, len);
+            newStr = String::fromLatin1(reinterpret_cast<const LChar*>(src), len);
         }
         map->insert(newStr);
         m_string = newStr;
@@ -250,7 +245,7 @@ void AtomicString::init(AtomicStringMap* map, const char16_t* src, size_t len)
     if (map->end() == iter) {
         String* newStr;
         if (isAllASCII(src, len)) {
-            newStr = new ASCIIString(src, len);
+            newStr = String::fromLatin1(src, len);
         } else {
             newStr = new UTF16String(src, len);
         }
@@ -276,7 +271,7 @@ AtomicString::AtomicString(Context* c, const StringView& sv)
         String* newString;
         auto buffer = sv.bufferAccessData();
         if (buffer.has8BitContent) {
-            newString = new Latin1String((const char*)buffer.buffer, buffer.length);
+            newString = String::fromLatin1(reinterpret_cast<const LChar*>(buffer.buffer), buffer.length);
         } else {
             newString = new UTF16String((const char16_t*)buffer.buffer, buffer.length);
         }
@@ -290,11 +285,6 @@ AtomicString::AtomicString(Context* c, const StringView& sv)
     }
 }
 
-AtomicString::AtomicString(Context* c, String* name)
-{
-    init(c->m_atomicStringMap, name);
-}
-
 void AtomicString::initStaticString(AtomicStringMap* ec, String* name)
 {
     ASSERT(ec->find(name) == ec->end());
@@ -303,20 +293,15 @@ void AtomicString::initStaticString(AtomicStringMap* ec, String* name)
     name->m_tag = (size_t)POINTER_VALUE_STRING_TAG_IN_DATA | (size_t)m_string;
 }
 
-void AtomicString::init(AtomicStringMap* ec, String* name)
+void AtomicString::init(Context* c, String* name)
 {
-    size_t v = name->getTagInFirstDataArea();
-    if (v > POINTER_VALUE_STRING_TAG_IN_DATA) {
-        m_string = (String*)(v & ~POINTER_VALUE_STRING_TAG_IN_DATA);
-        return;
-    }
-
+    AtomicStringMap* ec = c->atomicStringMap();
     auto iter = ec->find(name);
     if (ec->end() == iter) {
         if (name->isStringView()) {
             auto buffer = name->bufferAccessData();
             if (buffer.has8BitContent) {
-                name = new Latin1String((const char*)buffer.buffer, buffer.length);
+                name = String::fromLatin1(reinterpret_cast<const LChar*>(buffer.buffer), buffer.length);
             } else {
                 name = new UTF16String((const char16_t*)buffer.buffer, buffer.length);
             }
index bc7a41608d67a2df8ff7279573f48b23ac873b20..8dea6355e25bf4a6ca600070c52794721532cc03 100644 (file)
@@ -58,7 +58,10 @@ public:
     AtomicString(AtomicStringMap* map, const char* src, size_t len, FromExternalMemoryTag);
     AtomicString(AtomicStringMap* map, const LChar* src, size_t len);
     AtomicString(AtomicStringMap* map, const char16_t* src, size_t len);
-    AtomicString(ExecutionState& ec, String* name);
+    AtomicString(ExecutionState& ec, String* name)
+        : AtomicString(ec.context(), name)
+    {
+    }
     AtomicString(ExecutionState& ec, const char16_t* src, size_t len);
     AtomicString(ExecutionState& ec, const char* src, size_t len);
     template <const size_t srcLen>
@@ -76,7 +79,16 @@ public:
     {
     }
     AtomicString(Context* c, const StringView& sv);
-    AtomicString(Context* c, String* name);
+    ALWAYS_INLINE AtomicString(Context* c, String* name)
+    {
+        // fast path
+        size_t v = name->getTagInFirstDataArea();
+        if (v > POINTER_VALUE_STRING_TAG_IN_DATA) {
+            m_string = (String*)(v & ~POINTER_VALUE_STRING_TAG_IN_DATA);
+            return;
+        }
+        init(c, name);
+    }
 
     inline String* string() const
     {
@@ -111,7 +123,7 @@ private:
     void init(AtomicStringMap* ec, const char* src, size_t len, bool fromExternalMemory = false);
     void init(AtomicStringMap* ec, const LChar* str, size_t len);
     void init(AtomicStringMap* ec, const char16_t* src, size_t len);
-    void init(AtomicStringMap* ec, String* name);
+    void init(Context* c, String* name);
     void initStaticString(AtomicStringMap* ec, String* name);
     String* m_string;
 };
index 93974fdd9497968a624e3120cbcac787edbbfc22..f235a11708e7e3761d677210bcff58af5731e7c0 100644 (file)
@@ -185,6 +185,14 @@ SharedBackingStore::SharedBackingStore(SharedDataBlockInfo* sharedInfo)
                                    nullptr, nullptr, nullptr);
 }
 
+void SharedBackingStore::resize(size_t newByteLength)
+{
+    ASSERT(m_sharedDataBlockInfo->hasValidReference());
+    ASSERT(isResizable() && newByteLength <= maxByteLength());
+
+    m_sharedDataBlockInfo->grow(newByteLength);
+}
+
 void* SharedBackingStore::operator new(size_t size)
 {
     // SharedBackingStore does not have any GC member
index 6891731c0167145d462d9ecee9cb650437331734..1cb6c5e8c3f3a63e515e5d5dc29db91f00cc6272 100644 (file)
@@ -146,6 +146,12 @@ public:
         return 0;
     }
 
+    virtual void grow(size_t newByteLength)
+    {
+        UNUSED_PARAMETER(newByteLength);
+        ASSERT_NOT_REACHED();
+    }
+
     void* data() const
     {
         ASSERT(hasValidReference());
@@ -155,7 +161,7 @@ public:
     size_t byteLength() const
     {
         ASSERT(hasValidReference());
-        return m_byteLength;
+        return m_byteLength.load();
     }
 
     void ref()
@@ -172,7 +178,8 @@ public:
 
 protected:
     void* m_data;
-    size_t m_byteLength;
+    // defined as atomic value to not to use a lock
+    std::atomic<size_t> m_byteLength;
     std::atomic<size_t> m_refCount;
 };
 
@@ -194,8 +201,15 @@ public:
         return m_maxByteLength;
     }
 
+    virtual void grow(size_t newByteLength) override
+    {
+        ASSERT(newByteLength <= m_maxByteLength);
+        m_byteLength.store(newByteLength);
+    }
+
 private:
-    size_t m_maxByteLength;
+    // defined once and never change
+    const size_t m_maxByteLength;
 };
 
 class SharedBackingStore : public BackingStore {
@@ -242,6 +256,8 @@ public:
         return m_sharedDataBlockInfo->isGrowable();
     }
 
+    virtual void resize(size_t newByteLength) override;
+
     void* operator new(size_t size);
     void* operator new[](size_t size) = delete;
 
index 80c5604c5e4a425267b90d42529bd6b3b3c6dfd2..3894541f1d1bf7aace80601e064455a0f13199b7 100644 (file)
@@ -34,17 +34,4 @@ BigIntObject::BigIntObject(ExecutionState& state, Object* proto, BigInt* value)
 {
 }
 
-void* BigIntObject::operator new(size_t size)
-{
-    static MAY_THREAD_LOCAL bool typeInited = false;
-    static MAY_THREAD_LOCAL GC_descr descr;
-    if (!typeInited) {
-        GC_word obj_bitmap[GC_BITMAP_SIZE(BigIntObject)] = { 0 };
-        Object::fillGCDescriptor(obj_bitmap);
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(BigIntObject, m_primitiveValue));
-        descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(BigIntObject));
-        typeInited = true;
-    }
-    return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
-}
 } // namespace Escargot
index d553b5f2275d38be79fac0b3e292a90ed4f5a9d4..a49314457faf3d90a65ac8ab66315af7252e851a 100644 (file)
@@ -47,9 +47,6 @@ public:
         m_primitiveValue = data;
     }
 
-    void* operator new(size_t size);
-    void* operator new[](size_t size) = delete;
-
 private:
     BigInt* m_primitiveValue;
 };
index 229c3d0f8fd2a878d8ccd2ddcd92e43623ed69d7..09a3d9d9f158775ac094f25ff847151f8dd6d583 100644 (file)
@@ -34,16 +34,4 @@ BooleanObject::BooleanObject(ExecutionState& state, Object* proto, bool value)
 {
 }
 
-void* BooleanObject::operator new(size_t size)
-{
-    static MAY_THREAD_LOCAL bool typeInited = false;
-    static MAY_THREAD_LOCAL GC_descr descr;
-    if (!typeInited) {
-        GC_word obj_bitmap[GC_BITMAP_SIZE(BooleanObject)] = { 0 };
-        Object::fillGCDescriptor(obj_bitmap);
-        descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(BooleanObject));
-        typeInited = true;
-    }
-    return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
-}
 } // namespace Escargot
index 8d873a841d8a8e4e6938a478a3097fb33aa8d897..89d4048626d1704853f45de84560a32d56d65ab2 100644 (file)
@@ -44,9 +44,6 @@ public:
         return true;
     }
 
-    void* operator new(size_t size);
-    void* operator new[](size_t size) = delete;
-
 private:
     bool m_primitiveValue : 1;
 };
index 30668067504055dbbf3436ee0767c01d55db0ec8..d360e56a672bae7fac8114b157bdd5ad83d6626b 100644 (file)
@@ -44,6 +44,7 @@ CompressibleString::CompressibleString(VMInstance* instance)
     : String()
     , m_isOwnerMayFreed(false)
     , m_isCompressed(false)
+    , m_refCount(0)
     , m_vmInstance(instance)
     , m_lastUsedTickcount(fastTickCount())
 {
@@ -53,6 +54,8 @@ CompressibleString::CompressibleString(VMInstance* instance)
     v.push_back(this);
     GC_REGISTER_FINALIZER_NO_ORDER(this, [](void* obj, void*) {
         CompressibleString* self = (CompressibleString*)obj;
+        ASSERT(self->refCount() == 0);
+
         if (self->isCompressed()) {
             self->m_compressedData.~CompressedDataVector();
         } else {
@@ -146,15 +149,15 @@ void CompressibleString::deallocateStringDataBuffer(void* ptr, size_t byteLength
 bool CompressibleString::compress()
 {
     ASSERT(!m_isCompressed);
-    if (UNLIKELY(!m_bufferData.length)) {
+    if (UNLIKELY(!m_bufferData.length || m_refCount > 0)) {
         return false;
     }
 
     bool has8Bit = m_bufferData.has8BitContent;
     if (has8Bit) {
-        return compressWorker<LChar>(currentStackPointer());
+        return compressWorker<LChar>();
     } else {
-        return compressWorker<char16_t>(currentStackPointer());
+        return compressWorker<char16_t>();
     }
 }
 
@@ -174,37 +177,12 @@ void CompressibleString::decompress()
 constexpr static const size_t g_compressChunkSize = 1044465;
 static_assert(LZ4_COMPRESSBOUND(g_compressChunkSize) == 1024 * 1024, "");
 
-static ATTRIBUTE_NO_SANITIZE_ADDRESS bool testPointerExistsOnStack(size_t* start, size_t* end, const void* ptr)
-{
-    while (start != end) {
-        if (UNLIKELY(*start == (size_t)ptr)) {
-            // if there is reference on stack, we cannot compress string.
-            return true;
-        }
-        start++;
-    }
-
-    return false;
-}
-
 template <typename StringType>
-bool CompressibleString::compressWorker(void* callerSP)
+bool CompressibleString::compressWorker()
 {
-    ASSERT(!m_isCompressed);
+    ASSERT(!m_isCompressed && !m_refCount);
     ASSERT(m_bufferData.length > 0);
 
-#if defined(STACK_GROWS_DOWN)
-    size_t* start = (size_t*)((size_t)callerSP & ~(sizeof(size_t) - 1));
-    size_t* end = (size_t*)m_vmInstance->stackStartAddress();
-#else
-    size_t* start = (size_t*)m_vmInstance->stackStartAddress();
-    size_t* end = (size_t*)((size_t)callerSP & ~(sizeof(size_t) - 1));
-#endif
-
-    if (testPointerExistsOnStack(start, end, m_bufferData.buffer)) {
-        return false;
-    }
-
     size_t originByteLength = m_bufferData.length * sizeof(StringType);
     int lastBoundLength = 0;
     std::unique_ptr<char[]> compBuffer;
index c716ba87abdde29f2cf70ccba8f05b007a37e518..676347e519590d8ff8cde10ec55a6a7f43300dd2 100644 (file)
@@ -67,7 +67,9 @@ public:
         if (isCompressed()) {
             decompress();
         }
-        return StringBufferAccessData(m_bufferData.has8BitContent, m_bufferData.length, const_cast<void*>(m_bufferData.buffer));
+
+        // add refCount pointer to count its usage in StringBufferAccessData
+        return StringBufferAccessData(m_bufferData.has8BitContent, m_bufferData.length, const_cast<void*>(m_bufferData.buffer), &m_refCount);
     }
 
     bool isCompressed()
@@ -75,6 +77,11 @@ public:
         return m_isCompressed;
     }
 
+    size_t refCount() const
+    {
+        return m_refCount;
+    }
+
     void* operator new(size_t);
     void* operator new[](size_t) = delete;
     void operator delete[](void*) = delete;
@@ -100,12 +107,13 @@ private:
     }
 
     template <typename StringType>
-    NEVER_INLINE bool compressWorker(void* callerSP);
+    NEVER_INLINE bool compressWorker();
     template <typename StringType>
     NEVER_INLINE void decompressWorker();
 
     bool m_isOwnerMayFreed;
     bool m_isCompressed;
+    size_t m_refCount; // reference count representing the usage of this CompressibleString
     VMInstance* m_vmInstance;
     uint64_t m_lastUsedTickcount;
     typedef std::vector<std::vector<char>> CompressedDataVector;
index 8a4eb307cc820ce0e1576f4fe6e163442221e92a..be9b3bd123d82e8a19cccf53765a74a9917f49b3 100644 (file)
@@ -125,34 +125,80 @@ ASTAllocator& Context::astAllocator()
 
 #ifdef ESCARGOT_DEBUGGER
 
-bool Context::initDebugger(const char* options)
+bool Context::initDebuggerRemote(const char* options)
 {
-    if (m_debugger != nullptr) {
+    if (debuggerEnabled()) {
         // debugger cannot be re-initialized
         return false;
     }
 
-    m_debugger = createDebugger(options, &m_instance->m_debuggerEnabled);
-    return m_debugger->enabled();
+    Debugger::createDebuggerRemote(options, this);
+    return m_debugger != nullptr;
+}
+
+void Context::initDebugger(Debugger* debugger)
+{
+    ASSERT(m_debugger == nullptr);
+    m_debugger = debugger;
+}
+
+void Context::removeDebugger()
+{
+    ASSERT(m_debugger != nullptr);
+    m_debugger = nullptr;
+}
+
+bool Context::debuggerEnabled() const
+{
+    return m_debugger != nullptr;
 }
 
 void Context::printDebugger(StringView* output)
 {
-    if (!m_debugger || !m_debugger->enabled()) {
+    if (debuggerEnabled()) {
+        m_debugger->consoleOut(output);
+    }
+}
+
+String* Context::getClientSource(String** sourceName)
+{
+    if (debuggerEnabled()) {
+        return m_debugger->getClientSource(sourceName);
+    }
+    return nullptr;
+}
+
+void Context::setAsAlwaysStopState()
+{
+    if (!debuggerEnabled()) {
         return;
     }
-    m_debugger->sendType(Debugger::ESCARGOT_MESSAGE_PRINT);
-    if (m_debugger->enabled()) {
-        m_debugger->sendString(Debugger::ESCARGOT_MESSAGE_STRING_8BIT, output);
+
+    m_debugger->setStopState(ESCARGOT_DEBUGGER_ALWAYS_STOP);
+}
+
+bool Context::inDebuggingCodeMode() const
+{
+    if (!debuggerEnabled()) {
+        return false;
     }
+
+    return m_debugger->inDebuggingCodeMode();
 }
 
-String* Context::getClientSource(String** sourceName)
+void Context::pumpDebuggerEvents()
 {
-    if (!m_debugger || !m_debugger->enabled()) {
-        return nullptr;
+    if (!debuggerEnabled()) {
+        return;
     }
-    return m_debugger->getClientSource(sourceName);
+
+    SandBox sb(this);
+    sb.run([](ExecutionState& state, void* d) -> Value {
+        Debugger* debugger = reinterpret_cast<Debugger*>(d);
+        debugger->pumpDebuggerEvents(&state);
+        return Value();
+    },
+           m_debugger);
 }
 
 #endif /* ESCARGOT_DEBUGGER */
index 72433ad18f24e37aff2f0057d1d7b801857db39e..f73c45ae8c7f1e144e9e21cb9e38b7a97983b8a3 100644 (file)
@@ -317,8 +317,14 @@ public:
         return m_debugger;
     }
 
-    bool initDebugger(const char* options);
+    bool initDebuggerRemote(const char* options);
+    void initDebugger(Debugger* debugger);
+    void removeDebugger();
+    bool debuggerEnabled() const;
     void printDebugger(StringView* output);
+    void pumpDebuggerEvents();
+    void setAsAlwaysStopState();
+    bool inDebuggingCodeMode() const;
     String* getClientSource(String** sourceName);
 #endif /* ESCARGOT_DEBUGGER */
 
index a78743b50c01ee3d27dde05e117f2f47e9ca218e..e13a138bccad06d11794ef576a440803ebcc0f33 100644 (file)
@@ -279,7 +279,7 @@ time64_t DateObject::applyLocalTimezoneOffset(ExecutionState& state, time64_t t)
     int32_t stdOffset = 0, dstOffset = 0;
 
 // roughly check range before calling yearFromTime function
-#if defined(ENABLE_ICU)
+#if defined(ENABLE_ICU) && !defined(OS_WINDOWS_UWP)
     stdOffset = vzone_getRawOffset(state.context()->vmInstance()->timezone());
 #else
     stdOffset = 0;
@@ -299,7 +299,7 @@ time64_t DateObject::applyLocalTimezoneOffset(ExecutionState& state, time64_t t)
     time64_t msBetweenYears = (realYear != equivalentYear) ? (timeFromYear(equivalentYear) - timeFromYear(realYear)) : 0;
 
     t += msBetweenYears;
-#if defined(ENABLE_ICU)
+#if defined(ENABLE_ICU) && !defined(OS_WINDOWS_UWP)
     vzone_getOffset3(state.context()->vmInstance()->timezone(), t, true, stdOffset, dstOffset, succ);
 #else
     dstOffset = 0;
@@ -1117,7 +1117,7 @@ void DateObject::resolveCache(ExecutionState& state)
     t += msBetweenYears;
 
     int32_t stdOffset = 0, dstOffset = 0;
-#if defined(ENABLE_ICU)
+#if defined(ENABLE_ICU) && !defined(OS_WINDOWS_UWP)
     UErrorCode succ = U_ZERO_ERROR;
     vzone_getOffset3(state.context()->vmInstance()->timezone(), t, true, stdOffset, dstOffset, succ);
 #endif
index 5e76b2aef316ba74c83a1d7a3b0544925a5ba582..45d8da2244e70f23073b7f4ff333ae645b912cdc 100644 (file)
@@ -151,6 +151,7 @@ class EncodedValue {
 public:
     enum ForceUninitializedTag { ForceUninitialized };
     enum EmptyValueInitTag { EmptyValue };
+    COMPILE_ASSERT(EncodedValue::EmptyValue == 0, "");
 
     EncodedValue(ForceUninitializedTag)
     {
@@ -350,6 +351,7 @@ private:
 class EncodedSmallValue {
 public:
     enum EmptyValueInitTag { EmptyValue };
+    COMPILE_ASSERT(EncodedSmallValue::EmptyValue == 0, "");
 
     EncodedSmallValue(EmptyValueInitTag)
     {
index ff9456be3514cb8597509e34c924b8a40262c143..c0f2e54a15675c00aa589002eee09ba2f6a5c121 100644 (file)
@@ -39,10 +39,10 @@ bool EnumerateObject::checkLastEnumerateKey(ExecutionState& state)
 
 void EnumerateObject::update(ExecutionState& state)
 {
-    EncodedValueVector newKeys;
+    EncodedValueTightVector newKeys;
     executeEnumeration(state, newKeys);
 
-    Vector<Value, GCUtil::gc_malloc_allocator<Value>> differenceKeys;
+    VectorWithInlineStorage<32, Value, GCUtil::gc_malloc_allocator<Value>> differenceKeys;
     for (size_t i = 0; i < newKeys.size(); i++) {
         const auto& key = newKeys[i];
         // If a property that has not yet been visited during enumeration is deleted, then it will not be visited.
@@ -110,7 +110,7 @@ void EnumerateObjectWithDestruction::fillRestElement(ExecutionState& state, Obje
     }
 }
 
-void EnumerateObjectWithDestruction::executeEnumeration(ExecutionState& state, EncodedValueVector& keys)
+void EnumerateObjectWithDestruction::executeEnumeration(ExecutionState& state, EncodedValueTightVector& keys)
 {
     ASSERT(!!m_object);
 
@@ -121,20 +121,20 @@ void EnumerateObjectWithDestruction::executeEnumeration(ExecutionState& state, E
     m_hiddenClass = m_object->structure();
 
     struct Properties {
-        std::vector<Value::ValueIndex> indexes;
+        std::multiset<Value::ValueIndex, std::less<Value::ValueIndex>> indexes;
         VectorWithInlineStorage<32, EncodedValue, GCUtil::gc_malloc_allocator<EncodedValue>> strings;
         VectorWithInlineStorage<4, Value, GCUtil::gc_malloc_allocator<Value>> symbols;
     } properties;
 
     m_object->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
         auto properties = (Properties*)data;
-        auto value = name.toPlainValue(state);
+        auto value = name.toPlainValue();
         if (desc.isEnumerable()) {
             Value::ValueIndex nameAsIndexValue;
             if (value.isSymbol()) {
                 properties->symbols.push_back(value);
             } else if (name.isIndexString() && (nameAsIndexValue = value.toIndex(state)) != Value::InvalidIndexValue) {
-                properties->indexes.push_back(nameAsIndexValue);
+                properties->indexes.insert(nameAsIndexValue);
             } else {
                 properties->strings.push_back(value);
             }
@@ -143,8 +143,6 @@ void EnumerateObjectWithDestruction::executeEnumeration(ExecutionState& state, E
     },
                           &properties, false);
 
-    std::sort(properties.indexes.begin(), properties.indexes.end(), std::less<Value::ValueIndex>());
-
     keys.resizeWithUninitializedValues(properties.indexes.size() + properties.strings.size() + properties.symbols.size());
 
     size_t idx = 0;
@@ -177,7 +175,7 @@ bool EnumerateObjectWithDestruction::checkIfModified(ExecutionState& state)
     return false;
 }
 
-void EnumerateObjectWithIteration::executeEnumeration(ExecutionState& state, EncodedValueVector& keys)
+void EnumerateObjectWithIteration::executeEnumeration(ExecutionState& state, EncodedValueTightVector& keys)
 {
     ASSERT(!!m_object);
     m_hiddenClassChain.clear();
@@ -189,94 +187,113 @@ void EnumerateObjectWithIteration::executeEnumeration(ExecutionState& state, Enc
     }
 
     bool shouldSearchProto = false;
-
     m_hiddenClassChain.push_back(m_object->structure());
 
     std::unordered_set<String*, std::hash<String*>, std::equal_to<String*>, GCUtil::gc_malloc_allocator<String*>> keyStringSet;
 
-    Value proto = m_object->getPrototype(state);
-    while (proto.isObject()) {
+    Object* proto = m_object->getPrototypeObject(state);
+    while (proto) {
         if (!shouldSearchProto) {
-            proto.asObject()->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
-                if (desc.isEnumerable()) {
-                    bool* shouldSearchProto = (bool*)data;
-                    *shouldSearchProto = true;
-                    return false;
-                }
-                return true;
-            },
-                                          &shouldSearchProto);
+            if (proto->hasOwnEnumeration()) {
+                proto->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
+                    if (desc.isEnumerable()) {
+                        bool* shouldSearchProto = (bool*)data;
+                        *shouldSearchProto = true;
+                        return false;
+                    }
+                    return true;
+                },
+                                   &shouldSearchProto);
+
+            } else {
+                shouldSearchProto |= proto->structure()->hasEnumerableProperty();
+            }
         }
-        ASSERT(!!proto.asObject()->structure());
-        m_hiddenClassChain.push_back(proto.asObject()->structure());
-        proto = proto.asObject()->getPrototype(state);
+        m_hiddenClassChain.push_back(proto->structure());
+        proto = proto->getPrototypeObject(state);
     }
 
     if (shouldSearchProto) {
         // TODO sorting properties
         struct EData {
             std::unordered_set<String*, std::hash<String*>, std::equal_to<String*>, GCUtil::gc_malloc_allocator<String*>>* keyStringSet;
-            EncodedValueVector* keys;
+            VectorWithInlineStorage<32, EncodedValue, GCUtil::gc_malloc_allocator<EncodedValue>> keys;
             Object* obj;
         } eData;
 
         eData.keyStringSet = &keyStringSet;
-        eData.keys = &keys;
         eData.obj = m_object;
 
-        Value target = m_object;
-        while (target.isObject()) {
-            target.asObject()->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
+        Object* target = m_object;
+        while (target) {
+            target->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
                 EData* eData = (EData*)data;
                 if (desc.isEnumerable()) {
-                    String* key = name.toPlainValue(state).toString(state);
+                    String* key = name.toPlainValue().toString(state);
                     auto iter = eData->keyStringSet->find(key);
                     if (iter == eData->keyStringSet->end()) {
                         eData->keyStringSet->insert(key);
-                        eData->keys->pushBack(Value(key));
+                        eData->keys.pushBack(Value(key));
                     }
                 } else if (self == eData->obj) {
                     // 12.6.4 The values of [[Enumerable]] attributes are not considered
                     // when determining if a property of a prototype object is shadowed by a previous object on the prototype chain.
-                    String* key = name.toPlainValue(state).toString(state);
+                    String* key = name.toPlainValue().toString(state);
                     ASSERT(eData->keyStringSet->find(key) == eData->keyStringSet->end());
                     eData->keyStringSet->insert(key);
                 }
                 return true;
             },
-                                           &eData);
-            target = target.asObject()->getPrototype(state);
+                                &eData);
+            target = target->getPrototypeObject(state);
         }
+
+        keys.resizeWithUninitializedValues(eData.keys.size());
+        for (size_t i = 0; i < eData.keys.size(); i++) {
+            keys[i] = eData.keys[i];
+        }
+
     } else {
-        struct Properties {
-            std::vector<Value::ValueIndex> indexes;
-            VectorWithInlineStorage<32, EncodedValue, GCUtil::gc_malloc_allocator<EncodedValue>> strings;
-        } properties;
-
-        m_object->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
-            auto properties = (Properties*)data;
-            auto value = name.toPlainValue(state);
-            if (desc.isEnumerable()) {
-                Value::ValueIndex nameAsIndexValue;
-                if (name.isIndexString() && (nameAsIndexValue = value.toIndex(state)) != Value::InvalidIndexValue) {
-                    properties->indexes.push_back(nameAsIndexValue);
-                } else {
-                    properties->strings.push_back(value);
+        if (m_object->hasOwnEnumeration() || m_object->structure()->hasIndexPropertyName()) {
+            struct Properties {
+                std::multiset<Value::ValueIndex, std::less<Value::ValueIndex>> indexes;
+                VectorWithInlineStorage<32, EncodedValue, GCUtil::gc_malloc_allocator<EncodedValue>> strings;
+            } properties;
+
+            m_object->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
+                auto properties = (Properties*)data;
+                auto value = name.toPlainValue();
+                if (desc.isEnumerable()) {
+                    Value::ValueIndex nameAsIndexValue;
+                    if (name.isIndexString() && (nameAsIndexValue = value.toIndex(state)) != Value::InvalidIndexValue) {
+                        properties->indexes.insert(nameAsIndexValue);
+                    } else {
+                        properties->strings.push_back(value);
+                    }
                 }
-            }
-            return true;
-        },
-                              &properties);
-
-        std::sort(properties.indexes.begin(), properties.indexes.end(), std::less<Value::ValueIndex>());
+                return true;
+            },
+                                  &properties);
 
-        keys.resizeWithUninitializedValues(properties.indexes.size() + properties.strings.size());
-        size_t idx = 0;
-        for (auto& v : properties.indexes) {
-            keys[idx++] = Value(v).toString(state);
-        }
-        for (auto& v : properties.strings) {
-            keys[idx++] = v;
+            keys.resizeWithUninitializedValues(properties.indexes.size() + properties.strings.size());
+            size_t idx = 0;
+            for (auto& v : properties.indexes) {
+                keys[idx++] = Value(v).toString(state);
+            }
+            for (auto& v : properties.strings) {
+                keys[idx++] = v;
+            }
+        } else {
+            m_object->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
+                EncodedValueTightVector* keys = reinterpret_cast<EncodedValueTightVector*>(data);
+                auto value = name.toPlainValue();
+                if (desc.isEnumerable()) {
+                    ASSERT(!name.isIndexString() || value.toIndex(state) == Value::InvalidIndexValue);
+                    keys->pushBack(value);
+                }
+                return true;
+            },
+                                  &keys);
         }
     }
 
@@ -294,9 +311,9 @@ bool EnumerateObjectWithIteration::checkIfModified(ExecutionState& state)
         if (UNLIKELY(hc != structure)) {
             return true;
         }
-        Value val = obj->getPrototype(state);
-        if (val.isObject()) {
-            obj = val.asObject();
+        Object* val = obj->getPrototypeObject(state);
+        if (val) {
+            obj = val;
         } else {
             break;
         }
@@ -314,3 +331,4 @@ bool EnumerateObjectWithIteration::checkIfModified(ExecutionState& state)
     return false;
 }
 } // namespace Escargot
+;
index 53acff4584411e28dcc560d8990fb490ecbb32a3..dcf3226a893f8f022d0c91ca4de817d3cd977293 100644 (file)
@@ -26,7 +26,7 @@ namespace Escargot {
 
 class EnumerateObject : public PointerValue {
 public:
-    virtual bool isEnumerateObject() const
+    virtual bool isEnumerateObject() const override
     {
         return true;
     }
@@ -39,7 +39,7 @@ public:
     }
 
     size_t m_index;
-    EncodedValueVector m_keys;
+    EncodedValueTightVector m_keys;
 
 protected:
     EnumerateObject(Object* obj)
@@ -52,11 +52,11 @@ protected:
 
     void update(ExecutionState& state);
 
-    virtual void executeEnumeration(ExecutionState& state, EncodedValueVector& keys) = 0;
+    virtual void executeEnumeration(ExecutionState& state, EncodedValueTightVector& keys) = 0;
     virtual bool checkIfModified(ExecutionState& state) = 0;
 
     Object* m_object;
-    uint64_t m_arrayLength;
+    uint32_t m_arrayLength;
 };
 
 // enumerate object for destruction operation e.g. var obj = { a, ...b };
@@ -72,18 +72,22 @@ public:
 
     virtual void fillRestElement(ExecutionState& state, Object* result) override;
 
+    inline void* operator new(size_t size, void* p)
+    {
+        return p;
+    }
     void* operator new(size_t size);
     void* operator new[](size_t size) = delete;
 
 protected:
-    virtual void executeEnumeration(ExecutionState& state, EncodedValueVector& keys) override;
+    virtual void executeEnumeration(ExecutionState& state, EncodedValueTightVector& keys) override;
     virtual bool checkIfModified(ExecutionState& state) override;
 
     ObjectStructure* m_hiddenClass;
 };
 
 // enumerate object for iteration operation (for-in)
-// exclude symbol, include prototype chain and check modification during enumetation
+// exclude symbol, include prototype chain and check modification during enumeration
 class EnumerateObjectWithIteration : public EnumerateObject {
 public:
     EnumerateObjectWithIteration(ExecutionState& state, Object* obj)
@@ -92,11 +96,15 @@ public:
         executeEnumeration(state, m_keys);
     }
 
+    inline void* operator new(size_t size, void* p)
+    {
+        return p;
+    }
     void* operator new(size_t size);
     void* operator new[](size_t size) = delete;
 
 protected:
-    virtual void executeEnumeration(ExecutionState& state, EncodedValueVector& keys) override;
+    virtual void executeEnumeration(ExecutionState& state, EncodedValueTightVector& keys) override;
     virtual bool checkIfModified(ExecutionState& state) override;
 
     Vector<ObjectStructure*, GCUtil::gc_malloc_allocator<ObjectStructure*>> m_hiddenClassChain;
index 01001da79239f0b1251b04ddfebb702d09c88027..6c8bdae59babcea3faf77e2a03afec3d1eec1cc7 100644 (file)
@@ -299,6 +299,26 @@ void FunctionEnvironmentRecordOnHeap<canBindThisValue, hasNewTarget>::setMutable
     m_heapStorage[slot.m_index] = v;
 }
 
+template <bool canBindThisValue, bool hasNewTarget, size_t inlineStorageSize>
+FunctionEnvironmentRecordOnHeapWithInlineStorage<canBindThisValue, hasNewTarget, inlineStorageSize>::FunctionEnvironmentRecordOnHeapWithInlineStorage(ScriptFunctionObject* function)
+    : FunctionEnvironmentRecordWithExtraData<canBindThisValue, hasNewTarget>(function)
+{
+}
+
+template <bool canBindThisValue, bool hasNewTarget, size_t inlineStorageSize>
+void FunctionEnvironmentRecordOnHeapWithInlineStorage<canBindThisValue, hasNewTarget, inlineStorageSize>::setMutableBindingByBindingSlot(ExecutionState& state, const EnvironmentRecord::BindingSlot& slot, const AtomicString& name, const Value& v)
+{
+    // Storing to const variable check only (TDZ check is already done by bytecode generation)
+    const auto& recordInfo = FunctionEnvironmentRecordWithExtraData<canBindThisValue, hasNewTarget>::functionObject()->interpretedCodeBlock()->identifierInfos();
+    if (UNLIKELY(!recordInfo[slot.m_index].m_isMutable)) {
+        if (state.inStrictMode()) {
+            ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, ErrorObject::Messages::AssignmentToConstantVariable, name);
+        }
+        return;
+    }
+    m_inlineStorage[slot.m_index] = v;
+}
+
 template <bool canBindThisValue, bool hasNewTarget>
 FunctionEnvironmentRecordNotIndexed<canBindThisValue, hasNewTarget>::FunctionEnvironmentRecordNotIndexed(ScriptFunctionObject* function)
     : FunctionEnvironmentRecordWithExtraData<canBindThisValue, hasNewTarget>(function)
@@ -412,6 +432,17 @@ template class FunctionEnvironmentRecordOnHeap<false, false>;
 template class FunctionEnvironmentRecordOnHeap<true, true>;
 template class FunctionEnvironmentRecordOnHeap<false, true>;
 
+#define DEFINE_FE_WITH_INLINE_STORAGE(num)                                              \
+    template class FunctionEnvironmentRecordOnHeapWithInlineStorage<false, false, num>; \
+    template class FunctionEnvironmentRecordOnHeapWithInlineStorage<true, true, num>;   \
+    template class FunctionEnvironmentRecordOnHeapWithInlineStorage<false, true, num>;
+
+DEFINE_FE_WITH_INLINE_STORAGE(1)
+DEFINE_FE_WITH_INLINE_STORAGE(2)
+DEFINE_FE_WITH_INLINE_STORAGE(3)
+DEFINE_FE_WITH_INLINE_STORAGE(4)
+DEFINE_FE_WITH_INLINE_STORAGE(5)
+
 template class FunctionEnvironmentRecordNotIndexed<false, false>;
 template class FunctionEnvironmentRecordNotIndexed<true, true>;
 template class FunctionEnvironmentRecordNotIndexed<false, true>;
index 76d018d84ef01ea6d92e15f5f230fa286002fe58..49b42e46c6a0e63660aeee1e1da6231525e18fcc 100644 (file)
@@ -308,7 +308,7 @@ private:
 // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-global-environment-records
 class GlobalEnvironmentRecord : public EnvironmentRecord {
 #ifdef ESCARGOT_DEBUGGER
-    friend class Debugger;
+    friend class DebuggerRemote;
 #endif /* ESCARGOT_DEBUGGER */
 public:
     GlobalEnvironmentRecord(ExecutionState& state, InterpretedCodeBlock* codeBlock, GlobalObject* global, IdentifierRecordVector* globalDeclarativeRecord, EncodedValueVector* globalDeclarativeStorage);
@@ -341,6 +341,11 @@ public:
         return m_globalCodeBlock;
     }
 
+    GlobalObject* globalObject()
+    {
+        return m_globalObject;
+    }
+
 private:
     InterpretedCodeBlock* m_globalCodeBlock;
     GlobalObject* m_globalObject;
@@ -570,7 +575,7 @@ private:
 // DeclarativeEnvironmentRecordNotIndexed record does not create binding self likes FunctionEnvironmentRecord
 class DeclarativeEnvironmentRecordNotIndexed : public DeclarativeEnvironmentRecord {
 #ifdef ESCARGOT_DEBUGGER
-    friend class Debugger;
+    friend class DebuggerRemote;
 #endif /* ESCARGOT_DEBUGGER */
 public:
     DeclarativeEnvironmentRecordNotIndexed(ExecutionState& state, bool isVarDeclarationTarget = false, bool isCatchClause = false)
@@ -813,11 +818,6 @@ public:
         return false;
     }
 
-    virtual EncodedValueTightVector& heapStorage()
-    {
-        RELEASE_ASSERT_NOT_REACHED();
-    }
-
     Object* homeObject()
     {
         return functionObject()->homeObject();
@@ -1030,13 +1030,84 @@ public:
         RELEASE_ASSERT_NOT_REACHED();
     }
 
-    EncodedValueTightVector& heapStorage() override
+private:
+    EncodedValueTightVector m_heapStorage;
+};
+
+template <bool canBindThisValue, bool hasNewTarget, size_t inlineStorageSize>
+class FunctionEnvironmentRecordOnHeapWithInlineStorage : public FunctionEnvironmentRecordWithExtraData<canBindThisValue, hasNewTarget> {
+    friend class LexicalEnvironment;
+    friend class ByteCodeInterpreter;
+    friend class ScriptFunctionObject;
+
+public:
+    FunctionEnvironmentRecordOnHeapWithInlineStorage(ScriptFunctionObject* function);
+
+    virtual void setHeapValueByIndex(ExecutionState& state, const size_t idx, const Value& v) override
+    {
+        m_inlineStorage[idx] = v;
+    }
+
+    virtual Value getHeapValueByIndex(ExecutionState& state, const size_t idx) override
+    {
+        return m_inlineStorage[idx];
+    }
+
+    virtual EnvironmentRecord::GetBindingValueResult getBindingValue(ExecutionState& state, const AtomicString& name) override
+    {
+        const auto& v = FunctionEnvironmentRecordWithExtraData<canBindThisValue, hasNewTarget>::functionObject()->interpretedCodeBlock()->identifierInfos();
+
+        for (size_t i = 0; i < v.size(); i++) {
+            if (v[i].m_name == name) {
+                return EnvironmentRecord::GetBindingValueResult(m_inlineStorage[v[i].m_indexForIndexedStorage]);
+            }
+        }
+        return EnvironmentRecord::GetBindingValueResult();
+    }
+
+    virtual EnvironmentRecord::BindingSlot hasBinding(ExecutionState& state, const AtomicString& name) override
+    {
+        const auto& v = FunctionEnvironmentRecordWithExtraData<canBindThisValue, hasNewTarget>::functionObject()->interpretedCodeBlock()->identifierInfos();
+
+        for (size_t i = 0; i < v.size(); i++) {
+            if (v[i].m_name == name) {
+                return EnvironmentRecord::BindingSlot(this, v[i].m_indexForIndexedStorage, false);
+            }
+        }
+        return EnvironmentRecord::BindingSlot(this, SIZE_MAX, false);
+    }
+
+    virtual bool deleteBinding(ExecutionState& state, const AtomicString& name) override
+    {
+        return false;
+    }
+
+    virtual void setMutableBindingByBindingSlot(ExecutionState& state, const EnvironmentRecord::BindingSlot& slot, const AtomicString& name, const Value& v) override;
+    virtual void setMutableBindingByIndex(ExecutionState& state, const size_t idx, const Value& v) override
+    {
+        m_inlineStorage[idx] = v;
+    }
+
+    virtual void initializeBindingByIndex(ExecutionState& state, const size_t idx, const Value& v) override
+    {
+        m_inlineStorage[idx] = v;
+    }
+
+    virtual void setMutableBinding(ExecutionState& state, const AtomicString& name, const Value& V) override
     {
-        return m_heapStorage;
+        const auto& v = FunctionEnvironmentRecordWithExtraData<canBindThisValue, hasNewTarget>::functionObject()->interpretedCodeBlock()->identifierInfos();
+
+        for (size_t i = 0; i < v.size(); i++) {
+            if (v[i].m_name == name) {
+                m_inlineStorage[v[i].m_indexForIndexedStorage] = V;
+                return;
+            }
+        }
+        RELEASE_ASSERT_NOT_REACHED();
     }
 
 private:
-    EncodedValueTightVector m_heapStorage;
+    EncodedValue m_inlineStorage[inlineStorageSize];
 };
 
 template <bool canBindThisValue, bool hasNewTarget>
@@ -1123,7 +1194,7 @@ public:
 
 class ModuleEnvironmentRecord : public DeclarativeEnvironmentRecord {
 #ifdef ESCARGOT_DEBUGGER
-    friend class Debugger;
+    friend class DebuggerRemote;
 #endif /* ESCARGOT_DEBUGGER */
 public:
     struct ModuleBindingRecord {
index e4172272beaf028cd7ec052ca286a13f710afed5..f1b3b9ddd92c12d7549f12ec37f53a4d7df6ff04 100644 (file)
@@ -144,22 +144,50 @@ public:
         WASMRuntimeError,
 #endif
     };
+
+    struct StackTraceGCData {
+        union {
+            ByteCodeBlock* byteCodeBlock;
+            String* infoString;
+        };
+    };
+
+    struct StackTraceNonGCData {
+        size_t byteCodePosition;
+    };
+
+    struct StackTraceData : public gc {
+        TightVector<StackTraceGCData, GCUtil::gc_malloc_allocator<StackTraceGCData>> gcValues;
+        TightVector<StackTraceNonGCData, GCUtil::gc_malloc_atomic_allocator<StackTraceNonGCData>> nonGCValues;
+        Value exception;
+
+        void buildStackTrace(Context* context, StringBuilder& builder);
+        static StackTraceData* create(SandBox* sandBox);
+
+    private:
+        StackTraceData() {}
+    };
+
     static void throwBuiltinError(ExecutionState& state, Code code, const char* templateString)
     {
         throwBuiltinError(state, code, String::emptyString, false, String::emptyString, templateString);
     }
+
     static void throwBuiltinError(ExecutionState& state, Code code, const char* templateString, AtomicString templateDataString)
     {
         throwBuiltinError(state, code, templateDataString.string(), false, String::emptyString, templateString);
     }
+
     static void throwBuiltinError(ExecutionState& state, Code code, const char* templateString, String* templateDataString)
     {
         throwBuiltinError(state, code, templateDataString, false, String::emptyString, templateString);
     }
+
     static ErrorObject* createBuiltinError(ExecutionState& state, Code code, const char* templateString)
     {
         return createBuiltinError(state, code, String::emptyString, false, String::emptyString, templateString);
     }
+
     static ErrorObject* createError(ExecutionState& state, ErrorObject::Code code, String* errorMessage);
     static ErrorObject* createBuiltinError(ExecutionState& state, Code code, String* objectName, bool prototype, String* functionName, const char* templateString);
     static void throwBuiltinError(ExecutionState& state, Code code, String* objectName, bool prototype, String* functionName, const char* templateString);
@@ -172,27 +200,6 @@ public:
         return true;
     }
 
-    struct StackTraceGCData {
-        union {
-            ByteCodeBlock* byteCodeBlock;
-            String* infoString;
-        };
-    };
-    struct StackTraceNonGCData {
-        size_t byteCodePosition;
-    };
-    struct StackTraceData : public gc {
-        TightVector<StackTraceGCData, GCUtil::gc_malloc_allocator<StackTraceGCData>> gcValues;
-        TightVector<StackTraceNonGCData, GCUtil::gc_malloc_atomic_allocator<StackTraceNonGCData>> nonGCValues;
-        Value exception;
-
-        void buildStackTrace(Context* context, StringBuilder& builder);
-        static StackTraceData* create(SandBox* sandBox);
-
-    private:
-        StackTraceData() {}
-    };
-
     StackTraceData* stackTraceData()
     {
         return m_stackTraceData;
index cbd06a12da208e59138ac0b1063800f04be1bee3..e111f4e895aa248074991e17a1f4ff49e1f1ff7e 100644 (file)
@@ -189,7 +189,8 @@ Value ExecutionPauser::start(ExecutionState& state, ExecutionPauser* self, Objec
             debugger->setActiveSavedStackTrace(activeSavedStackTraceExecutionState, activeSavedStackTrace);
         }
 
-        if (from != Generator && self->m_savedStackTrace == nullptr && debugger != nullptr && debugger->enabled()) {
+        debugger = state.context()->debugger();
+        if (from != Generator && self->m_savedStackTrace == nullptr && debugger != nullptr) {
             self->m_savedStackTrace = Debugger::saveStackTrace(state);
         }
 #endif /* ESCARGOT_DEBUGGER */
index c0acb9b6230ab9363df9cb1f412599ebdd008180..9002eb684c5e7df59362b2cfaf22666b38d9ee3f 100644 (file)
@@ -53,7 +53,7 @@ FunctionObject* ExecutionState::resolveCallee()
             if (record->isDeclarativeEnvironmentRecord() && record->asDeclarativeEnvironmentRecord()->isFunctionEnvironmentRecord()) {
                 return record->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord()->functionObject();
             }
-        } else if (es->m_isNativeFunctionObjectExecutionContext) {
+        } else if (es->isNativeFunctionObjectExecutionContext()) {
             return es->m_calledNativeFunctionObject;
         }
 
@@ -175,6 +175,36 @@ EnvironmentRecord* ExecutionState::getThisEnvironment()
     }
 }
 
+Value ExecutionState::thisValue()
+{
+    LexicalEnvironment* lex = m_lexicalEnvironment;
+    while (lex) {
+        EnvironmentRecord* envRec = lex->record();
+        if (envRec->hasThisBinding()) {
+            if (envRec->isDeclarativeEnvironmentRecord() && envRec->asDeclarativeEnvironmentRecord()->isFunctionEnvironmentRecord()) {
+                auto fnRecord = envRec->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord();
+                ScriptFunctionObject* f = fnRecord->functionObject();
+                if (f->codeBlock()->isInterpretedCodeBlock() && f->codeBlock()->asInterpretedCodeBlock()->needsToLoadThisBindingFromEnvironment()) {
+                    return fnRecord->getThisBinding(*this);
+                } else {
+                    return f;
+                }
+            } else if (envRec->isGlobalEnvironmentRecord()) {
+                if (envRec->asGlobalEnvironmentRecord()->globalCodeBlock()->isStrict()) {
+                    return Value();
+                } else {
+                    return envRec->asGlobalEnvironmentRecord()->globalObject();
+                }
+            } else if (envRec->isModuleEnvironmentRecord()) {
+                return Value();
+            }
+        }
+
+        lex = lex->outerEnvironment();
+    }
+    return m_context->globalObject();
+}
+
 Value ExecutionState::makeSuperPropertyReference()
 {
     // Let env be GetThisEnvironment( ).
index 0e0639b2f237a0d0fd01d334535e3ee60da4b31c..a99166c7376f5f255c486dc16ae4cf91156794b9 100644 (file)
@@ -277,6 +277,11 @@ public:
         return m_onFinally;
     }
 
+    bool isNativeFunctionObjectExecutionContext() const
+    {
+        return m_isNativeFunctionObjectExecutionContext;
+    }
+
     // callee is pauser && isNotInEvalCode
     bool inPauserScope();
 
@@ -319,6 +324,7 @@ public:
     Object* getNewTarget();
     // http://www.ecma-international.org/ecma-262/6.0/#sec-getthisenvironment
     EnvironmentRecord* getThisEnvironment();
+    Value thisValue();
     Value makeSuperPropertyReference();
     Value getSuperConstructor();
 
index c06ce08b90ac853f09373c293ae1feb14d2a58b3..d3aa3747d3d726259ee11b347b013a8808db7c02 100644 (file)
@@ -31,7 +31,7 @@
 
 namespace Escargot {
 
-void FunctionObject::initStructureAndValues(ExecutionState& state, bool isConstructor, bool isGenerator, bool isAsync)
+void FunctionObject::initStructureAndValues(ExecutionState& state, bool isConstructor, bool isGenerator)
 {
     if (isGenerator) {
         // Unlike function instances, the object that is the value of the GeneratorFunction’s of AsyncGeneratorFunction prototype property
@@ -75,7 +75,7 @@ FunctionObject::FunctionObject(ObjectStructure* structure, ObjectPropertyValueVe
 {
 }
 
-FunctionObject::FunctionSource FunctionObject::createFunctionSourceFromScriptSource(ExecutionState& state, AtomicString functionName, size_t argCount, Value* argArray, Value bodyValue, bool useStrict, bool isGenerator, bool isAsync, bool allowSuperCall, bool isInternalSource)
+static String* createFunctionSource(ExecutionState& state, AtomicString functionName, size_t argCount, Value* argArray, Value bodyValue, bool useStrict, bool isGenerator, bool isAsync, bool isInternalSource)
 {
     StringBuilder src, parameters;
     if (useStrict) {
@@ -144,18 +144,19 @@ FunctionObject::FunctionSource FunctionObject::createFunctionSourceFromScriptSou
 
                 char* dest = reinterpret_cast<char*>(malloc((data->m_dest->length()) * (is8Bit ? 1 : 2)));
 
+                {
                 auto headAccessData = data->m_head->bufferAccessData();
                 auto bodyAccessData = data->m_body->bufferAccessData();
 
                 if (is8Bit) {
-                    ASSERT(headAccessData.has8BitContent && bodyAccessData.has8BitContent);
-                    char* ptr = dest;
-                    memcpy(ptr, headAccessData.bufferAs8Bit, headAccessData.length);
-                    ptr += headAccessData.length;
-                    memcpy(ptr, bodyAccessData.bufferAs8Bit, bodyAccessData.length);
-                    ptr += bodyAccessData.length;
-                    ptr[0] = '\n';
-                    ptr[1] = '}';
+                ASSERT(headAccessData.has8BitContent && bodyAccessData.has8BitContent);
+                char* ptr = dest;
+                memcpy(ptr, headAccessData.bufferAs8Bit, headAccessData.length);
+                ptr += headAccessData.length;
+                memcpy(ptr, bodyAccessData.bufferAs8Bit, bodyAccessData.length);
+                ptr += bodyAccessData.length;
+                ptr[0] = '\n';
+                ptr[1] = '}';
                 } else {
                     char16_t* ptr = reinterpret_cast<char16_t*>(dest);
                     if (headAccessData.has8BitContent) {
@@ -179,10 +180,9 @@ FunctionObject::FunctionSource FunctionObject::createFunctionSourceFromScriptSou
                     ptr[0] = '\n';
                     ptr[1] = '}';
                 }
+                }
 
                 // unload original body source immediately
-                // set nullptr to unload body string
-                bodyAccessData.buffer = nullptr;
                 data->m_body->unload();
                 return dest; }, [](void* memoryPtr, void* callbackData) { free(memoryPtr); });
 
@@ -225,10 +225,18 @@ FunctionObject::FunctionSource FunctionObject::createFunctionSourceFromScriptSou
         scriptSource = src.finalize(&state);
     }
 
+    return scriptSource;
+}
+
+FunctionObject::FunctionSource FunctionObject::createFunctionScript(ExecutionState& state, AtomicString functionName, size_t argCount, Value* argArray, Value bodyValue, bool useStrict, bool isGenerator, bool isAsync, bool allowSuperCall, bool isInternalSource, String* sourceName)
+{
+    String* scriptSource = createFunctionSource(state, functionName, argCount, argArray, bodyValue, useStrict, isGenerator, isAsync, isInternalSource);
+
     ScriptParser parser(state.context());
-    String* srcName = String::emptyString;
+    String* srcName = sourceName;
+
     // find srcName through outer script except internal source
-    if (!isInternalSource) {
+    if (!isInternalSource && !srcName->length()) {
         auto script = state.resolveOuterScript();
         if (script) {
             srcName = script->srcName();
@@ -237,6 +245,8 @@ FunctionObject::FunctionSource FunctionObject::createFunctionSourceFromScriptSou
 
     Script* script = parser.initializeScript(scriptSource, srcName, nullptr, false, false, false, false, false, allowSuperCall, false, true, false).scriptThrowsExceptionIfParseError(state);
     InterpretedCodeBlock* cb = script->topCodeBlock()->childBlockAt(0);
+    // mark it as dynamic code
+    cb->setDynamicSourceCode();
     LexicalEnvironment* globalEnvironment = new LexicalEnvironment(new GlobalEnvironmentRecord(state, script->topCodeBlock(), state.context()->globalObject(), state.context()->globalDeclarativeRecord(), state.context()->globalDeclarativeStorage()), nullptr);
 
     FunctionObject::FunctionSource fs;
@@ -246,4 +256,25 @@ FunctionObject::FunctionSource FunctionObject::createFunctionSourceFromScriptSou
 
     return fs;
 }
+
+bool FunctionObject::setName(AtomicString name)
+{
+    // re-set function name is allowed only for native function or dynamically created function except class constructor
+    ASSERT(!!m_codeBlock);
+    if (m_codeBlock->isInterpretedCodeBlock()) {
+        InterpretedCodeBlock* cb = m_codeBlock->asInterpretedCodeBlock();
+        if (!cb->hasDynamicSourceCode() || cb->isClassConstructor()) {
+            return false;
+        }
+    }
+
+    // set function name property
+    size_t nameIndex = functionNameIndex();
+    m_values[nameIndex] = Value(name.string());
+
+    // set function name in CodeBlock
+    m_codeBlock->setFunctionName(name);
+
+    return true;
+}
 } // namespace Escargot
index 78a3cc353c8a4018fa0df823b3ffe3bd9d9df812..c554b1daa46931021a70b907558e50fdf84d076f 100644 (file)
@@ -107,19 +107,37 @@ public:
         InterpretedCodeBlock* codeBlock;
         LexicalEnvironment* outerEnvironment;
     };
-    static FunctionSource createFunctionSourceFromScriptSource(ExecutionState& state, AtomicString functionName, size_t argCount, Value* argArray, Value bodyString, bool useStrict, bool isGenerator, bool isAsync, bool allowSuperCall, bool isInternalSource = false);
+    static FunctionSource createFunctionScript(ExecutionState& state, AtomicString functionName, size_t argCount, Value* argArray, Value bodyString, bool useStrict, bool isGenerator, bool isAsync, bool allowSuperCall, bool isInternalSource = false, String* sourceName = String::emptyString);
+
+    bool setName(AtomicString name);
 
 protected:
     FunctionObject(ExecutionState& state, Object* proto, size_t defaultSpace); // function for derived classes. derived class MUST initlize member variable of FunctionObject.
     FunctionObject(ObjectStructure* structure, ObjectPropertyValueVector&& values, Object* proto); // ctor for FunctionTemplate
+    FunctionObject() // ctor for reading tag
+        : Object()
+        , m_codeBlock(nullptr)
+    {
+    }
 
-    void initStructureAndValues(ExecutionState& state, bool isConstructor, bool isGenerator, bool isAsync);
+    void initStructureAndValues(ExecutionState& state, bool isConstructor, bool isGenerator);
     virtual size_t functionPrototypeIndex()
     {
         ASSERT(isConstructor() || isGenerator());
         return ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER;
     }
 
+    size_t functionNameIndex()
+    {
+        // getting a function name index of ScriptClassConstructorFunctionObject is not supported now
+        ASSERT(!isScriptClassConstructorFunctionObject());
+        if (isConstructor() || isGenerator()) {
+            return ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2;
+        } else {
+            return ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 1;
+        }
+    }
+
     void ensureFunctionPrototype(ExecutionState& state, const size_t& prototypeIndex)
     {
         if (m_values[prototypeIndex].isEmpty()) {
index c55b4556dfd3798d6ced00efb8fee3372ddde914..97c946a3d715d072cbb065323188cf864019de1a 100644 (file)
@@ -91,12 +91,10 @@ public:
     template <typename FunctionObjectType, bool isConstructCall, bool hasNewTargetOnEnvironment, bool canBindThisValueOnEnvironment, typename ThisValueBinder, typename NewTargetBinder, typename ReturnValueBinder>
     static ALWAYS_INLINE Value processCall(ExecutionState& state, FunctionObjectType* self, const Value& thisArgument, const size_t argc, Value* argv, Object* newTarget) // newTarget is null on [[call]]
     {
-        volatile int sp;
-        size_t currentStackBase = (size_t)&sp;
 #ifdef STACK_GROWS_DOWN
-        if (UNLIKELY(state.stackLimit() > currentStackBase)) {
+        if (UNLIKELY(state.stackLimit() > (size_t)currentStackPointer())) {
 #else
-        if (UNLIKELY(state.stackLimit() < currentStackBase)) {
+        if (UNLIKELY(state.stackLimit() < (size_t)currentStackPointer())) {
 #endif
             ErrorObject::throwBuiltinError(state, ErrorObject::RangeError, "Maximum call stack size exceeded");
         }
@@ -132,15 +130,7 @@ public:
 #endif
             );
         } else {
-            if (LIKELY(codeBlock->canUseIndexedVariableStorage())) {
-                record = new FunctionEnvironmentRecordOnHeap<canBindThisValueOnEnvironment, hasNewTargetOnEnvironment>(self);
-            } else {
-                if (LIKELY(!codeBlock->needsVirtualIDOperation())) {
-                    record = new FunctionEnvironmentRecordNotIndexed<canBindThisValueOnEnvironment, hasNewTargetOnEnvironment>(self);
-                } else {
-                    record = new FunctionEnvironmentRecordNotIndexedWithVirtualID(self);
-                }
-            }
+            record = createFunctionEnvironmentRecord<FunctionObjectType, hasNewTargetOnEnvironment, canBindThisValueOnEnvironment>(state, self, codeBlock);
             lexEnv = new LexicalEnvironment(record, self->outerEnvironment());
         }
 
@@ -255,6 +245,34 @@ public:
 
         return returnValue;
     }
+
+private:
+    template <typename FunctionObjectType, bool hasNewTargetOnEnvironment, bool canBindThisValueOnEnvironment>
+    static NEVER_INLINE FunctionEnvironmentRecord* createFunctionEnvironmentRecord(ExecutionState& state, FunctionObjectType* self, InterpretedCodeBlock* codeBlock)
+    {
+        if (LIKELY(codeBlock->canUseIndexedVariableStorage())) {
+            switch (codeBlock->identifierOnHeapCount()) {
+            case 1:
+                return new FunctionEnvironmentRecordOnHeapWithInlineStorage<canBindThisValueOnEnvironment, hasNewTargetOnEnvironment, 1>(self);
+            case 2:
+                return new FunctionEnvironmentRecordOnHeapWithInlineStorage<canBindThisValueOnEnvironment, hasNewTargetOnEnvironment, 2>(self);
+            case 3:
+                return new FunctionEnvironmentRecordOnHeapWithInlineStorage<canBindThisValueOnEnvironment, hasNewTargetOnEnvironment, 3>(self);
+            case 4:
+                return new FunctionEnvironmentRecordOnHeapWithInlineStorage<canBindThisValueOnEnvironment, hasNewTargetOnEnvironment, 4>(self);
+            case 5:
+                return new FunctionEnvironmentRecordOnHeapWithInlineStorage<canBindThisValueOnEnvironment, hasNewTargetOnEnvironment, 5>(self);
+            default:
+                return new FunctionEnvironmentRecordOnHeap<canBindThisValueOnEnvironment, hasNewTargetOnEnvironment>(self);
+            }
+        } else {
+            if (LIKELY(!codeBlock->needsVirtualIDOperation())) {
+                return new FunctionEnvironmentRecordNotIndexed<canBindThisValueOnEnvironment, hasNewTargetOnEnvironment>(self);
+            } else {
+                return new FunctionEnvironmentRecordNotIndexedWithVirtualID(self);
+            }
+        }
+    }
 };
 
 template <bool isConstruct, bool shouldReturnsObjectOnConstructCall>
index 30a1e0bca7ce1f80fb4235052941fe5e39e06a2e..fb15c4e6fb069a517e4ab7c5fe5b062ec5f67761 100644 (file)
@@ -149,25 +149,25 @@ Object* FunctionTemplate::instantiate(Context* ctx)
     const size_t functionDefaultPropertyCount = m_isConstructor ? ctx->defaultStructureForFunctionObject()->propertyCount() : ctx->defaultStructureForNotConstructorFunctionObject()->propertyCount();
     if (!m_cachedObjectStructure.m_objectStructure) {
         if (m_isConstructor) {
-            // [prototype, name, length]
+            // [prototype, length, name]
             ASSERT(functionDefaultPropertyCount == 3);
             ObjectStructureItem structureItemVector[3] = {
                 ObjectStructureItem(ctx->staticStrings().prototype,
                                     ObjectStructurePropertyDescriptor::createDataDescriptor(ObjectStructurePropertyDescriptor::WritablePresent)),
-                ObjectStructureItem(ctx->staticStrings().name,
-                                    ObjectStructurePropertyDescriptor::createDataDescriptor(ObjectStructurePropertyDescriptor::ConfigurablePresent)),
                 ObjectStructureItem(ctx->staticStrings().length,
+                                    ObjectStructurePropertyDescriptor::createDataDescriptor(ObjectStructurePropertyDescriptor::ConfigurablePresent)),
+                ObjectStructureItem(ctx->staticStrings().name,
                                     ObjectStructurePropertyDescriptor::createDataDescriptor(ObjectStructurePropertyDescriptor::ConfigurablePresent))
 
             };
             m_cachedObjectStructure = constructObjectStructure(ctx, structureItemVector, 3);
         } else {
-            // [name, length]
+            // [length, name]
             ASSERT(functionDefaultPropertyCount == 2);
             ObjectStructureItem structureItemVector[2] = {
-                ObjectStructureItem(ctx->staticStrings().name,
-                                    ObjectStructurePropertyDescriptor::createDataDescriptor(ObjectStructurePropertyDescriptor::ConfigurablePresent)),
                 ObjectStructureItem(ctx->staticStrings().length,
+                                    ObjectStructurePropertyDescriptor::createDataDescriptor(ObjectStructurePropertyDescriptor::ConfigurablePresent)),
+                ObjectStructureItem(ctx->staticStrings().name,
                                     ObjectStructurePropertyDescriptor::createDataDescriptor(ObjectStructurePropertyDescriptor::ConfigurablePresent))
 
             };
@@ -179,21 +179,21 @@ Object* FunctionTemplate::instantiate(Context* ctx)
     ObjectPropertyValueVector objectPropertyValues;
     Object* functionPrototype = nullptr;
     if (m_isConstructor) {
-        // [prototype, name, length]
+        // [prototype, length, name]
         if (!m_prototypeTemplate->has(ctx->staticStrings().constructor.string())) {
             m_prototypeTemplate->set(ctx->staticStrings().constructor.string(), Value(), true, false, true);
         }
 
         ObjectPropertyValue baseValues[3];
         baseValues[0] = functionPrototype = m_prototypeTemplate->instantiate(ctx);
-        baseValues[1] = m_name.string();
-        baseValues[2] = Value(m_argumentCount);
+        baseValues[1] = Value(m_argumentCount);
+        baseValues[2] = m_name.string();
         constructObjectPropertyValues(ctx, baseValues, 3, objectPropertyValues);
     } else {
-        // [name, length]
+        // [length, name]
         ObjectPropertyValue baseValues[2];
-        baseValues[0] = m_name.string();
-        baseValues[1] = Value(m_argumentCount);
+        baseValues[0] = Value(m_argumentCount);
+        baseValues[1] = m_name.string();
         constructObjectPropertyValues(ctx, baseValues, 2, objectPropertyValues);
     }
 
index 7691b061fb76747496e85b6f84e909ec2adc2f4c..7247c75a17ab00d7d2b3b1762aee30f87fa85447 100644 (file)
@@ -22,6 +22,7 @@
 #include "runtime/Platform.h"
 #include "runtime/PointerValue.h"
 #include "runtime/ArrayObject.h"
+#include "runtime/ScriptFunctionObject.h"
 
 namespace Escargot {
 
@@ -48,6 +49,7 @@ void Global::initialize(Platform* platform)
     // tag values should be initialized once and not changed
     PointerValue::g_arrayObjectTag = ArrayObject().getTag();
     PointerValue::g_arrayPrototypeObjectTag = ArrayPrototypeObject().getTag();
+    PointerValue::g_scriptFunctionObjectTag = ScriptFunctionObject().getTag();
     PointerValue::g_objectRareDataTag = ObjectRareData(nullptr).getTag();
     PointerValue::g_doubleInEncodedValueTag = DoubleInEncodedValue(0).getTag();
 
@@ -100,7 +102,7 @@ Global::Waiter* Global::waiter(void* blockAddress)
 }
 #endif
 
-#ifdef ESCARGOT_USE_CUSTOM_LOGGING
+#ifdef ENABLE_CUSTOM_LOGGING
 void customEscargotInfoLogger(const char* format, ...)
 {
     va_list arg;
index f3823fabba458013c93c98c971ecafcbc825c478..b7c847f3ce88bd12853a8407aaad6af976565c83 100644 (file)
@@ -129,7 +129,7 @@ ObjectHasPropertyResult GlobalObject::hasProperty(ExecutionState& state, const O
             }
             target = target->getPrototypeObject(state);
         }
-        Value virtialIdResult = state.context()->virtualIdentifierCallback()(state, P.toPlainValue(state));
+        Value virtialIdResult = state.context()->virtualIdentifierCallback()(state, P.toPlainValue());
         if (!virtialIdResult.isEmpty()) {
             return ObjectHasPropertyResult(ObjectGetResult(virtialIdResult, true, true, true));
         }
@@ -150,7 +150,7 @@ ObjectGetResult GlobalObject::getOwnProperty(ExecutionState& state, const Object
             }
             target = target->getPrototypeObject(state);
         }
-        Value virtialIdResult = state.context()->virtualIdentifierCallback()(state, P.toPlainValue(state));
+        Value virtialIdResult = state.context()->virtualIdentifierCallback()(state, P.toPlainValue());
         if (!virtialIdResult.isEmpty())
             return ObjectGetResult(virtialIdResult, true, true, true);
     }
index f49f00c5529295fdc0f3e07df55e8003c67bce52..b57042b2ef9239c29b1ce9d903cfaf505d9d98e9 100644 (file)
@@ -97,24 +97,55 @@ class FunctionObject;
     F(generatorPrototype, Object, objName)
 //INTL
 #if defined(ENABLE_ICU) && defined(ENABLE_INTL)
-#define GLOBALOBJECT_BUILTIN_INTL(F, objName)           \
-    F(intl, Object, objName)                            \
-    F(intlCollator, FunctionObject, objName)            \
-    F(intlDateTimeFormat, FunctionObject, objName)      \
-    F(intlDateTimeFormatPrototype, Object, objName)     \
-    F(intlNumberFormat, FunctionObject, objName)        \
-    F(intlNumberFormatPrototype, Object, objName)       \
-    F(intlRelativeTimeFormat, FunctionObject, objName)  \
-    F(intlRelativeTimeFormatPrototype, Object, objName) \
-    F(intlDisplayNames, FunctionObject, objName)        \
-    F(intlDisplayNamesPrototype, Object, objName)       \
-    F(intlLocale, FunctionObject, objName)              \
-    F(intlLocalePrototype, Object, objName)             \
-    F(intlListFormat, FunctionObject, objName)          \
-    F(intlListFormatPrototype, Object, objName)         \
-    F(intlPluralRules, FunctionObject, objName)         \
+#if defined(ENABLE_INTL_DISPLAYNAMES)
+#define GLOBALOBJECT_BUILTIN_INTL_DISPLAYNAMES(F, objName) \
+    F(intlDisplayNames, FunctionObject, objName)           \
+    F(intlDisplayNamesPrototype, Object, objName)
+#else
+#define GLOBALOBJECT_BUILTIN_INTL_DISPLAYNAMES(F, objName)
+#endif
+#if defined(ENABLE_INTL_NUMBERFORMAT)
+#define GLOBALOBJECT_BUILTIN_INTL_NUMBERFORMAT(F, objName) \
+    F(intlNumberFormat, FunctionObject, objName)           \
+    F(intlNumberFormatPrototype, Object, objName)
+#else
+#define GLOBALOBJECT_BUILTIN_INTL_NUMBERFORMAT(F, objName)
+#endif
+#if defined(ENABLE_INTL_PLURALRULES)
+#define GLOBALOBJECT_BUILTIN_INTL_PLURALRULES(F, objName) \
+    F(intlPluralRules, FunctionObject, objName)           \
     F(intlPluralRulesPrototype, Object, objName)
 #else
+#define GLOBALOBJECT_BUILTIN_INTL_PLURALRULES(F, objName)
+#endif
+#if defined(ENABLE_INTL_RELATIVETIMEFORMAT)
+#define GLOBALOBJECT_BUILTIN_INTL_RELATIVETIMEFORMAT(F, objName) \
+    F(intlRelativeTimeFormat, FunctionObject, objName)           \
+    F(intlRelativeTimeFormatPrototype, Object, objName)
+#else
+#define GLOBALOBJECT_BUILTIN_INTL_RELATIVETIMEFORMAT(F, objName)
+#endif
+#if defined(ENABLE_INTL_LISTFORMAT)
+#define GLOBALOBJECT_BUILTIN_INTL_LISTFORMAT(F, objName) \
+    F(intlListFormat, FunctionObject, objName)           \
+    F(intlListFormatPrototype, Object, objName)
+#else
+#define GLOBALOBJECT_BUILTIN_INTL_LISTFORMAT(F, objName)
+#endif
+
+#define GLOBALOBJECT_BUILTIN_INTL(F, objName)                \
+    F(intl, Object, objName)                                 \
+    F(intlCollator, FunctionObject, objName)                 \
+    F(intlDateTimeFormat, FunctionObject, objName)           \
+    F(intlDateTimeFormatPrototype, Object, objName)          \
+    F(intlLocale, FunctionObject, objName)                   \
+    F(intlLocalePrototype, Object, objName)                  \
+    GLOBALOBJECT_BUILTIN_INTL_DISPLAYNAMES(F, objName)       \
+    GLOBALOBJECT_BUILTIN_INTL_NUMBERFORMAT(F, objName)       \
+    GLOBALOBJECT_BUILTIN_INTL_PLURALRULES(F, objName)        \
+    GLOBALOBJECT_BUILTIN_INTL_RELATIVETIMEFORMAT(F, objName) \
+    GLOBALOBJECT_BUILTIN_INTL_LISTFORMAT(F, objName)
+#else
 #define GLOBALOBJECT_BUILTIN_INTL(F, objName)
 #endif
 #define GLOBALOBJECT_BUILTIN_JSON(F, objName) \
index d5261c9d72b0c88605dcad699e11dd9ba90a0d3e..56760ebe5cbf985891498a4559ed0e0fd008cc18 100644 (file)
@@ -67,6 +67,11 @@ public:
     virtual bool isExtensible(ExecutionState&) override;
     virtual bool preventExtensions(ExecutionState&) override;
 
+    virtual bool hasOwnEnumeration() const override
+    {
+        return true;
+    }
+
     virtual bool canUseOwnPropertyKeysFastPath() override
     {
         return false;
index 07cce70c1bef367b3516954f4f5c499bc7af57bb..8b17fbf595dc609965df912718a38dbb309ebe44 100644 (file)
@@ -41,6 +41,11 @@ public:
         return false;
     }
 
+    virtual bool hasOwnEnumeration() const override
+    {
+        return true;
+    }
+
     // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-getprototypeof
     virtual Object* getPrototypeObject(ExecutionState&) override
     {
index 5dc334addc7fc0790b4b9d20ec57b8a45e287cd2..62a4d65ece34d6bfebfe1b4bfea31f737afa7896 100644 (file)
@@ -28,14 +28,14 @@ NativeFunctionObject::NativeFunctionObject(ExecutionState& state, const NativeFu
     : FunctionObject(state, state.context()->globalObject()->functionPrototype(), info.m_isConstructor ? (ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 3) : (ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2))
 {
     m_codeBlock = new NativeCodeBlock(state.context(), info);
-    initStructureAndValues(state, info.m_isConstructor, false, false);
+    initStructureAndValues(state, info.m_isConstructor, false);
 }
 
 NativeFunctionObject::NativeFunctionObject(ExecutionState& state, const NativeFunctionInfo& info, ForGlobalBuiltin)
     : FunctionObject(state, state.context()->globalObject()->objectPrototype(), ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2)
 {
     m_codeBlock = new NativeCodeBlock(state.context(), info);
-    initStructureAndValues(state, info.m_isConstructor, false, false);
+    initStructureAndValues(state, info.m_isConstructor, false);
     ASSERT(!NativeFunctionObject::isConstructor());
 }
 
@@ -43,7 +43,7 @@ NativeFunctionObject::NativeFunctionObject(ExecutionState& state, const NativeFu
     : FunctionObject(state, state.context()->globalObject()->functionPrototype(), info.m_isConstructor ? (ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 3) : (ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2))
 {
     m_codeBlock = new NativeCodeBlock(state.context(), info);
-    initStructureAndValues(state, info.m_isConstructor, false, false);
+    initStructureAndValues(state, info.m_isConstructor, false);
     if (info.m_isConstructor) {
         m_structure = state.context()->defaultStructureForBuiltinFunctionObject();
     }
index 873e57ccd112dfbb851f18ce3a485adadf905f97..ae024cb40e00607097b5f926cd0c704b77b4ec8d 100644 (file)
@@ -61,14 +61,22 @@ ObjectStructurePropertyName::ObjectStructurePropertyName(ExecutionState& state,
         m_data = (size_t)value.asSymbol();
         return;
     }
+
     String* string = value.toString(state);
+    size_t v = string->getTagInFirstDataArea();
+    if (v > POINTER_VALUE_STRING_TAG_IN_DATA) {
+        ASSERT(v == ((v & ~POINTER_VALUE_STRING_TAG_IN_DATA) | OBJECT_PROPERTY_NAME_ATOMIC_STRING_VIAS));
+        m_data = v;
+        return;
+    }
+
     const auto& data = string->bufferAccessData();
     if (data.length == 0) {
         m_data = ((size_t)AtomicString().string()) | OBJECT_PROPERTY_NAME_ATOMIC_STRING_VIAS;
         return;
     }
     bool needsRemainNormalString = false;
-    char16_t c = data.has8BitContent ? ((LChar*)data.buffer)[0] : ((char16_t*)data.buffer)[0];
+    char16_t c = data.charAt(0);
     if ((c == '.' || (c >= '0' && c <= '9')) && data.length > 16) {
         needsRemainNormalString = true;
     }
@@ -896,42 +904,45 @@ ObjectHasPropertyResult Object::hasIndexedProperty(ExecutionState& state, const
     return hasProperty(state, ObjectPropertyName(state, propertyName));
 }
 
+typedef std::pair<Value::ValueIndex, ObjectStructurePropertyDescriptor> IndexItem;
+struct CompareIndexItem {
+    bool operator()(const IndexItem& a, const IndexItem& b) const
+    {
+        return a.first < b.first;
+    }
+};
+
 template <typename ResultType, typename ResultBinder>
 static ResultType objectOwnPropertyKeys(ExecutionState& state, Object* self)
 {
     // https://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys
     struct Properties {
-        VectorWithInlineStorage<32, std::pair<Value::ValueIndex, ObjectStructurePropertyDescriptor>, GCUtil::gc_malloc_allocator<std::pair<Value::ValueIndex, ObjectStructurePropertyDescriptor>>> indexes;
+        std::multiset<IndexItem, CompareIndexItem, GCUtil::gc_malloc_allocator<IndexItem>> indexes;
         VectorWithInlineStorage<32, std::pair<String*, ObjectStructurePropertyDescriptor>, GCUtil::gc_malloc_allocator<std::pair<String*, ObjectStructurePropertyDescriptor>>> strings;
         VectorWithInlineStorage<4, std::pair<Symbol*, ObjectStructurePropertyDescriptor>, GCUtil::gc_malloc_allocator<std::pair<Symbol*, ObjectStructurePropertyDescriptor>>> symbols;
     } properties;
 
-    self->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
-        auto properties = (Properties*)data;
-
-        auto indexProperty = name.tryToUseAsIndexProperty();
-        if (indexProperty != Value::InvalidIndexPropertyValue) {
-            properties->indexes.push_back(std::make_pair(indexProperty, desc));
-        } else {
-            const ObjectStructurePropertyName& propertyName = name.objectStructurePropertyName();
+    self->enumeration(
+        state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) -> bool {
+            auto properties = (Properties*)data;
 
-            if (propertyName.isSymbol()) {
-                properties->symbols.push_back(std::make_pair(propertyName.symbol(), desc));
+            auto indexProperty = name.tryToUseAsIndexProperty();
+            if (indexProperty != Value::InvalidIndexPropertyValue) {
+                properties->indexes.insert(std::make_pair(indexProperty, desc));
             } else {
-                ASSERT(propertyName.isPlainString());
-                String* name = propertyName.plainString();
-                properties->strings.push_back(std::make_pair(name, desc));
-            }
-        }
-        return true;
-    },
-                      &properties, false);
-
-    std::sort(properties.indexes.begin(), properties.indexes.end(),
-              [](const std::pair<Value::ValueIndex, ObjectStructurePropertyDescriptor>& a, const std::pair<Value::ValueIndex, ObjectStructurePropertyDescriptor>& b) -> bool {
-                  return a.first < b.first;
-              });
+                const ObjectStructurePropertyName& propertyName = name.objectStructurePropertyName();
 
+                if (propertyName.isSymbol()) {
+                    properties->symbols.push_back(std::make_pair(propertyName.symbol(), desc));
+                } else {
+                    ASSERT(propertyName.isPlainString());
+                    String* name = propertyName.plainString();
+                    properties->strings.push_back(std::make_pair(name, desc));
+                }
+            }
+            return true;
+        },
+        &properties, false);
 
     ResultType result(properties.indexes.size() + properties.strings.size() + properties.symbols.size());
 
@@ -1007,7 +1018,8 @@ bool Object::set(ExecutionState& state, const ObjectPropertyName& propertyName,
     // 2. Let ownDesc be O.[[GetOwnProperty]](P).
     auto ownDesc = this->getOwnProperty(state, propertyName);
     // 4. If ownDesc is undefined, then
-    if (!ownDesc.hasValue()) {
+    bool hasValue = ownDesc.hasValue();
+    if (!hasValue) {
         // FIXME need to optimize prototype iteration
         // 4.a. Let parent be O.[[GetPrototypeOf]]().
         Value parent = this->getPrototype(state);
@@ -1044,7 +1056,17 @@ bool Object::set(ExecutionState& state, const ObjectPropertyName& propertyName,
 
         // 5.c. Let existingDescriptor be Receiver.[[GetOwnProperty]](P).
         Object* receiverObj = receiver.asObject();
-        auto existingDesc = receiverObj->getOwnProperty(state, propertyName);
+
+        ObjectGetResult existingDesc;
+        if (hasValue && LIKELY(this == receiverObj)) {
+            existingDesc = ownDesc;
+            ObjectPropertyDescriptor propertyDesc(v);
+            // 5.e.iv. Return Receiver.[[DefineOwnProperty]](P, valueDesc).
+            return receiverObj->defineOwnProperty(state, propertyName, propertyDesc);
+        }
+
+        existingDesc = receiverObj->getOwnProperty(state, propertyName);
+
         // 5.e. If existingDescriptor is not undefined, then
         if (existingDesc.hasValue()) {
             // 5.e.i. If IsAccessorDescriptor(existingDescriptor) is true, return false.
@@ -1142,8 +1164,13 @@ Object* Object::getPrototypeFromConstructor(ExecutionState& state, Object* const
     // Assert: IsCallable(constructor) is true.
     ASSERT(constructor->isCallable());
 
-    // Let proto be ? Get(constructor, "prototype").
-    Value proto = constructor->get(state, ObjectPropertyName(state.context()->staticStrings().prototype)).value(state, constructor);
+    Value proto;
+    if (LIKELY(constructor->isFunctionObject())) {
+        proto = constructor->asFunctionObject()->getFunctionPrototype(state);
+    } else {
+        // Let proto be ? Get(constructor, "prototype").
+        proto = constructor->get(state, ObjectPropertyName(state.context()->staticStrings().prototype)).value(state, constructor);
+    }
 
     // If Type(proto) is not Object, then
     if (!proto.isObject()) {
@@ -1560,20 +1587,21 @@ void Object::nextIndexForward(ExecutionState& state, Object* obj, const int64_t
             return;
         }
 
-        ptr.asObject()->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) {
-            int64_t index;
-            Data* e = (Data*)data;
-            int64_t* ret = e->ret;
-            Value key = name.toPlainValue(state);
-            index = key.toNumber(state);
-            if ((uint64_t)index != Value::InvalidIndexValue) {
-                if (index > *e->cur && *ret > index) {
-                    *ret = std::min(index, *ret);
+        ptr.asObject()->enumeration(
+            state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) {
+                int64_t index;
+                Data* e = (Data*)data;
+                int64_t* ret = e->ret;
+                Value key = name.toPlainValue();
+                index = key.toNumber(state);
+                if ((uint64_t)index != Value::InvalidIndexValue) {
+                    if (index > *e->cur && *ret > index) {
+                        *ret = std::min(index, *ret);
+                    }
                 }
-            }
-            return true;
-        },
-                                    &data);
+                return true;
+            },
+            &data);
         ptr = ptr.asObject()->getPrototype(state);
     }
     nextIndex = std::max(ret, cur + 1);
@@ -1595,20 +1623,21 @@ void Object::nextIndexBackward(ExecutionState& state, Object* obj, const int64_t
             nextIndex = std::max(end, cur - 1);
             return;
         }
-        ptr.asObject()->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) {
-            int64_t index;
-            Data* e = (Data*)data;
-            int64_t* ret = e->ret;
-            Value key = name.toPlainValue(state);
-            index = key.toNumber(state);
-            if ((uint64_t)index != Value::InvalidIndexValue) {
-                if (index < *e->cur) {
-                    *ret = std::max(index, *ret);
+        ptr.asObject()->enumeration(
+            state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) {
+                int64_t index;
+                Data* e = (Data*)data;
+                int64_t* ret = e->ret;
+                Value key = name.toPlainValue();
+                index = key.toNumber(state);
+                if ((uint64_t)index != Value::InvalidIndexValue) {
+                    if (index < *e->cur) {
+                        *ret = std::max(index, *ret);
+                    }
                 }
-            }
-            return true;
-        },
-                                    &data);
+                return true;
+            },
+            &data);
         ptr = ptr.asObject()->getPrototype(state);
     }
     nextIndex = std::min(ret, cur - 1);
@@ -2052,11 +2081,13 @@ void Object::addFinalizer(ObjectFinalizer fn, void* data)
         rareData()->m_isFinalizerRegistered = true;
 
 #define FINALIZER_CALLBACK()                                     \
+    GC_disable();                                                \
     Object* self = (Object*)obj;                                 \
     auto r = self->ensureObjectExtendedExtraData();              \
     for (size_t i = 0; i < r->m_finalizer.size(); i++) {         \
         r->m_finalizer[i].first(self, r->m_finalizer[i].second); \
-    }
+    }                                                            \
+    GC_enable();
 
 #ifndef NDEBUG
         GC_finalization_proc of = nullptr;
@@ -2091,4 +2122,34 @@ bool Object::removeFinalizer(ObjectFinalizer fn, void* data)
     return false;
 }
 
+Object::FastLookupSymbolResult Object::fastLookupForSymbol(ExecutionState& state, Symbol* s, Optional<Object*> protochainSearchStopAt)
+{
+    ObjectStructurePropertyName name(s);
+    Object* obj = this;
+    while (true) {
+        if (protochainSearchStopAt.unwrap() == obj) {
+            return FastLookupSymbolResult(true, obj, SIZE_MAX);
+        }
+
+        if (!obj->isInlineCacheable()) {
+            break;
+        }
+
+        auto structure = obj->structure();
+        if (structure->hasSymbolPropertyName()) {
+            auto ret = structure->findProperty(name).first;
+            if (ret != SIZE_MAX) {
+                return FastLookupSymbolResult(true, obj, ret);
+            }
+        }
+        obj = obj->Object::getPrototypeObject(state);
+        if (!obj) {
+            return FastLookupSymbolResult(true, nullptr, SIZE_MAX);
+        }
+    }
+
+    // fast path was failed
+    return FastLookupSymbolResult();
+}
+
 } // namespace Escargot
index 7cdd8b0bd2770b281fe67582f94a66dd7bd693ef..c791291d6d2ebe1569134de97d4055dfe4d0f663 100644 (file)
@@ -231,7 +231,7 @@ public:
         return objectStructurePropertyName().tryToUseAsIndexProperty();
     }
 
-    Value toPlainValue(ExecutionState&) const
+    Value toPlainValue() const
     {
         if (isUIntType()) {
             return Value(uintValue());
@@ -796,6 +796,12 @@ public:
         return hasRareData() ? rareData()->m_isExtensible : true;
     }
 
+    // represent that this Object has its own enumeration function other than Object::enumeration
+    virtual bool hasOwnEnumeration() const
+    {
+        return false;
+    }
+
     // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-ordinary-object-internal-methods-and-internal-slots-preventextensions
     virtual bool preventExtensions(ExecutionState&)
     {
@@ -859,7 +865,7 @@ public:
     // callback function should skip un-Enumerable property if needs
     virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey = true);
     // ToLength(Get(obj, "length"))
-    uint64_t length(ExecutionState& state);
+    virtual uint64_t length(ExecutionState& state);
 
     // https://www.ecma-international.org/ecma-262/10.0/#sec-isarray
     bool isArray(ExecutionState& state);
@@ -1110,6 +1116,52 @@ public:
     void addFinalizer(ObjectFinalizer fn, void* data);
     bool removeFinalizer(ObjectFinalizer fn, void* data);
 
+    struct FastLookupSymbolResult {
+        FastLookupSymbolResult()
+            : m_wasSucessful(false)
+            , m_propertyIndexInStructure(0)
+        {
+        }
+
+        FastLookupSymbolResult(bool wasSucessful, Object* o, size_t idx)
+            : m_wasSucessful(wasSucessful)
+            , m_matchedObject(o)
+            , m_propertyIndexInStructure(idx)
+        {
+        }
+
+        bool wasSucessful() const
+        {
+            return m_wasSucessful;
+        }
+
+        Optional<Object*> matchedObject() const
+        {
+            return m_matchedObject;
+        }
+
+        size_t propertyIndexInStructure() const
+        {
+            return m_propertyIndexInStructure;
+        }
+
+        Value value(ExecutionState& state, Object* receiver)
+        {
+            ASSERT(wasSucessful());
+            if (m_matchedObject) {
+                return m_matchedObject->getOwnPropertyUtilForObject(state, m_propertyIndexInStructure, Value(receiver));
+            } else {
+                return Value();
+            }
+        }
+
+    private:
+        bool m_wasSucessful;
+        Optional<Object*> m_matchedObject;
+        size_t m_propertyIndexInStructure;
+    };
+    FastLookupSymbolResult fastLookupForSymbol(ExecutionState& state, Symbol* s, Optional<Object*> protochainSearchStopAt = nullptr);
+
 protected:
     static inline void fillGCDescriptor(GC_word* desc)
     {
@@ -1203,7 +1255,7 @@ protected:
     }
 
     Value getOwnPropertyUtilForObjectAccCase(ExecutionState& state, size_t idx, const Value& receiver);
-    ALWAYS_INLINE Value getOwnPropertyUtilForObject(ExecutionState& state, size_t idx, const Value& receiver)
+    Value getOwnPropertyUtilForObject(ExecutionState& state, size_t idx, const Value& receiver)
     {
         const ObjectStructureItem& item = m_structure->readProperty(idx);
         if (LIKELY(item.m_descriptor.isDataProperty())) {
@@ -1217,6 +1269,17 @@ protected:
         }
     }
 
+    NEVER_INLINE Value getOwnNonPlainDataPropertyUtilForObject(ExecutionState& state, size_t idx, const Value& receiver)
+    {
+        const ObjectStructureItem& item = m_structure->readProperty(idx);
+        if (LIKELY(item.m_descriptor.isDataProperty())) {
+            ASSERT(!item.m_descriptor.isPlainDataProperty());
+            return item.m_descriptor.nativeGetterSetterData()->m_getter(state, this, receiver, m_values[idx]);
+        } else {
+            return getOwnPropertyUtilForObjectAccCase(state, idx, receiver);
+        }
+    }
+
     bool setOwnPropertyUtilForObjectAccCase(ExecutionState& state, size_t idx, const Value& newValue, const Value& receiver);
     ALWAYS_INLINE bool setOwnPropertyUtilForObject(ExecutionState& state, size_t idx, const Value& newValue, const Value& receiver)
     {
index 1f011cb4b5b7c14f1c468882df94fb5dcaca8c63..94b2d115090e194cb8535cf7482146bcc109fa30 100644 (file)
@@ -52,17 +52,27 @@ std::pair<size_t, Optional<const ObjectStructureItem*>> ObjectStructureWithoutTr
 {
     size_t size = m_properties->size();
 
-    if (LIKELY(s.hasAtomicString() && !m_hasNonAtomicPropertyName)) {
-        for (size_t i = 0; i < size; i++) {
-            if ((*m_properties)[i].m_propertyName.rawValue() == s.rawValue()) {
-                return std::make_pair(i, &(*m_properties)[i]);
+    if (LIKELY(s.hasAtomicString())) {
+        if (LIKELY(!m_hasNonAtomicPropertyName)) {
+            for (size_t i = 0; i < size; i++) {
+                if ((*m_properties)[i].m_propertyName.rawValue() == s.rawValue()) {
+                    return std::make_pair(i, &(*m_properties)[i]);
+                }
+            }
+        } else {
+            AtomicString as = s.asAtomicString();
+            for (size_t i = 0; i < size; i++) {
+                if ((*m_properties)[i].m_propertyName == as) {
+                    return std::make_pair(i, &(*m_properties)[i]);
+                }
             }
         }
-    } else if (LIKELY(s.hasAtomicString())) {
-        AtomicString as = s.asAtomicString();
-        for (size_t i = 0; i < size; i++) {
-            if ((*m_properties)[i].m_propertyName == as) {
-                return std::make_pair(i, &(*m_properties)[i]);
+    } else if (s.isSymbol()) {
+        if (m_hasSymbolPropertyName) {
+            for (size_t i = 0; i < size; i++) {
+                if ((*m_properties)[i].m_propertyName == s) {
+                    return std::make_pair(i, &(*m_properties)[i]);
+                }
             }
         }
     } else {
@@ -95,14 +105,16 @@ ObjectStructure* ObjectStructureWithoutTransition::addProperty(const ObjectStruc
 {
     ObjectStructureItem newItem(name, desc);
     bool nameIsIndexString = m_hasIndexPropertyName ? true : name.isIndexString();
+    bool nameIsSymbol = m_hasSymbolPropertyName ? true : name.isSymbol();
     bool hasNonAtomicName = m_hasNonAtomicPropertyName ? true : !name.hasAtomicString();
+    bool hasEnumerableProperty = m_hasEnumerableProperty ? true : desc.isEnumerable();
     ObjectStructure* newStructure;
     m_properties->push_back(newItem);
 
     if (m_properties->size() + 1 > ESCARGOT_OBJECT_STRUCTURE_ACCESS_CACHE_BUILD_MIN_SIZE) {
-        newStructure = new ObjectStructureWithMap(m_properties, ObjectStructureWithMap::createPropertyNameMap(m_properties), m_hasIndexPropertyName || nameIsIndexString);
+        newStructure = new ObjectStructureWithMap(m_properties, ObjectStructureWithMap::createPropertyNameMap(m_properties), nameIsIndexString, nameIsSymbol, hasEnumerableProperty);
     } else {
-        newStructure = new ObjectStructureWithoutTransition(m_properties, nameIsIndexString, hasNonAtomicName);
+        newStructure = new ObjectStructureWithoutTransition(m_properties, nameIsIndexString, nameIsSymbol, hasNonAtomicName, hasEnumerableProperty);
     }
 
     m_properties = nullptr;
@@ -117,18 +129,22 @@ ObjectStructure* ObjectStructureWithoutTransition::removeProperty(size_t pIndex)
 
     size_t newIdx = 0;
     bool hasIndexString = false;
+    bool hasSymbol = false;
     bool hasNonAtomicName = false;
+    bool hasEnumerableProperty = false;
     for (size_t i = 0; i < ps; i++) {
         if (i == pIndex)
             continue;
         hasIndexString = hasIndexString | (*m_properties)[i].m_propertyName.isIndexString();
+        hasSymbol = hasSymbol | (*m_properties)[i].m_propertyName.isSymbol();
         hasNonAtomicName = hasNonAtomicName | !(*m_properties)[i].m_propertyName.hasAtomicString();
+        hasEnumerableProperty = hasEnumerableProperty | (*m_properties)[i].m_descriptor.isEnumerable();
         (*newProperties)[newIdx].m_propertyName = (*m_properties)[i].m_propertyName;
         (*newProperties)[newIdx].m_descriptor = (*m_properties)[i].m_descriptor;
         newIdx++;
     }
 
-    auto newStructure = new ObjectStructureWithoutTransition(newProperties, hasIndexString, hasNonAtomicName);
+    auto newStructure = new ObjectStructureWithoutTransition(newProperties, hasIndexString, hasSymbol, hasNonAtomicName, hasEnumerableProperty);
     m_properties = nullptr;
     return newStructure;
 }
@@ -136,7 +152,7 @@ ObjectStructure* ObjectStructureWithoutTransition::removeProperty(size_t pIndex)
 ObjectStructure* ObjectStructureWithoutTransition::replacePropertyDescriptor(size_t idx, const ObjectStructurePropertyDescriptor& newDesc)
 {
     m_properties->at(idx).m_descriptor = newDesc;
-    auto newStructure = new ObjectStructureWithoutTransition(m_properties, m_hasIndexPropertyName, m_hasNonAtomicPropertyName);
+    auto newStructure = new ObjectStructureWithoutTransition(m_properties, m_hasIndexPropertyName, m_hasSymbolPropertyName, m_hasNonAtomicPropertyName, m_hasEnumerableProperty);
     m_properties = nullptr;
     return newStructure;
 }
@@ -164,17 +180,27 @@ std::pair<size_t, Optional<const ObjectStructureItem*>> ObjectStructureWithTrans
 {
     size_t size = m_properties.size();
 
-    if (LIKELY(s.hasAtomicString() && !m_hasNonAtomicPropertyName)) {
-        for (size_t i = 0; i < size; i++) {
-            if (m_properties[i].m_propertyName.rawValue() == s.rawValue()) {
-                return std::make_pair(i, &m_properties[i]);
+    if (LIKELY(s.hasAtomicString())) {
+        if (LIKELY(!m_hasNonAtomicPropertyName)) {
+            for (size_t i = 0; i < size; i++) {
+                if (m_properties[i].m_propertyName.rawValue() == s.rawValue()) {
+                    return std::make_pair(i, &m_properties[i]);
+                }
+            }
+        } else {
+            AtomicString as = s.asAtomicString();
+            for (size_t i = 0; i < size; i++) {
+                if (m_properties[i].m_propertyName == as) {
+                    return std::make_pair(i, &m_properties[i]);
+                }
             }
         }
-    } else if (LIKELY(s.hasAtomicString())) {
-        AtomicString as = s.asAtomicString();
-        for (size_t i = 0; i < size; i++) {
-            if (m_properties[i].m_propertyName == as) {
-                return std::make_pair(i, &m_properties[i]);
+    } else if (s.isSymbol()) {
+        if (m_hasSymbolPropertyName) {
+            for (size_t i = 0; i < size; i++) {
+                if (m_properties[i].m_propertyName == s) {
+                    return std::make_pair(i, &m_properties[i]);
+                }
             }
         }
     } else {
@@ -222,18 +248,20 @@ ObjectStructure* ObjectStructureWithTransition::addProperty(const ObjectStructur
 
     ObjectStructureItem newItem(name, desc);
     bool nameIsIndexString = m_hasIndexPropertyName ? true : name.isIndexString();
+    bool hasSymbol = m_hasSymbolPropertyName ? true : name.isSymbol();
     bool hasNonAtomicName = m_hasNonAtomicPropertyName ? true : !name.hasAtomicString();
+    bool hasEnumerableProperty = m_hasEnumerableProperty ? true : desc.isEnumerable();
     ObjectStructure* newObjectStructure;
 
     size_t nextSize = m_properties.size() + 1;
     if (nextSize > ESCARGOT_OBJECT_STRUCTURE_ACCESS_CACHE_BUILD_MIN_SIZE) {
-        newObjectStructure = new ObjectStructureWithMap(nameIsIndexString, m_properties, newItem);
+        newObjectStructure = new ObjectStructureWithMap(nameIsIndexString, hasSymbol, hasEnumerableProperty, m_properties, newItem);
     } else if (nextSize > ESCARGOT_OBJECT_STRUCTURE_TRANSITION_MODE_MAX_SIZE) {
         ObjectStructureItemVector* newProperties = new ObjectStructureItemVector(m_properties, newItem);
-        newObjectStructure = new ObjectStructureWithoutTransition(newProperties, nameIsIndexString, hasNonAtomicName);
+        newObjectStructure = new ObjectStructureWithoutTransition(newProperties, nameIsIndexString, hasSymbol, hasNonAtomicName, hasEnumerableProperty);
     } else {
         ObjectStructureItemTightVector newProperties(m_properties, newItem);
-        newObjectStructure = new ObjectStructureWithTransition(std::move(newProperties), nameIsIndexString, hasNonAtomicName);
+        newObjectStructure = new ObjectStructureWithTransition(std::move(newProperties), nameIsIndexString, hasSymbol, hasNonAtomicName, hasEnumerableProperty);
         ObjectStructureTransitionVectorItem newTransitionItem(name, desc, newObjectStructure);
 
         if (m_doesTransitionTableUseMap) {
@@ -276,31 +304,35 @@ ObjectStructure* ObjectStructureWithTransition::removeProperty(size_t pIndex)
 
     size_t newIdx = 0;
     bool hasIndexString = false;
+    bool hasSymbol = false;
     bool hasNonAtomicName = false;
+    bool hasEnumerableProperty = false;
     for (size_t i = 0; i < pc; i++) {
         if (i == pIndex)
             continue;
         hasIndexString = hasIndexString | m_properties[i].m_propertyName.isIndexString();
+        hasSymbol = hasSymbol | m_properties[i].m_propertyName.isSymbol();
         hasNonAtomicName = hasNonAtomicName | !m_properties[i].m_propertyName.hasAtomicString();
+        hasEnumerableProperty = hasEnumerableProperty | m_properties[i].m_descriptor.isEnumerable();
         (*newProperties)[newIdx].m_propertyName = m_properties[i].m_propertyName;
         (*newProperties)[newIdx].m_descriptor = m_properties[i].m_descriptor;
         newIdx++;
     }
 
-    return new ObjectStructureWithoutTransition(newProperties, hasIndexString, hasNonAtomicName);
+    return new ObjectStructureWithoutTransition(newProperties, hasIndexString, hasSymbol, hasNonAtomicName, hasEnumerableProperty);
 }
 
 ObjectStructure* ObjectStructureWithTransition::replacePropertyDescriptor(size_t idx, const ObjectStructurePropertyDescriptor& newDesc)
 {
     ObjectStructureItemVector* newProperties = new ObjectStructureItemVector(m_properties);
     newProperties->at(idx).m_descriptor = newDesc;
-    return new ObjectStructureWithoutTransition(newProperties, m_hasIndexPropertyName, m_hasNonAtomicPropertyName);
+    return new ObjectStructureWithoutTransition(newProperties, m_hasIndexPropertyName, m_hasSymbolPropertyName, m_hasNonAtomicPropertyName, m_hasEnumerableProperty);
 }
 
 ObjectStructure* ObjectStructureWithTransition::convertToNonTransitionStructure()
 {
     ObjectStructureItemVector* newProperties = new ObjectStructureItemVector(m_properties);
-    return new ObjectStructureWithoutTransition(newProperties, m_hasIndexPropertyName, m_hasNonAtomicPropertyName);
+    return new ObjectStructureWithoutTransition(newProperties, m_hasIndexPropertyName, m_hasSymbolPropertyName, m_hasNonAtomicPropertyName, m_hasEnumerableProperty);
 }
 
 void* ObjectStructureWithMap::operator new(size_t size)
@@ -346,10 +378,12 @@ ObjectStructure* ObjectStructureWithMap::addProperty(const ObjectStructureProper
 {
     ObjectStructureItem newItem(name, desc);
     bool nameIsIndexString = m_hasIndexPropertyName ? true : name.isIndexString();
+    bool hasSymbol = m_hasSymbolPropertyName ? true : name.isSymbol();
+    bool hasEnumerableProperty = m_hasEnumerableProperty ? true : desc.isEnumerable();
 
     m_propertyNameMap->insert(std::make_pair(name, m_properties->size()));
     m_properties->push_back(newItem);
-    ObjectStructure* newStructure = new ObjectStructureWithMap(m_properties, m_propertyNameMap, nameIsIndexString);
+    ObjectStructure* newStructure = new ObjectStructureWithMap(m_properties, m_propertyNameMap, nameIsIndexString, hasSymbol, hasEnumerableProperty);
     m_properties = nullptr;
     m_propertyNameMap = nullptr;
     return newStructure;
@@ -363,16 +397,20 @@ ObjectStructure* ObjectStructureWithMap::removeProperty(size_t pIndex)
 
     size_t newIdx = 0;
     bool hasIndexString = false;
+    bool hasSymbol = false;
+    bool hasEnumerableProperty = false;
     for (size_t i = 0; i < ps; i++) {
         if (i == pIndex)
             continue;
         hasIndexString = hasIndexString | (*m_properties)[i].m_propertyName.isIndexString();
+        hasSymbol = hasSymbol | (*m_properties)[i].m_propertyName.isSymbol();
+        hasEnumerableProperty = hasEnumerableProperty | (*m_properties)[i].m_descriptor.isEnumerable();
         (*newProperties)[newIdx].m_propertyName = (*m_properties)[i].m_propertyName;
         (*newProperties)[newIdx].m_descriptor = (*m_properties)[i].m_descriptor;
         newIdx++;
     }
 
-    ObjectStructure* newStructure = new ObjectStructureWithMap(newProperties, ObjectStructureWithMap::createPropertyNameMap(newProperties), hasIndexString);
+    ObjectStructure* newStructure = new ObjectStructureWithMap(newProperties, ObjectStructureWithMap::createPropertyNameMap(newProperties), hasIndexString, hasSymbol, hasEnumerableProperty);
     m_properties = nullptr;
     m_propertyNameMap = nullptr;
     return newStructure;
@@ -381,7 +419,7 @@ ObjectStructure* ObjectStructureWithMap::removeProperty(size_t pIndex)
 ObjectStructure* ObjectStructureWithMap::replacePropertyDescriptor(size_t idx, const ObjectStructurePropertyDescriptor& newDesc)
 {
     m_properties->at(idx).m_descriptor = newDesc;
-    ObjectStructure* newStructure = new ObjectStructureWithMap(m_properties, m_propertyNameMap, m_hasIndexPropertyName);
+    ObjectStructure* newStructure = new ObjectStructureWithMap(m_properties, m_propertyNameMap, m_hasIndexPropertyName, m_hasSymbolPropertyName, m_hasEnumerableProperty);
     m_properties = nullptr;
     m_propertyNameMap = nullptr;
     return newStructure;
index 45e603a62f473b61eb40f6b9366095627e80b2ff..528e0af1773147d67b009c1479ad4e54f78657ef 100644 (file)
@@ -101,14 +101,26 @@ public:
 };
 
 #if defined(ESCARGOT_SMALL_CONFIG)
+#ifndef ESCARGOT_OBJECT_STRUCTURE_ACCESS_CACHE_BUILD_MIN_SIZE
 #define ESCARGOT_OBJECT_STRUCTURE_ACCESS_CACHE_BUILD_MIN_SIZE 256
+#endif
+#ifndef ESCARGOT_OBJECT_STRUCTURE_TRANSITION_MODE_MAX_SIZE
 #define ESCARGOT_OBJECT_STRUCTURE_TRANSITION_MODE_MAX_SIZE 12
+#endif
+#ifndef ESCARGOT_OBJECT_STRUCTURE_TRANSITION_MAP_MIN_SIZE
 #define ESCARGOT_OBJECT_STRUCTURE_TRANSITION_MAP_MIN_SIZE 32
+#endif
 #else
+#ifndef ESCARGOT_OBJECT_STRUCTURE_ACCESS_CACHE_BUILD_MIN_SIZE
 #define ESCARGOT_OBJECT_STRUCTURE_ACCESS_CACHE_BUILD_MIN_SIZE 96
+#endif
+#ifndef ESCARGOT_OBJECT_STRUCTURE_TRANSITION_MODE_MAX_SIZE
 #define ESCARGOT_OBJECT_STRUCTURE_TRANSITION_MODE_MAX_SIZE 48
+#endif
+#ifndef ESCARGOT_OBJECT_STRUCTURE_TRANSITION_MAP_MIN_SIZE
 #define ESCARGOT_OBJECT_STRUCTURE_TRANSITION_MAP_MIN_SIZE 32
 #endif
+#endif
 
 class ObjectStructure : public gc {
 public:
@@ -134,16 +146,65 @@ public:
     virtual ObjectStructure* replacePropertyDescriptor(size_t idx, const ObjectStructurePropertyDescriptor& newDesc) = 0;
 
     virtual ObjectStructure* convertToNonTransitionStructure() = 0;
-
     virtual bool inTransitionMode() = 0;
-    virtual bool hasIndexPropertyName() = 0;
+
+    bool hasIndexPropertyName() const
+    {
+        return m_hasIndexPropertyName;
+    }
+
+    bool hasSymbolPropertyName() const
+    {
+        return m_hasSymbolPropertyName;
+    }
+
+    bool hasEnumerableProperty() const
+    {
+        return m_hasEnumerableProperty;
+    }
+
+protected:
+    ObjectStructure(bool hasIndexPropertyName,
+                    bool hasSymbolPropertyName, bool hasEnumerableProperty)
+        : m_doesTransitionTableUseMap(false)
+        , m_hasIndexPropertyName(hasIndexPropertyName)
+        , m_hasSymbolPropertyName(hasSymbolPropertyName)
+        , m_hasNonAtomicPropertyName(false)
+        , m_hasEnumerableProperty(hasEnumerableProperty)
+        , m_transitionTableVectorBufferSize(0)
+        , m_transitionTableVectorBufferCapacity(0)
+    {
+    }
+
+    ObjectStructure(bool hasIndexPropertyName,
+                    bool hasSymbolPropertyName, bool hasNonAtomicPropertyName, bool hasEnumerableProperty)
+        : m_doesTransitionTableUseMap(false)
+        , m_hasIndexPropertyName(hasIndexPropertyName)
+        , m_hasSymbolPropertyName(hasSymbolPropertyName)
+        , m_hasNonAtomicPropertyName(hasNonAtomicPropertyName)
+        , m_hasEnumerableProperty(hasEnumerableProperty)
+        , m_transitionTableVectorBufferSize(0)
+        , m_transitionTableVectorBufferCapacity(0)
+    {
+    }
+
+    // every class should share flag members
+    // this way can reduce size of ObjectStructureWithTransition
+    bool m_doesTransitionTableUseMap : 1;
+    bool m_hasIndexPropertyName : 1;
+    bool m_hasSymbolPropertyName : 1;
+    bool m_hasNonAtomicPropertyName : 1;
+    bool m_hasEnumerableProperty : 1;
+    uint8_t m_transitionTableVectorBufferSize : 8;
+    uint8_t m_transitionTableVectorBufferCapacity : 8;
 };
 
 class ObjectStructureWithoutTransition : public ObjectStructure {
 public:
-    ObjectStructureWithoutTransition(ObjectStructureItemVector* properties, bool hasIndexPropertyName, bool hasNonAtomicPropertyName)
-        : m_hasIndexPropertyName(hasIndexPropertyName)
-        , m_hasNonAtomicPropertyName(hasNonAtomicPropertyName)
+    ObjectStructureWithoutTransition(ObjectStructureItemVector* properties, bool hasIndexPropertyName,
+                                     bool hasSymbolPropertyName, bool hasNonAtomicPropertyName, bool hasEnumerableProperty)
+        : ObjectStructure(hasIndexPropertyName,
+                          hasSymbolPropertyName, hasNonAtomicPropertyName, hasEnumerableProperty)
         , m_properties(properties)
     {
     }
@@ -162,29 +223,19 @@ public:
         return false;
     }
 
-    virtual bool hasIndexPropertyName() override
-    {
-        return m_hasIndexPropertyName;
-    }
-
     void* operator new(size_t size);
     void* operator new[](size_t size) = delete;
 
 private:
-    bool m_hasIndexPropertyName;
-    bool m_hasNonAtomicPropertyName;
     ObjectStructureItemVector* m_properties;
 };
 
 class ObjectStructureWithTransition : public ObjectStructure {
 public:
-    ObjectStructureWithTransition(ObjectStructureItemTightVector&& properties, bool hasIndexPropertyName, bool hasNonAtomicPropertyName)
-        : m_properties(std::move(properties))
-        , m_doesTransitionTableUseMap(false)
-        , m_hasIndexPropertyName(hasIndexPropertyName)
-        , m_hasNonAtomicPropertyName(hasNonAtomicPropertyName)
-        , m_transitionTableVectorBufferSize(0)
-        , m_transitionTableVectorBufferCapacity(0)
+    ObjectStructureWithTransition(ObjectStructureItemTightVector&& properties, bool hasIndexPropertyName, bool hasSymbolPropertyName, bool hasNonAtomicPropertyName, bool hasEnumerableProperty)
+        : ObjectStructure(hasIndexPropertyName,
+                          hasSymbolPropertyName, hasNonAtomicPropertyName, hasEnumerableProperty)
+        , m_properties(std::move(properties))
         , m_transitionTableVectorBuffer(nullptr)
     {
     }
@@ -203,11 +254,6 @@ public:
         return true;
     }
 
-    virtual bool hasIndexPropertyName() override
-    {
-        return m_hasIndexPropertyName;
-    }
-
     void* operator new(size_t size);
     void* operator new[](size_t size) = delete;
 
@@ -222,13 +268,6 @@ private:
     }
 
     ObjectStructureItemTightVector m_properties;
-
-    bool m_doesTransitionTableUseMap : 1;
-    bool m_hasIndexPropertyName : 1;
-    bool m_hasNonAtomicPropertyName : 1;
-    uint8_t m_transitionTableVectorBufferSize;
-    uint8_t m_transitionTableVectorBufferCapacity;
-
     union {
         ObjectStructureTransitionVectorItem* m_transitionTableVectorBuffer;
         ObjectStructureTransitionTableMap* m_transitionTableMap;
@@ -240,16 +279,19 @@ COMPILE_ASSERT(sizeof(ObjectStructureWithTransition) == sizeof(size_t) * 5, "");
 
 class ObjectStructureWithMap : public ObjectStructure {
 public:
-    ObjectStructureWithMap(ObjectStructureItemVector* properties, PropertyNameMap* map, bool hasIndexPropertyName)
-        : m_hasIndexPropertyName(hasIndexPropertyName)
+    ObjectStructureWithMap(ObjectStructureItemVector* properties, PropertyNameMap* map, bool hasIndexPropertyName, bool hasSymbolPropertyName, bool hasEnumerableProperty)
+        : ObjectStructure(hasIndexPropertyName,
+                          hasSymbolPropertyName, hasEnumerableProperty)
         , m_properties(properties)
         , m_propertyNameMap(map)
     {
     }
 
     template <typename SourceProperties>
-    ObjectStructureWithMap(bool hasIndexPropertyName, const SourceProperties& properties, const ObjectStructureItem& newItem)
-        : m_hasIndexPropertyName(hasIndexPropertyName)
+    ObjectStructureWithMap(bool hasIndexPropertyName, bool hasSymbolPropertyName, bool hasEnumerableProperty, const SourceProperties& properties, const ObjectStructureItem& newItem)
+        : ObjectStructure(hasIndexPropertyName,
+                          hasSymbolPropertyName, hasEnumerableProperty)
+
     {
         ObjectStructureItemVector* newProperties = new ObjectStructureItemVector();
         newProperties->resizeWithUninitializedValues(properties.size() + 1);
@@ -260,8 +302,10 @@ public:
         m_propertyNameMap = ObjectStructureWithMap::createPropertyNameMap(newProperties);
     }
 
-    ObjectStructureWithMap(bool hasIndexPropertyName, const ObjectStructureItemTightVector& properties)
-        : m_hasIndexPropertyName(hasIndexPropertyName)
+    ObjectStructureWithMap(bool hasIndexPropertyName, bool hasSymbolPropertyName, bool hasEnumerableProperty, const ObjectStructureItemTightVector& properties)
+        : ObjectStructure(hasIndexPropertyName,
+                          hasSymbolPropertyName, hasEnumerableProperty)
+
     {
         ObjectStructureItemVector* newProperties = new ObjectStructureItemVector();
         newProperties->resizeWithUninitializedValues(properties.size());
@@ -271,8 +315,9 @@ public:
         m_propertyNameMap = ObjectStructureWithMap::createPropertyNameMap(newProperties);
     }
 
-    ObjectStructureWithMap(bool hasIndexPropertyName, ObjectStructureItemTightVector&& properties)
-        : m_hasIndexPropertyName(hasIndexPropertyName)
+    ObjectStructureWithMap(bool hasIndexPropertyName, bool hasSymbolPropertyName, bool hasEnumerableProperty, ObjectStructureItemTightVector&& properties)
+        : ObjectStructure(hasIndexPropertyName,
+                          hasSymbolPropertyName, hasEnumerableProperty)
     {
         m_properties = new ObjectStructureItemVector(std::move(properties));
         m_propertyNameMap = ObjectStructureWithMap::createPropertyNameMap(m_properties);
@@ -291,10 +336,6 @@ public:
     {
         return false;
     }
-    virtual bool hasIndexPropertyName() override
-    {
-        return m_hasIndexPropertyName;
-    }
 
     void* operator new(size_t size);
     void* operator new[](size_t size) = delete;
@@ -312,7 +353,6 @@ public:
     }
 
 private:
-    bool m_hasIndexPropertyName;
     ObjectStructureItemVector* m_properties;
     PropertyNameMap* m_propertyNameMap;
 };
index a48947da4db90641004133eebc3b56bddb5e4d2d..95ffec2e2456cded6a3fcb1f9fe572c8a8331ed7 100644 (file)
 
 namespace Escargot {
 
-void* ObjectTemplate::operator new(size_t size)
-{
-    static MAY_THREAD_LOCAL bool typeInited = false;
-    static MAY_THREAD_LOCAL GC_descr descr;
-    if (!typeInited) {
-        GC_word objBitmap[GC_BITMAP_SIZE(ObjectTemplate)] = { 0 };
-        Template::fillGCDescriptor(objBitmap);
-        GC_set_bit(objBitmap, GC_WORD_OFFSET(ObjectTemplate, m_constructor));
-        GC_set_bit(objBitmap, GC_WORD_OFFSET(ObjectTemplate, m_namedPropertyHandler));
-        descr = GC_make_descriptor(objBitmap, GC_WORD_LEN(ObjectTemplate));
-        typeInited = true;
+class ObjectTemplatePropertyHandlerData : public gc {
+    friend class ObjectWithPropertyHandler;
+
+public:
+    explicit ObjectTemplatePropertyHandlerData(const ObjectTemplatePropertyHandlerConfiguration& data)
+        : m_getter(data.getter)
+        , m_setter(data.setter)
+        , m_query(data.query)
+        , m_deleter(data.deleter)
+        , m_enumerator(data.enumerator)
+        , m_definer(data.definer)
+        , m_descriptor(data.descriptor)
+        , m_data(data.data)
+    {
     }
-    return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
-}
 
-ObjectTemplate::ObjectTemplate(Optional<FunctionTemplate*> constructor)
-    : m_constructor(constructor)
-    , m_namedPropertyHandler(nullptr)
-{
-}
+    void* operator new(size_t size)
+    {
+        static MAY_THREAD_LOCAL bool typeInited = false;
+        static MAY_THREAD_LOCAL GC_descr descr;
+        if (!typeInited) {
+            // only mark m_data
+            GC_word obj_bitmap[GC_BITMAP_SIZE(ObjectTemplatePropertyHandlerData)] = { 0 };
+            GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ObjectTemplatePropertyHandlerData, m_data));
+            descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(ObjectTemplatePropertyHandlerData));
+            typeInited = true;
+        }
+        return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
+    }
+
+private:
+    PropertyHandlerGetterCallback m_getter;
+    PropertyHandlerSetterCallback m_setter;
+    PropertyHandlerQueryCallback m_query;
+    PropertyHandlerDeleteCallback m_deleter;
+    PropertyHandlerEnumerationCallback m_enumerator;
+    PropertyHandlerDefineOwnPropertyCallback m_definer;
+    PropertyHandlerGetPropertyDescriptorCallback m_descriptor;
+    void* m_data;
+};
 
-class ObjectWithNamedPropertyHandler : public Object {
+class ObjectWithPropertyHandler : public Object {
 public:
-    ObjectWithNamedPropertyHandler(ObjectStructure* structure, ObjectPropertyValueVector&& values, Object* proto, ObjectTemplateNamedPropertyHandlerData* data)
+    ObjectWithPropertyHandler(ObjectStructure* structure, ObjectPropertyValueVector&& values, Object* proto, ObjectTemplatePropertyHandlerData* namedData, ObjectTemplatePropertyHandlerData* indexedData)
         : Object(structure, std::move(values), proto)
-        , m_data(data)
+        , m_namedPropertyHandler(namedData)
+        , m_indexedPropertyHandler(indexedData)
     {
+        ASSERT(namedData || indexedData);
     }
 
     virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override
     {
-        if (!P.isIndexString() && m_data->getter) {
-            OptionalRef<ValueRef> ret(m_data->getter(toRef(&state), toRef(this), toRef(this), m_data->data,
-                                                     toRef(P.toPropertyKeyValue())));
-
-            if (ret) {
-                if (m_data->query) {
-                    auto attr = m_data->query(toRef(&state), toRef(this), toRef(this), m_data->data,
-                                              toRef(P.toPropertyKeyValue()));
-                    return ObjectGetResult(toImpl(ret.value()), attr & TemplatePropertyAttribute::TemplatePropertyAttributeWritable, attr & TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable, attr & TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable);
+        ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
+        if (propertyHandler && propertyHandler->m_getter) {
+            auto ret = propertyHandler->m_getter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
+                                                 toRef(P.toPlainValue()));
+
+            if (ret.hasValue()) {
+                if (propertyHandler->m_query) {
+                    auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
+                                                         toRef(P.toPlainValue()));
+                    return ObjectGetResult(toImpl(ret.value()), attr & ObjectTemplatePropertyAttribute::PropertyAttributeWritable, attr & ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable, attr & ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
                 } else {
                     return ObjectGetResult(toImpl(ret.value()), true, true, true);
                 }
             }
         }
+
         return Object::getOwnProperty(state, P);
     }
 
     virtual Value getOwnPropertyDescriptor(ExecutionState& state, const ObjectPropertyName& P) override
     {
-        if (m_data->descriptor) {
-            auto ret = m_data->descriptor(toRef(&state), toRef(this), toRef(this), m_data->data,
-                                          toRef(P.toPropertyKeyValue()));
+        ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
+        if (propertyHandler && propertyHandler->m_descriptor) {
+            auto ret = propertyHandler->m_descriptor(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
+                                                     toRef(P.toPlainValue()));
             if (ret.hasValue()) {
                 return toImpl(ret.value());
-            } else {
-                return Object::getOwnPropertyDescriptor(state, P);
             }
-        } else {
-            return Object::getOwnPropertyDescriptor(state, P);
         }
+
+        return Object::getOwnPropertyDescriptor(state, P);
     }
 
     virtual bool defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) override
     {
-        if (!P.isIndexString()) {
-            if (m_data->definer) {
-                auto ret = m_data->definer(toRef(&state), toRef(this), toRef(this), m_data->data, toRef(P.toPropertyKeyValue()), ObjectPropertyDescriptorRef((void*)&desc));
+        ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
+        if (propertyHandler) {
+            if (propertyHandler->m_definer) {
+                auto ret = propertyHandler->m_definer(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data, toRef(P.toPlainValue()), ObjectPropertyDescriptorRef((void*)&desc));
                 if (ret.hasValue()) {
                     return ret.value()->toBoolean(toRef(&state));
                 }
-            } else if (m_data->setter && desc.isValuePresent() && desc.isWritable() && desc.isEnumerable() && desc.isConfigurable()) {
-                auto ret = m_data->setter(toRef(&state), toRef(this), toRef(this), m_data->data, toRef(P.toPropertyKeyValue()), toRef(desc.value()));
+            } else if (propertyHandler->m_setter && desc.isValuePresent() && desc.isWritable() && desc.isEnumerable() && desc.isConfigurable()) {
+                auto ret = propertyHandler->m_setter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data, toRef(P.toPlainValue()), toRef(desc.value()));
                 if (ret.hasValue()) {
                     return ret.value()->toBoolean(toRef(&state));
                 }
             }
         }
+
         return Object::defineOwnProperty(state, P, desc);
     }
 
-    virtual bool hasOwnProperty(ExecutionState& state, const ObjectPropertyName& propertyName) override
+    virtual bool hasOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override
     {
-        if (m_data->query) {
-            auto attr = m_data->query(toRef(&state), toRef(this), toRef(this), m_data->data,
-                                      toRef(propertyName.toPropertyKeyValue()));
-            return attr & TemplatePropertyAttributeExist;
+        ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
+        if (propertyHandler && propertyHandler->m_query) {
+            auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
+                                                 toRef(P.toPlainValue()));
+            return attr & ObjectTemplatePropertyAttribute::PropertyAttributeExist;
         }
-        return Object::hasOwnProperty(state, propertyName);
+
+        return Object::hasOwnProperty(state, P);
     }
 
     virtual ObjectHasPropertyResult hasProperty(ExecutionState& state, const ObjectPropertyName& P) override
     {
-        if (m_data->query) {
-            auto attr = m_data->query(toRef(&state), toRef(this), toRef(this), m_data->data,
-                                      toRef(P.toPropertyKeyValue()));
-            if (attr & TemplatePropertyAttributeExist) {
-                bool isWritable = attr & TemplatePropertyAttribute::TemplatePropertyAttributeWritable;
-                bool isEnumerable = attr & TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable;
-                bool isConfigurable = attr & TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable;
-
-                Value v;
-                if (m_data->getter) {
-                    OptionalRef<ValueRef> ret = (m_data->getter(toRef(&state), toRef(this), toRef(this), m_data->data,
-                                                                toRef(P.toPropertyKeyValue())));
-                    if (ret) {
-                        v = toImpl(ret.value());
+        ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
+        if (propertyHandler) {
+            if (propertyHandler->m_query) {
+                auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
+                                                     toRef(P.toPlainValue()));
+                if (attr & ObjectTemplatePropertyAttribute::PropertyAttributeExist) {
+                    bool isWritable = attr & ObjectTemplatePropertyAttribute::PropertyAttributeWritable;
+                    bool isEnumerable = attr & ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable;
+                    bool isConfigurable = attr & ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable;
+
+                    Value v;
+                    if (propertyHandler->m_getter) {
+                        OptionalRef<ValueRef> ret = propertyHandler->m_getter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
+                                                                              toRef(P.toPlainValue()));
+                        if (ret.hasValue()) {
+                            v = toImpl(ret.value());
+                        }
                     }
-                }
 
-                ObjectHasPropertyResult result(ObjectGetResult(v, isWritable, isEnumerable, isConfigurable));
-                return result;
-            }
-        } else if (m_data->getter) {
-            OptionalRef<ValueRef> ret = (m_data->getter(toRef(&state), toRef(this), toRef(this), m_data->data,
-                                                        toRef(P.toPropertyKeyValue())));
-            if (ret) {
-                return ObjectGetResult(toImpl(ret.value()), true, true, true);
+                    ObjectHasPropertyResult result(ObjectGetResult(v, isWritable, isEnumerable, isConfigurable));
+                    return result;
+                }
+            } else if (propertyHandler->m_getter) {
+                OptionalRef<ValueRef> ret = propertyHandler->m_getter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
+                                                                      toRef(P.toPlainValue()));
+                if (ret.hasValue()) {
+                    return ObjectGetResult(toImpl(ret.value()), true, true, true);
+                }
             }
         }
 
@@ -155,74 +185,90 @@ public:
 
     virtual bool deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override
     {
-        if (m_data->deleter) {
-            auto ret = m_data->deleter(toRef(&state), toRef(this), toRef(this), m_data->data,
-                                       toRef(P.toPropertyKeyValue()));
+        ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
+        if (propertyHandler && propertyHandler->m_deleter) {
+            auto ret = propertyHandler->m_deleter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
+                                                  toRef(P.toPlainValue()));
             if (ret.hasValue()) {
                 return ret.value()->toBoolean(toRef(&state));
             }
         }
+
         return Object::deleteOwnProperty(state, P);
     }
 
     virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey = true) override
     {
-        if (m_data->enumerator) {
-            auto ret = m_data->enumerator(toRef(&state), toRef(this), toRef(this), m_data->data);
-            if (m_data->query) {
-                for (size_t i = 0; i < ret->size(); i++) {
-                    if (shouldSkipSymbolKey && ret->at(i)->isSymbol()) {
-                        continue;
+        ObjectTemplatePropertyHandlerData* propertyHandler = m_namedPropertyHandler;
+        for (size_t i = 0; i < 2; i++) {
+            if (propertyHandler && propertyHandler->m_enumerator) {
+                auto ret = propertyHandler->m_enumerator(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data);
+                if (propertyHandler->m_query) {
+                    for (size_t i = 0; i < ret->size(); i++) {
+                        if (shouldSkipSymbolKey && ret->at(i)->isSymbol()) {
+                            continue;
+                        }
+
+                        auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
+                                                             ret->at(i));
+
+                        ObjectStructurePropertyDescriptor desc = ObjectStructurePropertyDescriptor::createDataDescriptor(
+                            (ObjectStructurePropertyDescriptor::PresentAttribute)(
+                                ((attr & ObjectTemplatePropertyAttribute::PropertyAttributeWritable) ? ObjectStructurePropertyDescriptor::WritablePresent : 0) | ((attr & ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable) ? ObjectStructurePropertyDescriptor::EnumerablePresent : 0) | ((attr & ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable) ? ObjectStructurePropertyDescriptor::ConfigurablePresent : 0)));
+                        if (!callback(state, this, ObjectPropertyName(state, toImpl(ret->at(i))), desc, data)) {
+                            return;
+                        }
                     }
-
-                    auto attr = m_data->query(toRef(&state), toRef(this), toRef(this), m_data->data,
-                                              ret->at(i));
-
-                    ObjectStructurePropertyDescriptor desc = ObjectStructurePropertyDescriptor::createDataDescriptor(
-                        (ObjectStructurePropertyDescriptor::PresentAttribute)(
-                            ((attr & TemplatePropertyAttribute::TemplatePropertyAttributeWritable) ? ObjectStructurePropertyDescriptor::WritablePresent : 0) | ((attr & TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable) ? ObjectStructurePropertyDescriptor::EnumerablePresent : 0) | ((attr & TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable) ? ObjectStructurePropertyDescriptor::ConfigurablePresent : 0)));
-                    callback(state, this, ObjectPropertyName(state, toImpl(ret->at(i))), desc, data);
-                }
-            } else {
-                for (size_t i = 0; i < ret->size(); i++) {
-                    if (shouldSkipSymbolKey && ret->at(i)->isSymbol()) {
-                        continue;
+                } else {
+                    for (size_t i = 0; i < ret->size(); i++) {
+                        if (shouldSkipSymbolKey && ret->at(i)->isSymbol()) {
+                            continue;
+                        }
+                        ObjectStructurePropertyDescriptor desc = ObjectStructurePropertyDescriptor::createDataDescriptor();
+                        if (!callback(state, this, ObjectPropertyName(state, toImpl(ret->at(i))), desc, data)) {
+                            return;
+                        }
                     }
-                    ObjectStructurePropertyDescriptor desc = ObjectStructurePropertyDescriptor::createDataDescriptor();
-                    callback(state, this, ObjectPropertyName(state, toImpl(ret->at(i))), desc, data);
                 }
             }
+
+            propertyHandler = m_indexedPropertyHandler;
         }
+
         Object::enumeration(state, callback, data, shouldSkipSymbolKey);
     }
 
     virtual ObjectGetResult get(ExecutionState& state, const ObjectPropertyName& P, const Value& receiver) override
     {
-        if (!P.isIndexString()) {
-            OptionalRef<ValueRef> ret(m_data->getter(toRef(&state), toRef(this), toRef(receiver), m_data->data,
-                                                     toRef(P.toPropertyKeyValue())));
-
-            if (ret) {
-                if (m_data->query) {
-                    auto attr = m_data->query(toRef(&state), toRef(this), toRef(receiver), m_data->data,
-                                              toRef(P.toPropertyKeyValue()));
-                    return ObjectGetResult(toImpl(ret.value()), attr & TemplatePropertyAttribute::TemplatePropertyAttributeWritable, attr & TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable, attr & TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable);
+        ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
+        if (propertyHandler && propertyHandler->m_getter) {
+            auto ret = propertyHandler->m_getter(toRef(&state), toRef(this), toRef(receiver), propertyHandler->m_data,
+                                                 toRef(P.toPlainValue()));
+
+            if (ret.hasValue()) {
+                if (propertyHandler->m_query) {
+                    auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(receiver), propertyHandler->m_data,
+                                                         toRef(P.toPlainValue()));
+                    return ObjectGetResult(toImpl(ret.value()), attr & ObjectTemplatePropertyAttribute::PropertyAttributeWritable, attr & ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable, attr & ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
                 } else {
                     return ObjectGetResult(toImpl(ret.value()), true, true, true);
                 }
             }
         }
+
         return Object::get(state, P, receiver);
     }
 
     virtual bool set(ExecutionState& state, const ObjectPropertyName& P, const Value& v, const Value& receiver) override
     {
-        if (m_data->setter && !P.isIndexString()) {
-            auto ret = m_data->setter(toRef(&state), toRef(this), toRef(receiver), m_data->data, toRef(P.toPropertyKeyValue()), toRef(v));
+        ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
+        if (propertyHandler && propertyHandler->m_setter) {
+            auto ret = propertyHandler->m_setter(toRef(&state), toRef(this), toRef(receiver), propertyHandler->m_data, toRef(P.toPlainValue()), toRef(v));
             if (ret.hasValue()) {
                 return ret.value()->toBoolean(toRef(&state));
             }
         }
+
         return Object::set(state, P, v, receiver);
     }
 
@@ -237,9 +283,33 @@ public:
     }
 
 private:
-    ObjectTemplateNamedPropertyHandlerData* m_data;
+    ObjectTemplatePropertyHandlerData* m_namedPropertyHandler;
+    ObjectTemplatePropertyHandlerData* m_indexedPropertyHandler;
 };
 
+void* ObjectTemplate::operator new(size_t size)
+{
+    static MAY_THREAD_LOCAL bool typeInited = false;
+    static MAY_THREAD_LOCAL GC_descr descr;
+    if (!typeInited) {
+        GC_word objBitmap[GC_BITMAP_SIZE(ObjectTemplate)] = { 0 };
+        Template::fillGCDescriptor(objBitmap);
+        GC_set_bit(objBitmap, GC_WORD_OFFSET(ObjectTemplate, m_constructor));
+        GC_set_bit(objBitmap, GC_WORD_OFFSET(ObjectTemplate, m_namedPropertyHandler));
+        GC_set_bit(objBitmap, GC_WORD_OFFSET(ObjectTemplate, m_indexedPropertyHandler));
+        descr = GC_make_descriptor(objBitmap, GC_WORD_LEN(ObjectTemplate));
+        typeInited = true;
+    }
+    return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
+}
+
+ObjectTemplate::ObjectTemplate(Optional<FunctionTemplate*> constructor)
+    : m_constructor(constructor)
+    , m_namedPropertyHandler(nullptr)
+    , m_indexedPropertyHandler(nullptr)
+{
+}
+
 Object* ObjectTemplate::instantiate(Context* ctx)
 {
     if (!m_cachedObjectStructure.m_objectStructure) {
@@ -262,8 +332,8 @@ Object* ObjectTemplate::instantiate(Context* ctx)
         proto = ctx->globalObject()->objectPrototype();
     }
 
-    if (m_namedPropertyHandler) {
-        result = new ObjectWithNamedPropertyHandler(m_cachedObjectStructure.m_objectStructure, std::move(objectPropertyValues), proto, m_namedPropertyHandler);
+    if (m_namedPropertyHandler || m_indexedPropertyHandler) {
+        result = new ObjectWithPropertyHandler(m_cachedObjectStructure.m_objectStructure, std::move(objectPropertyValues), proto, m_namedPropertyHandler, m_indexedPropertyHandler);
     } else {
         result = new Object(m_cachedObjectStructure.m_objectStructure, std::move(objectPropertyValues), proto);
     }
@@ -345,13 +415,29 @@ bool ObjectTemplate::installTo(Context* ctx, Object* target)
     return result.error.isEmpty();
 }
 
-void ObjectTemplate::setNamedPropertyHandler(const ObjectTemplateNamedPropertyHandlerData& data)
+void ObjectTemplate::setNamedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data)
 {
-    m_namedPropertyHandler = new (GC) ObjectTemplateNamedPropertyHandlerData(data);
+    ASSERT(!m_namedPropertyHandler);
+    m_namedPropertyHandler = new ObjectTemplatePropertyHandlerData(data);
+}
+
+void ObjectTemplate::setIndexedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data)
+{
+    ASSERT(!m_indexedPropertyHandler);
+    m_indexedPropertyHandler = new ObjectTemplatePropertyHandlerData(data);
 }
 
 void ObjectTemplate::removeNamedPropertyHandler()
 {
+    // just set nullptr here because property handler might be used in instantiated ObjectWithPropertyHandler
+    ASSERT(!m_namedPropertyHandler);
     m_namedPropertyHandler = nullptr;
 }
+
+void ObjectTemplate::removeIndexedPropertyHandler()
+{
+    // just set nullptr here because property handler might be used in instantiated ObjectWithPropertyHandler
+    ASSERT(!m_indexedPropertyHandler);
+    m_indexedPropertyHandler = nullptr;
+}
 } // namespace Escargot
index 7afe902036235c5c45e8bc896b2b95c8420d084c..13c2bf398ab6f45585c0d0c66005ddf89ca75fbd 100644 (file)
@@ -25,7 +25,8 @@
 namespace Escargot {
 
 class FunctionTemplate;
-struct ObjectTemplateNamedPropertyHandlerData;
+class ObjectTemplatePropertyHandlerData;
+struct ObjectTemplatePropertyHandlerConfiguration;
 
 class ObjectTemplate : public Template {
 public:
@@ -50,12 +51,15 @@ public:
     void* operator new(size_t size);
     void* operator new[](size_t size) = delete;
 
-    void setNamedPropertyHandler(const ObjectTemplateNamedPropertyHandlerData& data);
+    void setNamedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data);
+    void setIndexedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data);
     void removeNamedPropertyHandler();
+    void removeIndexedPropertyHandler();
 
-protected:
+private:
     Optional<FunctionTemplate*> m_constructor;
-    ObjectTemplateNamedPropertyHandlerData* m_namedPropertyHandler;
+    ObjectTemplatePropertyHandlerData* m_namedPropertyHandler;
+    ObjectTemplatePropertyHandlerData* m_indexedPropertyHandler;
 };
 } // namespace Escargot
 
index 9eae39b660db1f223b7b66ac6ec00626a66f0fef..c2e8fdf91869a9d78f08ae86813cba69292da0b7 100644 (file)
@@ -54,7 +54,7 @@ public:
     virtual void* allocateThreadLocalCustomData() = 0;
     virtual void deallocateThreadLocalCustomData() = 0;
 
-#ifdef ESCARGOT_USE_CUSTOM_LOGGING
+#ifdef ENABLE_CUSTOM_LOGGING
     // customized logging
     virtual void customInfoLogger(const char* format, va_list arg) = 0;
     virtual void customErrorLogger(const char* format, va_list arg) = 0;
index da298cc71e84f2f7dc1a205b16d8d54949f9cfc0..59692c9ac768087b39227fac0f4d04ecf59dd648 100644 (file)
@@ -26,6 +26,7 @@ namespace Escargot {
 
 size_t PointerValue::g_arrayObjectTag;
 size_t PointerValue::g_arrayPrototypeObjectTag;
+size_t PointerValue::g_scriptFunctionObjectTag;
 size_t PointerValue::g_objectRareDataTag;
 size_t PointerValue::g_doubleInEncodedValueTag;
 
index baef1b86b7f5fd09eff815ff69a1efb7792d8010..98b696d45d69e257c4ed7f704a6a259479b7daa0 100644 (file)
@@ -113,13 +113,6 @@ class PointerValue : public gc {
     friend class Global;
     friend class ByteCodeInterpreter;
 
-    // tag values for fast type check
-    // these values actually have unique virtual table address of each object class
-    static size_t g_arrayObjectTag;
-    static size_t g_arrayPrototypeObjectTag;
-    static size_t g_objectRareDataTag;
-    static size_t g_doubleInEncodedValueTag;
-
 public:
     virtual ~PointerValue() {}
     // fast type check with tag comparison
@@ -163,6 +156,11 @@ public:
         return hasTag(g_doubleInEncodedValueTag);
     }
 
+    inline bool hasArrayObjectTag() const
+    {
+        return hasTag(g_arrayObjectTag);
+    }
+
     // type check by virtual function call
     virtual bool isFunctionObject() const
     {
@@ -886,7 +884,7 @@ public:
         return *((size_t*)(this) + 1);
     }
 
-private:
+protected:
     inline bool hasTag(const size_t tag) const
     {
         ASSERT(!!tag);
@@ -898,8 +896,21 @@ private:
         return *((size_t*)(this));
     }
 
+    inline void writeTag(const size_t tag)
+    {
+        *((size_t*)(this)) = tag;
+    }
+
     virtual Value call(ExecutionState& state, const Value& thisValue, const size_t argc, Value* argv);
     virtual Value construct(ExecutionState& state, const size_t argc, Value* argv, Object* newTarget);
+
+    // tag values for fast type check
+    // these values actually have unique virtual table address of each object class
+    static size_t g_arrayObjectTag;
+    static size_t g_arrayPrototypeObjectTag;
+    static size_t g_scriptFunctionObjectTag;
+    static size_t g_objectRareDataTag;
+    static size_t g_doubleInEncodedValueTag;
 };
 } // namespace Escargot
 
index cb779d23800fe417bd92c6dec3ab0508f7719db5..61a6ebc4e776533b183cf46bcef1f5de3be2af32 100644 (file)
@@ -151,7 +151,11 @@ void PromiseObject::reject(ExecutionState& state, Value reason)
 {
     m_state = PromiseState::Rejected;
     m_promiseResult = reason;
-    triggerPromiseReactions(state, m_rejectReactions);
+    if (LIKELY(hasRejectHandlers() > 0)) {
+        triggerPromiseReactions(state, m_rejectReactions);
+    } else if (state.context()->vmInstance()->isPromiseRejectCallbackRegistered()) {
+        state.context()->vmInstance()->triggerPromiseRejectCallback(state, this, reason, VMInstance::PromiseRejectEvent::PromiseRejectWithNoHandler);
+    }
 
     m_fulfillReactions.clear();
     m_rejectReactions.clear();
@@ -183,7 +187,7 @@ Optional<Object*> PromiseObject::then(ExecutionState& state, Value onFulfilledVa
     PromiseReaction::Capability capability = resultCapability.hasValue() ? resultCapability.value() : PromiseReaction::Capability(nullptr, nullptr, nullptr);
 
 #ifdef ESCARGOT_DEBUGGER
-    if (state.context()->debugger() != nullptr && state.context()->debugger()->enabled()) {
+    if (state.context()->debuggerEnabled()) {
         capability.m_savedStackTrace = Debugger::saveStackTrace(state);
     }
 #endif /* ESCARGOT_DEBUGGER */
@@ -201,6 +205,10 @@ Optional<Object*> PromiseObject::then(ExecutionState& state, Value onFulfilledVa
     case PromiseObject::PromiseState::Rejected: {
         Job* job = new PromiseReactionJob(state.context(), PromiseReaction(onRejected, capability), promiseResult());
         state.context()->vmInstance()->enqueueJob(job);
+
+        if (UNLIKELY(state.context()->vmInstance()->isPromiseRejectCallbackRegistered())) {
+            state.context()->vmInstance()->triggerPromiseRejectCallback(state, this, promiseResult(), VMInstance::PromiseRejectEvent::PromiseHandlerAddedAfterReject);
+        }
         break;
     }
     default:
index fc8580f5af6d95e68383e14188181b28ee434762..ffc15d7787dbafdc04775ca298a76c0ef021d4ab 100644 (file)
@@ -154,6 +154,9 @@ public:
     // https://tc39.es/ecma262/#sec-promise.any-reject-element-functions
     static Value promiseAnyRejectElementFunction(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget);
 
+    bool hasResolveHandlers() const { return m_fulfillReactions.size() > 0; }
+    bool hasRejectHandlers() const { return m_rejectReactions.size() > 0; }
+
 protected:
     static inline void fillGCDescriptor(GC_word* desc)
     {
index 579b9230734b078f13340060e97a6967e7807cb2..eca03a809932291cd13c257f5c7bead1280c3458 100644 (file)
@@ -56,6 +56,11 @@ public:
         return m_isConstructible;
     }
 
+    virtual bool hasOwnEnumeration() const override
+    {
+        return true;
+    }
+
     virtual Context* getFunctionRealm(ExecutionState& state) override;
 
     static ProxyObject* createProxy(ExecutionState& state, const Value& target, const Value& handler);
index dd61b56618f9c7289ba441d64da7c171baa83e8a..5088c62390cdc86ea6d923d8f87e7f2b9074245d 100644 (file)
@@ -57,13 +57,13 @@ RegExpObject::RegExpObject(ExecutionState& state, Object* proto, bool hasLastInd
     : Object(state, proto, ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + (hasLastIndex ? 5 : 4))
     , m_source(NULL)
     , m_optionString(NULL)
-    , m_option(None)
+    , m_legacyFeaturesEnabled(true)
     , m_yarrPattern(NULL)
     , m_bytecodePattern(NULL)
     , m_lastIndex(Value(0))
     , m_lastExecutedString(NULL)
-    , m_legacyFeaturesEnabled(true)
 {
+    setOptionValueForGC(None);
     initRegExpObject(state, hasLastIndex);
 }
 
@@ -80,25 +80,6 @@ void RegExpObject::initRegExpObject(ExecutionState& state, bool hasLastIndex)
     }
 }
 
-void* RegExpObject::operator new(size_t size)
-{
-    static MAY_THREAD_LOCAL bool typeInited = false;
-    static MAY_THREAD_LOCAL GC_descr descr;
-    if (!typeInited) {
-        GC_word obj_bitmap[GC_BITMAP_SIZE(RegExpObject)] = { 0 };
-        Object::fillGCDescriptor(obj_bitmap);
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(RegExpObject, m_source));
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(RegExpObject, m_optionString));
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(RegExpObject, m_yarrPattern));
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(RegExpObject, m_bytecodePattern));
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(RegExpObject, m_lastIndex));
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(RegExpObject, m_lastExecutedString));
-        descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(RegExpObject));
-        typeInited = true;
-    }
-    return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
-}
-
 static String* escapeSlashInPattern(String* patternStr)
 {
     if (patternStr->length() == 0) {
@@ -159,16 +140,16 @@ void RegExpObject::internalInit(ExecutionState& state, String* source, Option op
     String* defaultRegExpString = state.context()->staticStrings().defaultRegExpString.string();
 
     String* previousSource = m_source;
-    RegExpObject::Option previousOptions = m_option;
+    RegExpObject::Option previousOptions = this->option();
 
-    m_option = option;
+    setOptionValueForGC(option);
     m_source = source->length() ? source : defaultRegExpString;
     m_source = escapeSlashInPattern(m_source);
 
-    auto entry = getCacheEntryAndCompileIfNeeded(state, m_source, m_option);
+    auto entry = getCacheEntryAndCompileIfNeeded(state, m_source, this->option());
     if (entry.m_yarrError) {
         m_source = previousSource;
-        m_option = previousOptions;
+        setOptionValueForGC(previousOptions);
         ErrorObject::throwBuiltinError(state, ErrorObject::SyntaxError, entry.m_yarrError);
     }
 
@@ -186,7 +167,7 @@ void RegExpObject::init(ExecutionState& state, String* source, String* option)
 
 void RegExpObject::setLastIndex(ExecutionState& state, const Value& v)
 {
-    if (UNLIKELY(hasRareData() && rareData()->m_hasNonWritableLastIndexRegExpObject && (m_option & (Option::Sticky | Option::Global)))) {
+    if (UNLIKELY(hasRareData() && rareData()->m_hasNonWritableLastIndexRegExpObject && (option() & (Option::Sticky | Option::Global)))) {
         Object::throwCannotWriteError(state, ObjectStructurePropertyName(state.context()->staticStrings().lastIndex));
     }
     m_lastIndex = v;
@@ -252,12 +233,13 @@ RegExpObject::Option RegExpObject::parseOption(ExecutionState& state, String* op
 
 void RegExpObject::setOption(const Option& option)
 {
-    if (((m_option & Option::MultiLine) != (option & Option::MultiLine))
-        || ((m_option & Option::IgnoreCase) != (option & Option::IgnoreCase))) {
+    Option currentOption = this->option();
+    if (((currentOption & Option::MultiLine) != (option & Option::MultiLine))
+        || ((currentOption & Option::IgnoreCase) != (option & Option::IgnoreCase))) {
         ASSERT(!m_yarrPattern);
         m_bytecodePattern = NULL;
     }
-    m_option = option;
+    setOptionValueForGC(option);
 }
 
 RegExpObject::RegExpCacheEntry& RegExpObject::getCacheEntryAndCompileIfNeeded(ExecutionState& state, String* source, const Option& option)
@@ -297,7 +279,7 @@ bool RegExpObject::match(ExecutionState& state, String* str, RegexMatchResult& m
     m_lastExecutedString = str;
 
     if (!m_bytecodePattern) {
-        RegExpCacheEntry& entry = getCacheEntryAndCompileIfNeeded(state, m_source, m_option);
+        RegExpCacheEntry& entry = getCacheEntryAndCompileIfNeeded(state, m_source, option());
         if (entry.m_yarrError) {
             matchResult.m_subPatternNum = 0;
             return false;
index 6ea1963b7093c402708ef8f955dcb782f7eb563b..68fa93389383f31f157770aff8aac99aeeb57098 100644 (file)
@@ -120,7 +120,7 @@ public:
 
     Option option()
     {
-        return m_option;
+        return static_cast<Option>(m_option >> 1);
     }
 
     JSC::Yarr::YarrPattern* yarrPatern()
@@ -162,13 +162,14 @@ public:
     ArrayObject* createRegExpMatchedArray(ExecutionState& state, const RegexMatchResult& result, String* input);
     void pushBackToRegExpMatchedArray(ExecutionState& state, ArrayObject* array, size_t& index, const size_t limit, const RegexMatchResult& result, String* str);
 
-    void* operator new(size_t size);
-    void* operator new[](size_t size) = delete;
-
 protected:
     explicit RegExpObject(ExecutionState& state, Object* proto, bool hasLastIndex = true);
 
 private:
+    void setOptionValueForGC(const Option& option)
+    {
+        m_option = static_cast<Option>(option << 1 | 1);
+    }
     void setOption(const Option& option);
     void internalInit(ExecutionState& state, String* source, Option option = None);
 
@@ -178,12 +179,12 @@ private:
 
     String* m_source;
     String* m_optionString;
-    Option m_option;
+    Option m_option : 16;
+    bool m_legacyFeaturesEnabled : 1;
     JSC::Yarr::YarrPattern* m_yarrPattern;
     JSC::Yarr::BytecodePattern* m_bytecodePattern;
     EncodedValue m_lastIndex;
     const String* m_lastExecutedString;
-    bool m_legacyFeaturesEnabled;
 };
 
 class RegExpStringIteratorObject : public IteratorObject {
index c512aa10d763d55266c200d914131ae8565272cb..06b46eae3d8e9e7d857368501154d8e92d6cc11e 100644 (file)
@@ -44,6 +44,7 @@ ReloadableString::ReloadableString(VMInstance* instance, bool is8Bit, size_t str
     : String()
     , m_isOwnerMayFreed(false)
     , m_isUnloaded(true)
+    , m_refCount(0)
     , m_vmInstance(instance)
     , m_callbackData(callbackData)
     , m_stringLoadCallback(loadCallback)
@@ -58,6 +59,8 @@ ReloadableString::ReloadableString(VMInstance* instance, bool is8Bit, size_t str
     v.push_back(this);
     GC_REGISTER_FINALIZER_NO_ORDER(this, [](void* obj, void*) {
         ReloadableString* self = (ReloadableString*)obj;
+        ASSERT(self->refCount() == 0);
+
         if (!self->m_isUnloaded) {
             self->m_stringUnloadCallback(const_cast<void*>(self->m_bufferData.buffer), self->m_callbackData);
         }
@@ -97,30 +100,16 @@ UTF16StringData ReloadableString::toUTF16StringData() const
 bool ReloadableString::unload()
 {
     ASSERT(!m_isUnloaded);
-    if (UNLIKELY(!m_bufferData.length)) {
+    if (UNLIKELY(!m_bufferData.length || m_refCount > 0)) {
         return false;
     }
 
-    return unloadWorker(currentStackPointer());
+    return unloadWorker();
 }
 
-bool ReloadableString::unloadWorker(void* callerSP)
+bool ReloadableString::unloadWorker()
 {
-#if defined(STACK_GROWS_DOWN)
-    size_t* start = (size_t*)((size_t)callerSP & ~(sizeof(size_t) - 1));
-    size_t* end = (size_t*)m_vmInstance->stackStartAddress();
-#else
-    size_t* start = (size_t*)m_vmInstance->stackStartAddress();
-    size_t* end = (size_t*)((size_t)callerSP & ~(sizeof(size_t) - 1));
-#endif
-
-    while (start != end) {
-        if (UNLIKELY(*start == (size_t)m_bufferData.buffer)) {
-            // if there is reference on stack, we cannot unload string.
-            return false;
-        }
-        start++;
-    }
+    ASSERT(!m_isUnloaded && !m_refCount);
 
     m_stringUnloadCallback(const_cast<void*>(m_bufferData.buffer), m_callbackData);
     m_bufferData.buffer = nullptr;
index 263e29183bf265207e1f72d7eac4e3dee0477ada..4850385d4d5e04f79e9847762a86401f2a7c526d 100644 (file)
@@ -58,7 +58,9 @@ public:
         if (isUnloaded()) {
             load();
         }
-        return StringBufferAccessData(m_bufferData.has8BitContent, m_bufferData.length, const_cast<void*>(m_bufferData.buffer));
+
+        // add refCount pointer to count its usage in StringBufferAccessData
+        return StringBufferAccessData(m_bufferData.has8BitContent, m_bufferData.length, const_cast<void*>(m_bufferData.buffer), &m_refCount);
     }
 
     bool isUnloaded()
@@ -66,6 +68,11 @@ public:
         return m_isUnloaded;
     }
 
+    size_t refCount() const
+    {
+        return m_refCount;
+    }
+
     void* operator new(size_t);
     void* operator new[](size_t) = delete;
     void operator delete[](void*) = delete;
@@ -75,7 +82,7 @@ public:
 
 private:
     void initBufferAccessData(void* data, size_t len, bool is8bit);
-    ATTRIBUTE_NO_SANITIZE_ADDRESS bool unloadWorker(void* callerSP);
+    ATTRIBUTE_NO_SANITIZE_ADDRESS bool unloadWorker();
 
     size_t unloadedBufferSize()
     {
@@ -88,6 +95,7 @@ private:
 
     bool m_isOwnerMayFreed;
     bool m_isUnloaded;
+    size_t m_refCount; // reference count representing the usage of this ReloadableString
     VMInstance* m_vmInstance;
     void* m_callbackData;
     void* (*m_stringLoadCallback)(void* callbackData);
index b3e443387097a9dc78aca3db01483ad75c08e123..906a69a73f5981b478657f9fdc043a105ed4d063 100644 (file)
 
 namespace Escargot {
 
-void* RopeString::operator new(size_t size)
+void* RopeString::operator new(size_t size, bool is8Bit)
 {
+    if (is8Bit) {
+        // if 8-bit string, we don't needs typed malloc
+        return GC_MALLOC(size);
+    }
     static MAY_THREAD_LOCAL bool typeInited = false;
     static MAY_THREAD_LOCAL GC_descr descr;
     if (!typeInited) {
@@ -50,26 +54,15 @@ String* RopeString::createRopeString(String* lstr, String* rstr, ExecutionState*
         return lstr;
     }
 
-    if (llen + rlen < ROPE_STRING_MIN_LENGTH) {
+    if (llen + rlen <= LATIN1_LARGE_INLINE_BUFFER_MAX_SIZE) {
         const auto& lData = lstr->bufferAccessData();
         const auto& rData = rstr->bufferAccessData();
         if (LIKELY(lData.has8BitContent && rData.has8BitContent)) {
-            Latin1StringData ret;
             size_t len = lData.length + rData.length;
-            ret.resizeWithUninitializedValues(len);
-
-            LChar* result = ret.data();
-            const LChar* buffer = (const LChar*)lData.buffer;
-            for (size_t i = 0; i < lData.length; i++) {
-                result[i] = buffer[i];
-            }
-
-            result += lData.length;
-            buffer = (const LChar*)rData.buffer;
-            for (size_t i = 0; i < rData.length; i++) {
-                result[i] = buffer[i];
-            }
-            return new Latin1String(std::move(ret));
+            LChar* result = reinterpret_cast<LChar*>(alloca(len));
+            memcpy(result, lData.buffer, lData.length);
+            memcpy(result + lData.length, rData.buffer, rData.length);
+            return String::fromLatin1(result, len);
         } else {
             StringBuilder builder;
             builder.appendString(lstr);
@@ -82,26 +75,14 @@ String* RopeString::createRopeString(String* lstr, String* rstr, ExecutionState*
         ErrorObject::throwBuiltinError(*state, ErrorObject::RangeError, ErrorObject::Messages::String_InvalidStringLength);
     }
 
-    RopeString* rope = new RopeString();
+    bool l8bit = lstr->has8BitContent();
+    bool r8bit = rstr->has8BitContent();
+    bool result8Bit = l8bit & r8bit;
+    RopeString* rope = new (result8Bit) RopeString();
     rope->m_bufferData.length = llen + rlen;
     rope->m_left = lstr;
     rope->m_bufferData.buffer = rstr;
-
-    bool l8bit;
-    if (lstr->isRopeString()) {
-        l8bit = ((RopeString*)lstr)->m_bufferData.has8BitContent;
-    } else {
-        l8bit = lstr->has8BitContent();
-    }
-
-    bool r8bit;
-    if (rstr->isRopeString()) {
-        r8bit = ((RopeString*)rstr)->m_bufferData.has8BitContent;
-    } else {
-        r8bit = rstr->has8BitContent();
-    }
-
-    rope->m_bufferData.has8BitContent = l8bit & r8bit;
+    rope->m_bufferData.has8BitContent = result8Bit;
     return rope;
 }
 
@@ -159,6 +140,71 @@ void RopeString::flattenRopeString()
     }
 }
 
+static MAY_THREAD_LOCAL const RopeString* g_lastUsedString;
+static MAY_THREAD_LOCAL bool g_headOfCharAt = true;
+class RopeStringUsageChecker {
+public:
+    RopeStringUsageChecker()
+    {
+        m_headOfCharAt = g_headOfCharAt;
+        g_headOfCharAt = false;
+    }
+
+    ~RopeStringUsageChecker()
+    {
+        g_headOfCharAt = m_headOfCharAt;
+    }
+
+    bool isOftenUsed(const RopeString* rs)
+    {
+        auto old = g_lastUsedString;
+        if (m_headOfCharAt) {
+            g_lastUsedString = rs;
+        }
+        return rs == old;
+    }
+
+private:
+    bool m_headOfCharAt;
+};
+
+// worker for preventing too many recursive calls with RopeString
+static char16_t charAtWorker(size_t idx, const RopeString* self)
+{
+    while (true) {
+        size_t leftLength = self->left()->length();
+        if (idx < leftLength) {
+            if (self->left()->isRopeString() && !self->left()->asRopeString()->wasFlattened()) {
+                self = self->left()->asRopeString();
+                continue;
+            }
+            return self->left()->charAt(idx);
+        } else {
+            if (self->right()->isRopeString() && !self->right()->asRopeString()->wasFlattened()) {
+                self = self->right()->asRopeString();
+                idx = idx - leftLength;
+                continue;
+            }
+            return self->right()->charAt(idx - leftLength);
+        }
+    }
+}
+
+char16_t RopeString::charAt(const size_t idx) const
+{
+    if (wasFlattened()) {
+        return bufferAccessData().charAt(idx);
+    }
+
+    RopeStringUsageChecker checker;
+
+    if (checker.isOftenUsed(this)) {
+        return bufferAccessData().charAt(idx);
+    }
+
+    return charAtWorker(idx, this);
+}
+
 UTF8StringDataNonGCStd RopeString::toNonGCUTF8StringData(int options) const
 {
     return bufferAccessData().toUTF8String<UTF8StringDataNonGCStd>();
index d694bf59d7ae8c818c07c65eeb664d4c7b285cec..33d39e7bab6c9ad411048bebfc0a2a785ef6006e 100644 (file)
@@ -80,7 +80,9 @@ public:
         return (String*)m_bufferData.buffer;
     }
 
-    void* operator new(size_t size);
+    virtual char16_t charAt(const size_t idx) const override;
+
+    void* operator new(size_t size, bool is8Bit);
     void* operator new[](size_t size) = delete;
 
 protected:
index da165d5795f5373ea568053389647f28428a1613..75b2559612ea8b31a03da40dc4b5424a2aacb8d5 100644 (file)
@@ -54,23 +54,15 @@ void SandBox::processCatch(const Value& error, SandBoxResult& result)
 
 #ifdef ESCARGOT_DEBUGGER
     Debugger* debugger = m_context->debugger();
-    if (debugger && debugger->enabled()) {
-        ExecutionState state(m_context);
-        String* message = error.toStringWithoutException(state);
-
-        debugger->sendType(Debugger::ESCARGOT_MESSAGE_EXCEPTION);
-        if (debugger->enabled()) {
-            StringView* messageView = new StringView(message);
-            debugger->sendString(Debugger::ESCARGOT_MESSAGE_STRING_8BIT, messageView);
-        }
-    }
+    Debugger::SavedStackTraceDataVector exceptionTrace;
 #endif /* ESCARGOT_DEBUGGER */
 
     ByteCodeLOCDataMap locMap;
-    for (size_t i = 0; i < m_stackTraceData.size(); i++) {
-        if ((size_t)m_stackTraceData[i].second.loc.index == SIZE_MAX && (size_t)m_stackTraceData[i].second.loc.actualCodeBlock != SIZE_MAX) {
+    for (size_t i = 0; i < m_stackTraceDataVector.size(); i++) {
+        if ((size_t)m_stackTraceDataVector[i].loc.index == SIZE_MAX && (size_t)m_stackTraceDataVector[i].loc.actualCodeBlock != SIZE_MAX) {
             // this means loc not computed yet.
-            ByteCodeBlock* block = m_stackTraceData[i].second.loc.actualCodeBlock;
+            StackTraceData traceData = m_stackTraceDataVector[i];
+            ByteCodeBlock* block = traceData.loc.actualCodeBlock;
 
             ByteCodeLOCData* locData;
             auto iterMap = locMap.find(block);
@@ -82,34 +74,32 @@ void SandBox::processCatch(const Value& error, SandBoxResult& result)
             }
 
             ExtendedNodeLOC loc = block->computeNodeLOCFromByteCode(m_context,
-                                                                    m_stackTraceData[i].second.loc.byteCodePosition, block->m_codeBlock, locData);
+                                                                    traceData.loc.byteCodePosition, block->m_codeBlock, locData);
 
-            StackTraceData traceData;
             traceData.loc = loc;
-            InterpretedCodeBlock* cb = block->m_codeBlock;
-            traceData.src = cb->script()->srcName();
-            traceData.sourceCode = cb->script()->sourceCode();
-            traceData.functionName = m_stackTraceData[i].second.functionName;
-            traceData.isFunction = m_stackTraceData[i].second.isFunction;
-            traceData.isConstructor = m_stackTraceData[i].second.isConstructor;
-            traceData.isAssociatedWithJavaScriptCode = m_stackTraceData[i].second.isAssociatedWithJavaScriptCode;
-            traceData.isEval = m_stackTraceData[i].second.isEval;
-
-            result.stackTraceData.pushBack(traceData);
+            result.stackTrace.pushBack(traceData);
 
 #ifdef ESCARGOT_DEBUGGER
-            if (i < 8 && debugger && debugger->enabled()) {
-                debugger->sendBacktraceInfo(Debugger::ESCARGOT_MESSAGE_EXCEPTION_BACKTRACE,
-                                            block, (uint32_t)loc.line, (uint32_t)loc.column, m_stackTraceData[i].second.executionStateDepth);
+            if (i < 8 && debugger != nullptr) {
+                exceptionTrace.pushBack(Debugger::SavedStackTraceData(block, (uint32_t)loc.line, (uint32_t)loc.column));
             }
 #endif /* ESCARGOT_DEBUGGER */
         } else {
-            result.stackTraceData.pushBack(m_stackTraceData[i].second);
+            result.stackTrace.pushBack(m_stackTraceDataVector[i]);
         }
     }
     for (auto iter = locMap.begin(); iter != locMap.end(); iter++) {
         delete iter->second;
     }
+
+#ifdef ESCARGOT_DEBUGGER
+    if (debugger != nullptr) {
+        ExecutionState state(m_context);
+        String* message = error.toStringWithoutException(state);
+
+        debugger->exceptionCaught(message, exceptionTrace);
+    }
+#endif /* ESCARGOT_DEBUGGER */
 }
 
 SandBox::SandBoxResult SandBox::run(Value (*scriptRunner)(ExecutionState&, void*), void* data)
@@ -136,7 +126,7 @@ SandBox::SandBoxResult SandBox::run(const std::function<Value()>& scriptRunner)
     return result;
 }
 
-bool SandBox::createStackTraceData(StackTraceDataVector& stackTraceData, ExecutionState& state, bool stopAtPause)
+bool SandBox::createStackTrace(StackTraceDataVector& stackTraceDataVector, ExecutionState& state, bool stopAtPause)
 {
     UNUSED_VARIABLE(stopAtPause);
 
@@ -145,11 +135,13 @@ bool SandBox::createStackTraceData(StackTraceDataVector& stackTraceData, Executi
     uint32_t executionStateDepthIndex = 0;
     ExecutionState* activeSavedStackTraceExecutionState = nullptr;
 
-    if (stopAtPause && state.context()->debugger() != nullptr) {
+    if (stopAtPause && state.context()->debuggerEnabled()) {
         activeSavedStackTraceExecutionState = state.context()->debugger()->activeSavedStackTraceExecutionState();
     }
 #endif /* ESCARGOT_DEBUGGER */
 
+    std::vector<ExecutionState*> stateStack;
+
     while (pstate) {
         FunctionObject* callee = pstate->resolveCallee();
         ExecutionState* es = pstate;
@@ -174,8 +166,8 @@ bool SandBox::createStackTraceData(StackTraceDataVector& stackTraceData, Executi
 
         bool alreadyExists = false;
 
-        for (size_t i = 0; i < stackTraceData.size(); i++) {
-            if (stackTraceData[i].first == es || stackTraceData[i].first->lexicalEnvironment() == es->lexicalEnvironment()) {
+        for (size_t i = 0; i < stateStack.size(); i++) {
+            if (stateStack[i] == es || stateStack[i]->lexicalEnvironment() == es->lexicalEnvironment()) {
                 alreadyExists = true;
                 break;
             }
@@ -194,14 +186,14 @@ bool SandBox::createStackTraceData(StackTraceDataVector& stackTraceData, Executi
                 if (cb) {
                     ByteCodeBlock* b = cb->byteCodeBlock();
                     ExtendedNodeLOC loc(SIZE_MAX, SIZE_MAX, SIZE_MAX);
-                    ASSERT(!pstate->m_isNativeFunctionObjectExecutionContext);
+                    ASSERT(!pstate->isNativeFunctionObjectExecutionContext());
                     if (pstate->m_programCounter != nullptr) {
                         loc.byteCodePosition = *pstate->m_programCounter - (size_t)b->m_code.data();
                         loc.actualCodeBlock = b;
                     }
                     SandBox::StackTraceData data;
                     data.loc = loc;
-                    data.src = cb->script()->srcName();
+                    data.srcName = cb->script()->srcName();
                     data.sourceCode = cb->script()->sourceCode();
                     data.isEval = true;
                     data.isFunction = false;
@@ -211,14 +203,15 @@ bool SandBox::createStackTraceData(StackTraceDataVector& stackTraceData, Executi
                     data.executionStateDepth = executionStateDepthIndex;
 #endif /* ESCARGOT_DEBUGGER */
 
-                    stackTraceData.pushBack(std::make_pair(es, data));
+                    stateStack.push_back(es);
+                    stackTraceDataVector.pushBack(data);
                 }
             } else if (pstate->codeBlock() && pstate->codeBlock()->isInterpretedCodeBlock() && pstate->codeBlock()->asInterpretedCodeBlock()->isEvalCodeInFunction()) {
                 CodeBlock* cb = pstate->codeBlock();
                 ExtendedNodeLOC loc(SIZE_MAX, SIZE_MAX, SIZE_MAX);
                 SandBox::StackTraceData data;
                 data.loc = loc;
-                data.src = cb->asInterpretedCodeBlock()->script()->srcName();
+                data.srcName = cb->asInterpretedCodeBlock()->script()->srcName();
                 data.sourceCode = String::emptyString;
                 data.isEval = true;
                 data.isFunction = false;
@@ -228,25 +221,26 @@ bool SandBox::createStackTraceData(StackTraceDataVector& stackTraceData, Executi
                 data.executionStateDepth = executionStateDepthIndex;
 #endif /* ESCARGOT_DEBUGGER */
 
-                stackTraceData.pushBack(std::make_pair(es, data));
+                stateStack.push_back(es);
+                stackTraceDataVector.pushBack(data);
             } else if (callee) {
                 CodeBlock* cb = callee->codeBlock();
                 ExtendedNodeLOC loc(SIZE_MAX, SIZE_MAX, SIZE_MAX);
                 if (cb->isInterpretedCodeBlock()) {
                     ByteCodeBlock* b = cb->asInterpretedCodeBlock()->byteCodeBlock();
-                    ASSERT(!pstate->m_isNativeFunctionObjectExecutionContext);
+                    ASSERT(!pstate->isNativeFunctionObjectExecutionContext());
                     if (pstate->m_programCounter != nullptr) {
                         loc.byteCodePosition = *pstate->m_programCounter - (size_t)b->m_code.data();
                         loc.actualCodeBlock = b;
                     }
                 }
+
                 SandBox::StackTraceData data;
                 data.loc = loc;
+
                 if (cb->isInterpretedCodeBlock() && cb->asInterpretedCodeBlock()->script()) {
-                    data.src = cb->asInterpretedCodeBlock()->script()->srcName();
-#ifdef ESCARGOT_DEBUGGER
-                    data.executionStateDepth = executionStateDepthIndex;
-#endif /* ESCARGOT_DEBUGGER */
+                    data.srcName = cb->asInterpretedCodeBlock()->script()->srcName();
+                    data.sourceCode = cb->asInterpretedCodeBlock()->script()->sourceCode();
                 } else {
                     StringBuilder builder;
                     builder.appendString("function ");
@@ -254,18 +248,22 @@ bool SandBox::createStackTraceData(StackTraceDataVector& stackTraceData, Executi
                     builder.appendString("() { ");
                     builder.appendString("[native function]");
                     builder.appendString(" } ");
-                    data.src = builder.finalize();
-#ifdef ESCARGOT_DEBUGGER
-                    data.executionStateDepth = executionStateDepthIndex;
-#endif /* ESCARGOT_DEBUGGER */
+                    data.srcName = builder.finalize();
+                    data.sourceCode = String::emptyString;
                 }
+
                 data.functionName = cb->functionName().string();
                 data.isEval = false;
                 data.isFunction = true;
+                data.callee = callee;
                 data.isAssociatedWithJavaScriptCode = cb->isInterpretedCodeBlock();
                 data.isConstructor = callee->isConstructor();
-                data.sourceCode = String::emptyString;
-                stackTraceData.pushBack(std::make_pair(es, data));
+#ifdef ESCARGOT_DEBUGGER
+                data.executionStateDepth = executionStateDepthIndex;
+#endif /* ESCARGOT_DEBUGGER */
+
+                stateStack.push_back(es);
+                stackTraceDataVector.pushBack(data);
             }
         }
 
@@ -286,8 +284,8 @@ bool SandBox::createStackTraceData(StackTraceDataVector& stackTraceData, Executi
 
 void SandBox::throwException(ExecutionState& state, Value exception)
 {
-    m_stackTraceData.clear();
-    createStackTraceData(m_stackTraceData, state);
+    m_stackTraceDataVector.clear();
+    createStackTrace(m_stackTraceDataVector, state);
 
     // We MUST save thrown exception Value.
     // because bdwgc cannot track `thrown value`(may turned off by GC_DONT_REGISTER_MAIN_STATIC_DATA)
@@ -295,11 +293,11 @@ void SandBox::throwException(ExecutionState& state, Value exception)
     throw exception;
 }
 
-void SandBox::rethrowPreviouslyCaughtException(ExecutionState& state, Value exception, const StackTraceDataVector& stackTraceData)
+void SandBox::rethrowPreviouslyCaughtException(ExecutionState& state, Value exception, const StackTraceDataVector& stackTraceDataVector)
 {
-    m_stackTraceData = stackTraceData;
+    m_stackTraceDataVector = stackTraceDataVector;
     // update stack trace data if needs
-    createStackTraceData(m_stackTraceData, state);
+    createStackTrace(m_stackTraceDataVector, state);
 
     // We MUST save thrown exception Value.
     // because bdwgc cannot track `thrown value`(may turned off by GC_DONT_REGISTER_MAIN_STATIC_DATA)
@@ -327,16 +325,16 @@ static Value builtinErrorObjectStackInfo(ExecutionState& state, Value thisValue,
 ErrorObject::StackTraceData* ErrorObject::StackTraceData::create(SandBox* sandBox)
 {
     ErrorObject::StackTraceData* data = new ErrorObject::StackTraceData();
-    data->gcValues.resizeWithUninitializedValues(sandBox->m_stackTraceData.size());
-    data->nonGCValues.resizeWithUninitializedValues(sandBox->m_stackTraceData.size());
+    data->gcValues.resizeWithUninitializedValues(sandBox->m_stackTraceDataVector.size());
+    data->nonGCValues.resizeWithUninitializedValues(sandBox->m_stackTraceDataVector.size());
     data->exception = sandBox->m_exception;
 
-    for (size_t i = 0; i < sandBox->m_stackTraceData.size(); i++) {
-        if ((size_t)sandBox->m_stackTraceData[i].second.loc.index == SIZE_MAX && (size_t)sandBox->m_stackTraceData[i].second.loc.actualCodeBlock != SIZE_MAX) {
-            data->gcValues[i].byteCodeBlock = sandBox->m_stackTraceData[i].second.loc.actualCodeBlock;
-            data->nonGCValues[i].byteCodePosition = sandBox->m_stackTraceData[i].second.loc.byteCodePosition;
+    for (size_t i = 0; i < sandBox->m_stackTraceDataVector.size(); i++) {
+        if ((size_t)sandBox->m_stackTraceDataVector[i].loc.index == SIZE_MAX && (size_t)sandBox->m_stackTraceDataVector[i].loc.actualCodeBlock != SIZE_MAX) {
+            data->gcValues[i].byteCodeBlock = sandBox->m_stackTraceDataVector[i].loc.actualCodeBlock;
+            data->nonGCValues[i].byteCodePosition = sandBox->m_stackTraceDataVector[i].loc.byteCodePosition;
         } else {
-            data->gcValues[i].infoString = sandBox->m_stackTraceData[i].second.src;
+            data->gcValues[i].infoString = sandBox->m_stackTraceDataVector[i].srcName;
             data->nonGCValues[i].byteCodePosition = SIZE_MAX;
         }
     }
@@ -452,10 +450,17 @@ void SandBox::fillStackDataIntoErrorObject(const Value& e)
 {
     if (e.isObject() && e.asObject()->isErrorObject()) {
         ErrorObject* obj = e.asObject()->asErrorObject();
+        ExecutionState state(m_context);
+
+        if (UNLIKELY(m_context->vmInstance()->isErrorCreationCallbackRegistered() && obj->hasOwnProperty(state, ObjectPropertyName(m_context->staticStrings().stack)))) {
+            // if ErrorCreationCallback is registered and this callback already inserts `stack` property for evert created ErrorObject,
+            // we just ignore adding `stack` data here
+            return;
+        }
+
         ErrorObject::StackTraceData* data = ErrorObject::StackTraceData::create(this);
         obj->setStackTraceData(data);
 
-        ExecutionState state(m_context);
         JSGetterSetter gs(
             new NativeFunctionObject(state, NativeFunctionInfo(m_context->staticStrings().stack, builtinErrorObjectStackInfo, 0, NativeFunctionInfo::Strict)),
             Value(Value::EmptyValue));
index 3e087b65431bd6a2eda9c3e58c88a61bc4dcecf5..a1fb1b3b9ebf6e3886017eab341b5a04bc00b0c7 100644 (file)
@@ -34,25 +34,29 @@ public:
     ~SandBox();
 
     struct StackTraceData : public gc {
-        String* src;
+        String* srcName;
         String* sourceCode;
         ExtendedNodeLOC loc;
         String* functionName;
+
 #ifdef ESCARGOT_DEBUGGER
         uint32_t executionStateDepth;
 #endif /* ESCARGOT_DEBUGGER */
+        Optional<FunctionObject*> callee;
         bool isFunction;
         bool isConstructor;
         bool isAssociatedWithJavaScriptCode;
         bool isEval;
+
         StackTraceData()
-            : src(String::emptyString)
+            : srcName(String::emptyString)
             , sourceCode(String::emptyString)
             , loc(SIZE_MAX, SIZE_MAX, SIZE_MAX)
             , functionName(String::emptyString)
 #ifdef ESCARGOT_DEBUGGER
             , executionStateDepth(0)
 #endif /* ESCARGOT_DEBUGGER */
+            , callee(nullptr)
             , isFunction(false)
             , isConstructor(false)
             , isAssociatedWithJavaScriptCode(false)
@@ -61,12 +65,13 @@ public:
         }
     };
 
-    typedef Vector<std::pair<ExecutionState*, StackTraceData>, GCUtil::gc_malloc_allocator<std::pair<ExecutionState*, StackTraceData>>> StackTraceDataVector;
+    typedef Vector<StackTraceData, GCUtil::gc_malloc_allocator<StackTraceData>> StackTraceDataVector;
 
     struct SandBoxResult {
         Value result;
         Value error;
-        Vector<StackTraceData, GCUtil::gc_malloc_allocator<StackTraceData>> stackTraceData;
+        StackTraceDataVector stackTrace;
+
         SandBoxResult()
             : result(Value::EmptyValue)
             , error(Value::EmptyValue)
@@ -76,13 +81,15 @@ public:
 
     SandBoxResult run(const std::function<Value()>& scriptRunner); // for capsule script executing with try-catch
     SandBoxResult run(Value (*runner)(ExecutionState&, void*), void* data);
-    static bool createStackTraceData(StackTraceDataVector& stackTraceData, ExecutionState& state, bool stopAtPause = false);
+
+    static bool createStackTrace(StackTraceDataVector& stackTraceDataVector, ExecutionState& state, bool stopAtPause = false);
+
     void throwException(ExecutionState& state, Value exception);
-    void rethrowPreviouslyCaughtException(ExecutionState& state, Value exception, const StackTraceDataVector& stackTraceData);
+    void rethrowPreviouslyCaughtException(ExecutionState& state, Value exception, const StackTraceDataVector& stackTraceDataVector);
 
-    StackTraceDataVector& stackTraceData()
+    StackTraceDataVector& stackTraceDataVector()
     {
-        return m_stackTraceData;
+        return m_stackTraceDataVector;
     }
 
     Context* context()
@@ -97,7 +104,7 @@ protected:
 private:
     Context* m_context;
     SandBox* m_oldSandBox;
-    StackTraceDataVector m_stackTraceData;
+    StackTraceDataVector m_stackTraceDataVector;
     Value m_exception; // To avoid accidential GC of exception value
 };
 } // namespace Escargot
index 2a08029a63876eb3e018e1688651b3a5014c536c..57566b4bb3556151d898b5c53fb8f1c7d183b84e 100644 (file)
@@ -27,7 +27,7 @@ namespace Escargot {
 class ScriptArrowFunctionObject : public ScriptFunctionObject {
 public:
     ScriptArrowFunctionObject(ExecutionState& state, Object* proto, InterpretedCodeBlock* codeBlock, LexicalEnvironment* outerEnvironment, EncodedValue thisValue)
-        : ScriptFunctionObject(state, proto, codeBlock, outerEnvironment, false, codeBlock->isGenerator(), codeBlock->isAsync())
+        : ScriptFunctionObject(state, proto, codeBlock, outerEnvironment, false, codeBlock->isGenerator())
         , m_thisValue(thisValue)
     {
     }
index e0bceb89d8592d5b9c5d5569e6dd3f5ed1b3007c..fe00bfd81b6cc4e1e80f80466348002f28f9fff9 100644 (file)
@@ -26,7 +26,7 @@
 namespace Escargot {
 
 ScriptAsyncFunctionObject::ScriptAsyncFunctionObject(ExecutionState& state, Object* proto, InterpretedCodeBlock* codeBlock, LexicalEnvironment* outerEnvironment, EncodedValue thisValue, Object* homeObject)
-    : ScriptFunctionObject(state, proto, codeBlock, outerEnvironment, false, false, true)
+    : ScriptFunctionObject(state, proto, codeBlock, outerEnvironment, false, false)
     , m_thisValue(thisValue)
     , m_homeObject(homeObject)
 {
index 1a317fdc181c8726b14322fef841af587045ed42..ecec1004c9e22fe7b555bcdfd18d079fcd808e57 100644 (file)
@@ -27,7 +27,7 @@ namespace Escargot {
 class ScriptAsyncGeneratorFunctionObject : public ScriptFunctionObject {
 public:
     ScriptAsyncGeneratorFunctionObject(ExecutionState& state, Object* proto, InterpretedCodeBlock* codeBlock, LexicalEnvironment* outerEnvironment, EncodedValue thisValue = EncodedValue(EncodedValue::EmptyValue), Object* homeObject = nullptr)
-        : ScriptFunctionObject(state, proto, codeBlock, outerEnvironment, false, true, true)
+        : ScriptFunctionObject(state, proto, codeBlock, outerEnvironment, false, true)
         , m_thisValue(thisValue)
         , m_homeObject(homeObject)
     {
index 17917c8c0785ed8b0687c8444dd438ee368b804a..54d2c3f546cb582bff45da7cc80d486a6e2f30c5 100644 (file)
@@ -28,7 +28,7 @@ namespace Escargot {
 class ScriptClassMethodFunctionObject : public ScriptFunctionObject {
 public:
     ScriptClassMethodFunctionObject(ExecutionState& state, Object* proto, InterpretedCodeBlock* codeBlock, LexicalEnvironment* outerEnvironment, Object* homeObject)
-        : ScriptFunctionObject(state, proto, codeBlock, outerEnvironment, false, codeBlock->isGenerator(), codeBlock->isAsync())
+        : ScriptFunctionObject(state, proto, codeBlock, outerEnvironment, false, codeBlock->isGenerator())
         , m_homeObject(homeObject)
     {
     }
index 42d11e8e7e1577a7ff3469e329eaeeee09d99acc..0cc1910fdd108d2650629b4ecdd2919f81ea882d 100644 (file)
@@ -30,6 +30,7 @@
 #include "runtime/EnvironmentRecord.h"
 #include "runtime/ErrorObject.h"
 #include "runtime/VMInstance.h"
+#include "runtime/ScriptSimpleFunctionObject.h"
 #include "parser/ScriptParser.h"
 #include "parser/ast/AST.h"
 
 
 namespace Escargot {
 
-ScriptFunctionObject::ScriptFunctionObject(ExecutionState& state, Object* proto, InterpretedCodeBlock* codeBlock, LexicalEnvironment* outerEnv, bool isConstructor, bool isGenerator, bool isAsync)
+ScriptFunctionObject::ScriptFunctionObject(ExecutionState& state, Object* proto, InterpretedCodeBlock* codeBlock, LexicalEnvironment* outerEnv, bool isConstructor, bool isGenerator)
     : ScriptFunctionObject(state, proto, codeBlock, outerEnv,
                            ((isConstructor || isGenerator) ? (ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 3) : (ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2)) + (codeBlock->isStrict() ? 2 : 0))
 {
-    initStructureAndValues(state, isConstructor, isGenerator, isAsync);
+    initStructureAndValues(state, isConstructor, isGenerator);
 }
 
 ScriptFunctionObject::ScriptFunctionObject(ExecutionState& state, Object* proto, InterpretedCodeBlock* codeBlock, LexicalEnvironment* outerEnvironment, size_t defaultPropertyCount)
@@ -77,6 +78,47 @@ NEVER_INLINE void ScriptFunctionObject::generateByteCodeBlock(ExecutionState& st
     auto& currentCodeSizeTotal = state.context()->vmInstance()->compiledByteCodeSize();
     ASSERT(currentCodeSizeTotal < std::numeric_limits<size_t>::max());
     currentCodeSizeTotal += interpretedCodeBlock()->byteCodeBlock()->memoryAllocatedSize();
+
+
+    if (hasTag(g_scriptFunctionObjectTag)) {
+        auto cb = m_codeBlock->asInterpretedCodeBlock();
+        auto byteCb = cb->byteCodeBlock();
+        size_t registerSize = byteCb->m_requiredRegisterFileSizeInValueSize;
+        size_t identifierOnStackCount = cb->identifierOnStackCount();
+        size_t stackStorageSize = cb->totalStackAllocatedVariableSize();
+        size_t literalStorageSize = byteCb->m_numeralLiteralData.size();
+        size_t registerFileSize = registerSize + stackStorageSize + literalStorageSize;
+
+        bool isStrict = cb->isStrict();
+        bool shouldClearStack = byteCb->m_shouldClearStack;
+
+#define DEFINE_SCRIPTSIMPLEFUNCTION_BRANCH(opt1, opt2)                   \
+    if (registerFileSize <= 4) {                                         \
+        writeTag(ScriptSimpleFunctionObject<opt1, opt2, 4>().getTag());  \
+    } else if (registerFileSize <= 8) {                                  \
+        writeTag(ScriptSimpleFunctionObject<opt1, opt2, 8>().getTag());  \
+    } else if (registerFileSize <= 16) {                                 \
+        writeTag(ScriptSimpleFunctionObject<opt1, opt2, 16>().getTag()); \
+    } else {                                                             \
+        writeTag(ScriptSimpleFunctionObject<opt1, opt2, 24>().getTag()); \
+    }
+
+        if (cb->canAllocateEnvironmentOnStack() && registerFileSize <= 24) {
+            if (isStrict) {
+                if (shouldClearStack) {
+                    DEFINE_SCRIPTSIMPLEFUNCTION_BRANCH(true, true);
+                } else {
+                    DEFINE_SCRIPTSIMPLEFUNCTION_BRANCH(true, false);
+                }
+            } else {
+                if (shouldClearStack) {
+                    DEFINE_SCRIPTSIMPLEFUNCTION_BRANCH(false, true);
+                } else {
+                    DEFINE_SCRIPTSIMPLEFUNCTION_BRANCH(false, false);
+                }
+            }
+        }
+    }
 }
 
 Value ScriptFunctionObject::call(ExecutionState& state, const Value& thisValue, const size_t argc, Value* argv)
@@ -161,7 +203,7 @@ void ScriptFunctionObject::generateArgumentsObject(ExecutionState& state, size_t
                 if (v[i].m_needToAllocateOnStack) {
                     stackStorage[v[i].m_indexForIndexedStorage] = newArgumentsObject;
                 } else {
-                    environmentRecordWillArgumentsObjectBeLocatedIn->heapStorage()[v[i].m_indexForIndexedStorage] = newArgumentsObject;
+                    environmentRecordWillArgumentsObjectBeLocatedIn->setHeapValueByIndex(state, v[i].m_indexForIndexedStorage, newArgumentsObject);
                 }
                 break;
             }
index 65e475f9ba3953c157fe9090acb126ad13b74d22..39f57054673fbe5ba897e457461270d3fb91998a 100644 (file)
@@ -28,6 +28,7 @@ class ScriptFunctionObject : public FunctionObject {
     friend class Script;
     friend class ByteCodeInterpreter;
     friend class FunctionObjectProcessCallGenerator;
+    friend class Global;
 
 public:
     enum ConstructorKind {
@@ -41,7 +42,7 @@ public:
         Global,
     };
 
-    ScriptFunctionObject(ExecutionState& state, Object* proto, InterpretedCodeBlock* codeBlock, LexicalEnvironment* outerEnvironment, bool isConstructor, bool isGenerator, bool isAsync);
+    ScriptFunctionObject(ExecutionState& state, Object* proto, InterpretedCodeBlock* codeBlock, LexicalEnvironment* outerEnvironment, bool isConstructor, bool isGenerator);
 
     virtual bool isGenerator() const override
     {
@@ -76,6 +77,14 @@ public:
     }
 
 protected:
+    ScriptFunctionObject()
+        : FunctionObject()
+        , m_outerEnvironment(nullptr)
+    {
+        // dummy default constructor
+        // only called by Global::initialize to set tag value
+    }
+
     ScriptFunctionObject(ExecutionState& state, Object* proto, InterpretedCodeBlock* codeBlock, LexicalEnvironment* outerEnvironment, size_t defaultPropertyCount);
 
     // https://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
index ac24175425fe056728337297caa8259720a5b7b2..bebb8ad8d49fdda668331ac61acf81d7b12dc105 100644 (file)
@@ -29,7 +29,7 @@ class ScriptGeneratorFunctionObject : public ScriptFunctionObject {
 public:
     // both thisValue, homeObject are optional
     ScriptGeneratorFunctionObject(ExecutionState& state, Object* proto, InterpretedCodeBlock* codeBlock, LexicalEnvironment* outerEnvironment, EncodedValue thisValue = EncodedValue(EncodedValue::EmptyValue), Object* homeObject = nullptr)
-        : ScriptFunctionObject(state, proto, codeBlock, outerEnvironment, false, true, false)
+        : ScriptFunctionObject(state, proto, codeBlock, outerEnvironment, false, true)
         , m_thisValue(thisValue)
         , m_homeObject(homeObject)
     {
diff --git a/lwnode/code/escargotshim/deps/escargot/src/runtime/ScriptSimpleFunctionObject.h b/lwnode/code/escargotshim/deps/escargot/src/runtime/ScriptSimpleFunctionObject.h
new file mode 100644 (file)
index 0000000..22bf1be
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2022-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
+ */
+
+#ifndef __EscargotScriptSimpleFunctionObject__
+#define __EscargotScriptSimpleFunctionObject__
+
+#include "runtime/ScriptFunctionObject.h"
+#include "runtime/Environment.h"
+#include "runtime/EnvironmentRecord.h"
+#include "runtime/ErrorObject.h"
+#include "runtime/VMInstance.h"
+#include "interpreter/ByteCode.h"
+#include "interpreter/ByteCodeGenerator.h"
+#include "interpreter/ByteCodeInterpreter.h"
+
+namespace Escargot {
+
+template <bool isStrict = false, bool shouldClearStack = false, unsigned registerFileSize = 12>
+class ScriptSimpleFunctionObject : public ScriptFunctionObject {
+    friend class ScriptFunctionObject;
+
+protected:
+    ScriptSimpleFunctionObject() // ctor for reading tag
+        : ScriptFunctionObject()
+    {
+    }
+
+    virtual Value call(ExecutionState& state, const Value& thisValue, const size_t argc, Value* argv) override
+    {
+#ifdef STACK_GROWS_DOWN
+        if (UNLIKELY(state.stackLimit() > (size_t)currentStackPointer())) {
+#else
+        if (UNLIKELY(state.stackLimit() < (size_t)currentStackPointer())) {
+#endif
+            ErrorObject::throwBuiltinError(state, ErrorObject::RangeError, "Maximum call stack size exceeded");
+        }
+
+        ASSERT(codeBlock()->isInterpretedCodeBlock());
+        InterpretedCodeBlock* codeBlock = interpretedCodeBlock();
+
+        // prepare ByteCodeBlock if needed
+        if (UNLIKELY(codeBlock->byteCodeBlock() == nullptr)) {
+            generateByteCodeBlock(state);
+        }
+
+        ByteCodeBlock* blk = codeBlock->byteCodeBlock();
+        Context* ctx = codeBlock->context();
+        const size_t stackStorageSize = codeBlock->totalStackAllocatedVariableSize();
+        const size_t identifierOnStackCount = codeBlock->identifierOnStackCount();
+        const size_t registerSize = blk->m_requiredRegisterFileSizeInValueSize;
+        const size_t literalStorageSize = blk->m_numeralLiteralData.size();
+        Value* literalStorageSrc = blk->m_numeralLiteralData.data();
+
+#if !defined(NDEBUG)
+        ASSERT(codeBlock->isStrict() == isStrict);
+        ASSERT(blk->m_requiredRegisterFileSizeInValueSize + stackStorageSize + literalStorageSize <= registerFileSize);
+#endif
+
+        // prepare env, ec
+        ASSERT(codeBlock->canAllocateEnvironmentOnStack());
+        FunctionEnvironmentRecordOnStack<false, false> record(this);
+        LexicalEnvironment lexEnv(&record, outerEnvironment()
+#ifndef NDEBUG
+                                               ,
+                                  false
+#endif
+        );
+
+        char* registerFileBuffer[sizeof(Value) * registerFileSize];
+        Value* registerFile = reinterpret_cast<Value*>(registerFileBuffer);
+        Value* stackStorage = registerFile + registerSize;
+
+        {
+            Value* literalStorage = stackStorage + stackStorageSize;
+            for (size_t i = 0; i < literalStorageSize; i++) {
+                literalStorage[i] = literalStorageSrc[i];
+            }
+        }
+
+        // binding function name
+        stackStorage[1] = this;
+
+        // initialize identifiers by undefined value
+        for (size_t i = 2; i < identifierOnStackCount; i++) {
+            stackStorage[i] = Value();
+        }
+
+        ExecutionState newState(ctx, &state, &lexEnv, argc, argv, isStrict);
+        if (isStrict) {
+            stackStorage[0] = thisValue;
+        } else {
+            if (thisValue.isUndefinedOrNull()) {
+                stackStorage[0] = newState.context()->globalObjectProxy();
+            } else {
+                stackStorage[0] = thisValue.toObject(newState);
+            }
+        }
+
+        if (shouldClearStack) {
+            const Value returnValue = ByteCodeInterpreter::interpret(&newState, blk, 0, registerFile);
+            clearStack<512>();
+            return returnValue;
+        } else {
+            return ByteCodeInterpreter::interpret(&newState, blk, 0, registerFile);
+        }
+    }
+};
+
+COMPILE_ASSERT(sizeof(ScriptSimpleFunctionObject<>) == sizeof(ScriptFunctionObject), "");
+
+} // namespace Escargot
+
+#endif
index 9ddf93142f18fb87b484bd24f81dc2f2f3ed772d..2591594159f77aa486c540532f8a659790643fd0 100644 (file)
@@ -29,7 +29,7 @@ class ScriptVirtualArrowFunctionObject : public ScriptFunctionObject {
 
 public:
     ScriptVirtualArrowFunctionObject(ExecutionState& state, Object* proto, InterpretedCodeBlock* codeBlock, LexicalEnvironment* outerEnvironment)
-        : ScriptFunctionObject(state, proto, codeBlock, outerEnvironment, false, codeBlock->isGenerator(), codeBlock->isAsync())
+        : ScriptFunctionObject(state, proto, codeBlock, outerEnvironment, false, codeBlock->isGenerator())
     {
         m_prototype = nullptr;
     }
index 5f523e476686ac64d177ae2f2c671a117c134f70..6e45baaf298cb3697e5ed71edf2611306b5a7e5e 100644 (file)
@@ -24,6 +24,7 @@
 #include "runtime/Global.h"
 #include "runtime/Platform.h"
 #include "runtime/SharedArrayBufferObject.h"
+#include "runtime/TypedArrayInlines.h"
 
 namespace Escargot {
 
@@ -118,6 +119,157 @@ void* SharedArrayBufferObject::operator new(size_t size)
     return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
 }
 
+void SharedArrayBufferObject::fillData(const uint8_t* newData, size_t length)
+{
+#if defined(HAVE_BUILTIN_ATOMIC_FUNCTIONS)
+    uint8_t* rawBytes = ALLOCA(8, uint8_t, nullptr);
+    uint8_t* rawTarget = data();
+    for (size_t i = 0; i < length; i++) {
+        __atomic_load(newData + i, rawBytes, __ATOMIC_SEQ_CST);
+        __atomic_store(rawTarget + i, rawBytes, __ATOMIC_SEQ_CST);
+    }
+#else
+    std::lock_guard<SpinLock> guard(Global::atomicsLock());
+    memcpy(data(), newData, length);
+#endif
+}
+
+Value SharedArrayBufferObject::getValueFromBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, bool isLittleEndian)
+{
+    ASSERT(byteLength());
+    size_t elemSize = TypedArrayHelper::elementSize(type);
+    ASSERT(byteindex + elemSize <= byteLength());
+
+    uint8_t* rawStart = data() + byteindex;
+#if defined(HAVE_BUILTIN_ATOMIC_FUNCTIONS)
+    uint8_t* rawBytes = ALLOCA(8, uint8_t, state);
+
+    switch (type) {
+    case TypedArrayType::Int8:
+        __atomic_load(reinterpret_cast<int8_t*>(rawStart), reinterpret_cast<int8_t*>(rawBytes), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Int16:
+        __atomic_load(reinterpret_cast<int16_t*>(rawStart), reinterpret_cast<int16_t*>(rawBytes), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Int32:
+        __atomic_load(reinterpret_cast<int32_t*>(rawStart), reinterpret_cast<int32_t*>(rawBytes), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Uint8:
+        __atomic_load(reinterpret_cast<uint8_t*>(rawStart), reinterpret_cast<uint8_t*>(rawBytes), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Uint16:
+        __atomic_load(reinterpret_cast<uint16_t*>(rawStart), reinterpret_cast<uint16_t*>(rawBytes), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Uint32:
+        __atomic_load(reinterpret_cast<uint32_t*>(rawStart), reinterpret_cast<uint32_t*>(rawBytes), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Uint8Clamped:
+        __atomic_load(reinterpret_cast<uint8_t*>(rawStart), reinterpret_cast<uint8_t*>(rawBytes), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Float32:
+        __atomic_load(reinterpret_cast<float*>(rawStart), reinterpret_cast<float*>(rawBytes), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Float64:
+        __atomic_load(reinterpret_cast<double*>(rawStart), reinterpret_cast<double*>(rawBytes), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::BigInt64:
+        __atomic_load(reinterpret_cast<int64_t*>(rawStart), reinterpret_cast<int64_t*>(rawBytes), __ATOMIC_SEQ_CST);
+        break;
+    default:
+        ASSERT(TypedArrayType::BigUint64 == type);
+        __atomic_load(reinterpret_cast<uint64_t*>(rawStart), reinterpret_cast<uint64_t*>(rawBytes), __ATOMIC_SEQ_CST);
+        break;
+    }
+
+    if (LIKELY(isLittleEndian)) {
+        return TypedArrayHelper::rawBytesToNumber(state, type, rawBytes);
+    } else {
+        uint8_t* rawBytes2 = ALLOCA(8, uint8_t, state);
+        for (size_t i = 0; i < elemSize; i++) {
+            rawBytes2[elemSize - i - 1] = rawBytes[i];
+        }
+        return TypedArrayHelper::rawBytesToNumber(state, type, rawBytes2);
+    }
+#else
+    std::lock_guard<SpinLock> guard(Global::atomicsLock());
+    if (LIKELY(isLittleEndian)) {
+        return TypedArrayHelper::rawBytesToNumber(state, type, rawStart);
+    } else {
+        uint8_t* rawBytes = ALLOCA(8, uint8_t, state);
+        for (size_t i = 0; i < elemSize; i++) {
+            rawBytes[elemSize - i - 1] = rawStart[i];
+        }
+        return TypedArrayHelper::rawBytesToNumber(state, type, rawBytes);
+    }
+#endif
+}
+
+void SharedArrayBufferObject::setValueInBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, const Value& val, bool isLittleEndian)
+{
+    ASSERT(byteLength());
+    size_t elemSize = TypedArrayHelper::elementSize(type);
+    ASSERT(byteindex + elemSize <= byteLength());
+
+    uint8_t* rawStart = data() + byteindex;
+    uint8_t* rawBytes = ALLOCA(8, uint8_t, state);
+    TypedArrayHelper::numberToRawBytes(state, type, val, rawBytes);
+#if defined(HAVE_BUILTIN_ATOMIC_FUNCTIONS)
+    uint8_t* rawBytes2 = ALLOCA(8, uint8_t, state);
+    if (LIKELY(isLittleEndian)) {
+        rawBytes2 = rawBytes;
+    } else {
+        for (size_t i = 0; i < elemSize; i++) {
+            rawBytes2[i] = rawBytes[elemSize - i - 1];
+        }
+    }
+
+    switch (type) {
+    case TypedArrayType::Int8:
+        __atomic_store(reinterpret_cast<int8_t*>(rawStart), reinterpret_cast<int8_t*>(rawBytes2), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Int16:
+        __atomic_store(reinterpret_cast<int16_t*>(rawStart), reinterpret_cast<int16_t*>(rawBytes2), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Int32:
+        __atomic_store(reinterpret_cast<int32_t*>(rawStart), reinterpret_cast<int32_t*>(rawBytes2), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Uint8:
+        __atomic_store(reinterpret_cast<uint8_t*>(rawStart), reinterpret_cast<uint8_t*>(rawBytes2), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Uint16:
+        __atomic_store(reinterpret_cast<uint16_t*>(rawStart), reinterpret_cast<uint16_t*>(rawBytes2), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Uint32:
+        __atomic_store(reinterpret_cast<uint32_t*>(rawStart), reinterpret_cast<uint32_t*>(rawBytes2), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Uint8Clamped:
+        __atomic_store(reinterpret_cast<uint8_t*>(rawStart), reinterpret_cast<uint8_t*>(rawBytes2), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Float32:
+        __atomic_store(reinterpret_cast<float*>(rawStart), reinterpret_cast<float*>(rawBytes2), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::Float64:
+        __atomic_store(reinterpret_cast<double*>(rawStart), reinterpret_cast<double*>(rawBytes2), __ATOMIC_SEQ_CST);
+        break;
+    case TypedArrayType::BigInt64:
+        __atomic_store(reinterpret_cast<int64_t*>(rawStart), reinterpret_cast<int64_t*>(rawBytes2), __ATOMIC_SEQ_CST);
+        break;
+    default:
+        ASSERT(TypedArrayType::BigUint64 == type);
+        __atomic_store(reinterpret_cast<uint64_t*>(rawStart), reinterpret_cast<uint64_t*>(rawBytes2), __ATOMIC_SEQ_CST);
+        break;
+    }
+#else
+    std::lock_guard<SpinLock> guard(Global::atomicsLock());
+    if (LIKELY(isLittleEndian)) {
+        memcpy(rawStart, rawBytes, elemSize);
+    } else {
+        for (size_t i = 0; i < elemSize; i++) {
+            rawStart[i] = rawBytes[elemSize - i - 1];
+        }
+    }
+#endif
+}
 } // namespace Escargot
 
 #endif
index a5d2d8ea7eed5ac115ff2a92ddfe3674fde42e13..ffb74bfbba7bb266d852bd4884d48f0a9c1c30ab 100644 (file)
@@ -40,6 +40,11 @@ public:
         return true;
     }
 
+    // thread-safe functions
+    virtual void fillData(const uint8_t* newData, size_t length) override;
+    virtual Value getValueFromBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, bool isLittleEndian = true) override;
+    virtual void setValueInBuffer(ExecutionState& state, size_t byteindex, TypedArrayType type, const Value& val, bool isLittleEndian = true) override;
+
     void* operator new(size_t size);
     void* operator new[](size_t size) = delete;
 };
index 201edab789a8731856113311510f84a39871591a..4115e1812b63c95f7d9ac8672461bc36f047443c 100644 (file)
@@ -270,6 +270,7 @@ namespace Escargot {
     F(global)                     \
     F(globalThis)                 \
     F(groups)                     \
+    F(grow)                       \
     F(growable)                   \
     F(has)                        \
     F(hasInstance)                \
@@ -496,7 +497,6 @@ namespace Escargot {
     F(exports)                         \
     F(f32)                             \
     F(f64)                             \
-    F(grow)                            \
     F(i32)                             \
     F(i64)                             \
     F(imports)                         \
@@ -825,6 +825,14 @@ public:
         free(numbers);
     }
 
+    Escargot::String* charCodeToString(char32_t ch)
+    {
+        if (LIKELY(ch < ESCARGOT_ASCII_TABLE_MAX)) {
+            return asciiTable[ch].string();
+        }
+        return String::fromCharCode(ch);
+    }
+
     // keyword string
     AtomicString stringBreak;
     AtomicString stringCase;
index 1752790b5cbfd91ea330fdce7ee38de0f5bf78cc..21230c5c88d37cb08e76d453989b1b280b1c76b8 100644 (file)
@@ -548,10 +548,10 @@ void CreateExponentialRepresentation(
                                  kMaxExponentLength - first_char_pos);
 }
 
-ASCIIStringData dtoa(double number)
+ASCIIStringDataNonGCStd dtoa(double number)
 {
     if (number == 0) {
-        return ASCIIStringData("0", 1);
+        return "0";
     }
     const int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN;
     bool sign = false;
@@ -609,24 +609,108 @@ ASCIIStringData dtoa(double number)
         str += *buf;
         buf++;
     }
-    return ASCIIStringData(str.data(), str.length());
+    return str;
+}
+
+void String::initEmptyString()
+{
+    ASSERT(!String::emptyString);
+    String* emptyStr = new (NoGC) ASCIIString("");
+    // mark empty string as AtomicString source
+    // because empty string is the default string value of empty AtomicString
+    emptyStr->m_tag = (size_t)POINTER_VALUE_STRING_TAG_IN_DATA | (size_t)emptyStr;
+
+    ASSERT(emptyStr->isAtomicStringSource());
+    String::emptyString = emptyStr;
 }
 
+#define LATIN1_LARGE_INLINE_BUFFER(F) \
+    F(1)                              \
+    F(2)                              \
+    F(3)                              \
+    F(4)                              \
+    F(5)                              \
+    F(6)                              \
+    F(7)                              \
+    F(8)                              \
+    F(9)                              \
+    F(10)                             \
+    F(11)                             \
+    F(12)                             \
+    F(13)                             \
+    F(14)                             \
+    F(15)                             \
+    F(16)                             \
+    F(17)                             \
+    F(18)                             \
+    F(19)                             \
+    F(20)                             \
+    F(21)                             \
+    F(22)                             \
+    F(23)                             \
+    F(24)
+
+#define LATIN1_LARGE_INLINE_BUFFER_DEFINE(N) \
+    template class Latin1StringWithLargeInlineBuffer<N>;
+
+LATIN1_LARGE_INLINE_BUFFER(LATIN1_LARGE_INLINE_BUFFER_DEFINE)
+
 String* String::fromASCII(const char* src, size_t len)
 {
-    return new ASCIIString(src, len);
+    if (len <= String::StringBufferData::bufferPointerAsArraySize) {
+        return new ASCIIStringWithInlineBuffer(src, len);
+    } else {
+        switch (len) {
+#define LATIN1_LARGE_INLINE_BUFFER_SWITCH_ASCII(N) \
+    case N:                                        \
+        return new Latin1StringWithLargeInlineBuffer<N>(reinterpret_cast<const LChar*>(src), len);
+            LATIN1_LARGE_INLINE_BUFFER(LATIN1_LARGE_INLINE_BUFFER_SWITCH_ASCII)
+        default:
+            return new ASCIIString(src, len);
+        }
+    }
+}
+
+String* String::fromLatin1(const LChar* src, size_t len)
+{
+    if (len <= String::StringBufferData::bufferPointerAsArraySize) {
+        return new Latin1StringWithInlineBuffer(src, len);
+    } else {
+        switch (len) {
+#define LATIN1_LARGE_INLINE_BUFFER_SWITCH(N) \
+    case N:                                  \
+        return new Latin1StringWithLargeInlineBuffer<N>(src, len);
+            LATIN1_LARGE_INLINE_BUFFER(LATIN1_LARGE_INLINE_BUFFER_SWITCH)
+        default:
+            return new Latin1String(src, len);
+        }
+    }
+}
+
+String* String::fromLatin1(const char16_t* src, size_t len)
+{
+    if (len <= LATIN1_LARGE_INLINE_BUFFER_MAX_SIZE) {
+        LChar* dest = static_cast<LChar*>(alloca(len));
+        for (size_t i = 0; i < len; i++) {
+            ASSERT(src[i] < 256);
+            dest[i] = src[i];
+        }
+        return String::fromLatin1(dest, len);
+    } else {
+        return new Latin1String(src, len);
+    }
 }
 
 String* String::fromDouble(double v)
 {
     auto s = dtoa(v);
-    return new ASCIIString(std::move(s));
+    return String::fromASCII(s.data(), s.length());
 }
 
 String* String::fromUTF8(const char* src, size_t len, bool maybeASCII)
 {
     if (maybeASCII && isAllASCII(src, len)) {
-        return new ASCIIString(src, len);
+        return String::fromASCII(src, len);
     } else {
         auto s = utf8StringToUTF16String(src, len);
         return new UTF16String(std::move(s));
@@ -645,6 +729,22 @@ String* String::fromUTF8ToCompressibleString(VMInstance* instance, const char* s
 }
 #endif
 
+String* String::fromCharCode(char32_t code)
+{
+    if (code < 128) {
+        char c = (char)code;
+        return new ASCIIStringWithInlineBuffer(&c, 1);
+    } else if (code < 0x10000) {
+        char16_t buf = code;
+        return new UTF16StringWithInlineBuffer(&buf, 1);
+    } else {
+        char16_t buf[2];
+        buf[0] = (char16_t)(0xD800 + ((code - 0x10000) >> 10));
+        buf[1] = (char16_t)(0xDC00 + ((code - 0x10000) & 1023));
+        return new UTF16StringWithInlineBuffer(buf, 2);
+    }
+}
+
 int String::stringCompare(size_t l1, size_t l2, const String* c1, const String* c2)
 {
     size_t s = 0;
@@ -744,7 +844,7 @@ uint32_t String::tryToUseAsIndexProperty() const
     return tryToUseAsIndex32();
 }
 
-size_t String::find(String* str, size_t pos)
+size_t String::find(String* str, size_t pos) const
 {
     const size_t srcStrLen = str->length();
     const size_t size = length();
@@ -788,6 +888,49 @@ size_t String::find(String* str, size_t pos)
     return SIZE_MAX;
 }
 
+size_t String::find(const char* str, size_t srcStrLen, size_t pos) const
+{
+    const size_t size = length();
+
+    if (srcStrLen == 0)
+        return pos <= size ? pos : SIZE_MAX;
+
+    if (srcStrLen <= size) {
+        char32_t src0 = str[0];
+        const auto& data = bufferAccessData();
+        if (data.has8BitContent) {
+            for (; pos <= size - srcStrLen; ++pos) {
+                if (((const LChar*)data.buffer)[pos] == src0) {
+                    bool same = true;
+                    for (size_t k = 1; k < srcStrLen; k++) {
+                        if (((const LChar*)data.buffer)[pos + k] != str[k]) {
+                            same = false;
+                            break;
+                        }
+                    }
+                    if (same)
+                        return pos;
+                }
+            }
+        } else {
+            for (; pos <= size - srcStrLen; ++pos) {
+                if (((const char16_t*)data.buffer)[pos] == src0) {
+                    bool same = true;
+                    for (size_t k = 1; k < srcStrLen; k++) {
+                        if (((const char16_t*)data.buffer)[pos + k] != str[k]) {
+                            same = false;
+                            break;
+                        }
+                    }
+                    if (same)
+                        return pos;
+                }
+            }
+        }
+    }
+    return SIZE_MAX;
+}
+
 size_t String::rfind(String* str, size_t pos)
 {
     const size_t srcStrLen = str->length();
@@ -875,21 +1018,20 @@ bool String::isAllSpecialCharacters(bool (*fn)(char))
 
 String* String::trim(String::StringTrimWhere where)
 {
-    const auto& bad = bufferAccessData();
-    int64_t stringLength = (int64_t)bad.length;
+    int64_t stringLength = (int64_t)length();
     int64_t s = 0;
     int64_t e = stringLength - 1;
 
     if (where == TrimStart || where == TrimBoth) {
         for (s = 0; s < stringLength; s++) {
-            if (!EscargotLexer::isWhiteSpaceOrLineTerminator(bad.charAt(s)))
+            if (!EscargotLexer::isWhiteSpaceOrLineTerminator(charAt(s)))
                 break;
         }
     }
 
     if (where == TrimEnd || where == TrimBoth) {
         for (e = stringLength - 1; e >= s; e--) {
-            if (!EscargotLexer::isWhiteSpaceOrLineTerminator(bad.charAt(e)))
+            if (!EscargotLexer::isWhiteSpaceOrLineTerminator(charAt(e)))
                 break;
         }
     }
@@ -901,32 +1043,6 @@ String* String::trim(String::StringTrimWhere where)
 }
 
 
-void* ASCIIString::operator new(size_t size)
-{
-    static MAY_THREAD_LOCAL bool typeInited = false;
-    static MAY_THREAD_LOCAL GC_descr descr;
-    if (!typeInited) {
-        GC_word obj_bitmap[GC_BITMAP_SIZE(ASCIIString)] = { 0 };
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ASCIIString, m_bufferData.buffer));
-        descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(ASCIIString));
-        typeInited = true;
-    }
-    return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
-}
-
-void* Latin1String::operator new(size_t size)
-{
-    static MAY_THREAD_LOCAL bool typeInited = false;
-    static MAY_THREAD_LOCAL GC_descr descr;
-    if (!typeInited) {
-        GC_word obj_bitmap[GC_BITMAP_SIZE(Latin1String)] = { 0 };
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(Latin1String, m_bufferData.buffer));
-        descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(Latin1String));
-        typeInited = true;
-    }
-    return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
-}
-
 void* UTF16String::operator new(size_t size)
 {
     static MAY_THREAD_LOCAL bool typeInited = false;
index c5c13a926fd1ef9c3813fa264afa29cc748371bb..803773093b957ac180603f7cea29a1fe27b06cd9 100644 (file)
@@ -59,7 +59,7 @@ char32_t readUTF8Sequence(const char*& sequence, bool& valid, int& charlen);
 UTF16StringData utf8StringToUTF16String(const char* buf, const size_t len);
 UTF8StringData utf16StringToUTF8String(const char16_t* buf, const size_t len);
 ASCIIStringData utf16StringToASCIIString(const char16_t* buf, const size_t len);
-ASCIIStringData dtoa(double number);
+ASCIIStringDataNonGCStd dtoa(double number);
 size_t utf32ToUtf8(char32_t uc, char* UTF8);
 size_t utf32ToUtf16(char32_t i, char16_t* u);
 
@@ -100,12 +100,30 @@ struct StringBufferAccessData {
     };
     void* extraData;
 
-    StringBufferAccessData(bool has8Bit, size_t len, void* buffer, void* extraDataKeepInStack = nullptr)
+    StringBufferAccessData(bool has8Bit, size_t len, void* buffer, void* extraDataToKeep = nullptr)
         : has8BitContent(has8Bit)
         , length(len)
         , buffer(buffer)
-        , extraData(extraDataKeepInStack)
+        , extraData(extraDataToKeep)
     {
+#if defined(ENABLE_COMPRESSIBLE_STRING) || defined(ENABLE_RELOADABLE_STRING)
+        if (extraData) {
+            // increase refCount in CompressibleString or ReloadableString
+            (*reinterpret_cast<size_t*>(extraData))++;
+        }
+#endif
+    }
+
+    ~StringBufferAccessData()
+    {
+#if defined(ENABLE_COMPRESSIBLE_STRING) || defined(ENABLE_RELOADABLE_STRING)
+        if (extraData) {
+            // decrease refCount in CompressibleString or ReloadableString
+            size_t& count = *reinterpret_cast<size_t*>(extraData);
+            ASSERT(count > 0);
+            count--;
+        }
+#endif
     }
 
     char16_t uncheckedCharAtFor8Bit(size_t idx) const
@@ -211,18 +229,27 @@ protected:
         {
         }
 
-        bool has8BitContent : 1;
-        bool hasSpecialImpl : 1;
+        union {
+            struct {
+                bool has8BitContent : 1;
+                bool hasSpecialImpl : 1;
 #if defined(ESCARGOT_32)
-        size_t length : 30;
+                size_t length : 30;
 #else
-        size_t length : 62;
+                size_t length : 62;
 #endif
+            };
+            size_t valueShouldBeOddForFewTypes;
+        };
+
+        static constexpr size_t bufferPointerAsArraySize = sizeof(size_t);
         union {
             const void* buffer;
             const char* bufferAs8Bit;
             const char16_t* bufferAs16Bit;
             String* bufferAsString;
+            LChar bufferPointerAsArray[bufferPointerAsArraySize];
+            char16_t bufferPointerAs16BitArray[bufferPointerAsArraySize / 2];
         };
 
         COMPILE_ASSERT(STRING_MAXIMUM_LENGTH < (std::numeric_limits<size_t>::max() >> 2), "");
@@ -298,6 +325,10 @@ public:
         return false;
     }
 
+    // initialize String::emptyString value
+    // its called only once by VMInstance constructor
+    static void initEmptyString();
+
     template <const size_t srcLen>
     static String* fromASCII(const char (&src)[srcLen])
     {
@@ -306,6 +337,12 @@ public:
     }
 
     static String* fromASCII(const char* s, size_t len);
+
+    // if you want to change this value, you  should change LATIN1_LARGE_INLINE_BUFFER macro in String.cpp
+#define LATIN1_LARGE_INLINE_BUFFER_MAX_SIZE 24
+    static String* fromLatin1(const LChar* s, size_t len);
+    static String* fromLatin1(const char16_t* s, size_t len);
+
     static String* fromCharCode(char32_t code);
     static String* fromDouble(double v);
     static String* fromInt32(int32_t v)
@@ -371,51 +408,14 @@ public:
         return true;
     }
 
-    size_t find(String* str, size_t pos = 0);
+    size_t find(String* str, size_t pos = 0) const;
+    size_t find(const char* str, size_t len, size_t pos = 0) const;
 
     template <size_t N>
-    size_t find(const char (&str)[N], size_t pos = 0) const
-    {
-        const size_t srcStrLen = N - 1;
-        const size_t size = length();
-
-        if (srcStrLen == 0)
-            return pos <= size ? pos : SIZE_MAX;
-
-        if (srcStrLen <= size) {
-            char32_t src0 = str[0];
-            const auto& data = bufferAccessData();
-            if (data.has8BitContent) {
-                for (; pos <= size - srcStrLen; ++pos) {
-                    if (((const LChar*)data.buffer)[pos] == src0) {
-                        bool same = true;
-                        for (size_t k = 1; k < srcStrLen; k++) {
-                            if (((const LChar*)data.buffer)[pos + k] != str[k]) {
-                                same = false;
-                                break;
-                            }
-                        }
-                        if (same)
-                            return pos;
-                    }
-                }
-            } else {
-                for (; pos <= size - srcStrLen; ++pos) {
-                    if (((const char16_t*)data.buffer)[pos] == src0) {
-                        bool same = true;
-                        for (size_t k = 1; k < srcStrLen; k++) {
-                            if (((const char16_t*)data.buffer)[pos + k] != str[k]) {
-                                same = false;
-                                break;
-                            }
-                        }
-                        if (same)
-                            return pos;
-                    }
-                }
-            }
-        }
-        return SIZE_MAX;
+    size_t find(const char (&src)[N], size_t pos = 0) const
+    {
+        ASSERT(N - 1 == strlen(src));
+        return find(src, N - 1, 0);
     }
 
     template <size_t N>
@@ -424,6 +424,11 @@ public:
         return find(str) != SIZE_MAX;
     }
 
+    bool contains(String* str) const
+    {
+        return find(str) != SIZE_MAX;
+    }
+
     size_t rfind(String* str, size_t pos);
 
     String* substring(size_t from, size_t to);
@@ -479,9 +484,30 @@ public:
     friend int stringCompare(const String& a, const String& b);
 
     // NOTE these function generates new copy of string data
-    virtual UTF16StringData toUTF16StringData() const = 0;
-    virtual UTF8StringData toUTF8StringData() const = 0;
-    virtual UTF8StringDataNonGCStd toNonGCUTF8StringData(int options = StringWriteOption::NoOptions) const = 0;
+    virtual UTF16StringData toUTF16StringData() const
+    {
+        UTF16StringData ret;
+        size_t len = length();
+        ret.resizeWithUninitializedValues(len);
+
+        auto bad = bufferAccessData();
+        for (size_t i = 0; i < len; i++) {
+            ret[i] = bad.charAt(i);
+        }
+
+        return ret;
+    }
+
+    virtual UTF8StringData toUTF8StringData() const
+    {
+        return bufferAccessData().toUTF8String<UTF8StringData, UTF8StringDataNonGCStd>();
+    }
+
+    virtual UTF8StringDataNonGCStd toNonGCUTF8StringData(int options = StringWriteOption::NoOptions) const
+    {
+        return bufferAccessData().toUTF8String<UTF8StringDataNonGCStd>();
+    }
+
     static MAY_THREAD_LOCAL String* emptyString;
 
     uint64_t tryToUseAsIndex() const;
@@ -555,6 +581,10 @@ protected:
     }
 };
 
+#if defined(NDEBUG) && defined(ESCARGOT_32) && !defined(COMPILER_MSVC)
+COMPILE_ASSERT(sizeof(String) == sizeof(size_t) * 4, "");
+#endif
+
 inline bool operator<(const String& a, const String& b)
 {
     return String::stringCompare(a.length(), b.length(), &a, &b) < 0;
@@ -650,13 +680,18 @@ public:
         m_bufferData.has8BitContent = true;
         m_bufferData.length = stringData.length();
         m_bufferData.buffer = stringData.takeBuffer();
+
+        ASSERT(m_bufferData.valueShouldBeOddForFewTypes & 1);
     }
 
     virtual UTF16StringData toUTF16StringData() const override;
     virtual UTF8StringData toUTF8StringData() const override;
     virtual UTF8StringDataNonGCStd toNonGCUTF8StringData(int options = StringWriteOption::NoOptions) const override;
 
-    void* operator new(size_t size);
+    void* operator new(size_t size)
+    {
+        return GC_MALLOC(size);
+    }
     void* operator new(size_t size, GCPlacement p)
     {
         return gc::operator new(size, p);
@@ -681,6 +716,34 @@ public:
     }
 };
 
+class ASCIIStringWithInlineBuffer : public String {
+public:
+    ASCIIStringWithInlineBuffer(const char* str, size_t len)
+        : String()
+    {
+        ASSERT(len <= m_bufferData.bufferPointerAsArraySize);
+        memcpy(m_bufferData.bufferPointerAsArray, str, len);
+        m_bufferData.length = len;
+        m_bufferData.hasSpecialImpl = true;
+        m_bufferData.has8BitContent = true;
+    }
+
+    void* operator new(size_t size)
+    {
+        return GC_MALLOC_ATOMIC(size);
+    }
+
+    virtual StringBufferAccessData bufferAccessDataSpecialImpl() override
+    {
+        return StringBufferAccessData(true, m_bufferData.length, &m_bufferData.bufferPointerAsArray);
+    }
+
+    virtual const LChar* characters8() const override
+    {
+        return (LChar*)&m_bufferData.bufferPointerAsArray;
+    }
+};
+
 class Latin1String : public String {
 public:
     explicit Latin1String()
@@ -739,6 +802,8 @@ public:
         m_bufferData.has8BitContent = true;
         m_bufferData.length = stringData.length();
         m_bufferData.buffer = stringData.takeBuffer();
+
+        ASSERT(m_bufferData.valueShouldBeOddForFewTypes & 1);
     }
 
     virtual char16_t charAt(const size_t idx) const override
@@ -755,8 +820,10 @@ public:
     virtual UTF8StringData toUTF8StringData() const override;
     virtual UTF8StringDataNonGCStd toNonGCUTF8StringData(int options = StringWriteOption::NoOptions) const override;
 
-    void* operator new(size_t size);
-    void* operator new[](size_t size) = delete;
+    void* operator new(size_t size)
+    {
+        return GC_MALLOC(size);
+    }
 };
 
 class Latin1StringFromExternalMemory : public Latin1String {
@@ -776,6 +843,62 @@ public:
     }
 };
 
+class Latin1StringWithInlineBuffer : public String {
+public:
+    Latin1StringWithInlineBuffer(const LChar* str, size_t len)
+        : String()
+    {
+        ASSERT(len <= m_bufferData.bufferPointerAsArraySize);
+        memcpy(m_bufferData.bufferPointerAsArray, str, len);
+        m_bufferData.length = len;
+        m_bufferData.hasSpecialImpl = true;
+        m_bufferData.has8BitContent = true;
+    }
+
+    void* operator new(size_t size)
+    {
+        return GC_MALLOC_ATOMIC(size);
+    }
+
+    virtual StringBufferAccessData bufferAccessDataSpecialImpl() override
+    {
+        return StringBufferAccessData(true, m_bufferData.length, &m_bufferData.bufferPointerAsArray);
+    }
+
+    virtual const LChar* characters8() const override
+    {
+        return (LChar*)&m_bufferData.bufferPointerAsArray;
+    }
+};
+
+template <const int bufferSize>
+class Latin1StringWithLargeInlineBuffer : public String {
+public:
+    Latin1StringWithLargeInlineBuffer(const LChar* str, size_t len)
+        : String()
+    {
+        ASSERT(len <= bufferSize);
+        m_bufferData.buffer = m_buffer;
+        m_bufferData.length = len;
+        m_bufferData.hasSpecialImpl = false;
+        m_bufferData.has8BitContent = true;
+        memcpy(m_buffer, str, len);
+    }
+
+    void* operator new(size_t size)
+    {
+        return GC_MALLOC_ATOMIC(size);
+    }
+
+    virtual const LChar* characters8() const override
+    {
+        return m_buffer;
+    }
+
+private:
+    LChar m_buffer[bufferSize];
+};
+
 class UTF16String : public String {
 public:
     explicit UTF16String()
@@ -842,25 +965,58 @@ public:
     }
 };
 
+class UTF16StringWithInlineBuffer : public String {
+public:
+    UTF16StringWithInlineBuffer(const char16_t* str, size_t len)
+        : String()
+    {
+        ASSERT(len <= m_bufferData.bufferPointerAsArraySize / 2);
+        memcpy(m_bufferData.bufferPointerAs16BitArray, str, len * 2);
+        m_bufferData.length = len;
+        m_bufferData.hasSpecialImpl = true;
+        m_bufferData.has8BitContent = false;
+    }
 
-inline String* String::fromCharCode(char32_t code)
-{
-    if (code < 128) {
-        char c = (char)code;
-        ASCIIStringData s(&c, 1);
-        return new ASCIIString(std::move(s));
-    } else if (code <= 0x10000) {
-        char16_t c = (char16_t)code;
-        UTF16StringData s(&c, 1);
-        return new UTF16String(std::move(s));
-    } else {
-        char16_t buf[3];
-        buf[0] = (char16_t)(0xD800 + ((code - 0x10000) >> 10));
-        buf[1] = (char16_t)(0xDC00 + ((code - 0x10000) & 1023));
-        buf[2] = 0;
-        return new UTF16String(buf, 2);
+    void* operator new(size_t size)
+    {
+        return GC_MALLOC_ATOMIC(size);
     }
-}
+
+    virtual StringBufferAccessData bufferAccessDataSpecialImpl() override
+    {
+        return StringBufferAccessData(false, m_bufferData.length, &m_bufferData.bufferPointerAs16BitArray);
+    }
+
+    virtual UTF16StringData toUTF16StringData() const override
+    {
+        UTF16StringData ret;
+        size_t len = length();
+        ret.resizeWithUninitializedValues(len);
+
+        auto bad = bufferAccessData();
+        for (size_t i = 0; i < len; i++) {
+            ret[i] = bad.charAt(i);
+        }
+
+        return ret;
+    }
+
+    virtual UTF8StringData toUTF8StringData() const override
+    {
+        return bufferAccessData().toUTF8String<UTF8StringData, UTF8StringDataNonGCStd>();
+    }
+
+    virtual UTF8StringDataNonGCStd toNonGCUTF8StringData(int options = StringWriteOption::NoOptions) const override
+    {
+        return bufferAccessData().toUTF8String<UTF8StringDataNonGCStd>();
+    }
+
+    virtual const char16_t* characters16() const override
+    {
+        return (char16_t*)&m_bufferData.bufferPointerAs16BitArray;
+    }
+};
+
 } // namespace Escargot
 
 namespace std {
index 082af32c36bfb68f12ab823e7696926d715ee378..e76f1be0ea18678c5ee63675ff149697d52231eb 100644 (file)
@@ -37,8 +37,16 @@ String* StringBuilderBase::finalizeBase(StringBuilderPiece* piecesInlineStorage,
     }
 
     if (m_has8BitContent) {
-        Latin1StringData ret;
-        ret.resizeWithUninitializedValues(m_contentLength);
+        Latin1StringData retString;
+        LChar* retArray;
+        LChar* ret;
+        if (m_contentLength <= LATIN1_LARGE_INLINE_BUFFER_MAX_SIZE) {
+            retArray = static_cast<LChar*>(alloca(m_contentLength));
+            ret = retArray;
+        } else {
+            retString.resizeWithUninitializedValues(m_contentLength);
+            ret = retString.data();
+        }
 
         size_t currentLength = 0;
         for (size_t i = 0; i < m_piecesInlineStorageUsage; i++) {
@@ -96,7 +104,11 @@ String* StringBuilderBase::finalizeBase(StringBuilderPiece* piecesInlineStorage,
         }
 
         clear();
-        return new Latin1String(std::move(ret));
+        if (currentLength <= LATIN1_LARGE_INLINE_BUFFER_MAX_SIZE) {
+            return String::fromLatin1(retArray, currentLength);
+        } else {
+            return new Latin1String(std::move(retString));
+        }
     } else {
         UTF16StringData ret;
         ret.resizeWithUninitializedValues(m_contentLength);
index 8b02b43a558ad50e843f4e03ce97ea4363537552..ab0900a46f22536bd020b3dfe73540eee9fa9222 100644 (file)
@@ -56,7 +56,7 @@ ObjectHasPropertyResult StringObject::hasProperty(ExecutionState& state, const O
     if (idx != Value::InvalidIndexPropertyValue) {
         size_t strLen = m_primitiveValue->length();
         if (LIKELY(idx < strLen)) {
-            return ObjectHasPropertyResult(ObjectGetResult(Value(String::fromCharCode(m_primitiveValue->charAt(idx))), false, true, false));
+            return ObjectHasPropertyResult(ObjectGetResult(state.context()->staticStrings().charCodeToString(m_primitiveValue->charAt(idx)), false, true, false));
         }
     }
     return Object::hasProperty(state, P);
@@ -69,7 +69,7 @@ ObjectGetResult StringObject::getOwnProperty(ExecutionState& state, const Object
     if (idx != Value::InvalidIndexPropertyValue) {
         size_t strLen = m_primitiveValue->length();
         if (LIKELY(idx < strLen)) {
-            return ObjectGetResult(Value(String::fromCharCode(m_primitiveValue->charAt(idx))), false, true, false);
+            return ObjectGetResult(state.context()->staticStrings().charCodeToString(m_primitiveValue->charAt(idx)), false, true, false);
         }
     }
     return Object::getOwnProperty(state, P);
@@ -108,7 +108,7 @@ ObjectGetResult StringObject::getIndexedProperty(ExecutionState& state, const Va
     if (idx != Value::InvalidIndexPropertyValue) {
         size_t strLen = m_primitiveValue->length();
         if (LIKELY(idx < strLen)) {
-            return ObjectGetResult(Value(String::fromCharCode(m_primitiveValue->charAt(idx))), false, true, false);
+            return ObjectGetResult(state.context()->staticStrings().charCodeToString(m_primitiveValue->charAt(idx)), false, true, false);
         }
     }
     return get(state, ObjectPropertyName(state, property), receiver);
@@ -120,7 +120,7 @@ ObjectHasPropertyResult StringObject::hasIndexedProperty(ExecutionState& state,
     if (idx != Value::InvalidIndexPropertyValue) {
         size_t strLen = m_primitiveValue->length();
         if (LIKELY(idx < strLen)) {
-            return ObjectHasPropertyResult(ObjectGetResult(Value(String::fromCharCode(m_primitiveValue->charAt(idx))), false, true, false));
+            return ObjectHasPropertyResult(ObjectGetResult(state.context()->staticStrings().charCodeToString(m_primitiveValue->charAt(idx)), false, true, false));
         }
     }
     return hasProperty(state, ObjectPropertyName(state, propertyName));
@@ -173,13 +173,13 @@ std::pair<Value, bool> StringIteratorObject::advance(ExecutionState& state)
     // If first < 0xD800 or first > 0xDBFF or position+1 = len, let resultString be the string consisting of the single code unit first.
     String* resultString;
     if (first < 0xD800 || first > 0xDBFF || (position + 1 == len)) {
-        resultString = String::fromCharCode(first);
+        resultString = state.context()->staticStrings().charCodeToString(first);
     } else {
         // Let second be the code unit value at index position+1 in the String S.
         auto second = s->charAt(position + 1);
         // If second < 0xDC00 or second > 0xDFFF, let resultString be the string consisting of the single code unit first.
         if (second < 0xDC00 || second > 0xDFFF) {
-            resultString = String::fromCharCode(first);
+            resultString = state.context()->staticStrings().charCodeToString(first);
         } else {
             // Else, let resultString be the string consisting of the code unit first followed by the code unit second.
             char16_t s[2] = { first, second };
index a40612f761f5380a5c2364c71c8f2b383cc7547d..9b4b79e0783f1bd26c18ac4fcd1d1d0496359957 100644 (file)
@@ -40,6 +40,11 @@ public:
         return true;
     }
 
+    virtual bool hasOwnEnumeration() const override
+    {
+        return true;
+    }
+
     void setPrimitiveValue(ExecutionState& state, String* data)
     {
         m_primitiveValue = data;
index 63b0f3e7ed6b57dc90819259e6d5e52bf9694a89..27a50fcb24eb11f1a09541798d5d50b5d2826ecf 100644 (file)
@@ -139,9 +139,6 @@ protected:
         ASSERT(m_bufferData.hasSpecialImpl);
 
         StringBufferAccessData r = m_bufferData.bufferAsString->bufferAccessData();
-        // keep original buffer pointer in stack
-        // without this, compressible string can free this pointer
-        r.extraData = const_cast<void*>(r.buffer);
         r.length = m_bufferData.length;
         if (r.has8BitContent) {
             r.bufferAs8Bit += m_start;
index 9a2f7f7648f655cc39491276e12cdf84c927456a..3006a5d9aa93a90f01f10db8ba4107ca9521af3e 100644 (file)
@@ -95,7 +95,9 @@ Template::CachedObjectStructure Template::constructObjectStructure(Context* ctx,
     }
 
     bool hasIndexStringAsPropertyName = false;
+    bool hasSymbol = false;
     bool hasNonAtomicPropertyName = false;
+    bool hasEnumerableProperty = false;
     bool isInlineNonCacheable = false;
     for (size_t i = baseItemCount; i < propertyCount; i++) {
         auto propertyIndex = i - baseItemCount;
@@ -107,6 +109,7 @@ Template::CachedObjectStructure Template::constructObjectStructure(Context* ctx,
         } else {
             ASSERT(propertyNameValue.isSymbol());
             propertyName = ObjectStructurePropertyName(propertyNameValue.asSymbol());
+            hasSymbol = true;
         }
 
         if (!hasIndexStringAsPropertyName) {
@@ -126,14 +129,17 @@ Template::CachedObjectStructure Template::constructObjectStructure(Context* ctx,
             ASSERT(type == Template::TemplatePropertyData::PropertyType::PropertyAccessorData);
             desc = ObjectStructurePropertyDescriptor::createAccessorDescriptor(m_properties[propertyIndex].second.presentAttributes());
         }
+
+        hasEnumerableProperty |= desc.isEnumerable();
+
         structureItemVector[i] = ObjectStructureItem(propertyName, desc);
     }
 
     ObjectStructure* newObjectStructure;
     if (propertyCount > ESCARGOT_OBJECT_STRUCTURE_ACCESS_CACHE_BUILD_MIN_SIZE) {
-        newObjectStructure = new ObjectStructureWithMap(hasIndexStringAsPropertyName, std::move(structureItemVector));
+        newObjectStructure = new ObjectStructureWithMap(hasIndexStringAsPropertyName, hasSymbol, hasEnumerableProperty, std::move(structureItemVector));
     } else {
-        newObjectStructure = new ObjectStructureWithTransition(std::move(structureItemVector), hasIndexStringAsPropertyName, hasNonAtomicPropertyName);
+        newObjectStructure = new ObjectStructureWithTransition(std::move(structureItemVector), hasIndexStringAsPropertyName, hasSymbol, hasNonAtomicPropertyName, hasEnumerableProperty);
     }
 
     CachedObjectStructure s;
index a46d5f34bcc781ba603e4ad407f3fc16ff6b8bdb..b2bc29c4b7ff2b22f090adc27158507fe19a094c 100644 (file)
@@ -53,7 +53,7 @@ public:
     }
 
 private:
-    Vector<Object*, GCUtil::gc_malloc_allocator<Object*>> m_registeredItems;
+    VectorWithInlineStorage<8, Object*, GCUtil::gc_malloc_allocator<Object*>> m_registeredItems;
 };
 
 class ToStringRecursionPreventerItemAutoHolder {
index 47dfa1fe64d266f76f211c7f4ab3c3ffb86e7906..617e6d3eb70dedd755f16d51ac93ae89a9525b0f 100644 (file)
@@ -72,6 +72,11 @@ public:
         RELEASE_ASSERT_NOT_REACHED();
     }
 
+    virtual bool hasOwnEnumeration() const override
+    {
+        return true;
+    }
+
     virtual ObjectHasPropertyResult hasProperty(ExecutionState& state, const ObjectPropertyName& P) override;
     virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override;
     virtual bool defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) override;
index ddf605bcd924b7485db22bf87e04db9b0ec90cad..883fb40159572da134f640343e45bf1536e2c6cf 100644 (file)
@@ -56,7 +56,7 @@ namespace Escargot {
 
 #if defined(ENABLE_WASM)
 #ifndef ESCARGOT_WASM_GC_CHECK_INTERVAL
-#define ESCARGOT_WASM_GC_CHECK_INTERVAL 5000
+#define ESCARGOT_WASM_GC_CHECK_INTERVAL 10000
 #endif
 #endif
 
@@ -207,26 +207,23 @@ void vmMarkStartCallback(void* data)
 {
     VMInstance* self = (VMInstance*)data;
 
-#ifdef ESCARGOT_DEBUGGER
-    if (!self->m_debuggerEnabled) {
-#endif
-        if (self->m_regexpCache->size() > REGEXP_CACHE_SIZE_MAX || UNLIKELY(self->inIdleMode())) {
-            self->m_regexpCache->clear();
-        }
+#if !defined(ESCARGOT_DEBUGGER)
+    // in debugger mode, do not remove ByteCodeBlock
+    if (self->m_regexpCache->size() > REGEXP_CACHE_SIZE_MAX || UNLIKELY(self->inIdleMode())) {
+        self->m_regexpCache->clear();
+    }
 
-        auto& currentCodeSizeTotal = self->compiledByteCodeSize();
-        if (currentCodeSizeTotal > SCRIPT_FUNCTION_OBJECT_BYTECODE_SIZE_MAX || UNLIKELY(self->inIdleMode())) {
-            currentCodeSizeTotal = std::numeric_limits<size_t>::max();
+    auto& currentCodeSizeTotal = self->compiledByteCodeSize();
+    if (currentCodeSizeTotal > SCRIPT_FUNCTION_OBJECT_BYTECODE_SIZE_MAX || UNLIKELY(self->inIdleMode())) {
+        currentCodeSizeTotal = std::numeric_limits<size_t>::max();
 
-            auto& v = self->compiledByteCodeBlocks();
-            for (size_t i = 0; i < v.size(); i++) {
-                auto cb = v[i]->m_codeBlock;
-                if (LIKELY(!cb->isAsync() && !cb->isGenerator())) {
-                    v[i]->m_codeBlock->setByteCodeBlock(nullptr);
-                }
+        auto& v = self->compiledByteCodeBlocks();
+        for (size_t i = 0; i < v.size(); i++) {
+            auto cb = v[i]->m_codeBlock;
+            if (LIKELY(!cb->isAsync() && !cb->isGenerator())) {
+                v[i]->m_codeBlock->setByteCodeBlock(nullptr);
             }
         }
-#ifdef ESCARGOT_DEBUGGER
     }
 #endif
 }
@@ -260,7 +257,12 @@ void vmReclaimEndCallback(void* data)
             currentCodeSizeTotal = 0;
             auto& v = self->compiledByteCodeBlocks();
             for (size_t i = 0; i < v.size(); i++) {
-                v[i]->m_codeBlock->setByteCodeBlock(v[i]);
+                auto cb = v[i]->m_codeBlock;
+                if (UNLIKELY(!cb->isAsync() && !cb->isGenerator())) {
+                    v[i]->m_codeBlock->setByteCodeBlock(v[i]);
+                }
+                ASSERT(v[i]->m_codeBlock->byteCodeBlock() == v[i]);
+
                 currentCodeSizeTotal += v[i]->memoryAllocatedSize();
             }
         }
@@ -323,7 +325,7 @@ VMInstance::~VMInstance()
     }
 
     clearCachesRelatedWithContext();
-#ifdef ENABLE_ICU
+#if defined(ENABLE_ICU) && !defined(OS_WINDOWS_UWP)
     vzone_close(m_timezone);
 #endif
 
@@ -338,9 +340,6 @@ VMInstance::VMInstance(const char* locale, const char* timezone, const char* bas
     , m_isFinalized(false)
     , m_inIdleMode(false)
     , m_didSomePrototypeObjectDefineIndexedProperty(false)
-#ifdef ESCARGOT_DEBUGGER
-    , m_debuggerEnabled(false)
-#endif /* ESCARGOT_DEBUGGER */
     , m_compiledByteCodeSize(0)
 #if defined(ENABLE_COMPRESSIBLE_STRING)
     , m_lastCompressibleStringsTestTime(0)
@@ -352,6 +351,8 @@ VMInstance::VMInstance(const char* locale, const char* timezone, const char* bas
     , m_errorCreationCallbackPublic(nullptr)
     , m_promiseHook(nullptr)
     , m_promiseHookPublic(nullptr)
+    , m_promiseRejectCallback(nullptr)
+    , m_promiseRejectCallbackPublic(nullptr)
     , m_cachedUTC(nullptr)
 {
     GC_REGISTER_FINALIZER_NO_ORDER(this, [](void* obj, void*) {
@@ -377,7 +378,8 @@ VMInstance::VMInstance(const char* locale, const char* timezone, const char* bas
     RELEASE_ASSERT(((size_t)m_stackStartAddress) % sizeof(size_t) == 0);
 
     if (!String::emptyString) {
-        String::emptyString = new (NoGC) ASCIIString("");
+        String::initEmptyString();
+        ASSERT(!!String::emptyString && String::emptyString->isAtomicStringSource());
     }
     m_staticStrings.initStaticStrings();
 
@@ -385,8 +387,10 @@ VMInstance::VMInstance(const char* locale, const char* timezone, const char* bas
     m_regexpOptionStringCache = (ASCIIString**)GC_MALLOC(64 * sizeof(ASCIIString*));
     memset(m_regexpOptionStringCache, 0, 64 * sizeof(ASCIIString*));
 
-#ifdef ENABLE_ICU
+#if defined(ENABLE_ICU)
+#if !defined(OS_WINDOWS_UWP)
     m_timezone = nullptr;
+#endif
     if (timezone) {
         m_timezoneID = timezone;
     } else if (getenv("TZ")) {
@@ -419,7 +423,7 @@ VMInstance::VMInstance(const char* locale, const char* timezone, const char* bas
 
     ExecutionState stateForInit((Context*)nullptr);
 
-    m_defaultStructureForObject = new ObjectStructureWithTransition(ObjectStructureItemTightVector(), false, false);
+    m_defaultStructureForObject = new ObjectStructureWithTransition(ObjectStructureItemTightVector(), false, false, false, false);
 
     m_defaultStructureForFunctionObject = m_defaultStructureForObject->addProperty(m_staticStrings.prototype,
                                                                                    ObjectStructurePropertyDescriptor::createDataButHasNativeGetterSetterDescriptor(&functionPrototypeNativeGetterSetterData));
@@ -505,6 +509,23 @@ static std::string findTimezone()
 {
     return RuntimeICUBinder::ICU::findSystemTimezoneName();
 }
+#elif defined(OS_WINDOWS_UWP)
+static std::string findTimezone()
+{
+    DYNAMIC_TIME_ZONE_INFORMATION tz;
+    DWORD ret = GetDynamicTimeZoneInformation(&tz);
+    UErrorCode status = U_ZERO_ERROR;
+    UChar result[256];
+    int32_t len = ucal_getTimeZoneIDForWindowsID(
+        (const UChar*)tz.TimeZoneKeyName, -1,
+        "en_US",
+        result,
+        sizeof(result) / sizeof(UChar),
+        &status);
+
+    RELEASE_ASSERT(status == U_ZERO_ERROR);
+    return (new UTF16String(result, len))->toNonGCUTF8StringData();
+}
 #else
 static std::string findTimezone()
 {
@@ -524,11 +545,15 @@ void VMInstance::ensureTimezone()
     if (m_timezoneID == "") {
         m_timezoneID = findTimezone();
     } else {
+#if !defined(OS_WINDOWS_UWP)
         tzset();
+#endif
     }
 
+#if !defined(OS_WINDOWS_UWP)
     auto u16 = utf8StringToUTF16String(m_timezoneID.data(), m_timezoneID.size());
     m_timezone = vzone_openID(u16.data(), u16.size());
+#endif
 }
 #endif
 
index 649c18d1da951060918214f6eb1cebf3530eee3d..3617572a5a3c1a282515da81774cc94ce6a1ba3e 100644 (file)
@@ -87,7 +87,15 @@ public:
         After
     };
 
+    enum PromiseRejectEvent {
+        PromiseRejectWithNoHandler = 0,
+        PromiseHandlerAddedAfterReject = 1,
+        PromiseRejectAfterResolved = 2,
+        PromiseResolveAfterResolved = 3,
+    };
+
     typedef void (*PromiseHook)(ExecutionState& state, PromiseHookType type, PromiseObject* promise, const Value& parent, void* hook);
+    typedef void (*PromiseRejectCallback)(ExecutionState& state, PromiseObject* promise, const Value& value, PromiseRejectEvent event, void* callback);
 
     VMInstance(const char* locale = nullptr, const char* timezone = nullptr, const char* baseCacheDir = nullptr);
     ~VMInstance();
@@ -119,6 +127,9 @@ public:
         return m_timezoneID;
     }
 
+    void ensureTimezone();
+
+#if !defined(OS_WINDOWS_UWP)
     VZone* timezone()
     {
         if (m_timezone == nullptr) {
@@ -126,8 +137,8 @@ public:
         }
         return m_timezone;
     }
+#endif
 
-    void ensureTimezone();
 #endif
     DateObject* cachedUTC(ExecutionState& state);
 
@@ -277,6 +288,33 @@ public:
         }
     }
 
+    // trigger PromiseRejectCallback
+    // Third party app registers PromiseRejectCallback when it is necessary
+    bool isPromiseRejectCallbackRegistered()
+    {
+        return !!m_promiseRejectCallback;
+    }
+
+    void registerPromiseRejectCallback(PromiseRejectCallback promiseRejectCallback, void* promiseRejectCallbackPublic)
+    {
+        m_promiseRejectCallback = promiseRejectCallback;
+        m_promiseRejectCallbackPublic = promiseRejectCallbackPublic;
+    }
+
+    void unregisterPromiseRejectCallback()
+    {
+        m_promiseRejectCallback = nullptr;
+        m_promiseRejectCallbackPublic = nullptr;
+    }
+
+    void triggerPromiseRejectCallback(ExecutionState& state, PromiseObject* promise, const Value& value, PromiseRejectEvent event)
+    {
+        ASSERT(!!m_promiseRejectCallback);
+        if (m_promiseRejectCallbackPublic) {
+            m_promiseRejectCallback(state, promise, value, event, m_promiseRejectCallbackPublic);
+        }
+    }
+
 #if defined(ENABLE_ICU) && defined(ENABLE_INTL)
     const Vector<String*, GCUtil::gc_malloc_allocator<String*>>& intlCollatorAvailableLocales();
     const Vector<String*, GCUtil::gc_malloc_allocator<String*>>& intlDateTimeFormatAvailableLocales();
@@ -307,9 +345,6 @@ private:
     bool m_inIdleMode;
     // this flag should affect VM-wide array object
     bool m_didSomePrototypeObjectDefineIndexedProperty;
-#ifdef ESCARGOT_DEBUGGER
-    bool m_debuggerEnabled;
-#endif /* ESCARGOT_DEBUGGER */
 
     ObjectStructure* m_defaultStructureForObject;
     ObjectStructure* m_defaultStructureForFunctionObject;
@@ -352,6 +387,10 @@ private:
     PromiseHook m_promiseHook;
     void* m_promiseHookPublic;
 
+    // Third party app registers PromiseRejectCallback when it is necessary
+    PromiseRejectCallback m_promiseRejectCallback;
+    void* m_promiseRejectCallbackPublic;
+
     ToStringRecursionPreventer m_toStringRecursionPreventer;
 
     void* m_stackStartAddress;
@@ -363,7 +402,9 @@ private:
 // date object data
 #ifdef ENABLE_ICU
     std::string m_locale;
+#if !defined(OS_WINDOWS_UWP)
     VZone* m_timezone;
+#endif
     std::string m_timezoneID;
 #endif
     DateObject* m_cachedUTC;
index 593f3fb3f0b571b6fee37ab91df8779bfe755f47..695bce38dd4c9cbc89b875c57cd5f88a2835e643 100644 (file)
@@ -231,6 +231,16 @@ Value Value::toPrimitiveSlowCase(ExecutionState& state, PrimitiveTypeHint prefer
     const StaticStrings& strings = state.context()->staticStrings();
     Object* input = asObject();
 
+    // fast path
+    auto ret = input->fastLookupForSymbol(state, state.context()->vmInstance()->globalSymbols().toPrimitive);
+    if (ret.wasSucessful() && !ret.matchedObject().hasValue()) {
+        // If hint is "default", let hint be "number".
+        if (preferredType == PreferDefault) {
+            preferredType = PreferNumber;
+        }
+        return ordinaryToPrimitive(state, preferredType);
+    }
+
     // Let exoticToPrim be GetMethod(input, @@toPrimitive).
     Value exoticToPrim = Object::getMethod(state, input, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toPrimitive));
     // If exoticToPrim is not undefined, then
@@ -260,6 +270,38 @@ Value Value::toPrimitiveSlowCase(ExecutionState& state, PrimitiveTypeHint prefer
     return ordinaryToPrimitive(state, preferredType);
 }
 
+bool Value::toBooleanSlowCase(ExecutionState& ec) const
+{
+    if (isDouble()) {
+        double d = asDouble();
+        if (std::isnan(d))
+            return false;
+        if (d == 0.0)
+            return false;
+        return true;
+    }
+
+    if (isUndefinedOrNull())
+        return false;
+
+    ASSERT(isPointerValue());
+
+    if (UNLIKELY(asPointerValue()->isString()))
+        return asString()->length();
+
+    if (UNLIKELY(isBigInt())) {
+        return !asBigInt()->isZero();
+    }
+
+#if defined(ESCARGOT_ENABLE_TEST)
+    if (UNLIKELY(checkIfObjectWithIsHTMLDDA())) {
+        return false;
+    }
+#endif
+    // Symbol, Objects..
+    return true;
+}
+
 bool Value::abstractEqualsToSlowCase(ExecutionState& state, const Value& val) const
 {
     bool selfIsNumber = isNumber();
@@ -269,13 +311,15 @@ bool Value::abstractEqualsToSlowCase(ExecutionState& state, const Value& val) co
         double a = asNumber();
         double b = val.asNumber();
 
-        if (std::isnan(a) || std::isnan(b))
+        if (UNLIKELY(std::isnan(a) || std::isnan(b)))
             return false;
-        else if (a == b)
-            return true;
 
-        return false;
+        return a == b;
     } else {
+        if (u.asInt64 == val.u.asInt64) {
+            return true;
+        }
+
         bool selfIsUndefinedOrNull = isUndefinedOrNull();
         bool valIsUndefinedOrNull = val.isUndefinedOrNull();
         if (selfIsUndefinedOrNull && valIsUndefinedOrNull)
@@ -384,34 +428,31 @@ bool Value::abstractEqualsToSlowCase(ExecutionState& state, const Value& val) co
 
 bool Value::equalsToSlowCase(ExecutionState& state, const Value& val) const
 {
-    if (isUndefined())
-        return val.isUndefined();
-
-    if (isNull())
-        return val.isNull();
+    if (!val.isPointerValue()) {
+        if (isNumber() && val.isNumber()) {
+            double a = asNumber();
+            double b = val.asNumber();
+            if (UNLIKELY(std::isnan(a) || std::isnan(b))) {
+                return false;
+            }
+            // we can pass [If x is +0 and y is −0, return true. If x is −0 and y is +0, return true.]
+            // because
+            // double a = -0.0;
+            // double b = 0.0;
+            // a == b; is true
+            return a == b;
+        }
 
-    if (isBoolean())
-        return val.isBoolean() && asBoolean() == val.asBoolean();
+        return u.asInt64 == val.u.asInt64;
+    } else {
+        if (u.asInt64 == val.u.asInt64) {
+            return true;
+        }
 
-    if (isNumber()) {
-        if (!val.isNumber())
+        if (!isPointerValue())
             return false;
-        double a = asNumber();
-        double b = val.asNumber();
-        if (std::isnan(a) || std::isnan(b))
-            return false;
-        // we can pass [If x is +0 and y is −0, return true. If x is −0 and y is +0, return true.]
-        // because
-        // double a = -0.0;
-        // double b = 0.0;
-        // a == b; is true
-        return a == b;
-    }
 
-    if (isPointerValue()) {
         PointerValue* o = asPointerValue();
-        if (!val.isPointerValue())
-            return false;
         PointerValue* o2 = val.asPointerValue();
         if (o->isString()) {
             if (!o2->isString())
@@ -424,50 +465,41 @@ bool Value::equalsToSlowCase(ExecutionState& state, const Value& val) const
             }
             return o->asBigInt()->equals(o2->asBigInt());
         }
-        return o == o2;
     }
+
     return false;
 }
 
 bool Value::equalsToByTheSameValueAlgorithm(ExecutionState& ec, const Value& val) const
 {
-    if (isUndefined()) {
-        return val.isUndefined();
-    }
-
-    if (isNull()) {
-        return val.isNull();
-    }
+    if (!val.isPointerValue()) {
+        if (isNumber() && val.isNumber()) {
+            double a = asNumber();
+            double b = val.asNumber();
 
-    if (isBoolean()) {
-        return val.isBoolean() && asBoolean() == val.asBoolean();
-    }
+            if (UNLIKELY(std::isnan(a) || std::isnan(b))) {
+                return std::isnan(a) && std::isnan(b);
+            }
 
-    if (isNumber()) {
-        if (!val.isNumber()) {
-            return false;
+            // we can pass [If x is +0 and y is −0, return true. If x is −0 and y is +0, return true.]
+            // because
+            // double a = -0.0;
+            // double b = 0.0;
+            // a == b; is true
+            return a == b && std::signbit(a) == std::signbit(b);
         }
-        double a = asNumber();
-        double b = val.asNumber();
-        if (std::isnan(a) && std::isnan(b)) {
+
+        return u.asInt64 == val.u.asInt64;
+    } else {
+        if (u.asInt64 == val.u.asInt64) {
             return true;
         }
-        if (std::isnan(a) || std::isnan(b)) {
+
+        if (!isPointerValue()) {
             return false;
         }
-        // we can pass [If x is +0 and y is −0, return true. If x is −0 and y is +0, return true.]
-        // because
-        // double a = -0.0;
-        // double b = 0.0;
-        // a == b; is true
-        return a == b && std::signbit(a) == std::signbit(b);
-    }
 
-    if (isPointerValue()) {
         PointerValue* o = asPointerValue();
-        if (!val.isPointerValue()) {
-            return false;
-        }
         PointerValue* o2 = val.asPointerValue();
         if (o->isString()) {
             if (!o2->isString()) {
@@ -475,56 +507,42 @@ bool Value::equalsToByTheSameValueAlgorithm(ExecutionState& ec, const Value& val
             }
             return *o->asString() == *o2->asString();
         }
-        if (o->isSymbol()) {
-            if (!o2->isSymbol()) {
-                return false;
-            }
-        }
         if (UNLIKELY(o->isBigInt())) {
             if (!o2->isBigInt()) {
                 return false;
             }
             return o->asBigInt()->equals(o2->asBigInt());
         }
-        return o == o2;
     }
+
     return false;
 }
 
 bool Value::equalsToByTheSameValueZeroAlgorithm(ExecutionState& ec, const Value& val) const
 {
-    if (isUndefined()) {
-        return val.isUndefined();
-    }
+    if (LIKELY(!val.isPointerValue())) {
+        if (isNumber() && val.isNumber()) {
+            double a = asNumber();
+            double b = val.asNumber();
 
-    if (isNull()) {
-        return val.isNull();
-    }
-
-    if (isBoolean()) {
-        return val.isBoolean() && asBoolean() == val.asBoolean();
-    }
+            if (UNLIKELY(std::isnan(a) || std::isnan(b))) {
+                return std::isnan(a) && std::isnan(b);
+            }
 
-    if (isNumber()) {
-        if (!val.isNumber()) {
-            return false;
+            return a == b;
         }
-        double a = asNumber();
-        double b = val.asNumber();
-        if (std::isnan(a) && std::isnan(b)) {
+
+        return u.asInt64 == val.u.asInt64;
+    } else {
+        if (u.asInt64 == val.u.asInt64) {
             return true;
         }
-        if (std::isnan(a) || std::isnan(b)) {
+
+        if (!isPointerValue()) {
             return false;
         }
-        return a == b;
-    }
 
-    if (isPointerValue()) {
         PointerValue* o = asPointerValue();
-        if (!val.isPointerValue()) {
-            return false;
-        }
         PointerValue* o2 = val.asPointerValue();
         if (o->isString()) {
             if (!o2->isString()) {
@@ -532,19 +550,14 @@ bool Value::equalsToByTheSameValueZeroAlgorithm(ExecutionState& ec, const Value&
             }
             return *o->asString() == *o2->asString();
         }
-        if (o->isSymbol()) {
-            if (!o2->isSymbol()) {
-                return false;
-            }
-        }
         if (UNLIKELY(o->isBigInt())) {
             if (!o2->isBigInt()) {
                 return false;
             }
             return o->asBigInt()->equals(o2->asBigInt());
         }
-        return o == o2;
     }
+
     return false;
 }
 
@@ -556,6 +569,14 @@ bool Value::instanceOf(ExecutionState& state, const Value& other) const
         ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, ErrorObject::Messages::InstanceOf_NotFunction);
     }
     Object* C = other.asObject();
+
+    // fast path
+    auto globalFunctionPrototype = state.context()->globalObject()->functionPrototype();
+    auto fastPathResult = C->fastLookupForSymbol(state, state.context()->vmInstance()->globalSymbols().hasInstance, globalFunctionPrototype);
+    if (fastPathResult.wasSucessful() && fastPathResult.matchedObject().unwrap() == globalFunctionPrototype) {
+        return C->hasInstance(state, *this);
+    }
+
     // Let instOfHandler be GetMethod(C,@@hasInstance).
     Value instOfHandler = Object::getMethod(state, other, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().hasInstance));
     // If instOfHandler is not undefined, then
index 56aee94d633c9226e23eaec6220c4ce1291af13d..eb774eff99a6bab88aebe138fd0d21ba6fd54aef 100644 (file)
@@ -279,6 +279,7 @@ private:
     String* toStringSlowCase(ExecutionState& ec) const; // $7.1.12 ToString
     Object* toObjectSlowCase(ExecutionState& ec) const; // $7.1.13 ToObject
     Value toPrimitiveSlowCase(ExecutionState& ec, PrimitiveTypeHint) const; // $7.1.1 ToPrimitive
+    bool toBooleanSlowCase(ExecutionState& ec) const; // $7.1.2 ToBoolean
     int32_t toInt32SlowCase(ExecutionState& ec) const; // $7.1.5 ToInt32
     ValueIndex tryToUseAsIndexSlowCase(ExecutionState& ec) const;
     uint32_t tryToUseAsIndex32SlowCase(ExecutionState& ec) const;
index 1bc7f13faa050c53b9be323a08542edc586007de..bc7b577088b4c57dbf884be9ad128c76d413dbbd 100644 (file)
@@ -773,12 +773,10 @@ inline bool Value::abstractEqualsTo(ExecutionState& state, const Value& val) con
 {
     if (isInt32() && val.isInt32()) {
 #ifdef ESCARGOT_64
-        if (u.asInt64 == val.u.asInt64)
+        return u.asInt64 == val.u.asInt64;
 #else
-        if (u.asBits.payload == val.u.asBits.payload)
+        return u.asBits.payload == val.u.asBits.payload;
 #endif
-            return true;
-        return false;
     } else {
         return abstractEqualsToSlowCase(state, val);
     }
@@ -788,12 +786,10 @@ inline bool Value::equalsTo(ExecutionState& state, const Value& val) const
 {
     if (isInt32() && val.isInt32()) {
 #ifdef ESCARGOT_64
-        if (u.asInt64 == val.u.asInt64)
+        return u.asInt64 == val.u.asInt64;
 #else
-        if (u.asBits.payload == val.u.asBits.payload)
+        return u.asBits.payload == val.u.asBits.payload;
 #endif
-            return true;
-        return false;
     } else {
         return equalsToSlowCase(state, val);
     }
@@ -807,34 +803,7 @@ inline bool Value::toBoolean(ExecutionState& ec) const // $7.1.2 ToBoolean
     if (isInt32())
         return asInt32();
 
-    if (isDouble()) {
-        double d = asDouble();
-        if (std::isnan(d))
-            return false;
-        if (d == 0.0)
-            return false;
-        return true;
-    }
-
-    if (isUndefinedOrNull())
-        return false;
-
-    ASSERT(isPointerValue());
-
-    if (UNLIKELY(asPointerValue()->isString()))
-        return asString()->length();
-
-    if (UNLIKELY(isBigInt())) {
-        return !asBigInt()->isZero();
-    }
-
-#if defined(ESCARGOT_ENABLE_TEST)
-    if (UNLIKELY(checkIfObjectWithIsHTMLDDA())) {
-        return false;
-    }
-#endif
-    // Symbol, Objects..
-    return true;
+    return toBooleanSlowCase(ec);
 }
 
 inline int32_t Value::toInt32(ExecutionState& state) const // $7.1.5 ToInt3
index 08a9c30a858197e315651c301fb1f0e558f53996..dc53b461b9d2f644b7400a6241db8ada3a9c8b0e 100644 (file)
@@ -713,8 +713,8 @@ static bool evalScript(ContextRef* context, StringRef* source, StringRef* srcNam
 
     if (!evalResult.isSuccessful()) {
         fprintf(stderr, "Uncaught %s:\n", evalResult.resultOrErrorToString(context)->toStdUTF8String().data());
-        for (size_t i = 0; i < evalResult.stackTraceData.size(); i++) {
-            fprintf(stderr, "%s (%d:%d)\n", evalResult.stackTraceData[i].src->toStdUTF8String().data(), (int)evalResult.stackTraceData[i].loc.line, (int)evalResult.stackTraceData[i].loc.column);
+        for (size_t i = 0; i < evalResult.stackTrace.size(); i++) {
+            fprintf(stderr, "%s (%d:%d)\n", evalResult.stackTrace[i].srcName->toStdUTF8String().data(), (int)evalResult.stackTrace[i].loc.line, (int)evalResult.stackTrace[i].loc.column);
         }
         return false;
     }
@@ -935,6 +935,8 @@ int main(int argc, char* argv[])
     mallopt(M_MMAP_MAX, 1024 * 1024);
 #endif
 
+    bool wait_before_exit = false;
+
     ShellPlatform* platform = new ShellPlatform();
     Globals::initialize(platform);
 
@@ -972,7 +974,7 @@ int main(int argc, char* argv[])
                     continue;
                 }
                 if (strcmp(argv[i], "--start-debug-server") == 0) {
-                    context->initDebugger(nullptr);
+                    context->initDebuggerRemote(nullptr);
                     continue;
                 }
                 if (strcmp(argv[i], "--debugger-wait-source") == 0) {
@@ -988,6 +990,10 @@ int main(int argc, char* argv[])
                     }
                     continue;
                 }
+                if (strcmp(argv[i], "--wait-before-exit") == 0) {
+                    wait_before_exit = true;
+                    continue;
+                }
             } else { // `-option` case
                 if (strcmp(argv[i], "-e") == 0) {
                     runShell = false;
@@ -1037,6 +1043,14 @@ int main(int argc, char* argv[])
         printf("escargot version:%s, %s%s\n", Globals::version(), Globals::buildDate(), Globals::supportsThreading() ? "(supports threading)" : "");
     }
 
+    if (wait_before_exit || context->isWaitBeforeExit()) {
+        context->setAsAlwaysStopState();
+        auto evalResult = Evaluator::execute(context, [](ExecutionStateRef* state, ScriptRef* script) -> ValueRef* {
+            return script->execute(state);
+        },
+                                             context->scriptParser()->initializeScript(StringRef::createFromASCII(""), StringRef::createFromASCII("<ScriptEnd>"), seenModule).script.get());
+    }
+
     while (runShell) {
         static char buf[2048];
         printf("escargot> ");
@@ -1045,7 +1059,7 @@ int main(int argc, char* argv[])
             return 3;
         }
         StringRef* str = Escargot::StringRef::createFromUTF8(buf, strlen(buf));
-        evalScript(context, str, StringRef::createFromASCII("from shell input"), true, false);
+        evalScript(context, str, StringRef::emptyString(), true, false);
     }
 
 #if defined(ESCARGOT_ENABLE_TEST)
index d96ef74db3d24dd5af57360f203d0aad1badf3f6..d2daf73c5eb4e392958995680edef864464fb193 100644 (file)
@@ -31,7 +31,7 @@ class SpinLock {
 
 public:
     SpinLock()
-        : m_locked(0)
+        : m_locked(ATOMIC_FLAG_INIT)
     {
     }
 
index 3eff6d339c1a1359a35bc1640272ce0253cefd70..43cfb01ee9e8b1a73440b7c8c6ae87f0d2a1fe28 100644 (file)
@@ -246,6 +246,10 @@ public:
         }
     }
 
+    using iterator = T*;
+    constexpr iterator begin() const { return m_buffer; }
+    constexpr iterator end() const { return m_buffer + m_size; }
+
     void* operator new(size_t size)
     {
         static MAY_THREAD_LOCAL bool typeInited = false;
index 57e76467e9548490514797578c2737b50c820db8..f20d75c4f7b77138d9222f6e73515a8eb35a5342 100644 (file)
@@ -61,6 +61,13 @@ struct timezone {
     int tz_dsttime; /* type of dst correction */
 };
 
+#if !defined(_WINSOCKAPI_)
+struct timeval {
+    long tv_sec;
+    long tv_usec;
+};
+#endif
+
 int gettimeofday(struct timeval *tv, struct timezone *tz)
 {
     FILETIME ft;
@@ -83,7 +90,9 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
 
     if (NULL != tz) {
         if (!tzflag) {
+#if !defined(OS_WINDOWS_UWP)
             _tzset();
+#endif
             tzflag++;
         }
         tz->tz_minuteswest = _timezone / 60;
index d936b8152343894bc68ea0b5cd5ddb0b444634c0..ca3e56d03cc2f42c9e4d75021a1e7f01db99c82f 100644 (file)
@@ -95,10 +95,6 @@ static Value callExportedFunction(ExecutionState& state, Value thisValue, size_t
 
     // Let (store, ret) be the result of func_invoke(store, funcaddr, args).
     own wasm_trap_t* trap = wasm_func_call(funcaddr, args.data, ret.data);
-    // FIXME wabt allocates a Thread object for each function call
-    // Thread object is never explicitly reclaimed
-    // invoke collectHeap right after wasm_func_call
-    WASMOperations::collectHeap();
 
     // If ret is error, throw an exception. This exception should be a WebAssembly RuntimeError exception, unless otherwise indicated by the WebAssembly error mapping.
     if (trap) {
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/GCutil/windows/GCutil/config.h b/lwnode/code/escargotshim/deps/escargot/third_party/GCutil/windows/GCutil/config.h
deleted file mode 100644 (file)
index 4f0e5d2..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-/* include/config.h.in.  Generated from configure.ac by autoheader.  */
-
-/* See doc/README.macros. */
-/* #undef DARWIN_DONT_PARSE_STACK */
-
-/* Define to force debug headers on all objects. */
-/* #define DBG_HDRS_ALL 1 */
-
-/* Define to enable support for DB/UX threads. */
-/* #undef DGUX_THREADS */
-
-/* Define to enable eCos target support. */
-/* #undef ECOS */
-
-/* Wine getenv may not return NULL for missing entry. */
-/* #undef EMPTY_GETENV_RESULTS */
-
-/* Define to enable alternative finalization interface. */
-#define ENABLE_DISCLAIM 1
-
-/* Define to support IBM AIX threads. */
-/* #undef GC_AIX_THREADS */
-
-/* Define to enable internal debug assertions. */
-/* #define GC_ASSERTIONS 1 */
-
-/* Define to enable atomic uncollectible allocation. */
-#define GC_ATOMIC_UNCOLLECTABLE 1
-
-/* Define to support Darwin pthreads. */
-/* #undef GC_DARWIN_THREADS */
-
-/* Define to enable support for DB/UX threads on i386. */
-/* #undef GC_DGUX386_THREADS */
-
-/* Define to build dynamic libraries with only API symbols exposed. */
-#define GC_DLL 1
-
-/* Define to support FreeBSD pthreads. */
-/* #undef GC_FREEBSD_THREADS */
-
-/* Define to include support for gcj. */
-/* #define GC_GCJ_SUPPORT 1 */
-
-/* Define to support GNU pthreads. */
-/* #undef GC_GNU_THREADS */
-
-/* Define if backtrace information is supported. */
-/* #undef GC_HAVE_BUILTIN_BACKTRACE */
-
-/* Define to support HP/UX 11 pthreads. */
-/* #undef GC_HPUX_THREADS */
-
-/* Enable Win32 DllMain-based approach of threads registering. */
-/* #undef GC_INSIDE_DLL */
-
-/* Define to support Irix pthreads. */
-/* #undef GC_IRIX_THREADS */
-
-/* Define to support pthreads on Linux. */
-/* #undef GC_LINUX_THREADS */
-
-/* Define to support NetBSD pthreads. */
-/* #undef GC_NETBSD_THREADS */
-
-/* Define to support OpenBSD pthreads. */
-/* #undef GC_OPENBSD_THREADS */
-
-/* Define to support Tru64 pthreads. */
-/* #undef GC_OSF1_THREADS */
-
-/* Read environment variables from the GC 'env' file. */
-/* #undef GC_READ_ENV_FILE */
-
-/* Define to support rtems-pthreads. */
-/* #undef GC_RTEMS_PTHREADS */
-
-/* Define to support Solaris pthreads. */
-/* #undef GC_SOLARIS_THREADS */
-
-/* Define to support platform-specific threads. */
-/* #undef GC_THREADS */
-
-/* Explicitly prefix exported/imported WINAPI symbols with '_'. */
-/* #undef GC_UNDERSCORE_STDCALL */
-
-/* Force the GC to use signals based on SIGRTMIN+k. */
-/* #undef GC_USESIGRT_SIGNALS */
-
-/* See doc/README.macros. */
-/* #undef GC_USE_DLOPEN_WRAP */
-
-/* The major version number of this GC release. */
-#define GC_VERSION_MAJOR 8
-
-/* The micro version number of this GC release. */
-#define GC_VERSION_MICRO 4
-
-/* The minor version number of this GC release. */
-#define GC_VERSION_MINOR 0
-
-/* Define to support pthreads-win32 or winpthreads. */
-/* #undef GC_WIN32_PTHREADS */
-
-/* Define to support Win32 threads. */
-/* #undef GC_WIN32_THREADS */
-
-/* Define to install pthread_atfork() handlers by default. */
-/* #undef HANDLE_FORK */
-
-/* Define to use 'dladdr' function. */
-/* #undef HAVE_DLADDR */
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-/* #undef HAVE_DLFCN_H */
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-/* #undef HAVE_INTTYPES_H */
-
-/* Define to 1 if you have the <memory.h> header file. */
-/* #undef HAVE_MEMORY_H */
-
-/* Define to 1 if you have the <stdint.h> header file. */
-/* #undef HAVE_STDINT_H */
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-/* #undef HAVE_SYS_STAT_H */
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-/* #undef HAVE_SYS_TYPES_H */
-
-/* Define to 1 if you have the <unistd.h> header file. */
-/* #undef HAVE_UNISTD_H */
-
-/* See doc/README.macros. */
-/* #undef JAVA_FINALIZATION */
-
-/* Define to save back-pointers in debugging headers. */
-/* #define KEEP_BACK_PTRS */
-
-/* Define to optimize for large heaps or root sets. */
-#define LARGE_CONFIG
-
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
-   */
-/* #undef LT_OBJDIR */
-
-/* See doc/README.macros. */
-/* #undef MAKE_BACK_GRAPH */
-
-/* Number of GC cycles to wait before unmapping an unused block. */
-/* #undef MUNMAP_THRESHOLD */
-
-/* Define to not use system clock (cross compiling). */
-/* #undef NO_CLOCK */
-
-/* Disable debugging, like GC_dump and its callees. */
-#ifdef NDEBUG
-#define NO_DEBUGGING 1
-#else
-#define DBG_HDRS_ALL 1
-#define KEEP_BACK_PTRS 1
-#endif
-
-/* Define to make the collector not allocate executable memory by default. */
-/* #undef NO_EXECUTE_PERMISSION */
-
-/* Prohibit installation of pthread_atfork() handlers. */
-/* #undef NO_HANDLE_FORK */
-
-/* Name of package */
-/* #undef PACKAGE */
-
-/* Define to the address where bug reports for this package should be sent. */
-/* #undef PACKAGE_BUGREPORT */
-
-/* Define to the full name of this package. */
-/* #undef PACKAGE_NAME */
-
-/* Define to the full name and version of this package. */
-/* #undef PACKAGE_STRING */
-
-/* Define to the one symbol short name of this package. */
-/* #undef PACKAGE_TARNAME */
-
-/* Define to the home page for this package. */
-/* #undef PACKAGE_URL */
-
-/* Define to the version of this package. */
-/* #undef PACKAGE_VERSION */
-
-/* Define to enable parallel marking. */
-/* #undef PARALLEL_MARK */
-
-/* If defined, redirect free to this function. */
-/* #undef REDIRECT_FREE */
-
-/* If defined, redirect malloc to this function. */
-/* #undef REDIRECT_MALLOC */
-
-/* If defined, redirect GC_realloc to this function. */
-/* #undef REDIRECT_REALLOC */
-
-/* The number of caller frames saved when allocating with the debugging API.
-   */
-/* #define SAVE_CALL_COUNT 8 */
-
-/* Shorten the headers to minimize object size at the expense of checking for
-   writes past the end (see doc/README.macros). */
-/* #undef SHORT_DBG_HDRS */
-
-/* Define to tune the collector for small heap sizes. */
-/* #undef SMALL_CONFIG */
-
-/* See the comment in gcconfig.h. */
-/* #undef SOLARIS25_PROC_VDB_BUG_FIXED */
-
-/* Define to 1 if you have the ANSI C header files. */
-/* #undef STDC_HEADERS */
-
-/* Define to work around a Solaris 5.3 bug (see dyn_load.c). */
-/* #undef SUNOS53_SHARED_LIB */
-
-/* Define to enable thread-local allocation optimization. */
-/* #undef THREAD_LOCAL_ALLOC */
-
-/* Use Unicode (W) variant of Win32 API instead of ASCII (A) one. */
-/* #undef UNICODE */
-
-/* Define to use of compiler-support for thread-local variables. */
-/* #undef USE_COMPILER_TLS */
-
-/* Define to use mmap instead of sbrk to expand the heap. */
-/* #undef USE_MMAP */
-
-/* Define to return memory to OS with munmap calls (see doc/README.macros). */
-/* #undef USE_MUNMAP */
-
-/* Define to use Win32 VirtualAlloc (instead of sbrk or mmap) to expand the
-   heap. */
-#define USE_WINALLOC 1
-
-/* Version number of package */
-#define VERSION "8.0.4"
-
-/* The POSIX feature macro. */
-/* #undef _POSIX_C_SOURCE */
-
-/* Indicates the use of pthreads (NetBSD). */
-/* #undef _PTHREADS */
-
-/* Required define if using POSIX threads. */
-/* #undef _REENTRANT */
-
-#define ALL_INTERIOR_POINTERS 0
-#define GC_DONT_REGISTER_MAIN_STATIC_DATA 1
-#define GC_ENABLE_SUSPEND_THREAD 1
-#define GC_NO_THREADS_DISCOVERY 1
-#define IGNORE_DYNAMIC_LOADING 1
-#define JAVA_FINALIZATION 1
-
-/* Define to `__inline__' or `__inline' if that's what the C compiler
-   calls it, or to nothing if 'inline' is not supported under any name.  */
-#ifndef __cplusplus
-#define inline
-#endif
\ No newline at end of file
index 9e49187c5b0c88cc313507a35b102ec1c2107a36..11cf6bfd8bdd498f11f93176754c02136b11e0f8 100644 (file)
@@ -149,7 +149,7 @@ set(WABT_SRC
 # disable -Wpointer-arith: this is a GCC extension, and doesn't work in MSVC.
 set(WASM_CXX_FLAGS_INTERNAL
     -Wall -Wextra -Werror -Wno-unused-parameter -Wpointer-arith
-    -Wuninitialized -fno-exceptions -fPIC -fdata-sections -ffunction-sections
+    -Wuninitialized -fPIC -fdata-sections -ffunction-sections
 )
 
 # set c++ flags
index c8f721212e42d28fc46d4cce1077c6ed3b6eda58..2d67da81e9b47b0f6dc0d556b495d2645cd64c46 100644 (file)
@@ -15,7 +15,7 @@
 #
 
 cmake_minimum_required(VERSION 3.0.0)
-project(WABT VERSION 1.0.24)
+project(WABT VERSION 1.0.26)
 include(GNUInstallDirs)
 
 if (POLICY CMP0077)
index abe3efbbb5f7e5fc64496d599d2648b8f6af252c..154d0b813236de56db982337f46acbd371bfbf91 100644 (file)
@@ -50,14 +50,15 @@ Wabt has been compiled to JavaScript via emscripten. Some of the functionality i
 | [mutable globals][] | `--disable-mutable-globals` | ✓ | ✓ | ✓ | ✓ | ✓ |
 | [nontrapping float-to-int conversions][] | `--disable-saturating-float-to-int` | ✓ | ✓ | ✓ | ✓ | ✓ |
 | [sign extension][] | `--disable-sign-extension` | ✓ | ✓ | ✓ | ✓ | ✓ |
-| [simd][] | `--enable-simd` | | ✓ | ✓ | ✓ | ✓ |
+| [simd][] | `--disable-simd` | ✓ | ✓ | ✓ | ✓ | ✓ |
 | [threads][] | `--enable-threads` | | ✓ | ✓ | ✓ | ✓ |
 | [multi-value][] | `--disable-multi-value` | ✓ | ✓ | ✓ | ✓ | ✓ |
 | [tail-call][] | `--enable-tail-call` | | ✓ | ✓ | ✓ | ✓ |
-| [bulk memory][] | `--enable-bulk-memory` | | ✓ | ✓ | ✓ | ✓ |
-| [reference types][] | `--enable-reference-types` | | ✓ | ✓ | ✓ | ✓ |
+| [bulk memory][] | `--disable-bulk-memory` | ✓ | ✓ | ✓ | ✓ | ✓ |
+| [reference types][] | `--disable-reference-types` | ✓ | ✓ | ✓ | ✓ | ✓ |
 | [annotations][] | `--enable-annotations` | | | ✓ | | |
 | [memory64][] | `--enable-memory64` | | | | | |
+| [multi-memory][] | `--enable-multi-memory` | | ✓ | ✓ | ✓ | ✓ |
 
 [exception handling]: https://github.com/WebAssembly/exception-handling
 [mutable globals]: https://github.com/WebAssembly/mutable-global
@@ -71,6 +72,7 @@ Wabt has been compiled to JavaScript via emscripten. Some of the functionality i
 [reference types]: https://github.com/WebAssembly/reference-types
 [annotations]: https://github.com/WebAssembly/annotations
 [memory64]: https://github.com/WebAssembly/memory64
+[multi-memory]: https://github.com/WebAssembly/multi-memory
 
 ## Cloning
 
index 321e263e406c5a1a7424d7567ccaaef434d00eb3..b5b11c47786f4c0fa24c24c8bb58315092cb37e6 100644 (file)
@@ -20,6 +20,7 @@
 #include <cstdio>
 #include <vector>
 
+#include "src/cast.h"
 #include "src/expr-visitor.h"
 #include "src/ir.h"
 #include "src/string-view.h"
@@ -253,12 +254,12 @@ Result NameApplier::OnDataDropExpr(DataDropExpr* expr) {
   return Result::Ok;
 }
 
-Result NameApplier::OnMemoryInitExpr(MemoryInitExpr* expr)  {
+Result NameApplier::OnMemoryInitExpr(MemoryInitExpr* expr) {
   CHECK_RESULT(UseNameForDataSegmentVar(&expr->var));
   return Result::Ok;
 }
 
-Result NameApplier::OnElemDropExpr(ElemDropExpr* expr)  {
+Result NameApplier::OnElemDropExpr(ElemDropExpr* expr) {
   CHECK_RESULT(UseNameForElemSegmentVar(&expr->var));
   return Result::Ok;
 }
@@ -269,33 +270,33 @@ Result NameApplier::OnTableCopyExpr(TableCopyExpr* expr) {
   return Result::Ok;
 }
 
-Result NameApplier::OnTableInitExpr(TableInitExpr* expr)  {
+Result NameApplier::OnTableInitExpr(TableInitExpr* expr) {
   CHECK_RESULT(UseNameForElemSegmentVar(&expr->segment_index));
   CHECK_RESULT(UseNameForTableVar(&expr->table_index));
   return Result::Ok;
 }
 
-Result NameApplier::OnTableGetExpr(TableGetExpr* expr)  {
+Result NameApplier::OnTableGetExpr(TableGetExpr* expr) {
   CHECK_RESULT(UseNameForTableVar(&expr->var));
   return Result::Ok;
 }
 
-Result NameApplier::OnTableSetExpr(TableSetExpr* expr)  {
+Result NameApplier::OnTableSetExpr(TableSetExpr* expr) {
   CHECK_RESULT(UseNameForTableVar(&expr->var));
   return Result::Ok;
 }
 
-Result NameApplier::OnTableGrowExpr(TableGrowExpr* expr)  {
+Result NameApplier::OnTableGrowExpr(TableGrowExpr* expr) {
   CHECK_RESULT(UseNameForTableVar(&expr->var));
   return Result::Ok;
 }
 
-Result NameApplier::OnTableSizeExpr(TableSizeExpr* expr)  {
+Result NameApplier::OnTableSizeExpr(TableSizeExpr* expr) {
   CHECK_RESULT(UseNameForTableVar(&expr->var));
   return Result::Ok;
 }
 
-Result NameApplier::OnTableFillExpr(TableFillExpr* expr)  {
+Result NameApplier::OnTableFillExpr(TableFillExpr* expr) {
   CHECK_RESULT(UseNameForTableVar(&expr->var));
   return Result::Ok;
 }
@@ -460,9 +461,10 @@ Result NameApplier::VisitElemSegment(Index elem_segment_index,
                                      ElemSegment* segment) {
   CHECK_RESULT(UseNameForTableVar(&segment->table_var));
   CHECK_RESULT(visitor_.VisitExprList(segment->offset));
-  for (ElemExpr& elem_expr : segment->elem_exprs) {
-    if (elem_expr.kind == ElemExprKind::RefFunc) {
-      CHECK_RESULT(UseNameForFuncVar(&elem_expr.var));
+  for (ExprList& elem_expr : segment->elem_exprs) {
+    Expr* expr = &elem_expr.front();
+    if (expr->type() == ExprType::RefFunc) {
+      CHECK_RESULT(UseNameForFuncVar(&cast<RefFuncExpr>(expr)->var));
     }
   }
   return Result::Ok;
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/base-types.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/base-types.h
new file mode 100644 (file)
index 0000000..dbf3770
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WABT_BASE_TYPES_H_
+#define WABT_BASE_TYPES_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace wabt {
+
+typedef uint32_t Index;    // An index into one of the many index spaces.
+typedef uint64_t Address;  // An address or size in linear memory.
+typedef size_t Offset;     // An offset into a host's file or memory buffer.
+
+static const Address kInvalidAddress = ~0;
+static const Index kInvalidIndex = ~0;
+static const Offset kInvalidOffset = ~0;
+
+}  // namespace wabt
+
+#endif  // WABT_BASE_TYPES_H_
index 8290b95f5c86ae6a251f6340d0b7a3fab9861bf6..3722e4bd177aaef69abb2575846d6b497af23fd4 100644 (file)
@@ -45,9 +45,7 @@ LabelNode::LabelNode(LabelType label_type, ExprList* exprs, Expr* context)
 
 class BinaryReaderIR : public BinaryReaderNop {
  public:
-  BinaryReaderIR(Module* out_module,
-                 const char* filename,
-                 Errors* errors);
+  BinaryReaderIR(Module* out_module, const char* filename, Errors* errors);
 
   bool OnError(const Error&) override;
 
@@ -165,18 +163,19 @@ class BinaryReaderIR : public BinaryReaderNop {
   Result OnI64ConstExpr(uint64_t value) override;
   Result OnIfExpr(Type sig_type) override;
   Result OnLoadExpr(Opcode opcode,
+                    Index memidx,
                     Address alignment_log2,
                     Address offset) override;
   Result OnLocalGetExpr(Index local_index) override;
   Result OnLocalSetExpr(Index local_index) override;
   Result OnLocalTeeExpr(Index local_index) override;
   Result OnLoopExpr(Type sig_type) override;
-  Result OnMemoryCopyExpr() override;
+  Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) override;
   Result OnDataDropExpr(Index segment_index) override;
-  Result OnMemoryFillExpr() override;
-  Result OnMemoryGrowExpr() override;
-  Result OnMemoryInitExpr(Index segment_index) override;
-  Result OnMemorySizeExpr() override;
+  Result OnMemoryFillExpr(Index memidx) override;
+  Result OnMemoryGrowExpr(Index memidx) override;
+  Result OnMemoryInitExpr(Index segment_index, Index memidx) override;
+  Result OnMemorySizeExpr(Index memidx) override;
   Result OnTableCopyExpr(Index dst_index, Index src_index) override;
   Result OnElemDropExpr(Index segment_index) override;
   Result OnTableInitExpr(Index segment_index, Index table_index) override;
@@ -193,6 +192,7 @@ class BinaryReaderIR : public BinaryReaderNop {
   Result OnReturnExpr() override;
   Result OnSelectExpr(Index result_count, Type* result_types) override;
   Result OnStoreExpr(Opcode opcode,
+                     Index memidx,
                      Address alignment_log2,
                      Address offset) override;
   Result OnThrowExpr(Index tag_index) override;
@@ -203,10 +203,12 @@ class BinaryReaderIR : public BinaryReaderNop {
   Result EndFunctionBody(Index index) override;
   Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) override;
   Result OnSimdLoadLaneExpr(Opcode opcode,
+                            Index memidx,
                             Address alignment_log2,
                             Address offset,
                             uint64_t value) override;
   Result OnSimdStoreLaneExpr(Opcode opcode,
+                             Index memidx,
                              Address alignment_log2,
                              Address offset,
                              uint64_t value) override;
@@ -257,28 +259,30 @@ class BinaryReaderIR : public BinaryReaderNop {
   Result OnTagType(Index index, Index sig_index) override;
   Result EndTagSection() override { return Result::Ok; }
 
-  Result OnInitExprF32ConstExpr(Index index, uint32_t value) override;
-  Result OnInitExprF64ConstExpr(Index index, uint64_t value) override;
-  Result OnInitExprV128ConstExpr(Index index, v128 value) override;
-  Result OnInitExprGlobalGetExpr(Index index, Index global_index) override;
-  Result OnInitExprI32ConstExpr(Index index, uint32_t value) override;
-  Result OnInitExprI64ConstExpr(Index index, uint64_t value) override;
-  Result OnInitExprRefNull(Index index, Type type) override;
-  Result OnInitExprRefFunc(Index index, Index func_index) override;
-
-  Result OnDataSymbol(Index index, uint32_t flags, string_view name,
-                       Index segment, uint32_t offset, uint32_t size) override;
-  Result OnFunctionSymbol(Index index, uint32_t flags, string_view name,
-                           Index func_index) override;
-  Result OnGlobalSymbol(Index index, uint32_t flags, string_view name,
-                         Index global_index) override;
-  Result OnSectionSymbol(Index index, uint32_t flags,
-                          Index section_index) override;
+  Result OnDataSymbol(Index index,
+                      uint32_t flags,
+                      string_view name,
+                      Index segment,
+                      uint32_t offset,
+                      uint32_t size) override;
+  Result OnFunctionSymbol(Index index,
+                          uint32_t flags,
+                          string_view name,
+                          Index func_index) override;
+  Result OnGlobalSymbol(Index index,
+                        uint32_t flags,
+                        string_view name,
+                        Index global_index) override;
+  Result OnSectionSymbol(Index index,
+                         uint32_t flags,
+                         Index section_index) override;
   Result OnTagSymbol(Index index,
                      uint32_t flags,
                      string_view name,
                      Index tag_index) override;
-  Result OnTableSymbol(Index index, uint32_t flags, string_view name,
+  Result OnTableSymbol(Index index,
+                       uint32_t flags,
+                       string_view name,
                        Index table_index) override;
 
  private:
@@ -287,6 +291,8 @@ class BinaryReaderIR : public BinaryReaderNop {
   void PushLabel(LabelType label_type,
                  ExprList* first,
                  Expr* context = nullptr);
+  Result BeginInitExpr(ExprList* init_expr);
+  Result EndInitExpr();
   Result PopLabel();
   Result GetLabelAt(LabelNode** label, Index depth);
   Result TopLabel(LabelNode** label);
@@ -301,6 +307,7 @@ class BinaryReaderIR : public BinaryReaderNop {
   Result SetGlobalName(Index index, string_view name);
   Result SetDataSegmentName(Index index, string_view name);
   Result SetElemSegmentName(Index index, string_view name);
+  Result SetTagName(Index index, string_view name);
 
   std::string GetUniqueName(BindingHash* bindings,
                             const std::string& original_name);
@@ -310,7 +317,6 @@ class BinaryReaderIR : public BinaryReaderNop {
 
   Func* current_func_ = nullptr;
   std::vector<LabelNode> label_stack_;
-  ExprList* current_init_expr_ = nullptr;
   const char* filename_;
 };
 
@@ -608,13 +614,11 @@ Result BinaryReaderIR::BeginGlobal(Index index, Type type, bool mutable_) {
 Result BinaryReaderIR::BeginGlobalInitExpr(Index index) {
   assert(index == module_->globals.size() - 1);
   Global* global = module_->globals[index];
-  current_init_expr_ = &global->init_expr;
-  return Result::Ok;
+  return BeginInitExpr(&global->init_expr);
 }
 
 Result BinaryReaderIR::EndGlobalInitExpr(Index index) {
-  current_init_expr_ = nullptr;
-  return Result::Ok;
+  return EndInitExpr();
 }
 
 Result BinaryReaderIR::OnExportCount(Index count) {
@@ -644,7 +648,13 @@ Result BinaryReaderIR::OnStartFunction(Index func_index) {
 }
 
 Result BinaryReaderIR::OnFunctionBodyCount(Index count) {
-  assert(module_->num_func_imports + count == module_->funcs.size());
+  // Can hit this case on a malformed module if we don't stop on first error.
+  if (module_->num_func_imports + count != module_->funcs.size()) {
+    PrintError(
+        "number of imported func + func count in code section does not match "
+        "actual number of funcs in module");
+    return Result::Error;
+  }
   return Result::Ok;
 }
 
@@ -757,7 +767,8 @@ Result BinaryReaderIR::OnReturnCallExpr(Index func_index) {
   return AppendExpr(MakeUnique<ReturnCallExpr>(Var(func_index)));
 }
 
-Result BinaryReaderIR::OnReturnCallIndirectExpr(Index sig_index, Index table_index) {
+Result BinaryReaderIR::OnReturnCallIndirectExpr(Index sig_index,
+                                                Index table_index) {
   auto expr = MakeUnique<ReturnCallIndirectExpr>();
   SetFuncDeclaration(&expr->decl, Var(sig_index, GetLocation()));
   expr->table = Var(table_index);
@@ -795,29 +806,32 @@ Result BinaryReaderIR::OnElseExpr() {
 }
 
 Result BinaryReaderIR::OnEndExpr() {
-  LabelNode* label;
-  Expr* expr;
-  CHECK_RESULT(TopLabelExpr(&label, &expr));
-  switch (label->label_type) {
-    case LabelType::Block:
-      cast<BlockExpr>(expr)->block.end_loc = GetLocation();
-      break;
-    case LabelType::Loop:
-      cast<LoopExpr>(expr)->block.end_loc = GetLocation();
-      break;
-    case LabelType::If:
-      cast<IfExpr>(expr)->true_.end_loc = GetLocation();
-      break;
-    case LabelType::Else:
-      cast<IfExpr>(expr)->false_end_loc = GetLocation();
-      break;
-    case LabelType::Try:
-      cast<TryExpr>(expr)->block.end_loc = GetLocation();
-      break;
-
-    case LabelType::Func:
-    case LabelType::Catch:
-      break;
+  if (label_stack_.size() > 1) {
+    LabelNode* label;
+    Expr* expr;
+    CHECK_RESULT(TopLabelExpr(&label, &expr));
+    switch (label->label_type) {
+      case LabelType::Block:
+        cast<BlockExpr>(expr)->block.end_loc = GetLocation();
+        break;
+      case LabelType::Loop:
+        cast<LoopExpr>(expr)->block.end_loc = GetLocation();
+        break;
+      case LabelType::If:
+        cast<IfExpr>(expr)->true_.end_loc = GetLocation();
+        break;
+      case LabelType::Else:
+        cast<IfExpr>(expr)->false_end_loc = GetLocation();
+        break;
+      case LabelType::Try:
+        cast<TryExpr>(expr)->block.end_loc = GetLocation();
+        break;
+
+      case LabelType::InitExpr:
+      case LabelType::Func:
+      case LabelType::Catch:
+        break;
+    }
   }
 
   return PopLabel();
@@ -865,9 +879,11 @@ Result BinaryReaderIR::OnIfExpr(Type sig_type) {
 }
 
 Result BinaryReaderIR::OnLoadExpr(Opcode opcode,
+                                  Index memidx,
                                   Address alignment_log2,
                                   Address offset) {
-  return AppendExpr(MakeUnique<LoadExpr>(opcode, 1 << alignment_log2, offset));
+  return AppendExpr(
+      MakeUnique<LoadExpr>(opcode, Var(memidx), 1 << alignment_log2, offset));
 }
 
 Result BinaryReaderIR::OnLoopExpr(Type sig_type) {
@@ -879,28 +895,29 @@ Result BinaryReaderIR::OnLoopExpr(Type sig_type) {
   return Result::Ok;
 }
 
-Result BinaryReaderIR::OnMemoryCopyExpr() {
-  return AppendExpr(MakeUnique<MemoryCopyExpr>());
+Result BinaryReaderIR::OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) {
+  return AppendExpr(
+      MakeUnique<MemoryCopyExpr>(Var(srcmemidx), Var(destmemidx)));
 }
 
 Result BinaryReaderIR::OnDataDropExpr(Index segment) {
   return AppendExpr(MakeUnique<DataDropExpr>(Var(segment)));
 }
 
-Result BinaryReaderIR::OnMemoryFillExpr() {
-  return AppendExpr(MakeUnique<MemoryFillExpr>());
+Result BinaryReaderIR::OnMemoryFillExpr(Index memidx) {
+  return AppendExpr(MakeUnique<MemoryFillExpr>(Var(memidx)));
 }
 
-Result BinaryReaderIR::OnMemoryGrowExpr() {
-  return AppendExpr(MakeUnique<MemoryGrowExpr>());
+Result BinaryReaderIR::OnMemoryGrowExpr(Index memidx) {
+  return AppendExpr(MakeUnique<MemoryGrowExpr>(Var(memidx)));
 }
 
-Result BinaryReaderIR::OnMemoryInitExpr(Index segment) {
-  return AppendExpr(MakeUnique<MemoryInitExpr>(Var(segment)));
+Result BinaryReaderIR::OnMemoryInitExpr(Index segment, Index memidx) {
+  return AppendExpr(MakeUnique<MemoryInitExpr>(Var(segment), Var(memidx)));
 }
 
-Result BinaryReaderIR::OnMemorySizeExpr() {
-  return AppendExpr(MakeUnique<MemorySizeExpr>());
+Result BinaryReaderIR::OnMemorySizeExpr(Index memidx) {
+  return AppendExpr(MakeUnique<MemorySizeExpr>(Var(memidx)));
 }
 
 Result BinaryReaderIR::OnTableCopyExpr(Index dst_index, Index src_index) {
@@ -975,9 +992,11 @@ Result BinaryReaderIR::OnLocalSetExpr(Index local_index) {
 }
 
 Result BinaryReaderIR::OnStoreExpr(Opcode opcode,
+                                   Index memidx,
                                    Address alignment_log2,
                                    Address offset) {
-  return AppendExpr(MakeUnique<StoreExpr>(opcode, 1 << alignment_log2, offset));
+  return AppendExpr(
+      MakeUnique<StoreExpr>(opcode, Var(memidx), 1 << alignment_log2, offset));
 }
 
 Result BinaryReaderIR::OnThrowExpr(Index tag_index) {
@@ -1010,7 +1029,8 @@ Result BinaryReaderIR::AppendCatch(Catch&& catch_) {
 
   auto* try_ = cast<TryExpr>(label->context);
 
-  if (catch_.IsCatchAll() && !try_->catches.empty() && try_->catches.back().IsCatchAll()) {
+  if (catch_.IsCatchAll() && !try_->catches.empty() &&
+      try_->catches.back().IsCatchAll()) {
     PrintError("only one catch_all allowed in try block");
     return Result::Error;
   }
@@ -1072,7 +1092,6 @@ Result BinaryReaderIR::OnUnreachableExpr() {
 }
 
 Result BinaryReaderIR::EndFunctionBody(Index index) {
-  CHECK_RESULT(PopLabel());
   current_func_ = nullptr;
   return Result::Ok;
 }
@@ -1082,19 +1101,21 @@ Result BinaryReaderIR::OnSimdLaneOpExpr(Opcode opcode, uint64_t value) {
 }
 
 Result BinaryReaderIR::OnSimdLoadLaneExpr(Opcode opcode,
+                                          Index memidx,
                                           Address alignment_log2,
                                           Address offset,
                                           uint64_t value) {
-  return AppendExpr(
-      MakeUnique<SimdLoadLaneExpr>(opcode, 1 << alignment_log2, offset, value));
+  return AppendExpr(MakeUnique<SimdLoadLaneExpr>(
+      opcode, Var(memidx), 1 << alignment_log2, offset, value));
 }
 
 Result BinaryReaderIR::OnSimdStoreLaneExpr(Opcode opcode,
-                                          Address alignment_log2,
-                                          Address offset,
-                                          uint64_t value) {
-  return AppendExpr(
-      MakeUnique<SimdStoreLaneExpr>(opcode, 1 << alignment_log2, offset, value));
+                                           Index memidx,
+                                           Address alignment_log2,
+                                           Address offset,
+                                           uint64_t value) {
+  return AppendExpr(MakeUnique<SimdStoreLaneExpr>(
+      opcode, Var(memidx), 1 << alignment_log2, offset, value));
 }
 
 Result BinaryReaderIR::OnSimdShuffleOpExpr(Opcode opcode, v128 value) {
@@ -1139,16 +1160,23 @@ Result BinaryReaderIR::BeginElemSegment(Index index,
   return Result::Ok;
 }
 
+Result BinaryReaderIR::BeginInitExpr(ExprList* expr) {
+  PushLabel(LabelType::InitExpr, expr);
+  return Result::Ok;
+}
+
 Result BinaryReaderIR::BeginElemSegmentInitExpr(Index index) {
   assert(index == module_->elem_segments.size() - 1);
   ElemSegment* segment = module_->elem_segments[index];
-  current_init_expr_ = &segment->offset;
+  return BeginInitExpr(&segment->offset);
+}
+
+Result BinaryReaderIR::EndInitExpr() {
   return Result::Ok;
 }
 
 Result BinaryReaderIR::EndElemSegmentInitExpr(Index index) {
-  current_init_expr_ = nullptr;
-  return Result::Ok;
+  return EndInitExpr();
 }
 
 Result BinaryReaderIR::OnElemSegmentElemType(Index index, Type elem_type) {
@@ -1171,7 +1199,10 @@ Result BinaryReaderIR::OnElemSegmentElemExpr_RefNull(Index segment_index,
                                                      Type type) {
   assert(segment_index == module_->elem_segments.size() - 1);
   ElemSegment* segment = module_->elem_segments[segment_index];
-  segment->elem_exprs.emplace_back(type);
+  Location loc = GetLocation();
+  ExprList init_expr;
+  init_expr.push_back(MakeUnique<RefNullExpr>(type, loc));
+  segment->elem_exprs.push_back(std::move(init_expr));
   return Result::Ok;
 }
 
@@ -1179,7 +1210,10 @@ Result BinaryReaderIR::OnElemSegmentElemExpr_RefFunc(Index segment_index,
                                                      Index func_index) {
   assert(segment_index == module_->elem_segments.size() - 1);
   ElemSegment* segment = module_->elem_segments[segment_index];
-  segment->elem_exprs.emplace_back(Var(func_index, GetLocation()));
+  Location loc = GetLocation();
+  ExprList init_expr;
+  init_expr.push_back(MakeUnique<RefFuncExpr>(Var(func_index, loc), loc));
+  segment->elem_exprs.push_back(std::move(init_expr));
   return Result::Ok;
 }
 
@@ -1208,13 +1242,11 @@ Result BinaryReaderIR::BeginDataSegment(Index index,
 Result BinaryReaderIR::BeginDataSegmentInitExpr(Index index) {
   assert(index == module_->data_segments.size() - 1);
   DataSegment* segment = module_->data_segments[index];
-  current_init_expr_ = &segment->offset;
-  return Result::Ok;
+  return BeginInitExpr(&segment->offset);
 }
 
 Result BinaryReaderIR::EndDataSegmentInitExpr(Index index) {
-  current_init_expr_ = nullptr;
-  return Result::Ok;
+  return EndInitExpr();
 }
 
 Result BinaryReaderIR::OnDataSegmentData(Index index,
@@ -1348,6 +1380,22 @@ Result BinaryReaderIR::SetMemoryName(Index index, string_view name) {
   return Result::Ok;
 }
 
+Result BinaryReaderIR::SetTagName(Index index, string_view name) {
+  if (name.empty()) {
+    return Result::Ok;
+  }
+  if (index >= module_->tags.size()) {
+    PrintError("invalid tag index: %" PRIindex, index);
+    return Result::Error;
+  }
+  Tag* tag = module_->tags[index];
+  std::string dollar_name =
+      GetUniqueName(&module_->tag_bindings, MakeDollarName(name));
+  tag->name = dollar_name;
+  module_->global_bindings.emplace(dollar_name, Binding(index));
+  return Result::Ok;
+}
+
 Result BinaryReaderIR::OnFunctionName(Index index, string_view name) {
   return SetFunctionName(index, name);
 }
@@ -1364,6 +1412,9 @@ Result BinaryReaderIR::OnNameEntry(NameSectionSubsection type,
     case NameSectionSubsection::Label:
     case NameSectionSubsection::Type:
       break;
+    case NameSectionSubsection::Tag:
+      SetTagName(index, name);
+      break;
     case NameSectionSubsection::Global:
       SetGlobalName(index, name);
       break;
@@ -1396,62 +1447,6 @@ Result BinaryReaderIR::OnLocalNameLocalCount(Index index, Index count) {
   return Result::Ok;
 }
 
-Result BinaryReaderIR::OnInitExprF32ConstExpr(Index index, uint32_t value) {
-  Location loc = GetLocation();
-  current_init_expr_->push_back(
-      MakeUnique<ConstExpr>(Const::F32(value, loc), loc));
-  return Result::Ok;
-}
-
-Result BinaryReaderIR::OnInitExprF64ConstExpr(Index index, uint64_t value) {
-  Location loc = GetLocation();
-  current_init_expr_->push_back(
-      MakeUnique<ConstExpr>(Const::F64(value, loc), loc));
-  return Result::Ok;
-}
-
-Result BinaryReaderIR::OnInitExprV128ConstExpr(Index index, v128 value) {
-  Location loc = GetLocation();
-  current_init_expr_->push_back(
-      MakeUnique<ConstExpr>(Const::V128(value, loc), loc));
-  return Result::Ok;
-}
-
-Result BinaryReaderIR::OnInitExprGlobalGetExpr(Index index,
-                                               Index global_index) {
-  Location loc = GetLocation();
-  current_init_expr_->push_back(
-      MakeUnique<GlobalGetExpr>(Var(global_index, loc), loc));
-  return Result::Ok;
-}
-
-Result BinaryReaderIR::OnInitExprI32ConstExpr(Index index, uint32_t value) {
-  Location loc = GetLocation();
-  current_init_expr_->push_back(
-      MakeUnique<ConstExpr>(Const::I32(value, loc), loc));
-  return Result::Ok;
-}
-
-Result BinaryReaderIR::OnInitExprI64ConstExpr(Index index, uint64_t value) {
-  Location loc = GetLocation();
-  current_init_expr_->push_back(
-      MakeUnique<ConstExpr>(Const::I64(value, loc), loc));
-  return Result::Ok;
-}
-
-Result BinaryReaderIR::OnInitExprRefNull(Index index, Type type) {
-  Location loc = GetLocation();
-  current_init_expr_->push_back(MakeUnique<RefNullExpr>(type, loc));
-  return Result::Ok;
-}
-
-Result BinaryReaderIR::OnInitExprRefFunc(Index index, Index func_index) {
-  Location loc = GetLocation();
-  current_init_expr_->push_back(
-      MakeUnique<RefFuncExpr>(Var(func_index, loc), loc));
-  return Result::Ok;
-}
-
 Result BinaryReaderIR::OnLocalName(Index func_index,
                                    Index local_index,
                                    string_view name) {
@@ -1473,9 +1468,12 @@ Result BinaryReaderIR::OnTagType(Index index, Index sig_index) {
   return Result::Ok;
 }
 
-Result BinaryReaderIR::OnDataSymbol(Index index, uint32_t flags,
-                                    string_view name, Index segment,
-                                    uint32_t offset, uint32_t size) {
+Result BinaryReaderIR::OnDataSymbol(Index index,
+                                    uint32_t flags,
+                                    string_view name,
+                                    Index segment,
+                                    uint32_t offset,
+                                    uint32_t size) {
   if (name.empty()) {
     return Result::Ok;
   }
@@ -1500,8 +1498,10 @@ Result BinaryReaderIR::OnDataSymbol(Index index, uint32_t flags,
   return Result::Ok;
 }
 
-Result BinaryReaderIR::OnFunctionSymbol(Index index, uint32_t flags,
-                                        string_view name, Index func_index) {
+Result BinaryReaderIR::OnFunctionSymbol(Index index,
+                                        uint32_t flags,
+                                        string_view name,
+                                        Index func_index) {
   if (name.empty()) {
     return Result::Ok;
   }
@@ -1521,12 +1521,15 @@ Result BinaryReaderIR::OnFunctionSymbol(Index index, uint32_t flags,
   return Result::Ok;
 }
 
-Result BinaryReaderIR::OnGlobalSymbol(Index index, uint32_t flags,
-                                      string_view name, Index global_index) {
+Result BinaryReaderIR::OnGlobalSymbol(Index index,
+                                      uint32_t flags,
+                                      string_view name,
+                                      Index global_index) {
   return SetGlobalName(global_index, name);
 }
 
-Result BinaryReaderIR::OnSectionSymbol(Index index, uint32_t flags,
+Result BinaryReaderIR::OnSectionSymbol(Index index,
+                                       uint32_t flags,
                                        Index section_index) {
   return Result::Ok;
 }
@@ -1550,8 +1553,10 @@ Result BinaryReaderIR::OnTagSymbol(Index index,
   return Result::Ok;
 }
 
-Result BinaryReaderIR::OnTableSymbol(Index index, uint32_t flags,
-                                     string_view name, Index table_index) {
+Result BinaryReaderIR::OnTableSymbol(Index index,
+                                     uint32_t flags,
+                                     string_view name,
+                                     Index table_index) {
   return SetTableName(index, name);
 }
 
index 61ad43aac71504c8e21fbe7b74e9398efbde3a04..459fca24d5f269890496082b295ab15f78cb0289 100644 (file)
@@ -80,7 +80,7 @@ void BinaryReaderLogging::LogType(Type type) {
   if (type.IsIndex()) {
     LOGF_NOINDENT("typeidx[%d]", type.GetIndex());
   } else {
-    LOGF_NOINDENT("%s", type.GetName());
+    LOGF_NOINDENT("%s", type.GetName().c_str());
   }
 }
 
@@ -208,7 +208,7 @@ Result BinaryReaderLogging::OnImportTable(Index import_index,
   SPrintLimits(buf, sizeof(buf), elem_limits);
   LOGF("OnImportTable(import_index: %" PRIindex ", table_index: %" PRIindex
        ", elem_type: %s, %s)\n",
-       import_index, table_index, elem_type.GetName(), buf);
+       import_index, table_index, elem_type.GetName().c_str(), buf);
   return reader_->OnImportTable(import_index, module_name, field_name,
                                 table_index, elem_type, elem_limits);
 }
@@ -236,7 +236,8 @@ Result BinaryReaderLogging::OnImportGlobal(Index import_index,
   LOGF("OnImportGlobal(import_index: %" PRIindex ", global_index: %" PRIindex
        ", type: %s, mutable: "
        "%s)\n",
-       import_index, global_index, type.GetName(), mutable_ ? "true" : "false");
+       import_index, global_index, type.GetName().c_str(),
+       mutable_ ? "true" : "false");
   return reader_->OnImportGlobal(import_index, module_name, field_name,
                                  global_index, type, mutable_);
 }
@@ -259,7 +260,7 @@ Result BinaryReaderLogging::OnTable(Index index,
   char buf[100];
   SPrintLimits(buf, sizeof(buf), elem_limits);
   LOGF("OnTable(index: %" PRIindex ", elem_type: %s, %s)\n", index,
-       elem_type.GetName(), buf);
+       elem_type.GetName().c_str(), buf);
   return reader_->OnTable(index, elem_type, elem_limits);
 }
 
@@ -272,7 +273,7 @@ Result BinaryReaderLogging::OnMemory(Index index, const Limits* page_limits) {
 
 Result BinaryReaderLogging::BeginGlobal(Index index, Type type, bool mutable_) {
   LOGF("BeginGlobal(index: %" PRIindex ", type: %s, mutable: %s)\n", index,
-       type.GetName(), mutable_ ? "true" : "false");
+       type.GetName().c_str(), mutable_ ? "true" : "false");
   return reader_->BeginGlobal(index, type, mutable_);
 }
 
@@ -295,7 +296,7 @@ Result BinaryReaderLogging::OnLocalDecl(Index decl_index,
                                         Index count,
                                         Type type) {
   LOGF("OnLocalDecl(index: %" PRIindex ", count: %" PRIindex ", type: %s)\n",
-       decl_index, count, type.GetName());
+       decl_index, count, type.GetName().c_str());
   return reader_->OnLocalDecl(decl_index, count, type);
 }
 
@@ -412,7 +413,7 @@ Result BinaryReaderLogging::BeginElemSegment(Index index,
 
 Result BinaryReaderLogging::OnElemSegmentElemType(Index index, Type elem_type) {
   LOGF("OnElemSegmentElemType(index: %" PRIindex ", type: %s)\n", index,
-       elem_type.GetName());
+       elem_type.GetName().c_str());
   return reader_->OnElemSegmentElemType(index, elem_type);
 }
 
@@ -491,48 +492,6 @@ Result BinaryReaderLogging::OnNameEntry(NameSectionSubsection type,
   return reader_->OnNameEntry(type, index, name);
 }
 
-Result BinaryReaderLogging::OnInitExprF32ConstExpr(Index index,
-                                                   uint32_t value_bits) {
-  float value;
-  memcpy(&value, &value_bits, sizeof(value));
-  LOGF("OnInitExprF32ConstExpr(index: %" PRIindex ", value: %g (0x04%x))\n",
-       index, value, value_bits);
-  return reader_->OnInitExprF32ConstExpr(index, value_bits);
-}
-
-Result BinaryReaderLogging::OnInitExprF64ConstExpr(Index index,
-                                                   uint64_t value_bits) {
-  double value;
-  memcpy(&value, &value_bits, sizeof(value));
-  LOGF("OnInitExprF64ConstExpr(index: %" PRIindex " value: %g (0x08%" PRIx64
-       "))\n",
-       index, value, value_bits);
-  return reader_->OnInitExprF64ConstExpr(index, value_bits);
-}
-
-Result BinaryReaderLogging::OnInitExprV128ConstExpr(Index index,
-                                                    v128 value_bits) {
-  LOGF("OnInitExprV128ConstExpr(index: %" PRIindex
-       " value: ( 0x%08x 0x%08x 0x%08x 0x%08x))\n",
-       index, value_bits.u32(0), value_bits.u32(1), value_bits.u32(2),
-       value_bits.u32(3));
-  return reader_->OnInitExprV128ConstExpr(index, value_bits);
-}
-
-Result BinaryReaderLogging::OnInitExprI32ConstExpr(Index index,
-                                                   uint32_t value) {
-  LOGF("OnInitExprI32ConstExpr(index: %" PRIindex ", value: %u)\n", index,
-       value);
-  return reader_->OnInitExprI32ConstExpr(index, value);
-}
-
-Result BinaryReaderLogging::OnInitExprI64ConstExpr(Index index,
-                                                   uint64_t value) {
-  LOGF("OnInitExprI64ConstExpr(index: %" PRIindex ", value: %" PRIu64 ")\n",
-       index, value);
-  return reader_->OnInitExprI64ConstExpr(index, value);
-}
-
 Result BinaryReaderLogging::OnDylinkInfo(uint32_t mem_size,
                                          uint32_t mem_align,
                                          uint32_t table_size,
@@ -550,8 +509,23 @@ Result BinaryReaderLogging::OnDylinkNeeded(string_view so_name) {
   return reader_->OnDylinkNeeded(so_name);
 }
 
-Result BinaryReaderLogging::OnRelocCount(Index count,
-                                         Index section_index) {
+Result BinaryReaderLogging::OnDylinkExport(string_view name, uint32_t flags) {
+  LOGF("OnDylinkExport(name: " PRIstringview ", flags: 0x%x)\n",
+       WABT_PRINTF_STRING_VIEW_ARG(name), flags);
+  return reader_->OnDylinkExport(name, flags);
+}
+
+Result BinaryReaderLogging::OnDylinkImport(string_view module,
+                                           string_view name,
+                                           uint32_t flags) {
+  LOGF("OnDylinkImport(module: " PRIstringview ", name: " PRIstringview
+       ", flags: 0x%x)\n",
+       WABT_PRINTF_STRING_VIEW_ARG(module), WABT_PRINTF_STRING_VIEW_ARG(name),
+       flags);
+  return reader_->OnDylinkImport(module, name, flags);
+}
+
+Result BinaryReaderLogging::OnRelocCount(Index count, Index section_index) {
   LOGF("OnRelocCount(count: %" PRIindex ", section: %" PRIindex ")\n", count,
        section_index);
   return reader_->OnRelocCount(count, section_index);
@@ -568,11 +542,10 @@ Result BinaryReaderLogging::OnReloc(RelocType type,
   return reader_->OnReloc(type, offset, index, addend);
 }
 
-Result BinaryReaderLogging::OnSymbol(Index symbol_index,
-                                     SymbolType type,
-                                     uint32_t flags) {
-  LOGF("OnSymbol(type: %s flags: 0x%x)\n", GetSymbolTypeName(type), flags);
-  return reader_->OnSymbol(symbol_index, type, flags);
+Result BinaryReaderLogging::OnFeature(uint8_t prefix, string_view name) {
+  LOGF("OnFeature(prefix: '%c', name: '" PRIstringview "')\n", prefix,
+       WABT_PRINTF_STRING_VIEW_ARG(name));
+  return reader_->OnFeature(prefix, name);
 }
 
 Result BinaryReaderLogging::OnDataSymbol(Index index,
@@ -629,7 +602,7 @@ Result BinaryReaderLogging::OnTableSymbol(Index index,
                                           string_view name,
                                           Index table_index) {
   LOGF("OnTableSymbol(name: " PRIstringview " flags: 0x%x index: %" PRIindex
-           ")\n",
+       ")\n",
        WABT_PRINTF_STRING_VIEW_ARG(name), flags, table_index);
   return reader_->OnTableSymbol(index, flags, name, table_index);
 }
@@ -684,10 +657,10 @@ Result BinaryReaderLogging::OnComdatEntry(ComdatType kind, Index index) {
     return reader_->name(value);                  \
   }
 
-#define DEFINE_TYPE(name)                       \
-  Result BinaryReaderLogging::name(Type type) { \
-    LOGF(#name "(%s)\n", type.GetName());       \
-    return reader_->name(type);                 \
+#define DEFINE_TYPE(name)                         \
+  Result BinaryReaderLogging::name(Type type) {   \
+    LOGF(#name "(%s)\n", type.GetName().c_str()); \
+    return reader_->name(type);                   \
   }
 
 #define DEFINE_INDEX_DESC(name, desc)                 \
@@ -696,10 +669,11 @@ Result BinaryReaderLogging::OnComdatEntry(ComdatType kind, Index index) {
     return reader_->name(value);                      \
   }
 
-#define DEFINE_INDEX_TYPE(name)                                              \
-  Result BinaryReaderLogging::name(Index value, Type type) {                 \
-    LOGF(#name "(index: %" PRIindex ", type: %s)\n", value, type.GetName()); \
-    return reader_->name(value, type);                                       \
+#define DEFINE_INDEX_TYPE(name)                              \
+  Result BinaryReaderLogging::name(Index value, Type type) { \
+    LOGF(#name "(index: %" PRIindex ", type: %s)\n", value,  \
+         type.GetName().c_str());                            \
+    return reader_->name(value, type);                       \
   }
 
 #define DEFINE_INDEX_INDEX(name, desc0, desc1)                           \
@@ -733,13 +707,25 @@ Result BinaryReaderLogging::OnComdatEntry(ComdatType kind, Index index) {
     return reader_->name(opcode, alignment_log2, offset);                 \
   }
 
+#define DEFINE_MEMORY_LOAD_STORE_OPCODE(name)                                 \
+  Result BinaryReaderLogging::name(Opcode opcode, Index memidx,               \
+                                   Address alignment_log2, Address offset) {  \
+    LOGF(#name "(opcode: \"%s\" (%u), memidx: %" PRIindex                     \
+               ", align log2: %" PRIaddress ", offset: %" PRIaddress ")\n",   \
+         opcode.GetName(), opcode.GetCode(), memidx, alignment_log2, offset); \
+    return reader_->name(opcode, memidx, alignment_log2, offset);             \
+  }
+
 #define DEFINE_SIMD_LOAD_STORE_LANE_OPCODE(name)                             \
-  Result BinaryReaderLogging::name(Opcode opcode, Address alignment_log2,    \
-                                   Address offset, uint64_t value) {         \
-    LOGF(#name "(opcode: \"%s\" (%u), align log2: %" PRIaddress              \
-               ", offset: %" PRIaddress ", lane: %" PRIu64 ")\n",            \
-         opcode.GetName(), opcode.GetCode(), alignment_log2, offset, value); \
-    return reader_->name(opcode, alignment_log2, offset, value);             \
+  Result BinaryReaderLogging::name(Opcode opcode, Index memidx,              \
+                                   Address alignment_log2, Address offset,   \
+                                   uint64_t value) {                         \
+    LOGF(#name "(opcode: \"%s\" (%u), memidx: %" PRIindex                    \
+               ", align log2: %" PRIaddress ", offset: %" PRIaddress         \
+               ", lane: %" PRIu64 ")\n",                                     \
+         opcode.GetName(), opcode.GetCode(), memidx, alignment_log2, offset, \
+         value);                                                             \
+    return reader_->name(opcode, memidx, alignment_log2, offset, value);     \
   }
 
 #define DEFINE0(name)                  \
@@ -813,16 +799,16 @@ DEFINE0(OnElseExpr)
 DEFINE0(OnEndExpr)
 DEFINE_INDEX_DESC(OnGlobalGetExpr, "index")
 DEFINE_INDEX_DESC(OnGlobalSetExpr, "index")
-DEFINE_LOAD_STORE_OPCODE(OnLoadExpr);
+DEFINE_MEMORY_LOAD_STORE_OPCODE(OnLoadExpr);
 DEFINE_INDEX_DESC(OnLocalGetExpr, "index")
 DEFINE_INDEX_DESC(OnLocalSetExpr, "index")
 DEFINE_INDEX_DESC(OnLocalTeeExpr, "index")
-DEFINE0(OnMemoryCopyExpr)
+DEFINE_INDEX_INDEX(OnMemoryCopyExpr, "src_memory_index", "dest_memory_index")
 DEFINE_INDEX(OnDataDropExpr)
-DEFINE0(OnMemoryFillExpr)
-DEFINE0(OnMemoryGrowExpr)
-DEFINE_INDEX(OnMemoryInitExpr)
-DEFINE0(OnMemorySizeExpr)
+DEFINE_INDEX(OnMemoryFillExpr)
+DEFINE_INDEX(OnMemoryGrowExpr)
+DEFINE_INDEX_INDEX(OnMemoryInitExpr, "segment_index", "memory_index")
+DEFINE_INDEX(OnMemorySizeExpr)
 DEFINE_INDEX_INDEX(OnTableCopyExpr, "dst_index", "src_index")
 DEFINE_INDEX(OnElemDropExpr)
 DEFINE_INDEX_INDEX(OnTableInitExpr, "segment_index", "table_index")
@@ -842,7 +828,7 @@ DEFINE_INDEX_INDEX(OnReturnCallIndirectExpr, "sig_index", "table_index")
 DEFINE0(OnReturnExpr)
 DEFINE_LOAD_STORE_OPCODE(OnLoadSplatExpr);
 DEFINE_LOAD_STORE_OPCODE(OnLoadZeroExpr);
-DEFINE_LOAD_STORE_OPCODE(OnStoreExpr);
+DEFINE_MEMORY_LOAD_STORE_OPCODE(OnStoreExpr);
 DEFINE_INDEX_DESC(OnThrowExpr, "tag_index")
 DEFINE0(OnUnreachableExpr)
 DEFINE_OPCODE(OnUnaryExpr)
@@ -883,14 +869,16 @@ DEFINE_END(EndNamesSection)
 DEFINE_BEGIN(BeginRelocSection)
 DEFINE_END(EndRelocSection)
 
-DEFINE_INDEX_INDEX(OnInitExprGlobalGetExpr, "index", "global_index")
-DEFINE_INDEX_TYPE(OnInitExprRefNull)
-DEFINE_INDEX_INDEX(OnInitExprRefFunc, "index", "func_index")
-
 DEFINE_BEGIN(BeginDylinkSection)
 DEFINE_INDEX(OnDylinkNeededCount)
+DEFINE_INDEX(OnDylinkExportCount)
+DEFINE_INDEX(OnDylinkImportCount)
 DEFINE_END(EndDylinkSection)
 
+DEFINE_BEGIN(BeginTargetFeaturesSection)
+DEFINE_INDEX(OnFeatureCount)
+DEFINE_END(EndTargetFeaturesSection)
+
 DEFINE_BEGIN(BeginLinkingSection)
 DEFINE_INDEX(OnSymbolCount)
 DEFINE_INDEX(OnSegmentInfoCount)
@@ -960,8 +948,4 @@ Result BinaryReaderLogging::OnOpcodeType(Type type) {
   return reader_->OnOpcodeType(type);
 }
 
-Result BinaryReaderLogging::OnEndFunc() {
-  return reader_->OnEndFunc();
-}
-
 }  // namespace wabt
index 579d394cbf06b88ed4eff189565a317eb53c707d..1c2f302a3754f7eb168f9fcda735e60fcaad6335 100644 (file)
@@ -176,7 +176,6 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
   Result OnDropExpr() override;
   Result OnElseExpr() override;
   Result OnEndExpr() override;
-  Result OnEndFunc() override;
   Result OnF32ConstExpr(uint32_t value_bits) override;
   Result OnF64ConstExpr(uint64_t value_bits) override;
   Result OnV128ConstExpr(v128 value_bits) override;
@@ -186,18 +185,19 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
   Result OnI64ConstExpr(uint64_t value) override;
   Result OnIfExpr(Type sig_type) override;
   Result OnLoadExpr(Opcode opcode,
+                    Index memidx,
                     Address alignment_log2,
                     Address offset) override;
   Result OnLocalGetExpr(Index local_index) override;
   Result OnLocalSetExpr(Index local_index) override;
   Result OnLocalTeeExpr(Index local_index) override;
   Result OnLoopExpr(Type sig_type) override;
-  Result OnMemoryCopyExpr() override;
+  Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) override;
   Result OnDataDropExpr(Index segment_index) override;
-  Result OnMemoryFillExpr() override;
-  Result OnMemoryGrowExpr() override;
-  Result OnMemoryInitExpr(Index segment_index) override;
-  Result OnMemorySizeExpr() override;
+  Result OnMemoryFillExpr(Index memidx) override;
+  Result OnMemoryGrowExpr(Index memidx) override;
+  Result OnMemoryInitExpr(Index segment_index, Index memidx) override;
+  Result OnMemorySizeExpr(Index memidx) override;
   Result OnTableCopyExpr(Index dst_index, Index src_index) override;
   Result OnElemDropExpr(Index segment_index) override;
   Result OnTableInitExpr(Index segment_index, Index table_index) override;
@@ -216,6 +216,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
   Result OnReturnExpr() override;
   Result OnSelectExpr(Index result_count, Type* result_types) override;
   Result OnStoreExpr(Opcode opcode,
+                     Index memidx,
                      Address alignment_log2,
                      Address offset) override;
   Result OnThrowExpr(Index tag_index) override;
@@ -234,10 +235,12 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
   Result EndCodeSection() override;
   Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) override;
   Result OnSimdLoadLaneExpr(Opcode opcode,
+                            Index memidx,
                             Address alignment_log2,
                             Address offset,
                             uint64_t value) override;
   Result OnSimdStoreLaneExpr(Opcode opcode,
+                             Index memidx,
                              Address alignment_log2,
                              Address offset,
                              uint64_t value) override;
@@ -324,11 +327,21 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
                       uint32_t table_align) override;
   Result OnDylinkNeededCount(Index count) override;
   Result OnDylinkNeeded(string_view needed) override;
+  Result OnDylinkImportCount(Index count) override;
+  Result OnDylinkExportCount(Index count) override;
+  Result OnDylinkImport(string_view module,
+                        string_view name,
+                        uint32_t flags) override;
+  Result OnDylinkExport(string_view name, uint32_t flags) override;
   Result EndDylinkSection() override;
 
+  Result BeginTargetFeaturesSection(Offset size) override;
+  Result OnFeatureCount(Index count) override;
+  Result OnFeature(uint8_t prefix, string_view name) override;
+  Result EndTargetFeaturesSection() override;
+
   Result BeginLinkingSection(Offset size) override;
   Result OnSymbolCount(Index count) override;
-  Result OnSymbol(Index sybmol_index, SymbolType type, uint32_t flags) override;
   Result OnDataSymbol(Index index,
                       uint32_t flags,
                       string_view name,
@@ -371,15 +384,6 @@ class BinaryReaderLogging : public BinaryReaderDelegate {
   Result OnTagType(Index index, Index sig_index) override;
   Result EndTagSection() override;
 
-  Result OnInitExprF32ConstExpr(Index index, uint32_t value) override;
-  Result OnInitExprF64ConstExpr(Index index, uint64_t value) override;
-  Result OnInitExprV128ConstExpr(Index index, v128 value) override;
-  Result OnInitExprGlobalGetExpr(Index index, Index global_index) override;
-  Result OnInitExprI32ConstExpr(Index index, uint32_t value) override;
-  Result OnInitExprI64ConstExpr(Index index, uint64_t value) override;
-  Result OnInitExprRefNull(Index index, Type type) override;
-  Result OnInitExprRefFunc(Index index, Index func_index) override;
-
  private:
   void Indent();
   void Dedent();
index 0d74272ba6403d04426d0cb6390cf26a99332e75..d87ec9227d36236945ece733ff33dfa9e0dbe8e5 100644 (file)
@@ -58,9 +58,7 @@ class BinaryReaderNop : public BinaryReaderDelegate {
                       TypeMut* fields) override {
     return Result::Ok;
   }
-  Result OnArrayType(Index index, TypeMut field) override {
-    return Result::Ok;
-  }
+  Result OnArrayType(Index index, TypeMut field) override { return Result::Ok; }
   Result EndTypeSection() override { return Result::Ok; }
 
   /* Import section */
@@ -221,9 +219,7 @@ class BinaryReaderNop : public BinaryReaderDelegate {
   Result OnAtomicWaitExpr(Opcode, Address, Address) override {
     return Result::Ok;
   }
-  Result OnAtomicFenceExpr(uint32_t) override {
-    return Result::Ok;
-  }
+  Result OnAtomicFenceExpr(uint32_t) override { return Result::Ok; }
   Result OnAtomicNotifyExpr(Opcode, Address, Address) override {
     return Result::Ok;
   }
@@ -237,7 +233,9 @@ class BinaryReaderNop : public BinaryReaderDelegate {
     return Result::Ok;
   }
   Result OnCallExpr(Index func_index) override { return Result::Ok; }
-  Result OnCallIndirectExpr(Index sig_index, Index table_index) override { return Result::Ok; }
+  Result OnCallIndirectExpr(Index sig_index, Index table_index) override {
+    return Result::Ok;
+  }
   Result OnCallRefExpr() override { return Result::Ok; }
   Result OnCatchExpr(Index tag_index) override { return Result::Ok; }
   Result OnCatchAllExpr() override { return Result::Ok; }
@@ -247,7 +245,6 @@ class BinaryReaderNop : public BinaryReaderDelegate {
   Result OnDropExpr() override { return Result::Ok; }
   Result OnElseExpr() override { return Result::Ok; }
   Result OnEndExpr() override { return Result::Ok; }
-  Result OnEndFunc() override { return Result::Ok; }
   Result OnF32ConstExpr(uint32_t value_bits) override { return Result::Ok; }
   Result OnF64ConstExpr(uint64_t value_bits) override { return Result::Ok; }
   Result OnV128ConstExpr(v128 value_bits) override { return Result::Ok; }
@@ -257,6 +254,7 @@ class BinaryReaderNop : public BinaryReaderDelegate {
   Result OnI64ConstExpr(uint64_t value) override { return Result::Ok; }
   Result OnIfExpr(Type sig_type) override { return Result::Ok; }
   Result OnLoadExpr(Opcode opcode,
+                    Index memidx,
                     Address alignment_log2,
                     Address offset) override {
     return Result::Ok;
@@ -265,12 +263,16 @@ class BinaryReaderNop : public BinaryReaderDelegate {
   Result OnLocalSetExpr(Index local_index) override { return Result::Ok; }
   Result OnLocalTeeExpr(Index local_index) override { return Result::Ok; }
   Result OnLoopExpr(Type sig_type) override { return Result::Ok; }
-  Result OnMemoryCopyExpr() override { return Result::Ok; }
+  Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) override {
+    return Result::Ok;
+  }
   Result OnDataDropExpr(Index segment_index) override { return Result::Ok; }
-  Result OnMemoryFillExpr() override { return Result::Ok; }
-  Result OnMemoryGrowExpr() override { return Result::Ok; }
-  Result OnMemoryInitExpr(Index segment_index) override { return Result::Ok; }
-  Result OnMemorySizeExpr() override { return Result::Ok; }
+  Result OnMemoryFillExpr(Index memidx) override { return Result::Ok; }
+  Result OnMemoryGrowExpr(Index memidx) override { return Result::Ok; }
+  Result OnMemoryInitExpr(Index segment_index, Index memidx) override {
+    return Result::Ok;
+  }
+  Result OnMemorySizeExpr(Index memidx) override { return Result::Ok; }
   Result OnTableCopyExpr(Index dst_index, Index src_index) override {
     return Result::Ok;
   }
@@ -289,12 +291,15 @@ class BinaryReaderNop : public BinaryReaderDelegate {
   Result OnNopExpr() override { return Result::Ok; }
   Result OnRethrowExpr(Index depth) override { return Result::Ok; }
   Result OnReturnCallExpr(Index sig_index) override { return Result::Ok; }
-  Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override { return Result::Ok; }
+  Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override {
+    return Result::Ok;
+  }
   Result OnReturnExpr() override { return Result::Ok; }
   Result OnSelectExpr(Index result_count, Type* result_types) override {
     return Result::Ok;
   }
   Result OnStoreExpr(Opcode opcode,
+                     Index memidx,
                      Address alignment_log2,
                      Address offset) override {
     return Result::Ok;
@@ -310,12 +315,14 @@ class BinaryReaderNop : public BinaryReaderDelegate {
     return Result::Ok;
   }
   Result OnSimdLoadLaneExpr(Opcode opcode,
+                            Index memidx,
                             Address alignment_log2,
                             Address offset,
                             uint64_t value) override {
     return Result::Ok;
   }
   Result OnSimdStoreLaneExpr(Opcode opcode,
+                             Index memidx,
                              Address alignment_log2,
                              Address offset,
                              uint64_t value) override {
@@ -465,16 +472,29 @@ class BinaryReaderNop : public BinaryReaderDelegate {
   }
   Result OnDylinkNeededCount(Index count) override { return Result::Ok; }
   Result OnDylinkNeeded(string_view so_name) override { return Result::Ok; }
+  Result OnDylinkImportCount(Index count) override { return Result::Ok; }
+  Result OnDylinkExportCount(Index count) override { return Result::Ok; }
+  Result OnDylinkImport(string_view module,
+                        string_view name,
+                        uint32_t flags) override {
+    return Result::Ok;
+  }
+  Result OnDylinkExport(string_view name, uint32_t flags) override {
+    return Result::Ok;
+  }
   Result EndDylinkSection() override { return Result::Ok; }
 
+  /* target_features section */
+  Result BeginTargetFeaturesSection(Offset size) override { return Result::Ok; }
+  Result OnFeatureCount(Index count) override { return Result::Ok; }
+  Result OnFeature(uint8_t prefix, string_view name) override {
+    return Result::Ok;
+  }
+  Result EndTargetFeaturesSection() override { return Result::Ok; }
+
   /* Linking section */
   Result BeginLinkingSection(Offset size) override { return Result::Ok; }
   Result OnSymbolCount(Index count) override { return Result::Ok; }
-  Result OnSymbol(Index sybmol_index,
-                  SymbolType type,
-                  uint32_t flags) override {
-    return Result::Ok;
-  }
   Result OnDataSymbol(Index index,
                       uint32_t flags,
                       string_view name,
@@ -531,33 +551,6 @@ class BinaryReaderNop : public BinaryReaderDelegate {
     return Result::Ok;
   }
   Result EndLinkingSection() override { return Result::Ok; }
-
-  /* InitExpr - used by elem, data and global sections; these functions are
-   * only called between calls to Begin*InitExpr and End*InitExpr */
-  Result OnInitExprF32ConstExpr(Index index, uint32_t value) override {
-    return Result::Ok;
-  }
-  Result OnInitExprF64ConstExpr(Index index, uint64_t value) override {
-    return Result::Ok;
-  }
-  Result OnInitExprV128ConstExpr(Index index, v128 value) override {
-    return Result::Ok;
-  }
-  Result OnInitExprGlobalGetExpr(Index index, Index global_index) override {
-    return Result::Ok;
-  }
-  Result OnInitExprI32ConstExpr(Index index, uint32_t value) override {
-    return Result::Ok;
-  }
-  Result OnInitExprI64ConstExpr(Index index, uint64_t value) override {
-    return Result::Ok;
-  }
-  Result OnInitExprRefNull(Index index, Type type) override {
-    return Result::Ok;
-  }
-  Result OnInitExprRefFunc(Index index, Index func_index) override {
-    return Result::Ok;
-  }
 };
 
 }  // namespace wabt
index 7bfe4c6312b9547e5f293838b378d50d0bbc9071..bf7028da088a94a1f5d82b6cdf04ca27e157d117 100644 (file)
@@ -54,6 +54,7 @@ class BinaryReaderObjdumpBase : public BinaryReaderNop {
  protected:
   string_view GetFunctionName(Index index) const;
   string_view GetGlobalName(Index index) const;
+  string_view GetLocalName(Index function_index, Index local_index) const;
   string_view GetSectionName(Index index) const;
   string_view GetTagName(Index index) const;
   string_view GetSymbolName(Index index) const;
@@ -145,6 +146,11 @@ string_view BinaryReaderObjdumpBase::GetGlobalName(Index index) const {
   return objdump_state_->global_names.Get(index);
 }
 
+string_view BinaryReaderObjdumpBase::GetLocalName(Index function_index,
+                                                  Index local_index) const {
+  return objdump_state_->local_names.Get(function_index, local_index);
+}
+
 string_view BinaryReaderObjdumpBase::GetSectionName(Index index) const {
   return objdump_state_->section_names.Get(index);
 }
@@ -240,6 +246,15 @@ class BinaryReaderObjdumpPrepass : public BinaryReaderObjdumpBase {
     return Result::Ok;
   }
 
+  Result OnFuncType(Index index,
+                    Index param_count,
+                    Type* param_types,
+                    Index result_count,
+                    Type* result_types) override {
+    objdump_state_->function_param_counts[index] = param_count;
+    return Result::Ok;
+  }
+
   Result OnNameEntry(NameSectionSubsection type,
                      Index index,
                      string_view name) override {
@@ -260,12 +275,22 @@ class BinaryReaderObjdumpPrepass : public BinaryReaderObjdumpBase {
       case NameSectionSubsection::DataSegment:
         SetSegmentName(index, name);
         break;
+      case NameSectionSubsection::Tag:
+        SetTagName(index, name);
+        break;
       default:
         break;
     }
     return Result::Ok;
   }
 
+  Result OnLocalName(Index function_index,
+                     Index local_index,
+                     string_view local_name) override {
+    SetLocalName(function_index, local_index, local_name);
+    return Result::Ok;
+  }
+
   Result OnSymbolCount(Index count) override {
     objdump_state_->symtab.resize(count);
     return Result::Ok;
@@ -416,6 +441,7 @@ class BinaryReaderObjdumpPrepass : public BinaryReaderObjdumpBase {
  protected:
   void SetFunctionName(Index index, string_view name);
   void SetGlobalName(Index index, string_view name);
+  void SetLocalName(Index function_index, Index local_index, string_view name);
   void SetTagName(Index index, string_view name);
   void SetTableName(Index index, string_view name);
   void SetSegmentName(Index index, string_view name);
@@ -430,6 +456,12 @@ void BinaryReaderObjdumpPrepass::SetGlobalName(Index index, string_view name) {
   objdump_state_->global_names.Set(index, name);
 }
 
+void BinaryReaderObjdumpPrepass::SetLocalName(Index function_index,
+                                              Index local_index,
+                                              string_view name) {
+  objdump_state_->local_names.Set(function_index, local_index, name);
+}
+
 void BinaryReaderObjdumpPrepass::SetTagName(Index index, string_view name) {
   objdump_state_->tag_names.Set(index, name);
 }
@@ -462,6 +494,7 @@ class BinaryReaderObjdumpDisassemble : public BinaryReaderObjdumpBase {
   std::string BlockSigToString(Type type) const;
 
   Result BeginFunctionBody(Index index, Offset size) override;
+  Result EndFunctionBody(Index index) override;
 
   Result OnLocalDeclCount(Index count) override;
   Result OnLocalDecl(Index decl_index, Index count, Type type) override;
@@ -472,7 +505,9 @@ class BinaryReaderObjdumpDisassemble : public BinaryReaderObjdumpBase {
   Result OnOpcodeIndexIndex(Index value, Index value2) override;
   Result OnOpcodeUint32(uint32_t value) override;
   Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) override;
-  Result OnOpcodeUint32Uint32Uint32(uint32_t value, uint32_t value2, uint32_t value3) override;
+  Result OnOpcodeUint32Uint32Uint32(uint32_t value,
+                                    uint32_t value2,
+                                    uint32_t value3) override;
   Result OnOpcodeUint64(uint64_t value) override;
   Result OnOpcodeF32(uint32_t value) override;
   Result OnOpcodeF64(uint64_t value) override;
@@ -485,17 +520,18 @@ class BinaryReaderObjdumpDisassemble : public BinaryReaderObjdumpBase {
                        Index default_target_depth) override;
   Result OnDelegateExpr(Index) override;
   Result OnEndExpr() override;
-  Result OnEndFunc() override;
 
  private:
-  void LogOpcode(size_t data_size, const char* fmt, ...);
+  void LogOpcode(const char* fmt, ...);
 
   Opcode current_opcode = Opcode::Unreachable;
   Offset current_opcode_offset = 0;
   Offset last_opcode_end = 0;
   int indent_level = 0;
   Index next_reloc = 0;
+  Index current_function_index = 0;
   Index local_index_ = 0;
+  bool in_function_body = false;
 };
 
 std::string BinaryReaderObjdumpDisassemble::BlockSigToString(Type type) const {
@@ -509,6 +545,9 @@ std::string BinaryReaderObjdumpDisassemble::BlockSigToString(Type type) const {
 }
 
 Result BinaryReaderObjdumpDisassemble::OnOpcode(Opcode opcode) {
+  if (!in_function_body) {
+    return Result::Ok;
+  }
   if (options_->debug) {
     const char* opcode_name = opcode.GetName();
     err_stream_->Writef("on_opcode: %#" PRIzx ": %s\n", state->offset,
@@ -520,7 +559,7 @@ Result BinaryReaderObjdumpDisassemble::OnOpcode(Opcode opcode) {
       Opcode missing_opcode = Opcode::FromCode(data_[last_opcode_end]);
       const char* opcode_name = missing_opcode.GetName();
       fprintf(stderr,
-              "warning: %#" PRIzx " missing opcode callback at %#" PRIzx
+              "error: %#" PRIzx " missing opcode callback at %#" PRIzx
               " (%#02x=%s)\n",
               state->offset, last_opcode_end + 1, data_[last_opcode_end],
               opcode_name);
@@ -536,7 +575,9 @@ Result BinaryReaderObjdumpDisassemble::OnOpcode(Opcode opcode) {
 #define IMMEDIATE_OCTET_COUNT 9
 
 Result BinaryReaderObjdumpDisassemble::OnLocalDeclCount(Index count) {
-  local_index_ = 0;
+  if (!in_function_body) {
+    return Result::Ok;
+  }
   current_opcode_offset = state->offset;
   return Result::Ok;
 }
@@ -544,6 +585,9 @@ Result BinaryReaderObjdumpDisassemble::OnLocalDeclCount(Index count) {
 Result BinaryReaderObjdumpDisassemble::OnLocalDecl(Index decl_index,
                                                    Index count,
                                                    Type type) {
+  if (!in_function_body) {
+    return Result::Ok;
+  }
   Offset offset = current_opcode_offset;
   size_t data_size = state->offset - offset;
 
@@ -562,7 +606,7 @@ Result BinaryReaderObjdumpDisassemble::OnLocalDecl(Index decl_index,
   }
   local_index_ += count;
 
-  printf("] type=%s\n", type.GetName());
+  printf("] type=%s\n", type.GetName().c_str());
 
   last_opcode_end = current_opcode_offset + data_size;
   current_opcode_offset = last_opcode_end;
@@ -570,11 +614,14 @@ Result BinaryReaderObjdumpDisassemble::OnLocalDecl(Index decl_index,
   return Result::Ok;
 }
 
-void BinaryReaderObjdumpDisassemble::LogOpcode(size_t data_size,
-                                               const char* fmt,
-                                               ...) {
+void BinaryReaderObjdumpDisassemble::LogOpcode(const char* fmt, ...) {
+  // BinaryReaderObjdumpDisassemble is only used to disassembly function bodies
+  // so this should never be called for instructions outside of function bodies
+  // (i.e. init expresions).
+  assert(in_function_body);
+  const Offset immediate_len = state->offset - current_opcode_offset;
   const Offset opcode_size = current_opcode.GetLength();
-  const Offset total_size = opcode_size + data_size;
+  const Offset total_size = opcode_size + immediate_len;
   // current_opcode_offset has already read past this opcode; rewind it by the
   // size of this opcode, which may be more than one byte.
   Offset offset = current_opcode_offset - opcode_size;
@@ -627,7 +674,7 @@ void BinaryReaderObjdumpDisassemble::LogOpcode(size_t data_size,
     printf("\n");
   }
 
-  last_opcode_end = offset_end;
+  last_opcode_end = state->offset;
 
   // Print relocation after then full (potentially multi-line) instruction.
   if (options_->relocs &&
@@ -643,58 +690,77 @@ void BinaryReaderObjdumpDisassemble::LogOpcode(size_t data_size,
 }
 
 Result BinaryReaderObjdumpDisassemble::OnOpcodeBare() {
+  if (!in_function_body) {
+    return Result::Ok;
+  }
   LogOpcode(0, nullptr);
   return Result::Ok;
 }
 
 Result BinaryReaderObjdumpDisassemble::OnOpcodeIndex(Index value) {
-  Offset immediate_len = state->offset - current_opcode_offset;
+  if (!in_function_body) {
+    return Result::Ok;
+  }
   string_view name;
   if (current_opcode == Opcode::Call &&
       !(name = GetFunctionName(value)).empty()) {
-    LogOpcode(immediate_len, "%d <" PRIstringview ">", value,
+    LogOpcode("%d <" PRIstringview ">", value,
+              WABT_PRINTF_STRING_VIEW_ARG(name));
+  } else if (current_opcode == Opcode::Throw &&
+             !(name = GetTagName(value)).empty()) {
+    LogOpcode("%d <" PRIstringview ">", value,
               WABT_PRINTF_STRING_VIEW_ARG(name));
   } else if ((current_opcode == Opcode::GlobalGet ||
               current_opcode == Opcode::GlobalSet) &&
              !(name = GetGlobalName(value)).empty()) {
-    LogOpcode(immediate_len, "%d <" PRIstringview ">", value,
+    LogOpcode("%d <" PRIstringview ">", value,
+              WABT_PRINTF_STRING_VIEW_ARG(name));
+  } else if ((current_opcode == Opcode::LocalGet ||
+              current_opcode == Opcode::LocalSet) &&
+             !(name = GetLocalName(current_function_index, value)).empty()) {
+    LogOpcode("%d <" PRIstringview ">", value,
               WABT_PRINTF_STRING_VIEW_ARG(name));
   } else {
-    LogOpcode(immediate_len, "%d", value);
+    LogOpcode("%d", value);
   }
   return Result::Ok;
 }
 
 Result BinaryReaderObjdumpDisassemble::OnOpcodeIndexIndex(Index value,
                                                           Index value2) {
-  Offset immediate_len = state->offset - current_opcode_offset;
-  LogOpcode(immediate_len, "%" PRIindex " %" PRIindex, value, value2);
+  if (!in_function_body) {
+    return Result::Ok;
+  }
+  LogOpcode("%" PRIindex " %" PRIindex, value, value2);
   return Result::Ok;
 }
 
 Result BinaryReaderObjdumpDisassemble::OnOpcodeUint32(uint32_t value) {
-  Offset immediate_len = state->offset - current_opcode_offset;
+  if (!in_function_body) {
+    return Result::Ok;
+  }
   string_view name;
   if (current_opcode == Opcode::DataDrop &&
       !(name = GetSegmentName(value)).empty()) {
-    LogOpcode(immediate_len, "%d <" PRIstringview ">", value,
+    LogOpcode("%d <" PRIstringview ">", value,
               WABT_PRINTF_STRING_VIEW_ARG(name));
   } else {
-    LogOpcode(immediate_len, "%u", value);
+    LogOpcode("%u", value);
   }
   return Result::Ok;
 }
 
 Result BinaryReaderObjdumpDisassemble::OnOpcodeUint32Uint32(uint32_t value,
                                                             uint32_t value2) {
-  Offset immediate_len = state->offset - current_opcode_offset;
+  if (!in_function_body)
+    return Result::Ok;
   string_view name;
   if (current_opcode == Opcode::MemoryInit &&
       !(name = GetSegmentName(value)).empty()) {
-    LogOpcode(immediate_len, "%u %u <" PRIstringview ">", value, value2,
+    LogOpcode("%u %u <" PRIstringview ">", value, value2,
               WABT_PRINTF_STRING_VIEW_ARG(name));
   } else {
-    LogOpcode(immediate_len, "%u %u", value, value2);
+    LogOpcode("%u %u", value, value2);
   }
   return Result::Ok;
 }
@@ -703,44 +769,60 @@ Result BinaryReaderObjdumpDisassemble::OnOpcodeUint32Uint32Uint32(
     uint32_t value,
     uint32_t value2,
     uint32_t value3) {
-  Offset immediate_len = state->offset - current_opcode_offset;
-  LogOpcode(immediate_len, "%u %u %u", value, value2, value3);
+  if (!in_function_body) {
+    return Result::Ok;
+  }
+  LogOpcode("%u %u %u", value, value2, value3);
   return Result::Ok;
 }
 
 Result BinaryReaderObjdumpDisassemble::OnOpcodeUint64(uint64_t value) {
-  Offset immediate_len = state->offset - current_opcode_offset;
-  LogOpcode(immediate_len, "%" PRId64, value);
+  if (!in_function_body) {
+    return Result::Ok;
+  }
+  LogOpcode("%" PRId64, value);
   return Result::Ok;
 }
 
 Result BinaryReaderObjdumpDisassemble::OnOpcodeF32(uint32_t value) {
-  Offset immediate_len = state->offset - current_opcode_offset;
+  if (!in_function_body) {
+    return Result::Ok;
+  }
   char buffer[WABT_MAX_FLOAT_HEX];
   WriteFloatHex(buffer, sizeof(buffer), value);
-  LogOpcode(immediate_len, buffer);
+  LogOpcode(buffer);
   return Result::Ok;
 }
 
 Result BinaryReaderObjdumpDisassemble::OnOpcodeF64(uint64_t value) {
-  Offset immediate_len = state->offset - current_opcode_offset;
+  if (!in_function_body) {
+    return Result::Ok;
+  }
   char buffer[WABT_MAX_DOUBLE_HEX];
   WriteDoubleHex(buffer, sizeof(buffer), value);
-  LogOpcode(immediate_len, buffer);
+  LogOpcode(buffer);
   return Result::Ok;
 }
 
 Result BinaryReaderObjdumpDisassemble::OnOpcodeV128(v128 value) {
-  Offset immediate_len = state->offset - current_opcode_offset;
+  if (!in_function_body) {
+    return Result::Ok;
+  }
   // v128 is always dumped as i32x4:
-  LogOpcode(immediate_len, "0x%08x 0x%08x 0x%08x 0x%08x", value.u32(0),
-            value.u32(1), value.u32(2), value.u32(3));
+  LogOpcode("0x%08x 0x%08x 0x%08x 0x%08x", value.u32(0), value.u32(1),
+            value.u32(2), value.u32(3));
   return Result::Ok;
 }
 
 Result BinaryReaderObjdumpDisassemble::OnOpcodeType(Type type) {
-  Offset immediate_len = state->offset - current_opcode_offset;
-  LogOpcode(immediate_len, type.GetRefKindName());
+  if (!in_function_body) {
+    return Result::Ok;
+  }
+  if (current_opcode == Opcode::SelectT) {
+    LogOpcode(type.GetName().c_str());
+  } else {
+    LogOpcode(type.GetRefKindName());
+  }
   return Result::Ok;
 }
 
@@ -748,7 +830,9 @@ Result BinaryReaderObjdumpDisassemble::OnBrTableExpr(
     Index num_targets,
     Index* target_depths,
     Index default_target_depth) {
-  Offset immediate_len = state->offset - current_opcode_offset;
+  if (!in_function_body) {
+    return Result::Ok;
+  }
 
   std::string buffer = std::string();
   for (Index i = 0; i < num_targets; i++) {
@@ -756,11 +840,14 @@ Result BinaryReaderObjdumpDisassemble::OnBrTableExpr(
   }
   buffer.append(std::to_string(default_target_depth));
 
-  LogOpcode(immediate_len, "%s", buffer.c_str());
+  LogOpcode("%s", buffer.c_str());
   return Result::Ok;
 }
 
 Result BinaryReaderObjdumpDisassemble::OnDelegateExpr(Index depth) {
+  if (!in_function_body) {
+    return Result::Ok;
+  }
   // Because `delegate` ends the block we need to dedent here, and
   // we don't need to dedent it in LogOpcode.
   if (indent_level > 0) {
@@ -769,12 +856,10 @@ Result BinaryReaderObjdumpDisassemble::OnDelegateExpr(Index depth) {
   return Result::Ok;
 }
 
-Result BinaryReaderObjdumpDisassemble::OnEndFunc() {
-  LogOpcode(0, nullptr);
-  return Result::Ok;
-}
-
 Result BinaryReaderObjdumpDisassemble::OnEndExpr() {
+  if (!in_function_body) {
+    return Result::Ok;
+  }
   if (indent_level > 0) {
     indent_level--;
   }
@@ -793,15 +878,26 @@ Result BinaryReaderObjdumpDisassemble::BeginFunctionBody(Index index,
   printf(":\n");
 
   last_opcode_end = 0;
+  in_function_body = true;
+  current_function_index = index;
+  local_index_ = objdump_state_->function_param_counts[index];
+  return Result::Ok;
+}
+
+Result BinaryReaderObjdumpDisassemble::EndFunctionBody(Index index) {
+  assert(in_function_body);
+  in_function_body = false;
   return Result::Ok;
 }
 
 Result BinaryReaderObjdumpDisassemble::OnOpcodeBlockSig(Type sig_type) {
-  Offset immediate_len = state->offset - current_opcode_offset;
+  if (!in_function_body) {
+    return Result::Ok;
+  }
   if (sig_type != Type::Void) {
-    LogOpcode(immediate_len, "%s", BlockSigToString(sig_type).c_str());
+    LogOpcode("%s", BlockSigToString(sig_type).c_str());
   } else {
-    LogOpcode(immediate_len, nullptr);
+    LogOpcode(nullptr);
   }
   indent_level++;
   return Result::Ok;
@@ -912,15 +1008,6 @@ class BinaryReaderObjdump : public BinaryReaderObjdumpBase {
   Result OnFunctionBodyCount(Index count) override;
   Result BeginFunctionBody(Index index, Offset size) override;
 
-  Result BeginElemSection(Offset size) override {
-    in_elem_section_ = true;
-    return Result::Ok;
-  }
-  Result EndElemSection() override {
-    in_elem_section_ = false;
-    return Result::Ok;
-  }
-
   Result OnElemSegmentCount(Index count) override;
   Result BeginElemSegment(Index index,
                           Index table_index,
@@ -931,12 +1018,33 @@ class BinaryReaderObjdump : public BinaryReaderObjdumpBase {
   Result OnElemSegmentElemExpr_RefFunc(Index segment_index,
                                        Index func_index) override;
 
-  Result BeginDataSection(Offset size) override {
-    in_data_section_ = true;
+  Result BeginElemSegmentInitExpr(Index index) override {
+    reading_elem_init_expr_ = true;
     return Result::Ok;
   }
-  Result EndDataSection() override {
-    in_data_section_ = false;
+
+  Result EndElemSegmentInitExpr(Index index) override {
+    reading_elem_init_expr_ = false;
+    return Result::Ok;
+  }
+
+  Result BeginDataSegmentInitExpr(Index index) override {
+    reading_data_init_expr_ = true;
+    return Result::Ok;
+  }
+
+  Result EndDataSegmentInitExpr(Index index) override {
+    reading_data_init_expr_ = false;
+    return Result::Ok;
+  }
+
+  Result BeginGlobalInitExpr(Index index) override {
+    reading_global_init_expr_ = true;
+    return Result::Ok;
+  }
+
+  Result EndGlobalInitExpr(Index index) override {
+    reading_global_init_expr_ = false;
     return Result::Ok;
   }
 
@@ -958,21 +1066,18 @@ class BinaryReaderObjdump : public BinaryReaderObjdumpBase {
                      Index index,
                      string_view name) override;
 
-  Result OnInitExprF32ConstExpr(Index index, uint32_t value) override;
-  Result OnInitExprF64ConstExpr(Index index, uint64_t value) override;
-  Result OnInitExprV128ConstExpr(Index index, v128 value) override;
-  Result OnInitExprGlobalGetExpr(Index index, Index global_index) override;
-  Result OnInitExprI32ConstExpr(Index index, uint32_t value) override;
-  Result OnInitExprI64ConstExpr(Index index, uint64_t value) override;
-  Result OnInitExprRefNull(Index index, Type type) override;
-  Result OnInitExprRefFunc(Index index, Index func_index) override;
-
   Result OnDylinkInfo(uint32_t mem_size,
                       uint32_t mem_align_log2,
                       uint32_t table_size,
                       uint32_t table_align_log2) override;
   Result OnDylinkNeededCount(Index count) override;
   Result OnDylinkNeeded(string_view so_name) override;
+  Result OnDylinkImportCount(Index count) override;
+  Result OnDylinkExportCount(Index count) override;
+  Result OnDylinkImport(string_view module,
+                        string_view name,
+                        uint32_t flags) override;
+  Result OnDylinkExport(string_view name, uint32_t flags) override;
 
   Result OnRelocCount(Index count, Index section_index) override;
   Result OnReloc(RelocType type,
@@ -980,6 +1085,8 @@ class BinaryReaderObjdump : public BinaryReaderObjdumpBase {
                  Index index,
                  uint32_t addend) override;
 
+  Result OnFeature(uint8_t prefix, string_view name) override;
+
   Result OnSymbolCount(Index count) override;
   Result OnDataSymbol(Index index,
                       uint32_t flags,
@@ -1016,13 +1123,18 @@ class BinaryReaderObjdump : public BinaryReaderObjdumpBase {
   Result OnComdatCount(Index count) override;
   Result OnComdatBegin(string_view name, uint32_t flags, Index count) override;
   Result OnComdatEntry(ComdatType kind, Index index) override;
-  Result EndLinkingSection() override { return Result::Ok; }
 
   Result OnTagCount(Index count) override;
   Result OnTagType(Index index, Index sig_index) override;
 
+  Result OnI32ConstExpr(uint32_t value) override;
+  Result OnI64ConstExpr(uint64_t value) override;
+  Result OnF32ConstExpr(uint32_t value) override;
+  Result OnF64ConstExpr(uint64_t value) override;
+  Result OnGlobalGetExpr(Index global_index) override;
+
  private:
-  Result InitExprToConstOffset(const InitExpr& expr, uint32_t* out_offset);
+  Result InitExprToConstOffset(const InitExpr& expr, uint64_t* out_offset);
   Result HandleInitExpr(const InitExpr& expr);
   bool ShouldPrintDetails();
   void PrintDetails(const char* fmt, ...);
@@ -1035,15 +1147,21 @@ class BinaryReaderObjdump : public BinaryReaderObjdumpBase {
   Index elem_index_ = 0;
   Index table_index_ = 0;
   Index next_data_reloc_ = 0;
-  bool in_data_section_ = false;
-  bool in_elem_section_ = false;
+  bool reading_elem_init_expr_ = false;
+  bool reading_data_init_expr_ = false;
+  bool reading_global_init_expr_ = false;
   InitExpr data_init_expr_;
   InitExpr elem_init_expr_;
   uint8_t data_flags_ = 0;
   uint8_t elem_flags_ = 0;
   Index data_mem_index_ = 0;
-  uint32_t data_offset_ = 0;
-  uint32_t elem_offset_ = 0;
+  uint64_t data_offset_ = 0;
+  uint64_t elem_offset_ = 0;
+
+  bool ReadingInitExpr() {
+    return reading_elem_init_expr_ || reading_data_init_expr_ ||
+           reading_global_init_expr_;
+  }
 };
 
 BinaryReaderObjdump::BinaryReaderObjdump(const uint8_t* data,
@@ -1150,9 +1268,15 @@ Result BinaryReaderObjdump::EndModule() {
     return Result::Error;
   }
 
-  if (options_->relocs) {
+  if (options_->relocs && ShouldPrintDetails()) {
     if (next_data_reloc_ != objdump_state_->data_relocations.size()) {
-      err_stream_->Writef("Data reloctions outside of segments\n");
+      err_stream_->Writef("Data reloctions outside of segments!:\n");
+      for (size_t i = next_data_reloc_;
+           i < objdump_state_->data_relocations.size(); i++) {
+        const Reloc& reloc = objdump_state_->data_relocations[i];
+        PrintRelocation(reloc, reloc.offset);
+      }
+
       return Result::Error;
     }
   }
@@ -1177,7 +1301,7 @@ Result BinaryReaderObjdump::OnFuncType(Index index,
     if (i != 0) {
       printf(", ");
     }
-    printf("%s", param_types[i].GetName());
+    printf("%s", param_types[i].GetName().c_str());
   }
   printf(") -> ");
   switch (result_count) {
@@ -1185,7 +1309,7 @@ Result BinaryReaderObjdump::OnFuncType(Index index,
       printf("nil");
       break;
     case 1:
-      printf("%s", result_types[0].GetName());
+      printf("%s", result_types[0].GetName().c_str());
       break;
     default:
       printf("(");
@@ -1193,7 +1317,7 @@ Result BinaryReaderObjdump::OnFuncType(Index index,
         if (i != 0) {
           printf(", ");
         }
-        printf("%s", result_types[i].GetName());
+        printf("%s", result_types[i].GetName().c_str());
       }
       printf(")");
       break;
@@ -1213,7 +1337,7 @@ Result BinaryReaderObjdump::OnStructType(Index index,
     if (fields[i].mutable_) {
       printf(" (mut");
     }
-    printf(" %s", fields[i].type.GetName());
+    printf(" %s", fields[i].type.GetName().c_str());
     if (fields[i].mutable_) {
       printf(")");
     }
@@ -1230,7 +1354,7 @@ Result BinaryReaderObjdump::OnArrayType(Index index, TypeMut field) {
   if (field.mutable_) {
     printf(" (mut");
   }
-  printf(" %s", field.type.GetName());
+  printf(" %s", field.type.GetName().c_str());
   if (field.mutable_) {
     printf(")");
   }
@@ -1316,7 +1440,7 @@ Result BinaryReaderObjdump::OnImportTable(Index import_index,
                                           Type elem_type,
                                           const Limits* elem_limits) {
   PrintDetails(" - table[%" PRIindex "] type=%s initial=%" PRId64, table_index,
-               elem_type.GetName(), elem_limits->initial);
+               elem_type.GetName().c_str(), elem_limits->initial);
   if (elem_limits->has_max) {
     PrintDetails(" max=%" PRId64, elem_limits->max);
   }
@@ -1355,7 +1479,7 @@ Result BinaryReaderObjdump::OnImportGlobal(Index import_index,
                                            Type type,
                                            bool mutable_) {
   PrintDetails(" - global[%" PRIindex "] %s mutable=%d", global_index,
-               type.GetName(), mutable_);
+               type.GetName().c_str(), mutable_);
   PrintDetails(" <- " PRIstringview "." PRIstringview "\n",
                WABT_PRINTF_STRING_VIEW_ARG(module_name),
                WABT_PRINTF_STRING_VIEW_ARG(field_name));
@@ -1406,7 +1530,7 @@ Result BinaryReaderObjdump::OnTable(Index index,
                                     Type elem_type,
                                     const Limits* elem_limits) {
   PrintDetails(" - table[%" PRIindex "] type=%s initial=%" PRId64, index,
-               elem_type.GetName(), elem_limits->initial);
+               elem_type.GetName().c_str(), elem_limits->initial);
   if (elem_limits->has_max) {
     PrintDetails(" max=%" PRId64, elem_limits->max);
   }
@@ -1441,15 +1565,15 @@ Result BinaryReaderObjdump::OnExport(Index index,
 
 Result BinaryReaderObjdump::OnElemSegmentElemExpr_RefNull(Index segment_index,
                                                           Type type) {
-  PrintDetails("  - elem[%" PRIindex "] = ref.null %s\n",
-               elem_offset_ + elem_index_, type.GetName());
+  PrintDetails("  - elem[%" PRIzd "] = ref.null %s\n",
+               elem_offset_ + elem_index_, type.GetName().c_str());
   elem_index_++;
   return Result::Ok;
 }
 
 Result BinaryReaderObjdump::OnElemSegmentElemExpr_RefFunc(Index segment_index,
                                                           Index func_index) {
-  PrintDetails("  - elem[%" PRIindex "] = func[%" PRIindex "]",
+  PrintDetails("  - elem[%" PRIzd "] = func[%" PRIindex "]",
                elem_offset_ + elem_index_, func_index);
   auto name = GetFunctionName(func_index);
   if (!name.empty()) {
@@ -1496,8 +1620,8 @@ Result BinaryReaderObjdump::OnGlobalCount(Index count) {
 }
 
 Result BinaryReaderObjdump::BeginGlobal(Index index, Type type, bool mutable_) {
-  PrintDetails(" - global[%" PRIindex "] %s mutable=%d", index, type.GetName(),
-               mutable_);
+  PrintDetails(" - global[%" PRIindex "] %s mutable=%d", index,
+               type.GetName().c_str(), mutable_);
   string_view name = GetGlobalName(index);
   if (!name.empty()) {
     PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name));
@@ -1557,21 +1681,23 @@ void BinaryReaderObjdump::PrintInitExpr(const InitExpr& expr) {
 }
 
 Result BinaryReaderObjdump::InitExprToConstOffset(const InitExpr& expr,
-                                                  uint32_t* out_offset) {
+                                                  uint64_t* out_offset) {
   switch (expr.type) {
     case InitExprType::I32:
       *out_offset = expr.value.i32;
       break;
+    case InitExprType::I64:
+      *out_offset = expr.value.i64;
+      break;
     case InitExprType::Global:
       *out_offset = 0;
       break;
-    case InitExprType::I64:
     case InitExprType::F32:
     case InitExprType::F64:
     case InitExprType::V128:
     case InitExprType::FuncRef:
     case InitExprType::NullRef:
-      err_stream_->Writef("Segment/Elem offset must be an i32 init expr");
+      err_stream_->Writef("Invalid init expr for segment/elem offset");
       return Result::Error;
       break;
   }
@@ -1579,82 +1705,67 @@ Result BinaryReaderObjdump::InitExprToConstOffset(const InitExpr& expr,
 }
 
 Result BinaryReaderObjdump::HandleInitExpr(const InitExpr& expr) {
-  if (in_data_section_) {
+  if (reading_data_init_expr_) {
     data_init_expr_ = expr;
     return InitExprToConstOffset(expr, &data_offset_);
-  } else if (in_elem_section_) {
+  } else if (reading_elem_init_expr_) {
     elem_init_expr_ = expr;
     return InitExprToConstOffset(expr, &elem_offset_);
-  } else {
+  } else if (reading_global_init_expr_) {
     PrintInitExpr(expr);
+    return Result::Ok;
+  } else {
+    WABT_UNREACHABLE;
   }
-  return Result::Ok;
-}
-
-Result BinaryReaderObjdump::OnInitExprF32ConstExpr(Index index,
-                                                   uint32_t value) {
-  InitExpr expr;
-  expr.type = InitExprType::F32;
-  expr.value.f32 = value;
-  HandleInitExpr(expr);
-  return Result::Ok;
-}
-
-Result BinaryReaderObjdump::OnInitExprF64ConstExpr(Index index,
-                                                   uint64_t value) {
-  InitExpr expr;
-  expr.type = InitExprType::F64;
-  expr.value.f64 = value;
-  HandleInitExpr(expr);
-  return Result::Ok;
-}
-
-Result BinaryReaderObjdump::OnInitExprV128ConstExpr(Index index, v128 value) {
-  InitExpr expr;
-  expr.type = InitExprType::V128;
-  expr.value.v128_v = value;
-  HandleInitExpr(expr);
-  return Result::Ok;
 }
 
-Result BinaryReaderObjdump::OnInitExprGlobalGetExpr(Index index,
-                                                    Index global_index) {
-  InitExpr expr;
-  expr.type = InitExprType::Global;
-  expr.value.index = global_index;
-  HandleInitExpr(expr);
+Result BinaryReaderObjdump::OnI32ConstExpr(uint32_t value) {
+  if (ReadingInitExpr()) {
+    InitExpr expr;
+    expr.type = InitExprType::I32;
+    expr.value.i32 = value;
+    return HandleInitExpr(expr);
+  }
   return Result::Ok;
 }
 
-Result BinaryReaderObjdump::OnInitExprI32ConstExpr(Index index,
-                                                   uint32_t value) {
-  InitExpr expr;
-  expr.type = InitExprType::I32;
-  expr.value.i32 = value;
-  HandleInitExpr(expr);
+Result BinaryReaderObjdump::OnI64ConstExpr(uint64_t value) {
+  if (ReadingInitExpr()) {
+    InitExpr expr;
+    expr.type = InitExprType::I64;
+    expr.value.i64 = value;
+    return HandleInitExpr(expr);
+  }
   return Result::Ok;
 }
 
-Result BinaryReaderObjdump::OnInitExprI64ConstExpr(Index index,
-                                                   uint64_t value) {
-  InitExpr expr;
-  expr.type = InitExprType::I64;
-  expr.value.i64 = value;
-  HandleInitExpr(expr);
+Result BinaryReaderObjdump::OnF32ConstExpr(uint32_t value) {
+  if (ReadingInitExpr()) {
+    InitExpr expr;
+    expr.type = InitExprType::F32;
+    expr.value.f32 = value;
+    return HandleInitExpr(expr);
+  }
   return Result::Ok;
 }
 
-Result BinaryReaderObjdump::OnInitExprRefNull(Index index, Type type) {
-  InitExpr expr;
-  expr.type = InitExprType::NullRef;
-  expr.value.type = type;
-  HandleInitExpr(expr);
+Result BinaryReaderObjdump::OnF64ConstExpr(uint64_t value) {
+  if (ReadingInitExpr()) {
+    InitExpr expr;
+    expr.type = InitExprType::F64;
+    expr.value.f64 = value;
+    return HandleInitExpr(expr);
+  }
   return Result::Ok;
 }
 
-Result BinaryReaderObjdump::OnInitExprRefFunc(Index index, Index func_index) {
-  InitExpr expr{InitExprType::FuncRef, {func_index}};
-  HandleInitExpr(expr);
+Result BinaryReaderObjdump::OnGlobalGetExpr(Index global_index) {
+  if (ReadingInitExpr()) {
+    InitExpr expr;
+    expr.type = InitExprType::Global;
+    expr.value.index = global_index;
+    return HandleInitExpr(expr);
+  }
   return Result::Ok;
 }
 
@@ -1768,6 +1879,30 @@ Result BinaryReaderObjdump::OnDylinkNeededCount(Index count) {
   return Result::Ok;
 }
 
+Result BinaryReaderObjdump::OnDylinkImportCount(Index count) {
+  PrintDetails(" - imports[%u]:\n", count);
+  return Result::Ok;
+}
+
+Result BinaryReaderObjdump::OnDylinkExportCount(Index count) {
+  PrintDetails(" - exports[%u]:\n", count);
+  return Result::Ok;
+}
+
+Result BinaryReaderObjdump::OnDylinkExport(string_view name, uint32_t flags) {
+  PrintDetails("  - " PRIstringview, WABT_PRINTF_STRING_VIEW_ARG(name));
+  return PrintSymbolFlags(flags);
+}
+
+Result BinaryReaderObjdump::OnDylinkImport(string_view module,
+                                           string_view name,
+                                           uint32_t flags) {
+  PrintDetails("  - " PRIstringview "." PRIstringview,
+               WABT_PRINTF_STRING_VIEW_ARG(module),
+               WABT_PRINTF_STRING_VIEW_ARG(name));
+  return PrintSymbolFlags(flags);
+}
+
 Result BinaryReaderObjdump::OnDylinkNeeded(string_view so_name) {
   PrintDetails("  - " PRIstringview "\n", WABT_PRINTF_STRING_VIEW_ARG(so_name));
   return Result::Ok;
@@ -1810,6 +1945,12 @@ Result BinaryReaderObjdump::OnReloc(RelocType type,
   return Result::Ok;
 }
 
+Result BinaryReaderObjdump::OnFeature(uint8_t prefix, string_view name) {
+  PrintDetails("  - [%c] " PRIstringview "\n", prefix,
+               WABT_PRINTF_STRING_VIEW_ARG(name));
+  return Result::Ok;
+}
+
 Result BinaryReaderObjdump::OnSymbolCount(Index count) {
   PrintDetails("  - symbol table [count=%d]\n", count);
   return Result::Ok;
@@ -1867,6 +2008,10 @@ Result BinaryReaderObjdump::PrintSymbolFlags(uint32_t flags) {
     PrintDetails(" no_strip");
     flags &= ~WABT_SYMBOL_FLAG_NO_STRIP;
   }
+  if (flags & WABT_SYMBOL_FLAG_TLS) {
+    PrintDetails(" tls");
+    flags &= ~WABT_SYMBOL_FLAG_TLS;
+  }
   if (flags != 0) {
     PrintDetails(" unknown_flags=%#x", flags);
   }
@@ -1976,8 +2121,8 @@ Result BinaryReaderObjdump::OnSegmentInfo(Index index,
                                           string_view name,
                                           Address alignment_log2,
                                           uint32_t flags) {
-  PrintDetails("   - %d: " PRIstringview " p2align=%" PRIaddress,
-               index, WABT_PRINTF_STRING_VIEW_ARG(name), alignment_log2);
+  PrintDetails("   - %d: " PRIstringview " p2align=%" PRIaddress, index,
+               WABT_PRINTF_STRING_VIEW_ARG(name), alignment_log2);
   return PrintSegmentFlags(flags);
 }
 
@@ -1996,7 +2141,9 @@ Result BinaryReaderObjdump::OnComdatCount(Index count) {
   return Result::Ok;
 }
 
-Result BinaryReaderObjdump::OnComdatBegin(string_view name, uint32_t flags, Index count) {
+Result BinaryReaderObjdump::OnComdatBegin(string_view name,
+                                          uint32_t flags,
+                                          Index count) {
   PrintDetails("   - " PRIstringview ": [count=%d]\n",
                WABT_PRINTF_STRING_VIEW_ARG(name), count);
   return Result::Ok;
@@ -2050,6 +2197,21 @@ void ObjdumpNames::Set(Index index, string_view name) {
   names[index] = name.to_string();
 }
 
+string_view ObjdumpLocalNames::Get(Index function_index,
+                                   Index local_index) const {
+  auto iter = names.find(std::pair<Index, Index>(function_index, local_index));
+  if (iter == names.end())
+    return string_view();
+  return iter->second;
+}
+
+void ObjdumpLocalNames::Set(Index function_index,
+                            Index local_index,
+                            string_view name) {
+  names[std::pair<Index, Index>(function_index, local_index)] =
+      name.to_string();
+}
+
 Result ReadBinaryObjdump(const uint8_t* data,
                          size_t size,
                          ObjdumpOptions* options,
index 1c3d119e97a2e76b58c2ded9997dd70b8fbeb1d3..107b758d3b6a2712935d3d1403abf8ea5544d27d 100644 (file)
@@ -64,6 +64,13 @@ struct ObjdumpNames {
   std::map<Index, std::string> names;
 };
 
+struct ObjdumpLocalNames {
+  string_view Get(Index function_index, Index local_index) const;
+  void Set(Index function_index, Index local_index, string_view name);
+
+  std::map<std::pair<Index, Index>, std::string> names;
+};
+
 // read_binary_objdump uses this state to store information from previous runs
 // and use it to display more useful information.
 struct ObjdumpState {
@@ -75,7 +82,9 @@ struct ObjdumpState {
   ObjdumpNames tag_names;
   ObjdumpNames segment_names;
   ObjdumpNames table_names;
+  ObjdumpLocalNames local_names;
   std::vector<ObjdumpSymbol> symtab;
+  std::map<Index, Index> function_param_counts;
 };
 
 Result ReadBinaryObjdump(const uint8_t* data,
index 3908660d000e732b8944ac0462e74676d5f2a143..c01eca6a43cbc3c7f8ad3d28e94a895fdf70443a 100644 (file)
@@ -113,17 +113,33 @@ void OpcodeInfo::Write(Stream& stream) {
       break;
     }
 
+    case Kind::V128: {
+      auto data = *GetData<v128>();
+      auto l0 = data.u32(0);
+      auto l1 = data.u32(1);
+      auto l2 = data.u32(2);
+      auto l3 = data.u32(3);
+      stream.Writef(" %u %u %u %u (0x%x 0x%x 0x%x 0x%x)", l0, l1, l2, l3, l0,
+                    l1, l2, l3);
+      break;
+    }
+
     case Kind::Uint32Uint32:
       WriteArray<uint32_t>(
           stream, [&stream](uint32_t value) { stream.Writef("%u", value); });
       break;
 
+    case Kind::Uint32Uint32Uint32:
+      WriteArray<uint32_t>(
+          stream, [&stream](uint32_t value) { stream.Writef("%u", value); });
+      break;
+
     case Kind::BlockSig: {
       auto type = *GetData<Type>();
       if (type.IsIndex()) {
         stream.Writef(" type:%d", type.GetIndex());
       } else if (type != Type::Void) {
-        stream.Writef(" %s", type.GetName());
+        stream.Writef(" %s", type.GetName().c_str());
       }
       break;
     }
@@ -191,15 +207,18 @@ class BinaryReaderOpcnt : public BinaryReaderNop {
   Result OnOpcodeUint32(uint32_t value) override;
   Result OnOpcodeIndex(Index value) override;
   Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) override;
+  Result OnOpcodeUint32Uint32Uint32(uint32_t value,
+                                    uint32_t value2,
+                                    uint32_t value3) override;
   Result OnOpcodeUint64(uint64_t value) override;
   Result OnOpcodeF32(uint32_t value) override;
   Result OnOpcodeF64(uint64_t value) override;
+  Result OnOpcodeV128(v128 value) override;
   Result OnOpcodeBlockSig(Type sig_type) override;
   Result OnBrTableExpr(Index num_targets,
                        Index* target_depths,
                        Index default_target_depth) override;
   Result OnEndExpr() override;
-  Result OnEndFunc() override;
 
  private:
   template <typename... Args>
@@ -246,6 +265,14 @@ Result BinaryReaderOpcnt::OnOpcodeUint32Uint32(uint32_t value0,
   return Emplace(current_opcode_, OpcodeInfo::Kind::Uint32Uint32, array, 2);
 }
 
+Result BinaryReaderOpcnt::OnOpcodeUint32Uint32Uint32(uint32_t value0,
+                                                     uint32_t value1,
+                                                     uint32_t value2) {
+  uint32_t array[3] = {value0, value1, value2};
+  return Emplace(current_opcode_, OpcodeInfo::Kind::Uint32Uint32Uint32, array,
+                 3);
+}
+
 Result BinaryReaderOpcnt::OnOpcodeUint64(uint64_t value) {
   return Emplace(current_opcode_, OpcodeInfo::Kind::Uint64, &value);
 }
@@ -258,6 +285,10 @@ Result BinaryReaderOpcnt::OnOpcodeF64(uint64_t value) {
   return Emplace(current_opcode_, OpcodeInfo::Kind::Float64, &value);
 }
 
+Result BinaryReaderOpcnt::OnOpcodeV128(v128 value) {
+  return Emplace(current_opcode_, OpcodeInfo::Kind::V128, &value);
+}
+
 Result BinaryReaderOpcnt::OnOpcodeBlockSig(Type sig_type) {
   return Emplace(current_opcode_, OpcodeInfo::Kind::BlockSig, &sig_type);
 }
@@ -273,10 +304,6 @@ Result BinaryReaderOpcnt::OnEndExpr() {
   return Emplace(Opcode::End, OpcodeInfo::Kind::Bare);
 }
 
-Result BinaryReaderOpcnt::OnEndFunc() {
-  return Emplace(Opcode::End, OpcodeInfo::Kind::Bare);
-}
-
 }  // end anonymous namespace
 
 Result ReadBinaryOpcnt(const void* data,
index cfdd570c0ec67f637e3b1a57e038e0cae646ac7d..d7a947b08d8945673b0ed1501773da790f92d860 100644 (file)
@@ -39,8 +39,10 @@ class OpcodeInfo {
     Float32,
     Float64,
     Uint32Uint32,
+    Uint32Uint32Uint32,
     BlockSig,
     BrTable,
+    V128,
   };
 
   explicit OpcodeInfo(Opcode, Kind);
index d373770d55fc595ddfcbe82824533bfb6f1a6acf..c584b01855b633122427d33e908039509ea6596c 100644 (file)
@@ -110,6 +110,7 @@ class BinaryReader {
   Result ReadIndex(Index* index, const char* desc) WABT_WARN_UNUSED;
   Result ReadOffset(Offset* offset, const char* desc) WABT_WARN_UNUSED;
   Result ReadAlignment(Address* align_log2, const char* desc) WABT_WARN_UNUSED;
+  Result ReadMemidx(Index* memidx, const char* desc) WABT_WARN_UNUSED;
   Result ReadCount(Index* index, const char* desc) WABT_WARN_UNUSED;
   Result ReadField(TypeMut* out_value) WABT_WARN_UNUSED;
 
@@ -118,7 +119,7 @@ class BinaryReader {
 
   Index NumTotalFuncs();
 
-  Result ReadInitExpr(Index index, Type required = Type::Any) WABT_WARN_UNUSED;
+  Result ReadInitExpr(Index index) WABT_WARN_UNUSED;
   Result ReadTable(Type* out_elem_type,
                    Limits* out_elem_limits) WABT_WARN_UNUSED;
   Result ReadMemory(Limits* out_page_limits) WABT_WARN_UNUSED;
@@ -128,9 +129,16 @@ class BinaryReader {
                      Index memory,
                      const char* desc) WABT_WARN_UNUSED;
   Result ReadFunctionBody(Offset end_offset) WABT_WARN_UNUSED;
+  // ReadInstructions either until and END instruction, or until
+  // the given end_offset.
+  Result ReadInstructions(bool stop_on_end,
+                          Offset end_offset,
+                          Opcode* final_opcode) WABT_WARN_UNUSED;
   Result ReadNameSection(Offset section_size) WABT_WARN_UNUSED;
   Result ReadRelocSection(Offset section_size) WABT_WARN_UNUSED;
   Result ReadDylinkSection(Offset section_size) WABT_WARN_UNUSED;
+  Result ReadDylink0Section(Offset section_size) WABT_WARN_UNUSED;
+  Result ReadTargetFeaturesSections(Offset section_size) WABT_WARN_UNUSED;
   Result ReadLinkingSection(Offset section_size) WABT_WARN_UNUSED;
   Result ReadCustomSection(Index section_index,
                            Offset section_size) WABT_WARN_UNUSED;
@@ -320,7 +328,13 @@ Result BinaryReader::ReadS64Leb128(uint64_t* out_value, const char* desc) {
 Result BinaryReader::ReadType(Type* out_value, const char* desc) {
   uint32_t type = 0;
   CHECK_RESULT(ReadS32Leb128(&type, desc));
-  *out_value = static_cast<Type>(type);
+  if (static_cast<Type::Enum>(type) == Type::Reference) {
+    uint32_t heap_type = 0;
+    CHECK_RESULT(ReadS32Leb128(&heap_type, desc));
+    *out_value = Type(Type::Reference, heap_type);
+  } else {
+    *out_value = static_cast<Type>(type);
+  }
   return Result::Ok;
 }
 
@@ -390,7 +404,8 @@ Result BinaryReader::ReadOffset(Offset* offset, const char* desc) {
 Result BinaryReader::ReadAlignment(Address* alignment_log2, const char* desc) {
   uint32_t value;
   CHECK_RESULT(ReadU32Leb128(&value, desc));
-  if (value >= 32) {
+  if (value >= 128 ||
+      (value >= 32 && !options_.features.multi_memory_enabled())) {
     PrintError("invalid %s: %u", desc, value);
     return Result::Error;
   }
@@ -398,6 +413,13 @@ Result BinaryReader::ReadAlignment(Address* alignment_log2, const char* desc) {
   return Result::Ok;
 }
 
+Result BinaryReader::ReadMemidx(Index* memidx, const char* desc) {
+  CHECK_RESULT(ReadIndex(memidx, desc));
+  ERROR_UNLESS(*memidx < memories.size(), "memory index %u out of range",
+               *memidx);
+  return Result::Ok;
+}
+
 Result BinaryReader::ReadCount(Index* count, const char* desc) {
   CHECK_RESULT(ReadIndex(count, desc));
 
@@ -446,6 +468,9 @@ bool BinaryReader::IsConcreteType(Type type) {
     case Type::ExternRef:
       return options_.features.reference_types_enabled();
 
+    case Type::Reference:
+      return options_.features.function_references_enabled();
+
     default:
       return false;
   }
@@ -467,91 +492,9 @@ Index BinaryReader::NumTotalFuncs() {
   return num_func_imports_ + num_function_signatures_;
 }
 
-Result BinaryReader::ReadInitExpr(Index index, Type required) {
-  Opcode opcode;
-  CHECK_RESULT(ReadOpcode(&opcode, "opcode"));
-  ERROR_UNLESS_OPCODE_ENABLED(opcode);
-
-  switch (opcode) {
-    case Opcode::I32Const: {
-      uint32_t value = 0;
-      CHECK_RESULT(ReadS32Leb128(&value, "init_expr i32.const value"));
-      CALLBACK(OnInitExprI32ConstExpr, index, value);
-      break;
-    }
-
-    case Opcode::I64Const: {
-      uint64_t value = 0;
-      CHECK_RESULT(ReadS64Leb128(&value, "init_expr i64.const value"));
-      CALLBACK(OnInitExprI64ConstExpr, index, value);
-      break;
-    }
-
-    case Opcode::F32Const: {
-      uint32_t value_bits = 0;
-      CHECK_RESULT(ReadF32(&value_bits, "init_expr f32.const value"));
-      CALLBACK(OnInitExprF32ConstExpr, index, value_bits);
-      break;
-    }
-
-    case Opcode::F64Const: {
-      uint64_t value_bits = 0;
-      CHECK_RESULT(ReadF64(&value_bits, "init_expr f64.const value"));
-      CALLBACK(OnInitExprF64ConstExpr, index, value_bits);
-      break;
-    }
-
-    case Opcode::V128Const: {
-      v128 value_bits;
-      ZeroMemory(value_bits);
-      CHECK_RESULT(ReadV128(&value_bits, "init_expr v128.const value"));
-      CALLBACK(OnInitExprV128ConstExpr, index, value_bits);
-      break;
-    }
-
-    case Opcode::GlobalGet: {
-      Index global_index;
-      CHECK_RESULT(ReadIndex(&global_index, "init_expr global.get index"));
-      CALLBACK(OnInitExprGlobalGetExpr, index, global_index);
-      break;
-    }
-
-    case Opcode::RefNull: {
-      Type type;
-      CHECK_RESULT(ReadRefType(&type, "ref.null type"));
-      CALLBACK(OnInitExprRefNull, index, type);
-      break;
-    }
-
-    case Opcode::RefFunc: {
-      Index func_index;
-      CHECK_RESULT(ReadIndex(&func_index, "init_expr ref.func index"));
-      CALLBACK(OnInitExprRefFunc, index, func_index);
-      break;
-    }
-
-    case Opcode::End:
-      return Result::Ok;
-
-    default:
-      return ReportUnexpectedOpcode(opcode, "in initializer expression");
-  }
-
-  if (required == Type::I32 && opcode != Opcode::I32Const &&
-    opcode != Opcode::GlobalGet) {
-    PrintError("expected i32 init_expr");
-    return Result::Error;
-  }
-  if (required == Type::I64 && opcode != Opcode::I64Const &&
-      opcode != Opcode::GlobalGet) {
-    PrintError("expected i64 init_expr");
-    return Result::Error;
-  }
-
-  CHECK_RESULT(ReadOpcode(&opcode, "opcode"));
-  ERROR_UNLESS(opcode == Opcode::End,
-               "expected END opcode after initializer expression");
-  return Result::Ok;
+Result BinaryReader::ReadInitExpr(Index index) {
+  // Read instructions until END opcode is reached.
+  return ReadInstructions(/*stop_on_end=*/true, read_end_, NULL);
 }
 
 Result BinaryReader::ReadTable(Type* out_elem_type, Limits* out_elem_limits) {
@@ -652,12 +595,27 @@ Result BinaryReader::ReadAddress(Address* out_value,
 }
 
 Result BinaryReader::ReadFunctionBody(Offset end_offset) {
-  bool seen_end_opcode = false;
+  Opcode final_opcode(Opcode::Invalid);
+  CHECK_RESULT(
+      ReadInstructions(/*stop_on_end=*/false, end_offset, &final_opcode));
+  ERROR_UNLESS(state_.offset == end_offset,
+               "function body longer than given size");
+  ERROR_UNLESS(final_opcode == Opcode::End,
+               "function body must end with END opcode");
+  return Result::Ok;
+}
+
+Result BinaryReader::ReadInstructions(bool stop_on_end,
+                                      Offset end_offset,
+                                      Opcode* final_opcode) {
   while (state_.offset < end_offset) {
     Opcode opcode;
     CHECK_RESULT(ReadOpcode(&opcode, "opcode"));
     CALLBACK(OnOpcode, opcode);
     ERROR_UNLESS_OPCODE_ENABLED(opcode);
+    if (final_opcode) {
+      *final_opcode = opcode;
+    }
 
     switch (opcode) {
       case Opcode::Unreachable:
@@ -715,9 +673,13 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) {
           result_types_[i] = result_type;
         }
 
-        Type* result_types = num_results ? result_types_.data() : nullptr;
-        CALLBACK(OnSelectExpr, num_results, result_types);
-        CALLBACK0(OnOpcodeBare);
+        if (num_results) {
+          CALLBACK(OnSelectExpr, num_results, result_types_.data());
+          CALLBACK(OnOpcodeType, result_types_[0]);
+        } else {
+          CALLBACK(OnSelectExpr, 0, NULL);
+          CALLBACK0(OnOpcodeBare);
+        }
         break;
       }
 
@@ -780,11 +742,9 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) {
         break;
 
       case Opcode::End:
-        if (state_.offset == end_offset) {
-          seen_end_opcode = true;
-          CALLBACK0(OnEndFunc);
-        } else {
-          CALLBACK0(OnEndExpr);
+        CALLBACK0(OnEndExpr);
+        if (stop_on_end) {
+          return Result::Ok;
         }
         break;
 
@@ -944,8 +904,20 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) {
         CHECK_RESULT(ReadAlignment(&alignment_log2, "load alignment"));
         Address offset;
         CHECK_RESULT(ReadAddress(&offset, 0, "load offset"));
-        CALLBACK(OnLoadExpr, opcode, alignment_log2, offset);
-        CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset);
+        Index memidx = 0;
+        if (alignment_log2 >> 6) {
+          ERROR_IF(!options_.features.multi_memory_enabled(),
+                   "multi_memory not allowed");
+          CHECK_RESULT(ReadMemidx(&memidx, "store memidx"));
+          alignment_log2 = alignment_log2 & ((1 << 6) - 1);
+        }
+
+        CALLBACK(OnLoadExpr, opcode, memidx, alignment_log2, offset);
+        if (memidx) {
+          CALLBACK(OnOpcodeUint32Uint32Uint32, alignment_log2, offset, memidx);
+        } else {
+          CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset);
+        }
         break;
       }
 
@@ -963,27 +935,48 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) {
         CHECK_RESULT(ReadAlignment(&alignment_log2, "store alignment"));
         Address offset;
         CHECK_RESULT(ReadAddress(&offset, 0, "store offset"));
+        Index memidx = 0;
+        if (alignment_log2 >> 6) {
+          ERROR_IF(!options_.features.multi_memory_enabled(),
+                   "multi_memory not allowed");
+          CHECK_RESULT(ReadMemidx(&memidx, "store memidx"));
+          alignment_log2 = alignment_log2 & ((1 << 6) - 1);
+        }
 
-        CALLBACK(OnStoreExpr, opcode, alignment_log2, offset);
-        CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset);
+        CALLBACK(OnStoreExpr, opcode, memidx, alignment_log2, offset);
+        if (memidx) {
+          CALLBACK(OnOpcodeUint32Uint32Uint32, alignment_log2, offset, memidx);
+        } else {
+          CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset);
+        }
         break;
       }
 
       case Opcode::MemorySize: {
-        uint8_t reserved;
-        CHECK_RESULT(ReadU8(&reserved, "memory.size reserved"));
-        ERROR_UNLESS(reserved == 0, "memory.size reserved value must be 0");
-        CALLBACK0(OnMemorySizeExpr);
-        CALLBACK(OnOpcodeUint32, reserved);
+        Index memidx = 0;
+        if (!options_.features.multi_memory_enabled()) {
+          uint8_t reserved;
+          CHECK_RESULT(ReadU8(&reserved, "memory.size reserved"));
+          ERROR_UNLESS(reserved == 0, "memory.size reserved value must be 0");
+        } else {
+          CHECK_RESULT(ReadMemidx(&memidx, "memory.size memidx"));
+        }
+        CALLBACK(OnMemorySizeExpr, memidx);
+        CALLBACK(OnOpcodeUint32, memidx);
         break;
       }
 
       case Opcode::MemoryGrow: {
-        uint8_t reserved;
-        CHECK_RESULT(ReadU8(&reserved, "memory.grow reserved"));
-        ERROR_UNLESS(reserved == 0, "memory.grow reserved value must be 0");
-        CALLBACK0(OnMemoryGrowExpr);
-        CALLBACK(OnOpcodeUint32, reserved);
+        Index memidx = 0;
+        if (!options_.features.multi_memory_enabled()) {
+          uint8_t reserved;
+          CHECK_RESULT(ReadU8(&reserved, "memory.grow reserved"));
+          ERROR_UNLESS(reserved == 0, "memory.grow reserved value must be 0");
+        } else {
+          CHECK_RESULT(ReadMemidx(&memidx, "memory.grow memidx"));
+        }
+        CALLBACK(OnMemoryGrowExpr, memidx);
+        CALLBACK(OnOpcodeUint32, memidx);
         break;
       }
 
@@ -1335,12 +1328,20 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) {
       case Opcode::V128Load64Lane: {
         Address alignment_log2;
         CHECK_RESULT(ReadAlignment(&alignment_log2, "load alignment"));
+        Index memidx = 0;
+        if (alignment_log2 >> 6) {
+          ERROR_IF(!options_.features.multi_memory_enabled(),
+                   "multi_memory not allowed");
+          CHECK_RESULT(ReadMemidx(&memidx, "store memidx"));
+          alignment_log2 = alignment_log2 & ((1 << 6) - 1);
+        }
         Address offset;
         CHECK_RESULT(ReadAddress(&offset, 0, "load offset"));
         uint8_t lane_val;
         CHECK_RESULT(ReadU8(&lane_val, "Lane idx"));
 
-        CALLBACK(OnSimdLoadLaneExpr, opcode, alignment_log2, offset, lane_val);
+        CALLBACK(OnSimdLoadLaneExpr, opcode, memidx, alignment_log2, offset,
+                 lane_val);
         CALLBACK(OnOpcodeUint32Uint32Uint32, alignment_log2, offset, lane_val);
         break;
       }
@@ -1350,12 +1351,20 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) {
       case Opcode::V128Store64Lane: {
         Address alignment_log2;
         CHECK_RESULT(ReadAlignment(&alignment_log2, "load alignment"));
+        Index memidx = 0;
+        if (alignment_log2 >> 6) {
+          ERROR_IF(!options_.features.multi_memory_enabled(),
+                   "multi_memory not allowed");
+          CHECK_RESULT(ReadMemidx(&memidx, "store memidx"));
+          alignment_log2 = alignment_log2 & ((1 << 6) - 1);
+        }
         Address offset;
         CHECK_RESULT(ReadAddress(&offset, 0, "load offset"));
         uint8_t lane_val;
         CHECK_RESULT(ReadU8(&lane_val, "Lane idx"));
 
-        CALLBACK(OnSimdStoreLaneExpr, opcode, alignment_log2, offset, lane_val);
+        CALLBACK(OnSimdStoreLaneExpr, opcode, memidx, alignment_log2, offset,
+                 lane_val);
         CALLBACK(OnOpcodeUint32Uint32Uint32, alignment_log2, offset, lane_val);
         break;
       }
@@ -1631,11 +1640,16 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) {
         ERROR_IF(data_count_ == kInvalidIndex,
                  "memory.init requires data count section");
         CHECK_RESULT(ReadIndex(&segment, "elem segment index"));
-        uint8_t reserved;
-        CHECK_RESULT(ReadU8(&reserved, "reserved memory index"));
-        ERROR_UNLESS(reserved == 0, "reserved value must be 0");
-        CALLBACK(OnMemoryInitExpr, segment);
-        CALLBACK(OnOpcodeUint32Uint32, segment, reserved);
+        Index memidx = 0;
+        if (!options_.features.multi_memory_enabled()) {
+          uint8_t reserved;
+          CHECK_RESULT(ReadU8(&reserved, "reserved memory index"));
+          ERROR_UNLESS(reserved == 0, "reserved value must be 0");
+        } else {
+          CHECK_RESULT(ReadMemidx(&memidx, "memory.init memidx"));
+        }
+        CALLBACK(OnMemoryInitExpr, segment, memidx);
+        CALLBACK(OnOpcodeUint32Uint32, segment, memidx);
         break;
       }
 
@@ -1656,21 +1670,34 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) {
       }
 
       case Opcode::MemoryFill: {
-        uint8_t reserved;
-        CHECK_RESULT(ReadU8(&reserved, "reserved memory index"));
-        ERROR_UNLESS(reserved == 0, "reserved value must be 0");
-        CALLBACK(OnMemoryFillExpr);
-        CALLBACK(OnOpcodeUint32, reserved);
+        Index memidx = 0;
+        if (!options_.features.multi_memory_enabled()) {
+          uint8_t reserved;
+          CHECK_RESULT(ReadU8(&reserved, "memory.fill reserved"));
+          ERROR_UNLESS(reserved == 0, "memory.fill reserved value must be 0");
+        } else {
+          CHECK_RESULT(ReadMemidx(&memidx, "memory.fill memidx"));
+        }
+        CALLBACK(OnMemoryFillExpr, memidx);
+        CALLBACK(OnOpcodeUint32, memidx);
         break;
       }
+
       case Opcode::MemoryCopy: {
-        uint8_t reserved;
-        CHECK_RESULT(ReadU8(&reserved, "reserved memory index"));
-        ERROR_UNLESS(reserved == 0, "reserved value must be 0");
-        CHECK_RESULT(ReadU8(&reserved, "reserved memory index"));
-        ERROR_UNLESS(reserved == 0, "reserved value must be 0");
-        CALLBACK(OnMemoryCopyExpr);
-        CALLBACK(OnOpcodeUint32Uint32, reserved, reserved);
+        Index srcmemidx = 0;
+        Index destmemidx = 0;
+        if (!options_.features.multi_memory_enabled()) {
+          uint8_t reserved;
+          CHECK_RESULT(ReadU8(&reserved, "reserved memory index"));
+          ERROR_UNLESS(reserved == 0, "reserved value must be 0");
+          CHECK_RESULT(ReadU8(&reserved, "reserved memory index"));
+          ERROR_UNLESS(reserved == 0, "reserved value must be 0");
+        } else {
+          CHECK_RESULT(ReadMemidx(&srcmemidx, "memory.copy srcmemidx"));
+          CHECK_RESULT(ReadMemidx(&destmemidx, "memory.copy destmemindex"));
+        }
+        CALLBACK(OnMemoryCopyExpr, srcmemidx, destmemidx);
+        CALLBACK(OnOpcodeUint32Uint32, srcmemidx, destmemidx);
         break;
       }
 
@@ -1754,9 +1781,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) {
         return ReportUnexpectedOpcode(opcode);
     }
   }
-  ERROR_UNLESS(state_.offset == end_offset,
-               "function body longer than given size");
-  ERROR_UNLESS(seen_end_opcode, "function body must end with END opcode");
   return Result::Ok;
 }
 
@@ -1871,6 +1895,7 @@ Result BinaryReader::ReadNameSection(Offset section_size) {
       case NameSectionSubsection::Global:
       case NameSectionSubsection::ElemSegment:
       case NameSectionSubsection::DataSegment:
+      case NameSectionSubsection::Tag:
         if (subsection_size) {
           Index num_names;
           CHECK_RESULT(ReadCount(&num_names, "name count"));
@@ -1954,6 +1979,82 @@ Result BinaryReader::ReadRelocSection(Offset section_size) {
   return Result::Ok;
 }
 
+Result BinaryReader::ReadDylink0Section(Offset section_size) {
+  CALLBACK(BeginDylinkSection, section_size);
+
+  while (state_.offset < read_end_) {
+    uint32_t dylink_type;
+    Offset subsection_size;
+    CHECK_RESULT(ReadU32Leb128(&dylink_type, "type"));
+    CHECK_RESULT(ReadOffset(&subsection_size, "subsection size"));
+    size_t subsection_end = state_.offset + subsection_size;
+    ERROR_UNLESS(subsection_end <= read_end_,
+                 "invalid sub-section size: extends past end");
+    ReadEndRestoreGuard guard(this);
+    read_end_ = subsection_end;
+
+    uint32_t count;
+    switch (static_cast<DylinkEntryType>(dylink_type)) {
+      case DylinkEntryType::MemInfo: {
+        uint32_t mem_size;
+        uint32_t mem_align;
+        uint32_t table_size;
+        uint32_t table_align;
+
+        CHECK_RESULT(ReadU32Leb128(&mem_size, "mem_size"));
+        CHECK_RESULT(ReadU32Leb128(&mem_align, "mem_align"));
+        CHECK_RESULT(ReadU32Leb128(&table_size, "table_size"));
+        CHECK_RESULT(ReadU32Leb128(&table_align, "table_align"));
+        CALLBACK(OnDylinkInfo, mem_size, mem_align, table_size, table_align);
+        break;
+      }
+      case DylinkEntryType::Needed:
+        CHECK_RESULT(ReadU32Leb128(&count, "needed_dynlibs"));
+        CALLBACK(OnDylinkNeededCount, count);
+        while (count--) {
+          string_view so_name;
+          CHECK_RESULT(ReadStr(&so_name, "dylib so_name"));
+          CALLBACK(OnDylinkNeeded, so_name);
+        }
+        break;
+      case DylinkEntryType::ImportInfo:
+        CHECK_RESULT(ReadU32Leb128(&count, "count"));
+        CALLBACK(OnDylinkImportCount, count);
+        for (Index i = 0; i < count; ++i) {
+          uint32_t flags = 0;
+          string_view module;
+          string_view field;
+          CHECK_RESULT(ReadStr(&module, "module"));
+          CHECK_RESULT(ReadStr(&field, "field"));
+          CHECK_RESULT(ReadU32Leb128(&flags, "flags"));
+          CALLBACK(OnDylinkImport, module, field, flags);
+        }
+        break;
+      case DylinkEntryType::ExportInfo:
+        CHECK_RESULT(ReadU32Leb128(&count, "count"));
+        CALLBACK(OnDylinkExportCount, count);
+        for (Index i = 0; i < count; ++i) {
+          uint32_t flags = 0;
+          string_view name;
+          CHECK_RESULT(ReadStr(&name, "name"));
+          CHECK_RESULT(ReadU32Leb128(&flags, "flags"));
+          CALLBACK(OnDylinkExport, name, flags);
+        }
+        break;
+      default:
+        // Unknown subsection, skip it.
+        state_.offset = subsection_end;
+        break;
+    }
+    ERROR_UNLESS(state_.offset == subsection_end,
+                 "unfinished sub-section (expected end: 0x%" PRIzx ")",
+                 subsection_end);
+  }
+
+  CALLBACK0(EndDylinkSection);
+  return Result::Ok;
+}
+
 Result BinaryReader::ReadDylinkSection(Offset section_size) {
   CALLBACK(BeginDylinkSection, section_size);
   uint32_t mem_size;
@@ -1980,6 +2081,22 @@ Result BinaryReader::ReadDylinkSection(Offset section_size) {
   return Result::Ok;
 }
 
+Result BinaryReader::ReadTargetFeaturesSections(Offset section_size) {
+  CALLBACK(BeginTargetFeaturesSection, section_size);
+  uint32_t count;
+  CHECK_RESULT(ReadU32Leb128(&count, "sym count"));
+  CALLBACK(OnFeatureCount, count);
+  while (count--) {
+    uint8_t prefix;
+    string_view name;
+    CHECK_RESULT(ReadU8(&prefix, "prefix"));
+    CHECK_RESULT(ReadStr(&name, "feature name"));
+    CALLBACK(OnFeature, prefix, name);
+  }
+  CALLBACK0(EndTargetFeaturesSection);
+  return Result::Ok;
+}
+
 Result BinaryReader::ReadLinkingSection(Offset section_size) {
   CALLBACK(BeginLinkingSection, section_size);
   uint32_t version;
@@ -2008,7 +2125,6 @@ Result BinaryReader::ReadLinkingSection(Offset section_size) {
           CHECK_RESULT(ReadU32Leb128(&kind, "sym type"));
           CHECK_RESULT(ReadU32Leb128(&flags, "sym flags"));
           SymbolType sym_type = static_cast<SymbolType>(kind);
-          CALLBACK(OnSymbol, i, sym_type, flags);
           switch (sym_type) {
             case SymbolType::Function:
             case SymbolType::Global:
@@ -2153,11 +2269,15 @@ Result BinaryReader::ReadCustomSection(Index section_index,
   if (options_.read_debug_names && section_name == WABT_BINARY_SECTION_NAME) {
     CHECK_RESULT(ReadNameSection(section_size));
     did_read_names_section_ = true;
+  } else if (section_name == WABT_BINARY_SECTION_DYLINK0) {
+    CHECK_RESULT(ReadDylink0Section(section_size));
   } else if (section_name == WABT_BINARY_SECTION_DYLINK) {
     CHECK_RESULT(ReadDylinkSection(section_size));
   } else if (section_name.rfind(WABT_BINARY_SECTION_RELOC, 0) == 0) {
     // Reloc sections always begin with "reloc."
     CHECK_RESULT(ReadRelocSection(section_size));
+  } else if (section_name == WABT_BINARY_SECTION_TARGET_FEATURES) {
+    CHECK_RESULT(ReadTargetFeaturesSections(section_size));
   } else if (section_name == WABT_BINARY_SECTION_LINKING) {
     CHECK_RESULT(ReadLinkingSection(section_size));
   } else {
@@ -2181,7 +2301,7 @@ Result BinaryReader::ReadTypeSection(Offset section_size) {
     } else {
       uint8_t type;
       CHECK_RESULT(ReadU8(&type, "type form"));
-      ERROR_UNLESS(type == 0x60, "unexpected type form (got " "%#x" ")", type);
+      ERROR_UNLESS(type == 0x60, "unexpected type form (got %#x)", type);
       form = Type::Func;
     }
 
@@ -2452,7 +2572,7 @@ Result BinaryReader::ReadElemSection(Offset section_size) {
 
     if (!(flags & SegPassive)) {
       CALLBACK(BeginElemSegmentInitExpr, i);
-      CHECK_RESULT(ReadInitExpr(i, Type::I32));
+      CHECK_RESULT(ReadInitExpr(i));
       CALLBACK(EndElemSegmentInitExpr, i);
     }
 
@@ -2465,7 +2585,7 @@ Result BinaryReader::ReadElemSection(Offset section_size) {
         CHECK_RESULT(ReadExternalKind(&kind, "export kind"));
         ERROR_UNLESS(kind == ExternalKind::Func,
                      "segment elem type must be func (%s)",
-                     elem_type.GetName());
+                     elem_type.GetName().c_str());
         elem_type = Type::FuncRef;
       }
     }
@@ -2567,8 +2687,9 @@ Result BinaryReader::ReadDataSection(Offset section_size) {
     }
     CALLBACK(BeginDataSegment, i, memory_index, flags);
     if (!(flags & SegPassive)) {
+      ERROR_UNLESS(memories.size() > 0, "no memory to copy data to");
       CALLBACK(BeginDataSegmentInitExpr, i);
-      CHECK_RESULT(ReadInitExpr(i, memories[0].IndexType()));
+      CHECK_RESULT(ReadInitExpr(i));
       CALLBACK(EndDataSegmentInitExpr, i);
     }
 
index 1e3ec6a57d44dfc8a9ad7f3d315b4eaa16a9303a..10602e7caafa629cd23c84d9a493447725fd66a8 100644 (file)
@@ -242,7 +242,6 @@ class BinaryReaderDelegate {
   virtual Result OnDropExpr() = 0;
   virtual Result OnElseExpr() = 0;
   virtual Result OnEndExpr() = 0;
-  virtual Result OnEndFunc() = 0;
   virtual Result OnF32ConstExpr(uint32_t value_bits) = 0;
   virtual Result OnF64ConstExpr(uint64_t value_bits) = 0;
   virtual Result OnV128ConstExpr(v128 value_bits) = 0;
@@ -252,18 +251,19 @@ class BinaryReaderDelegate {
   virtual Result OnI64ConstExpr(uint64_t value) = 0;
   virtual Result OnIfExpr(Type sig_type) = 0;
   virtual Result OnLoadExpr(Opcode opcode,
+                            Index memidx,
                             Address alignment_log2,
                             Address offset) = 0;
   virtual Result OnLocalGetExpr(Index local_index) = 0;
   virtual Result OnLocalSetExpr(Index local_index) = 0;
   virtual Result OnLocalTeeExpr(Index local_index) = 0;
   virtual Result OnLoopExpr(Type sig_type) = 0;
-  virtual Result OnMemoryCopyExpr() = 0;
+  virtual Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) = 0;
   virtual Result OnDataDropExpr(Index segment_index) = 0;
-  virtual Result OnMemoryFillExpr() = 0;
-  virtual Result OnMemoryGrowExpr() = 0;
-  virtual Result OnMemoryInitExpr(Index segment_index) = 0;
-  virtual Result OnMemorySizeExpr() = 0;
+  virtual Result OnMemoryFillExpr(Index memidx) = 0;
+  virtual Result OnMemoryGrowExpr(Index memidx) = 0;
+  virtual Result OnMemoryInitExpr(Index segment_index, Index memidx) = 0;
+  virtual Result OnMemorySizeExpr(Index memidx) = 0;
   virtual Result OnTableCopyExpr(Index dst_index, Index src_index) = 0;
   virtual Result OnElemDropExpr(Index segment_index) = 0;
   virtual Result OnTableInitExpr(Index segment_index, Index table_index) = 0;
@@ -283,6 +283,7 @@ class BinaryReaderDelegate {
                                           Index table_index) = 0;
   virtual Result OnSelectExpr(Index result_count, Type* result_types) = 0;
   virtual Result OnStoreExpr(Opcode opcode,
+                             Index memidx,
                              Address alignment_log2,
                              Address offset) = 0;
   virtual Result OnThrowExpr(Index tag_index) = 0;
@@ -298,10 +299,12 @@ class BinaryReaderDelegate {
   virtual Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) = 0;
   virtual Result OnSimdShuffleOpExpr(Opcode opcode, v128 value) = 0;
   virtual Result OnSimdLoadLaneExpr(Opcode opcode,
+                                    Index memidx,
                                     Address alignment_log2,
                                     Address offset,
                                     uint64_t value) = 0;
   virtual Result OnSimdStoreLaneExpr(Opcode opcode,
+                                     Index memidx,
                                      Address alignment_log2,
                                      Address offset,
                                      uint64_t value) = 0;
@@ -381,8 +384,7 @@ class BinaryReaderDelegate {
 
   /* Reloc section */
   virtual Result BeginRelocSection(Offset size) = 0;
-  virtual Result OnRelocCount(Index count,
-                              Index section_index) = 0;
+  virtual Result OnRelocCount(Index count, Index section_index) = 0;
   virtual Result OnReloc(RelocType type,
                          Offset offset,
                          Index index,
@@ -395,14 +397,25 @@ class BinaryReaderDelegate {
                               uint32_t mem_align_log2,
                               uint32_t table_size,
                               uint32_t table_align_log2) = 0;
+  virtual Result OnDylinkImportCount(Index count) = 0;
+  virtual Result OnDylinkExportCount(Index count) = 0;
+  virtual Result OnDylinkImport(string_view module,
+                                string_view name,
+                                uint32_t flags) = 0;
+  virtual Result OnDylinkExport(string_view name, uint32_t flags) = 0;
   virtual Result OnDylinkNeededCount(Index count) = 0;
   virtual Result OnDylinkNeeded(string_view so_name) = 0;
   virtual Result EndDylinkSection() = 0;
 
+  /* target_features section */
+  virtual Result BeginTargetFeaturesSection(Offset size) = 0;
+  virtual Result OnFeatureCount(Index count) = 0;
+  virtual Result OnFeature(uint8_t prefix, string_view name) = 0;
+  virtual Result EndTargetFeaturesSection() = 0;
+
   /* Linking section */
   virtual Result BeginLinkingSection(Offset size) = 0;
   virtual Result OnSymbolCount(Index count) = 0;
-  virtual Result OnSymbol(Index index, SymbolType type, uint32_t flags) = 0;
   virtual Result OnDataSymbol(Index index,
                               uint32_t flags,
                               string_view name,
@@ -448,17 +461,6 @@ class BinaryReaderDelegate {
   virtual Result OnTagType(Index index, Index sig_index) = 0;
   virtual Result EndTagSection() = 0;
 
-  /* InitExpr - used by elem, data and global sections; these functions are
-   * only called between calls to Begin*InitExpr and End*InitExpr */
-  virtual Result OnInitExprF32ConstExpr(Index index, uint32_t value) = 0;
-  virtual Result OnInitExprF64ConstExpr(Index index, uint64_t value) = 0;
-  virtual Result OnInitExprV128ConstExpr(Index index, v128 value) = 0;
-  virtual Result OnInitExprGlobalGetExpr(Index index, Index global_index) = 0;
-  virtual Result OnInitExprI32ConstExpr(Index index, uint32_t value) = 0;
-  virtual Result OnInitExprI64ConstExpr(Index index, uint64_t value) = 0;
-  virtual Result OnInitExprRefNull(Index index, Type type) = 0;
-  virtual Result OnInitExprRefFunc(Index index, Index func_index) = 0;
-
   const State* state = nullptr;
 };
 
index 13e71122e5d65438762a68f1db074f1c00ee9300..96a2773b3e892eba695598ecda0420992a73ed51 100644 (file)
@@ -135,6 +135,7 @@ void BinaryWriterSpec::WriteCommandType(const Command& command) {
       "assert_return",
       "assert_trap",
       "assert_exhaustion",
+      "assert_exception",
   };
   WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(s_command_names) == kCommandTypeCount);
 
@@ -159,7 +160,7 @@ void BinaryWriterSpec::WriteVar(const Var& var) {
 void BinaryWriterSpec::WriteTypeObject(Type type) {
   json_stream_->Writef("{");
   WriteKey("type");
-  WriteString(type.GetName());
+  WriteString(type.GetName().c_str());
   json_stream_->Writef("}");
 }
 
@@ -258,7 +259,7 @@ void BinaryWriterSpec::WriteConst(const Const& const_) {
       WriteString("v128");
       WriteSeparator();
       WriteKey("lane_type");
-      WriteString(const_.lane_type().GetName());
+      WriteString(const_.lane_type().GetName().c_str());
       WriteSeparator();
       WriteKey("value");
       json_stream_->Writef("[");
@@ -579,6 +580,17 @@ void BinaryWriterSpec::WriteCommands() {
         WriteActionResultType(*assert_exhaustion_command->action);
         break;
       }
+
+      case CommandType::AssertException: {
+        auto* assert_exception_command = cast<AssertExceptionCommand>(command);
+        WriteLocation(assert_exception_command->action->loc);
+        WriteSeparator();
+        WriteAction(*assert_exception_command->action);
+        WriteSeparator();
+        WriteKey("expected");
+        WriteActionResultType(*assert_exception_command->action);
+        break;
+      }
     }
 
     json_stream_->Writef("}");
index aae2b4bf5ec69990d05cb610da679620c69e95cd..a633717f11910f1a707bb49acf4f36f391459748 100644 (file)
@@ -56,7 +56,11 @@ void WriteOpcode(Stream* stream, Opcode opcode) {
 }
 
 void WriteType(Stream* stream, Type type, const char* desc) {
-  WriteS32Leb128(stream, type, desc ? desc : type.GetName());
+  WriteS32Leb128(stream, type, desc ? desc : type.GetName().c_str());
+  if (type.IsReferenceWithIndex()) {
+    WriteS32Leb128(stream, type.GetReferenceIndex(),
+                   desc ? desc : type.GetName().c_str());
+  }
 }
 
 void WriteLimits(Stream* stream, const Limits* limits) {
@@ -73,7 +77,7 @@ void WriteLimits(Stream* stream, const Limits* limits) {
     WriteU32Leb128(stream, limits->initial, "limits: initial");
     if (limits->has_max) {
       WriteU32Leb128(stream, limits->max, "limits: max");
-    }  
+    }
   }
 }
 
@@ -174,7 +178,9 @@ class Symbol {
   bool undefined() const { return flags() & WABT_SYMBOL_FLAG_UNDEFINED; }
   bool defined() const { return !undefined(); }
   bool exported() const { return flags() & WABT_SYMBOL_FLAG_EXPORTED; }
-  bool explicit_name() const { return flags() & WABT_SYMBOL_FLAG_EXPLICIT_NAME; }
+  bool explicit_name() const {
+    return flags() & WABT_SYMBOL_FLAG_EXPLICIT_NAME;
+  }
   bool no_strip() const { return flags() & WABT_SYMBOL_FLAG_NO_STRIP; }
 
   bool IsFunction() const { return type() == Function::type; }
@@ -223,8 +229,10 @@ class SymbolTable {
 
   Result EnsureUnique(const string_view& name) {
     if (seen_names_.count(name)) {
-      fprintf(stderr, "error: duplicate symbol when writing relocatable "
-              "binary: %s\n", &name[0]);
+      fprintf(stderr,
+              "error: duplicate symbol when writing relocatable "
+              "binary: %s\n",
+              &name[0]);
       return Result::Error;
     }
     seen_names_.insert(name);
@@ -232,8 +240,11 @@ class SymbolTable {
   };
 
   template <typename T>
-  Result AddSymbol(std::vector<Index>* map, string_view name,
-                   bool imported, bool exported, T&& sym) {
+  Result AddSymbol(std::vector<Index>* map,
+                   string_view name,
+                   bool imported,
+                   bool exported,
+                   T&& sym) {
     uint8_t flags = 0;
     if (imported) {
       flags |= WABT_SYMBOL_FLAG_UNDEFINED;
@@ -286,20 +297,20 @@ class SymbolTable {
 
     for (const Export* export_ : module->exports) {
       switch (export_->kind) {
-      case ExternalKind::Func:
-        exported_funcs.insert(module->GetFuncIndex(export_->var));
-        break;
-      case ExternalKind::Table:
-        exported_tables.insert(module->GetTableIndex(export_->var));
-        break;
-      case ExternalKind::Memory:
-        break;
-      case ExternalKind::Global:
-        exported_globals.insert(module->GetGlobalIndex(export_->var));
-        break;
-      case ExternalKind::Tag:
-        exported_tags.insert(module->GetTagIndex(export_->var));
-        break;
+        case ExternalKind::Func:
+          exported_funcs.insert(module->GetFuncIndex(export_->var));
+          break;
+        case ExternalKind::Table:
+          exported_tables.insert(module->GetTableIndex(export_->var));
+          break;
+        case ExternalKind::Memory:
+          break;
+        case ExternalKind::Global:
+          exported_globals.insert(module->GetGlobalIndex(export_->var));
+          break;
+        case ExternalKind::Tag:
+          exported_tags.insert(module->GetTagIndex(export_->var));
+          break;
       }
     }
 
@@ -382,7 +393,13 @@ class BinaryWriter {
   template <typename T>
   void WriteLoadStoreExpr(const Func* func, const Expr* expr, const char* desc);
   template <typename T>
-  void WriteSimdLoadStoreLaneExpr(const Func* func, const Expr* expr, const char* desc);
+  void WriteMemoryLoadStoreExpr(const Func* func,
+                                const Expr* expr,
+                                const char* desc);
+  template <typename T>
+  void WriteSimdLoadStoreLaneExpr(const Func* func,
+                                  const Expr* expr,
+                                  const char* desc);
   void WriteExpr(const Func* func, const Expr* expr);
   void WriteExprList(const Func* func, const ExprList& exprs);
   void WriteInitExpr(const ExprList& expr);
@@ -494,7 +511,8 @@ void BinaryWriter::WriteBlockDecl(const BlockDeclaration& decl) {
   Index index = decl.has_func_type ? module_->GetFuncTypeIndex(decl.type_var)
                                    : module_->GetFuncTypeIndex(decl.sig);
   assert(index != kInvalidIndex);
-  WriteS32Leb128WithReloc(index, "block type function index", RelocType::TypeIndexLEB);
+  WriteS32Leb128WithReloc(index, "block type function index",
+                          RelocType::TypeIndexLEB);
 }
 
 void BinaryWriter::WriteSectionHeader(const char* desc,
@@ -579,7 +597,8 @@ void BinaryWriter::AddReloc(RelocType reloc_type, Index index) {
   // Add a new reloc section if needed
   if (!current_reloc_section_ ||
       current_reloc_section_->section_index != section_count_) {
-    reloc_sections_.emplace_back(GetSectionName(last_section_type_), section_count_);
+    reloc_sections_.emplace_back(GetSectionName(last_section_type_),
+                                 section_count_);
     current_reloc_section_ = &reloc_sections_.back();
   }
 
@@ -618,8 +637,7 @@ void BinaryWriter::WriteS32Leb128WithReloc(int32_t value,
   }
 }
 
-void BinaryWriter::WriteTableNumberWithReloc(Index value,
-                                             const char* desc) {
+void BinaryWriter::WriteTableNumberWithReloc(Index value, const char* desc) {
   // Unless reference types are enabled, all references to tables refer to table
   // 0, so no relocs need be emitted when making relocatable binaries.
   if (options_.relocatable && options_.features.reference_types_enabled()) {
@@ -654,6 +672,24 @@ void BinaryWriter::WriteLoadStoreExpr(const Func* func,
   WriteU32Leb128(stream_, typed_expr->offset, desc);
 }
 
+template <typename T>
+void BinaryWriter::WriteMemoryLoadStoreExpr(const Func* func,
+                                            const Expr* expr,
+                                            const char* desc) {
+  auto* typed_expr = cast<T>(expr);
+  WriteOpcode(stream_, typed_expr->opcode);
+  Address align = typed_expr->opcode.GetAlignment(typed_expr->align);
+  Index memidx = module_->GetMemoryIndex(typed_expr->memidx);
+  if (memidx != 0) {
+    stream_->WriteU8(log2_u32(align) | (1 << 6), "alignment");
+    WriteU32Leb128(stream_, typed_expr->offset, desc);
+    WriteU32Leb128(stream_, memidx, "memidx");
+  } else {
+    stream_->WriteU8(log2_u32(align), "alignment");
+    WriteU32Leb128(stream_, typed_expr->offset, desc);
+  }
+};
+
 template <typename T>
 void BinaryWriter::WriteSimdLoadStoreLaneExpr(const Func* func,
                                               const Expr* expr,
@@ -725,7 +761,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
       WriteU32Leb128(stream_, depth, "break depth for default");
       break;
     }
-    case ExprType::Call:{
+    case ExprType::Call: {
       Index index = module_->GetFuncIndex(cast<CallExpr>(expr)->var);
       WriteOpcode(stream_, Opcode::Call);
       WriteU32Leb128WithReloc(index, "function index", RelocType::FuncIndexLEB);
@@ -737,17 +773,18 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
       WriteU32Leb128WithReloc(index, "function index", RelocType::FuncIndexLEB);
       break;
     }
-    case ExprType::CallIndirect:{
+    case ExprType::CallIndirect: {
       Index sig_index =
-        module_->GetFuncTypeIndex(cast<CallIndirectExpr>(expr)->decl);
+          module_->GetFuncTypeIndex(cast<CallIndirectExpr>(expr)->decl);
       Index table_index =
-        module_->GetTableIndex(cast<CallIndirectExpr>(expr)->table);
+          module_->GetTableIndex(cast<CallIndirectExpr>(expr)->table);
       WriteOpcode(stream_, Opcode::CallIndirect);
-      WriteU32Leb128WithReloc(sig_index, "signature index", RelocType::TypeIndexLEB);
+      WriteU32Leb128WithReloc(sig_index, "signature index",
+                              RelocType::TypeIndexLEB);
       WriteTableNumberWithReloc(table_index, "table index");
       break;
     }
-    case ExprType::CallRef:{
+    case ExprType::CallRef: {
       WriteOpcode(stream_, Opcode::CallRef);
       break;
     }
@@ -757,7 +794,8 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
       Index table_index =
           module_->GetTableIndex(cast<ReturnCallIndirectExpr>(expr)->table);
       WriteOpcode(stream_, Opcode::ReturnCallIndirect);
-      WriteU32Leb128WithReloc(sig_index, "signature index", RelocType::TypeIndexLEB);
+      WriteU32Leb128WithReloc(sig_index, "signature index",
+                              RelocType::TypeIndexLEB);
       WriteTableNumberWithReloc(table_index, "table index");
       break;
     }
@@ -824,7 +862,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
       break;
     }
     case ExprType::Load:
-      WriteLoadStoreExpr<LoadExpr>(func, expr, "load offset");
+      WriteMemoryLoadStoreExpr<LoadExpr>(func, expr, "load offset");
       break;
     case ExprType::LocalGet: {
       Index index = GetLocalIndex(func, cast<LocalGetExpr>(expr)->var);
@@ -850,40 +888,55 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
       WriteExprList(func, cast<LoopExpr>(expr)->block.exprs);
       WriteOpcode(stream_, Opcode::End);
       break;
-    case ExprType::MemoryCopy:
+    case ExprType::MemoryCopy: {
+      Index srcmemidx =
+          module_->GetMemoryIndex(cast<MemoryCopyExpr>(expr)->srcmemidx);
+      Index destmemidx =
+          module_->GetMemoryIndex(cast<MemoryCopyExpr>(expr)->destmemidx);
       WriteOpcode(stream_, Opcode::MemoryCopy);
-      WriteU32Leb128(stream_, 0, "memory.copy reserved");
-      WriteU32Leb128(stream_, 0, "memory.copy reserved");
+      WriteU32Leb128(stream_, srcmemidx, "memory.copy srcmemidx");
+      WriteU32Leb128(stream_, destmemidx, "memory.copy destmemidx");
       break;
+    }
     case ExprType::DataDrop: {
-      Index index =
-          module_->GetDataSegmentIndex(cast<DataDropExpr>(expr)->var);
+      Index index = module_->GetDataSegmentIndex(cast<DataDropExpr>(expr)->var);
       WriteOpcode(stream_, Opcode::DataDrop);
       WriteU32Leb128(stream_, index, "data.drop segment");
       has_data_segment_instruction_ = true;
       break;
     }
-    case ExprType::MemoryFill:
+    case ExprType::MemoryFill: {
+      Index memidx =
+          module_->GetMemoryIndex(cast<MemoryFillExpr>(expr)->memidx);
       WriteOpcode(stream_, Opcode::MemoryFill);
-      WriteU32Leb128(stream_, 0, "memory.fill reserved");
+      WriteU32Leb128(stream_, memidx, "memory.fill memidx");
       break;
-    case ExprType::MemoryGrow:
+    }
+    case ExprType::MemoryGrow: {
+      Index memidx =
+          module_->GetMemoryIndex(cast<MemoryGrowExpr>(expr)->memidx);
       WriteOpcode(stream_, Opcode::MemoryGrow);
-      WriteU32Leb128(stream_, 0, "memory.grow reserved");
+      WriteU32Leb128(stream_, memidx, "memory.grow memidx");
       break;
+    }
     case ExprType::MemoryInit: {
       Index index =
           module_->GetDataSegmentIndex(cast<MemoryInitExpr>(expr)->var);
+      Index memidx =
+          module_->GetMemoryIndex(cast<MemoryInitExpr>(expr)->memidx);
       WriteOpcode(stream_, Opcode::MemoryInit);
       WriteU32Leb128(stream_, index, "memory.init segment");
-      WriteU32Leb128(stream_, 0, "memory.init reserved");
+      WriteU32Leb128(stream_, memidx, "memory.init memidx");
       has_data_segment_instruction_ = true;
       break;
     }
-    case ExprType::MemorySize:
+    case ExprType::MemorySize: {
+      Index memidx =
+          module_->GetMemoryIndex(cast<MemorySizeExpr>(expr)->memidx);
       WriteOpcode(stream_, Opcode::MemorySize);
-      WriteU32Leb128(stream_, 0, "memory.size reserved");
+      WriteU32Leb128(stream_, memidx, "memory.size memidx");
       break;
+    }
     case ExprType::TableCopy: {
       auto* copy_expr = cast<TableCopyExpr>(expr);
       Index dst = module_->GetTableIndex(copy_expr->dst_table);
@@ -894,8 +947,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
       break;
     }
     case ExprType::ElemDrop: {
-      Index index =
-          module_->GetElemSegmentIndex(cast<ElemDropExpr>(expr)->var);
+      Index index = module_->GetElemSegmentIndex(cast<ElemDropExpr>(expr)->var);
       WriteOpcode(stream_, Opcode::ElemDrop);
       WriteU32Leb128(stream_, index, "elem.drop segment");
       break;
@@ -911,36 +963,31 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
       break;
     }
     case ExprType::TableGet: {
-      Index index =
-          module_->GetTableIndex(cast<TableGetExpr>(expr)->var);
+      Index index = module_->GetTableIndex(cast<TableGetExpr>(expr)->var);
       WriteOpcode(stream_, Opcode::TableGet);
       WriteTableNumberWithReloc(index, "table.get table index");
       break;
     }
     case ExprType::TableSet: {
-      Index index =
-          module_->GetTableIndex(cast<TableSetExpr>(expr)->var);
+      Index index = module_->GetTableIndex(cast<TableSetExpr>(expr)->var);
       WriteOpcode(stream_, Opcode::TableSet);
       WriteTableNumberWithReloc(index, "table.set table index");
       break;
     }
     case ExprType::TableGrow: {
-      Index index =
-          module_->GetTableIndex(cast<TableGrowExpr>(expr)->var);
+      Index index = module_->GetTableIndex(cast<TableGrowExpr>(expr)->var);
       WriteOpcode(stream_, Opcode::TableGrow);
       WriteTableNumberWithReloc(index, "table.grow table index");
       break;
     }
     case ExprType::TableSize: {
-      Index index =
-          module_->GetTableIndex(cast<TableSizeExpr>(expr)->var);
+      Index index = module_->GetTableIndex(cast<TableSizeExpr>(expr)->var);
       WriteOpcode(stream_, Opcode::TableSize);
       WriteTableNumberWithReloc(index, "table.size table index");
       break;
     }
     case ExprType::TableFill: {
-      Index index =
-          module_->GetTableIndex(cast<TableFillExpr>(expr)->var);
+      Index index = module_->GetTableIndex(cast<TableFillExpr>(expr)->var);
       WriteOpcode(stream_, Opcode::TableFill);
       WriteTableNumberWithReloc(index, "table.fill table index");
       break;
@@ -985,7 +1032,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
       break;
     }
     case ExprType::Store:
-      WriteLoadStoreExpr<StoreExpr>(func, expr, "store offset");
+      WriteMemoryLoadStoreExpr<StoreExpr>(func, expr, "store offset");
       break;
     case ExprType::Throw:
       WriteOpcode(stream_, Opcode::Throw);
@@ -1012,8 +1059,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
           break;
         case TryKind::Delegate:
           WriteOpcode(stream_, Opcode::Delegate);
-          WriteU32Leb128(stream_,
-                         GetLabelVarDepth(&try_expr->delegate_target),
+          WriteU32Leb128(stream_, GetLabelVarDepth(&try_expr->delegate_target),
                          "delegate depth");
           break;
         case TryKind::Plain:
@@ -1495,31 +1541,25 @@ Result BinaryWriter::WriteModule() {
       // preceeded by length
       WriteU32Leb128(stream_, segment->elem_exprs.size(), "num elems");
       if (flags & SegUseElemExprs) {
-        for (const ElemExpr& elem_expr : segment->elem_exprs) {
-          switch (elem_expr.kind) {
-            case ElemExprKind::RefNull:
-              WriteOpcode(stream_, Opcode::RefNull);
-              WriteType(stream_, elem_expr.type, "elem expr ref.null type");
-              break;
-
-            case ElemExprKind::RefFunc:
-              WriteOpcode(stream_, Opcode::RefFunc);
-              WriteU32Leb128(stream_, module_->GetFuncIndex(elem_expr.var), "elem expr function index");
-              break;
-          }
-          WriteOpcode(stream_, Opcode::End);
+        for (const ExprList& elem_expr : segment->elem_exprs) {
+          WriteInitExpr(elem_expr);
         }
       } else {
-        for (const ElemExpr& elem_expr : segment->elem_exprs) {
-          assert(elem_expr.kind == ElemExprKind::RefFunc);
-          WriteU32Leb128(stream_, module_->GetFuncIndex(elem_expr.var), "elem function index");
+        for (const ExprList& elem_expr : segment->elem_exprs) {
+          assert(elem_expr.size() == 1);
+          const Expr* expr = &elem_expr.front();
+          assert(expr->type() == ExprType::RefFunc);
+          WriteU32Leb128(stream_,
+                         module_->GetFuncIndex(cast<RefFuncExpr>(expr)->var),
+                         "elem function index");
         }
       }
     }
     EndSection();
   }
 
-  if (options_.features.bulk_memory_enabled()) {
+  if (options_.features.bulk_memory_enabled() &&
+      module_->data_segments.size()) {
     // Keep track of the data count section offset so it can be removed if
     // it isn't needed.
     data_count_start_ = stream_->offset();
@@ -1546,10 +1586,11 @@ Result BinaryWriter::WriteModule() {
       auto func_start_offset = body_size_offset - last_section_payload_offset_;
       auto func_end_offset = stream_->offset() - last_section_payload_offset_;
       auto delta = WriteFixupU32Leb128Size(body_size_offset, leb_size_guess,
-                              "FIXUP func body size");
+                                           "FIXUP func body size");
       if (current_reloc_section_ && delta != 0) {
         for (Reloc& reloc : current_reloc_section_->relocations) {
-          if (reloc.offset >= func_start_offset && reloc.offset <= func_end_offset) {
+          if (reloc.offset >= func_start_offset &&
+              reloc.offset <= func_end_offset) {
             reloc.offset += delta;
           }
         }
@@ -1560,7 +1601,7 @@ Result BinaryWriter::WriteModule() {
 
   // Remove the DataCount section if there are no instructions that require it.
   if (options_.features.bulk_memory_enabled() &&
-      !has_data_segment_instruction_) {
+      module_->data_segments.size() && !has_data_segment_instruction_) {
     Offset size = stream_->offset() - data_count_end_;
     if (size) {
       // If the DataCount section was followed by anything, assert that it's
@@ -1593,7 +1634,13 @@ Result BinaryWriter::WriteModule() {
       uint8_t flags = segment->GetFlags(module_);
       stream_->WriteU8(flags, "segment flags");
       if (!(flags & SegPassive)) {
-        assert(module_->GetMemoryIndex(segment->memory_var) == 0);
+        if (options_.features.multi_memory_enabled() &&
+            (flags & SegExplicitIndex)) {
+          WriteU32Leb128(stream_, module_->GetMemoryIndex(segment->memory_var),
+                         "memidx");
+        } else {
+          assert(module_->GetMemoryIndex(segment->memory_var) == 0);
+        }
         WriteInitExpr(segment->offset);
       }
       WriteU32Leb128(stream_, segment->data.size(), "data segment size");
@@ -1626,17 +1673,25 @@ Result BinaryWriter::WriteModule() {
     for (size_t i = 0; i < module_->funcs.size(); ++i) {
       const Func* func = module_->funcs[i];
       Index num_params_and_locals = func->GetNumParamsAndLocals();
+      MakeTypeBindingReverseMapping(num_params_and_locals, func->bindings,
+                                    &index_to_name);
+      Index num_named = 0;
+      for (auto s : index_to_name) {
+        if (!s.empty()) {
+          num_named++;
+        }
+      }
 
       WriteU32Leb128(stream_, i, "function index");
-      WriteU32Leb128(stream_, num_params_and_locals, "num locals");
+      WriteU32Leb128(stream_, num_named, "num locals");
 
-      MakeTypeBindingReverseMapping(num_params_and_locals, func->bindings,
-                                    &index_to_name);
       for (size_t j = 0; j < num_params_and_locals; ++j) {
         const std::string& name = index_to_name[j];
-        wabt_snprintf(desc, sizeof(desc), "local name %" PRIzd, j);
-        WriteU32Leb128(stream_, j, "local index");
-        WriteDebugName(stream_, name, desc);
+        if (!name.empty()) {
+          wabt_snprintf(desc, sizeof(desc), "local name %" PRIzd, j);
+          WriteU32Leb128(stream_, j, "local index");
+          WriteDebugName(stream_, name, desc);
+        }
       }
     }
     EndSubsection();
@@ -1649,6 +1704,7 @@ Result BinaryWriter::WriteModule() {
                             NameSectionSubsection::ElemSegment);
     WriteNames<DataSegment>(module_->data_segments,
                             NameSectionSubsection::DataSegment);
+    WriteNames<Tag>(module_->tags, NameSectionSubsection::Tag);
 
     EndSection();
   }
index 60b20cbb6ad67f42c294485e687747558b0cc7f0..14ed98ce3b6de775cca72c6968eb356483b9bd53 100644 (file)
@@ -25,8 +25,8 @@ BinarySectionOrder GetSectionOrder(BinarySection sec) {
     return BinarySectionOrder::Name;
     WABT_FOREACH_BINARY_SECTION(V)
 #undef V
-  default:
-    WABT_UNREACHABLE;
+    default:
+      WABT_UNREACHABLE;
   }
 }
 
@@ -42,20 +42,26 @@ const char* GetSectionName(BinarySection sec) {
   }
 }
 
+// clang-format off
 const char* NameSubsectionName[] = {
-  "module",
-  "function",
-  "local",
-  "label",
-  "type",
-  "table",
-  "memory",
-  "global",
-  "elemseg",
-  "dataseg",
+    "module",
+    "function",
+    "local",
+    "label",
+    "type",
+    "table",
+    "memory",
+    "global",
+    "elemseg",
+    "dataseg",
+    "tag",
 };
+// clang-format on
 
 const char* GetNameSectionSubsectionName(NameSectionSubsection subsec) {
+  static_assert(WABT_ENUM_COUNT(NameSectionSubsection) ==
+                    WABT_ARRAY_SIZE(NameSubsectionName),
+                "Malformed ExprTypeName array");
   return NameSubsectionName[size_t(subsec)];
 }
 
index 2c94965a2e32350097e7f9739f7981eac57a2835..bd0a3de79484dbde2f6fda92ba8de6e07f6cacf4 100644 (file)
@@ -31,7 +31,9 @@
 #define WABT_BINARY_SECTION_NAME "name"
 #define WABT_BINARY_SECTION_RELOC "reloc"
 #define WABT_BINARY_SECTION_LINKING "linking"
+#define WABT_BINARY_SECTION_TARGET_FEATURES "target_features"
 #define WABT_BINARY_SECTION_DYLINK "dylink"
+#define WABT_BINARY_SECTION_DYLINK0 "dylink.0"
 
 #define WABT_FOREACH_BINARY_SECTION(V) \
   V(Custom, custom, 0)                 \
@@ -73,6 +75,8 @@ enum class BinarySectionOrder {
 BinarySectionOrder GetSectionOrder(BinarySection);
 const char* GetSectionName(BinarySection);
 
+// See
+// https://github.com/WebAssembly/extended-name-section/blob/main/proposals/extended-name-section/Overview.md
 enum class NameSectionSubsection {
   Module = 0,
   Function = 1,
@@ -84,7 +88,15 @@ enum class NameSectionSubsection {
   Global = 7,
   ElemSegment = 8,
   DataSegment = 9,
-  Last = DataSegment,
+  // tag names are yet part of the extended-name-section proposal (because it
+  // only deals with naming things that are in the spec already).  However, we
+  // include names for Tags in wabt using this enum value on the basis that tags
+  // can only exist when exceptions are enabled and that engines should ignore
+  // unknown name types.
+  Tag = 10,
+
+  First = Module,
+  Last = Tag,
 };
 const char* GetNameSectionSubsectionName(NameSectionSubsection subsec);
 
index 08897ea9ecc5a39d8ef2f5eddf7b5bd6aa602dc9..473f019918809c4bb7771be134980502945e3ae3 100644 (file)
@@ -48,9 +48,7 @@ struct Label {
         type_stack_size(type_stack_size),
         used(used) {}
 
-  bool HasValue() const {
-    return !sig.empty();
-  }
+  bool HasValue() const { return !sig.empty(); }
 
   LabelType label_type;
   const std::string& name;
@@ -636,7 +634,8 @@ void CWriter::Write(const GotoLabel& goto_label) {
     Index offset = type_stack_.size() - label->type_stack_size - amount;
     if (offset != 0) {
       for (Index i = 0; i < amount; ++i) {
-        Write(StackVar(amount - i - 1 + offset, label->sig[i]), " = ", StackVar(amount - i - 1), "; ");
+        Write(StackVar(amount - i - 1 + offset, label->sig[i]), " = ",
+              StackVar(amount - i - 1), "; ");
       }
     }
   }
@@ -844,7 +843,6 @@ void CWriter::WriteMultivalueTypes() {
   }
 }
 
-
 void CWriter::WriteFuncTypes() {
   Write(Newline());
   Writef("static u32 func_types[%" PRIzd "];", module_->types.size());
@@ -1001,7 +999,6 @@ void CWriter::WriteMemories() {
 
   Write(Newline());
 
-  assert(module_->memories.size() <= 1);
   Index memory_index = 0;
   for (const Memory* memory : module_->memories) {
     bool is_import = memory_index < module_->num_memory_imports;
@@ -1069,11 +1066,15 @@ void CWriter::WriteDataInitializers() {
   }
 
   Write(Newline(), "static void init_memory(void) ", OpenBrace());
-  if (memory && module_->num_memory_imports == 0) {
-    uint32_t max =
-        memory->page_limits.has_max ? memory->page_limits.max : 65536;
-    Write("wasm_rt_allocate_memory(", ExternalPtr(memory->name), ", ",
-          memory->page_limits.initial, ", ", max, ");", Newline());
+  if (module_->memories.size() > module_->num_memory_imports) {
+    Index memory_idx = module_->num_memory_imports;
+    for (Index i = memory_idx; i < module_->memories.size(); i++) {
+      memory = module_->memories[i];
+      uint32_t max =
+          memory->page_limits.has_max ? memory->page_limits.max : 65536;
+      Write("wasm_rt_allocate_memory(", ExternalPtr(memory->name), ", ",
+            memory->page_limits.initial, ", ", max, ");", Newline());
+    }
   }
   data_segment_index = 0;
   for (const DataSegment* data_segment : module_->data_segments) {
@@ -1100,21 +1101,26 @@ void CWriter::WriteElemInitializers() {
   }
   Index elem_segment_index = 0;
   for (const ElemSegment* elem_segment : module_->elem_segments) {
+    if (elem_segment->kind == SegmentKind::Passive) {
+      continue;
+    }
     Write("offset = ");
     WriteInitExpr(elem_segment->offset);
     Write(";", Newline());
 
     size_t i = 0;
-    for (const ElemExpr& elem_expr : elem_segment->elem_exprs) {
+    for (const ExprList& elem_expr : elem_segment->elem_exprs) {
       // We don't support the bulk-memory proposal here, so we know that we
       // don't have any passive segments (where ref.null can be used).
-      assert(elem_expr.kind == ElemExprKind::RefFunc);
-      const Func* func = module_->GetFunc(elem_expr.var);
+      assert(elem_expr.size() == 1);
+      const Expr* expr = &elem_expr.front();
+      assert(expr->type() == ExprType::RefFunc);
+      const Func* func = module_->GetFunc(cast<RefFuncExpr>(expr)->var);
       Index func_type_index = module_->GetFuncTypeIndex(func->decl.type_var);
 
       Write(ExternalRef(table->name), ".data[offset + ", i,
             "] = (wasm_rt_elem_t){func_types[", func_type_index,
-            "], (wasm_rt_anyfunc_t)", ExternalPtr(func->name), "};", Newline());
+            "], (wasm_rt_funcref_t)", ExternalPtr(func->name), "};", Newline());
       ++i;
     }
     ++elem_segment_index;
@@ -1608,8 +1614,8 @@ void CWriter::Write(const ExprList& exprs) {
         break;
 
       case ExprType::MemoryGrow: {
-        assert(module_->memories.size() == 1);
-        Memory* memory = module_->memories[0];
+        Memory* memory = module_->memories[module_->GetMemoryIndex(
+            cast<MemoryGrowExpr>(&expr)->memidx)];
 
         Write(StackVar(0), " = wasm_rt_grow_memory(", ExternalPtr(memory->name),
               ", ", StackVar(0), ");", Newline());
@@ -1617,8 +1623,8 @@ void CWriter::Write(const ExprList& exprs) {
       }
 
       case ExprType::MemorySize: {
-        assert(module_->memories.size() == 1);
-        Memory* memory = module_->memories[0];
+        Memory* memory = module_->memories[module_->GetMemoryIndex(
+            cast<MemorySizeExpr>(&expr)->memidx)];
 
         PushType(Type::I32);
         Write(StackVar(0), " = ", ExternalRef(memory->name), ".pages;",
@@ -2114,8 +2120,7 @@ void CWriter::Write(const LoadExpr& expr) {
       WABT_UNREACHABLE;
   }
 
-  assert(module_->memories.size() == 1);
-  Memory* memory = module_->memories[0];
+  Memory* memory = module_->memories[module_->GetMemoryIndex(expr.memidx)];
 
   Type result_type = expr.opcode.GetResultType();
   Write(StackVar(0, result_type), " = ", func, "(", ExternalPtr(memory->name),
@@ -2144,8 +2149,7 @@ void CWriter::Write(const StoreExpr& expr) {
       WABT_UNREACHABLE;
   }
 
-  assert(module_->memories.size() == 1);
-  Memory* memory = module_->memories[0];
+  Memory* memory = module_->memories[module_->GetMemoryIndex(expr.memidx)];
 
   Write(func, "(", ExternalPtr(memory->name), ", (u64)(", StackVar(1), ")");
   if (expr.offset != 0)
index 6fe754a2b22b20594917fa9a603cc225150d3d7d..706a013f1d7640c8103454ff896cabfe6db2385c 100644 (file)
@@ -22,8 +22,8 @@
 #include <cstdio>
 #include <cstring>
 
-#include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 
 #if COMPILER_IS_MSVC
 #include <fcntl.h>
index d90ba45b8d84b32f04b1870e94c3b00aaaedde7b..505ec950e5c61086216a77a9f220445068ddcba9 100644 (file)
 
 #include "config.h"
 
+#include "src/base-types.h"
 #include "src/make-unique.h"
 #include "src/result.h"
+#include "src/string-format.h"
 #include "src/string-view.h"
 #include "src/type.h"
 
 
 #define WABT_USE(x) static_cast<void>(x)
 
-#define WABT_PAGE_SIZE 0x10000 /* 64k */
-#define WABT_MAX_PAGES32 0x10000 /* # of pages that fit in 32-bit address \
-                                    space */
-#define WABT_MAX_PAGES64 0x1000000000000 /* # of pages that fit in 64-bit \
-                                            address space */
+// 64k
+#define WABT_PAGE_SIZE 0x10000
+// # of pages that fit in 32-bit address space
+#define WABT_MAX_PAGES32 0x10000
+// # of pages that fit in 64-bit address space
+#define WABT_MAX_PAGES64 0x1000000000000
 #define WABT_BYTES_TO_PAGES(x) ((x) >> 16)
 #define WABT_ALIGN_UP_TO_PAGE(x) \
   (((x) + WABT_PAGE_SIZE - 1) & ~(WABT_PAGE_SIZE - 1))
 
-#define PRIstringview "%.*s"
-#define WABT_PRINTF_STRING_VIEW_ARG(x) \
-  static_cast<int>((x).length()), (x).data()
-
-#define PRItypecode "%s%#x"
-#define WABT_PRINTF_TYPE_CODE(x) \
-  (static_cast<int32_t>(x) < 0 ? "-" : ""), std::abs(static_cast<int32_t>(x))
-
-#define WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE 128
-#define WABT_SNPRINTF_ALLOCA(buffer, len, format)                          \
-  va_list args;                                                            \
-  va_list args_copy;                                                       \
-  va_start(args, format);                                                  \
-  va_copy(args_copy, args);                                                \
-  char fixed_buf[WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE];                    \
-  char* buffer = fixed_buf;                                                \
-  size_t len = wabt_vsnprintf(fixed_buf, sizeof(fixed_buf), format, args); \
-  va_end(args);                                                            \
-  if (len + 1 > sizeof(fixed_buf)) {                                       \
-    buffer = static_cast<char*>(alloca(len + 1));                          \
-    len = wabt_vsnprintf(buffer, len + 1, format, args_copy);              \
-  }                                                                        \
-  va_end(args_copy)
-
 #define WABT_ENUM_COUNT(name) \
   (static_cast<int>(name::Last) - static_cast<int>(name::First) + 1)
 
 
 namespace wabt {
 #if WABT_BIG_ENDIAN
-  inline void MemcpyEndianAware(void *dst, const void *src, size_t dsize, size_t ssize, size_t doff, size_t soff, size_t len) {
-    memcpy(static_cast<char*>(dst) + (dsize) - (len) - (doff),
-      static_cast<const char*>(src) + (ssize) - (len) - (soff),
-      (len));
-  }
+inline void MemcpyEndianAware(void* dst,
+                              const void* src,
+                              size_t dsize,
+                              size_t ssize,
+                              size_t doff,
+                              size_t soff,
+                              size_t len) {
+  memcpy(static_cast<char*>(dst) + (dsize) - (len) - (doff),
+         static_cast<const char*>(src) + (ssize) - (len) - (soff), (len));
+}
 #else
-  inline void MemcpyEndianAware(void *dst, const void *src, size_t dsize, size_t ssize, size_t doff, size_t soff, size_t len) {
-    memcpy(static_cast<char*>(dst) + (doff),
-      static_cast<const char*>(src) + (soff),
-      (len));
-  }
+inline void MemcpyEndianAware(void* dst,
+                              const void* src,
+                              size_t dsize,
+                              size_t ssize,
+                              size_t doff,
+                              size_t soff,
+                              size_t len) {
+  memcpy(static_cast<char*>(dst) + (doff),
+         static_cast<const char*>(src) + (soff), (len));
+}
 #endif
 }
 
@@ -158,7 +147,8 @@ struct v128 {
     static_assert(sizeof(T) <= sizeof(v), "Invalid cast!");
     assert((lane + 1) * sizeof(T) <= sizeof(v));
     T result;
-    wabt::MemcpyEndianAware(&result, v, sizeof(result), sizeof(v), 0, lane * sizeof(T), sizeof(result));
+    wabt::MemcpyEndianAware(&result, v, sizeof(result), sizeof(v), 0,
+                            lane * sizeof(T), sizeof(result));
     return result;
   }
 
@@ -166,7 +156,8 @@ struct v128 {
   void From(int lane, T data) {
     static_assert(sizeof(T) <= sizeof(v), "Invalid cast!");
     assert((lane + 1) * sizeof(T) <= sizeof(v));
-    wabt::MemcpyEndianAware(v, &data, sizeof(v), sizeof(data), lane * sizeof(T), 0, sizeof(data));
+    wabt::MemcpyEndianAware(v, &data, sizeof(v), sizeof(data), lane * sizeof(T),
+                            0, sizeof(data));
   }
 
   uint8_t v[16];
@@ -174,14 +165,6 @@ struct v128 {
 
 namespace wabt {
 
-typedef uint32_t Index;    // An index into one of the many index spaces.
-typedef uint64_t Address;  // An address or size in linear memory.
-typedef size_t Offset;     // An offset into a host's file or memory buffer.
-
-static const Address kInvalidAddress = ~0;
-static const Index kInvalidIndex = ~0;
-static const Offset kInvalidOffset = ~0;
-
 template <typename Dst, typename Src>
 Dst WABT_VECTORCALL Bitcast(Src&& value) {
   static_assert(sizeof(Src) == sizeof(Dst), "Bitcast sizes must match.");
@@ -208,22 +191,9 @@ void Destruct(T& placement) {
   placement.~T();
 }
 
-inline std::string WABT_PRINTF_FORMAT(1, 2)
-    StringPrintf(const char* format, ...) {
-  va_list args;
-  va_list args_copy;
-  va_start(args, format);
-  va_copy(args_copy, args);
-  size_t len = wabt_vsnprintf(nullptr, 0, format, args) + 1;  // For \0.
-  std::vector<char> buffer(len);
-  va_end(args);
-  wabt_vsnprintf(buffer.data(), len, format, args_copy);
-  va_end(args_copy);
-  return std::string(buffer.data(), len - 1);
-}
-
 enum class LabelType {
   Func,
+  InitExpr,
   Block,
   Loop,
   If,
@@ -298,7 +268,7 @@ enum class RelocType {
   MemoryAddressSLEB = 4,  // e.g. Memory address in i32.const
   MemoryAddressI32 = 5,   // e.g. Memory address in DATA
   TypeIndexLEB = 6,       // e.g. Immediate type in call_indirect
-  GlobalIndexLEB = 7,     // e.g. Immediate of get_global inst
+  GlobalIndexLEB = 7,     // e.g. Immediate of global.get inst
   FunctionOffsetI32 = 8,  // e.g. Code offset in DWARF metadata
   SectionOffsetI32 = 9,   // e.g. Section offset in DWARF metadata
   TagIndexLEB = 10,       // Used in throw instructions
@@ -336,6 +306,13 @@ enum class LinkingEntryType {
   SymbolTable = 8,
 };
 
+enum class DylinkEntryType {
+  MemInfo = 1,
+  Needed = 2,
+  ExportInfo = 3,
+  ImportInfo = 4,
+};
+
 enum class SymbolType {
   Function = 0,
   Data = 1,
@@ -356,7 +333,8 @@ enum class ComdatType {
 #define WABT_SYMBOL_FLAG_EXPORTED 0x20
 #define WABT_SYMBOL_FLAG_EXPLICIT_NAME 0x40
 #define WABT_SYMBOL_FLAG_NO_STRIP 0x80
-#define WABT_SYMBOL_FLAG_MAX 0xff
+#define WABT_SYMBOL_FLAG_TLS 0x100
+#define WABT_SYMBOL_FLAG_MAX 0x1ff
 
 #define WABT_SEGMENT_FLAG_STRINGS 0x1
 #define WABT_SEGMENT_FLAG_TLS 0x2
@@ -420,8 +398,8 @@ extern const char* g_kind_name[];
 
 static WABT_INLINE const char* GetKindName(ExternalKind kind) {
   return static_cast<size_t>(kind) < kExternalKindCount
-    ? g_kind_name[static_cast<size_t>(kind)]
-    : "<error_kind>";
+             ? g_kind_name[static_cast<size_t>(kind)]
+             : "<error_kind>";
 }
 
 /* reloc */
@@ -430,8 +408,8 @@ extern const char* g_reloc_type_name[];
 
 static WABT_INLINE const char* GetRelocTypeName(RelocType reloc) {
   return static_cast<size_t>(reloc) < kRelocTypeCount
-    ? g_reloc_type_name[static_cast<size_t>(reloc)]
-    : "<error_reloc_type>";
+             ? g_reloc_type_name[static_cast<size_t>(reloc)]
+             : "<error_reloc_type>";
 }
 
 /* symbol */
@@ -472,10 +450,10 @@ inline void ConvertBackslashToSlash(std::string* s) {
   ConvertBackslashToSlash(s->begin(), s->end());
 }
 
-inline void SwapBytesSized(void *addr, size_t size) {
+inline void SwapBytesSized(voidaddr, size_t size) {
   auto bytes = static_cast<uint8_t*>(addr);
   for (size_t i = 0; i < size / 2; i++) {
-    std::swap(bytes[i], bytes[size-1-i]);
+    std::swap(bytes[i], bytes[size - 1 - i]);
   }
 }
 
index 9347c860a90e7f394a5c232eea93ca97241e7a41..00f60aa8133323b82d88077d668dbe8bf65f25c6 100644 (file)
@@ -55,7 +55,7 @@ int wabt_snprintf(char* str, size_t size, const char* format, ...) {
 // Allow the following functions to change the floating-point environment (e.g.
 // update to 64-bit precision in the mantissa). This is only needed for x87
 // floats, which are only used on MSVC 32-bit.
-#pragma fenv_access (on)
+#pragma fenv_access(on)
 namespace {
 
 typedef unsigned int FPControl;
@@ -158,5 +158,5 @@ float wabt_convert_int64_to_float(int64_t x) {
 }
 
 #if COMPILER_IS_MSVC && _M_IX86
-#pragma fenv_access (off)
+#pragma fenv_access(off)
 #endif
index ec5b3880ca78dcaab6a45b3f97353b4f45736259..584a837301019693079962196f3cd3d4f60226e7 100644 (file)
@@ -19,8 +19,8 @@
 
 #include "src/cast.h"
 #include "src/generate-names.h"
-#include "src/ir.h"
 #include "src/ir-util.h"
+#include "src/ir.h"
 
 #include <map>
 
@@ -45,15 +45,16 @@ struct Node {
   std::vector<Node> children;
   // Node specific annotations.
   union {
-    struct { Index var_start, var_count; };  // FlushedVar/FlushToVars
+    struct {
+      Index var_start, var_count;  // FlushedVar/FlushToVars
+    };
     const Var* var;  // Decl/DeclInit.
-    LabelType lt;  // br/br_if target.
+    LabelType lt;    // br/br_if target.
   } u;
 
-  Node() : ntype(NodeType::Uninitialized), etype(ExprType::Nop), e(nullptr) {
-  }
+  Node() : ntype(NodeType::Uninitialized), etype(ExprType::Nop), e(nullptr) {}
   Node(NodeType ntype, ExprType etype, const Expr* e, const Var* v)
-    : ntype(ntype), etype(etype), e(e) {
+      : ntype(ntype), etype(etype), e(e) {
     u.var = v;
   }
 
@@ -76,24 +77,26 @@ struct Node {
 };
 
 struct AST {
-  AST(ModuleContext& mc, const Func *f) : mc(mc), f(f) {
+  AST(ModuleContext& mc, const Funcf) : mc(mc), f(f) {
     if (f) {
       mc.BeginFunc(*f);
       for (Index i = 0; i < f->GetNumParams(); i++) {
         auto name = "$" + IndexToAlphaName(i);
-        vars_defined.insert({ name, { 0, false }});
+        vars_defined.insert({name, {0, false}});
       }
     }
   }
 
   ~AST() {
-    if (f) mc.EndFunc();
+    if (f) {
+      mc.EndFunc();
+    }
   }
 
   // Create a new node, take nargs existing nodes on the exp stack as children.
   Node& InsertNode(NodeType ntype, ExprType etype, const Expr* e, Index nargs) {
     assert(exp_stack.size() >= nargs);
-    Node n { ntype, etype, e, nullptr };
+    Node n{ntype, etype, e, nullptr};
     n.children.reserve(nargs);
     std::move(exp_stack.end() - nargs, exp_stack.end(),
               std::back_inserter(n.children));
@@ -102,7 +105,8 @@ struct AST {
     return exp_stack.back();
   }
 
-  template<ExprType T> void PreDecl(const VarExpr<T>& ve) {
+  template <ExprType T>
+  void PreDecl(const VarExpr<T>& ve) {
     // FIXME: this is slow, and would be better to avoid in callers.
     // See https://github.com/WebAssembly/wabt/issues/1565
     // And https://github.com/WebAssembly/wabt/issues/1665
@@ -114,9 +118,10 @@ struct AST {
     predecls.emplace_back(NodeType::Decl, ExprType::Nop, nullptr, &ve.var);
   }
 
-  template<ExprType T> void Get(const VarExpr<T>& ve, bool local) {
+  template <ExprType T>
+  void Get(const VarExpr<T>& ve, bool local) {
     if (local) {
-      auto ret = vars_defined.insert({ ve.var.name(), { cur_block_id, false }});
+      auto ret = vars_defined.insert({ve.var.name(), {cur_block_id, false}});
       if (ret.second) {
         // Use before def, may happen since locals are guaranteed 0.
         PreDecl(ve);
@@ -130,10 +135,11 @@ struct AST {
     InsertNode(NodeType::Expr, T, &ve, 0);
   }
 
-  template<ExprType T> void Set(const VarExpr<T>& ve, bool local) {
+  template <ExprType T>
+  void Set(const VarExpr<T>& ve, bool local) {
     // Seen this var before?
     if (local &&
-        vars_defined.insert({ ve.var.name(), { cur_block_id, false }}).second) {
+        vars_defined.insert({ve.var.name(), {cur_block_id, false}}).second) {
       if (value_stack_depth == 1) {
         // Top level, declare it here.
         InsertNode(NodeType::DeclInit, ExprType::Nop, nullptr, 1).u.var =
@@ -147,9 +153,11 @@ struct AST {
     InsertNode(NodeType::Expr, T, &ve, 1);
   }
 
-  template<ExprType T> void Block(const BlockExprBase<T>& be, LabelType label) {
+  template <ExprType T>
+  void Block(const BlockExprBase<T>& be, LabelType label) {
     mc.BeginBlock(label, be.block);
-    Construct(be.block.exprs, be.block.decl.GetNumResults(), be.block.decl.GetNumParams(), false);
+    Construct(be.block.exprs, be.block.decl.GetNumResults(),
+              be.block.decl.GetNumParams(), false);
     mc.EndBlock();
     InsertNode(NodeType::Expr, T, &be, 1);
   }
@@ -177,7 +185,7 @@ struct AST {
         auto& lt = *cast<LocalTeeExpr>(&e);
         Set(lt, true);
         if (value_stack_depth == 1) {  // Tee is the only thing on there.
-          Get(lt, true);  // Now Set + Get instead.
+          Get(lt, true);               // Now Set + Get instead.
         } else {
           // Things are above us on the stack so the Tee can't be eliminated.
           // The Set makes this work as a Tee when consumed by a parent.
@@ -188,13 +196,16 @@ struct AST {
         auto ife = cast<IfExpr>(&e);
         value_stack_depth--;  // Condition.
         mc.BeginBlock(LabelType::Block, ife->true_);
-        Construct(ife->true_.exprs, ife->true_.decl.GetNumResults(), ife->true_.decl.GetNumParams(), false);
+        Construct(ife->true_.exprs, ife->true_.decl.GetNumResults(),
+                  ife->true_.decl.GetNumParams(), false);
         if (!ife->false_.empty()) {
-          Construct(ife->false_, ife->true_.decl.GetNumResults(), ife->true_.decl.GetNumParams(), false);
+          Construct(ife->false_, ife->true_.decl.GetNumResults(),
+                    ife->true_.decl.GetNumParams(), false);
         }
         mc.EndBlock();
         value_stack_depth++;  // Put Condition back.
-        InsertNode(NodeType::Expr, ExprType::If, &e, ife->false_.empty() ? 2 : 3);
+        InsertNode(NodeType::Expr, ExprType::If, &e,
+                   ife->false_.empty() ? 2 : 3);
         return;
       }
       case ExprType::Block: {
@@ -222,7 +233,10 @@ struct AST {
     }
   }
 
-  void Construct(const ExprList& es, Index nresults, Index nparams, bool is_function_body) {
+  void Construct(const ExprList& es,
+                 Index nresults,
+                 Index nparams,
+                 bool is_function_body) {
     block_stack.push_back(cur_block_id);
     cur_block_id = blocks_closed.size();
     blocks_closed.push_back(false);
@@ -234,8 +248,8 @@ struct AST {
       Construct(e);
       auto arity = mc.GetExprArity(e);
       value_stack_depth -= arity.nargs;
-      value_stack_in_variables = std::min(value_stack_in_variables,
-                                          value_stack_depth);
+      value_stack_in_variables =
+          std::min(value_stack_in_variables, value_stack_depth);
       unreachable = unreachable || arity.unreachable;
       assert(unreachable || value_stack_depth >= value_stack_depth_start);
       value_stack_depth += arity.nreturns;
@@ -256,21 +270,20 @@ struct AST {
         auto num_vars = value_stack_in_variables - value_stack_depth_start;
         auto num_vals = value_stack_depth - value_stack_in_variables;
         auto GenFlushVars = [&](int nargs) {
-          auto& ftv = InsertNode(NodeType::FlushToVars, ExprType::Nop, nullptr,
-                                 nargs);
+          auto& ftv =
+              InsertNode(NodeType::FlushToVars, ExprType::Nop, nullptr, nargs);
           ftv.u.var_start = flushed_vars;
           ftv.u.var_count = num_vals;
         };
         auto MoveStatementsBelowVars = [&](size_t amount) {
           std::rotate(exp_stack.end() - num_vars - amount,
-                      exp_stack.end() - amount,
-                      exp_stack.end());
+                      exp_stack.end() - amount, exp_stack.end());
         };
         auto GenFlushedVars = [&]() {
           // Re-generate these values as vars.
           for (int i = 0; i < num_vals; i++) {
-            auto& fv = InsertNode(NodeType::FlushedVar, ExprType::Nop, nullptr,
-                                  0);
+            auto& fv =
+                InsertNode(NodeType::FlushedVar, ExprType::Nop, nullptr, 0);
             fv.u.var_start = flushed_vars++;
             fv.u.var_count = 1;
           }
@@ -316,8 +329,8 @@ struct AST {
         // Special optimisation: for constant instructions, we can mark these
         // as if they were variables, so they can be re-ordered for free with
         // the above code, without needing new variables!
-        // TODO: this would be nice to also do for get_local and maybe others,
-        // though that needs a way to ensure there's no set_local in between
+        // TODO: this would be nice to also do for local.get and maybe others,
+        // though that needs a way to ensure there's no local.set in between
         // when they get lifted, so complicates matters a bit.
         if (e.type() == ExprType::Const &&
             value_stack_in_variables == value_stack_depth - 1) {
@@ -325,9 +338,8 @@ struct AST {
         }
       }
     }
-    assert(unreachable ||
-           value_stack_depth - value_stack_depth_start ==
-           static_cast<int>(nresults));
+    assert(unreachable || value_stack_depth - value_stack_depth_start ==
+                              static_cast<int>(nresults));
     // Undo any changes to value_stack_depth, since parent takes care of arity
     // changes.
     value_stack_depth = value_stack_depth_start;
@@ -371,9 +383,12 @@ struct AST {
   ModuleContext& mc;
   std::vector<Node> exp_stack;
   std::vector<Node> predecls;
-  const Func *f;
+  const Funcf;
   int value_stack_depth = 0;
-  struct Variable { size_t block_id; bool defined; };
+  struct Variable {
+    size_t block_id;
+    bool defined;
+  };
   std::map<std::string, Variable> vars_defined;
   Index flushed_vars = 0;
   size_t cur_block_id = 0;
index f622e3fd9ffec6625fb28cc32c3db3319a576ded..ae6927113ac53aa81c00a8af0ea0b9b4cd4b6e6c 100644 (file)
@@ -24,7 +24,7 @@
 namespace wabt {
 
 // Names starting with "u" are unsigned, the rest are "signed or doesn't matter"
-inline const char *GetDecompTypeName(Type t) {
+inline const charGetDecompTypeName(Type t) {
   switch (t) {
     case Type::I8: return "byte";
     case Type::I8U: return "ubyte";
@@ -84,18 +84,20 @@ struct LoadStoreTracking {
   };
 
   void Track(const Node& n) {
-    for (auto& c : n.children) Track(c);
+    for (auto& c : n.children) {
+      Track(c);
+    }
     switch (n.etype) {
       case ExprType::Load: {
         auto& le = *cast<LoadExpr>(n.e);
-        LoadStore(le.offset, le.opcode, le.opcode.GetResultType(),
-                  le.align, n.children[0]);
+        LoadStore(le.offset, le.opcode, le.opcode.GetResultType(), le.align,
+                  n.children[0]);
         break;
       }
       case ExprType::Store: {
         auto& se = *cast<StoreExpr>(n.e);
-        LoadStore(se.offset, se.opcode, se.opcode.GetParamType2(),
-                  se.align, n.children[0]);
+        LoadStore(se.offset, se.opcode, se.opcode.GetParamType2(), se.align,
+                  n.children[0]);
         break;
       }
       default:
@@ -117,7 +119,10 @@ struct LoadStoreTracking {
     }
   }
 
-  void LoadStore(uint64_t offset, Opcode opc, Type type, Address align,
+  void LoadStore(uint64_t offset,
+                 Opcode opc,
+                 Type type,
+                 Address align,
                  const Node& addr_exp) {
     auto byte_size = opc.GetMemorySize();
     type = GetMemoryType(type, opc);
@@ -131,10 +136,8 @@ struct LoadStoreTracking {
     auto& access = var.accesses[offset];
     // Check if previous access at this offset (if any) is of same size
     // and type (see Checklayouts below).
-    if (access.byte_size &&
-        ((access.byte_size != byte_size) ||
-         (access.type != type) ||
-         (access.align != align)))
+    if (access.byte_size && ((access.byte_size != byte_size) ||
+                             (access.type != type) || (access.align != align)))
       access.is_uniform = false;
     // Also exclude weird alignment accesses from structs.
     if (!opc.IsNaturallyAligned(align))
@@ -202,9 +205,7 @@ struct LoadStoreTracking {
   }
 
   std::string GenAlign(Address align, Opcode opc) const {
-    return opc.IsNaturallyAligned(align)
-      ? ""
-      : cat("@", std::to_string(align));
+    return opc.IsNaturallyAligned(align) ? "" : cat("@", std::to_string(align));
   }
 
   std::string GenTypeDecl(const std::string& name) const {
@@ -215,7 +216,9 @@ struct LoadStoreTracking {
     if (it->second.struct_layout) {
       std::string s = "{ ";
       for (auto& access : it->second.accesses) {
-        if (access.second.idx) s += ", ";
+        if (access.second.idx) {
+          s += ", ";
+        }
         s += IdxToName(access.second.idx);
         s += ':';
         s += GetDecompTypeName(access.second.type);
@@ -243,7 +246,7 @@ struct LoadStoreTracking {
     }
     if (it->second.struct_layout) {
       auto ait = it->second.accesses.find(offset);
-      assert (ait != it->second.accesses.end());
+      assert(ait != it->second.accesses.end());
       return IdxToName(ait->second.idx);
     }
     // Not a struct, see if it is a typed pointer.
@@ -253,9 +256,7 @@ struct LoadStoreTracking {
     return "";
   }
 
-  void Clear() {
-    vars.clear();
-  }
+  void Clear() { vars.clear(); }
 
   std::map<std::string, LSVar> vars;
 };
index 6f34831702f4d4e974a63673dfd2f4c55763d1d1..155da00955bc31b3fa68de67a9ba8fb302b61240 100644 (file)
@@ -23,7 +23,8 @@
 
 namespace wabt {
 
-inline void RenameToIdentifier(std::string& name, Index i,
+inline void RenameToIdentifier(std::string& name,
+                               Index i,
                                BindingHash& bh,
                                const std::set<string_view>* filter) {
   // Filter out non-identifier characters, and try to reduce the size of
@@ -103,8 +104,9 @@ inline void RenameToIdentifier(std::string& name, Index i,
   bh.emplace(s, Binding(i));
 }
 
-template<typename T>
-void RenameToIdentifiers(std::vector<T*>& things, BindingHash& bh,
+template <typename T>
+void RenameToIdentifiers(std::vector<T*>& things,
+                         BindingHash& bh,
                          const std::set<string_view>* filter) {
   Index i = 0;
   for (auto thing : things) {
index 373d66938041ca7e47b0a7e6d80ed7535c6bf98b..1dd2886865e6a7dbb5d5b1a556f1db8696ae6012 100644 (file)
@@ -64,12 +64,11 @@ struct Decompiler {
     // but not if it is the reverse.
     Precedence precedence;
 
-    Value(std::vector<std::string>&& v, Precedence p)
-      : v(v), precedence(p) {}
+    Value(std::vector<std::string>&& v, Precedence p) : v(v), precedence(p) {}
 
     size_t width() {
       size_t w = 0;
-      for (auto &s : v) {
+      for (autos : v) {
         w = std::max(w, s.size());
       }
       return w;
@@ -90,9 +89,7 @@ struct Decompiler {
     return s;
   }
 
-  std::string Indent(size_t amount) {
-    return std::string(amount, ' ');
-  }
+  std::string Indent(size_t amount) { return std::string(amount, ' '); }
 
   std::string OpcodeToToken(Opcode opcode) {
     std::string s = opcode.GetDecomp();
@@ -100,7 +97,7 @@ struct Decompiler {
     return s;
   }
 
-  void IndentValue(Value &val, size_t amount, string_view first_indent) {
+  void IndentValue(Valueval, size_t amount, string_view first_indent) {
     auto indent = Indent(amount);
     for (auto& stat : val.v) {
       auto is = (&stat != &val.v[0] || first_indent.empty())
@@ -110,10 +107,12 @@ struct Decompiler {
     }
   }
 
-  Value WrapChild(Value &child, string_view prefix, string_view postfix,
+  Value WrapChild(Value& child,
+                  string_view prefix,
+                  string_view postfix,
                   Precedence precedence) {
     auto width = prefix.size() + postfix.size() + child.width();
-    auto &v = child.v;
+    autov = child.v;
     if (width < target_exp_width ||
         (prefix.size() <= indent_amount && postfix.size() <= indent_amount)) {
       if (v.size() == 1) {
@@ -135,35 +134,44 @@ struct Decompiler {
     return std::move(child);
   }
 
-  void BracketIfNeeded(Value &val, Precedence parent_precedence) {
+  void BracketIfNeeded(Valueval, Precedence parent_precedence) {
     if (parent_precedence < val.precedence ||
         (parent_precedence == val.precedence &&
-         Associative(parent_precedence))) return;
+         Associative(parent_precedence))) {
+      return;
+    }
     val = WrapChild(val, "(", ")", Precedence::Atomic);
   }
 
-  Value WrapBinary(std::vector<Value>& args, string_view infix,
-                   bool indent_right, Precedence precedence) {
+  Value WrapBinary(std::vector<Value>& args,
+                   string_view infix,
+                   bool indent_right,
+                   Precedence precedence) {
     assert(args.size() == 2);
     auto& left = args[0];
     auto& right = args[1];
     BracketIfNeeded(left, precedence);
     BracketIfNeeded(right, precedence);
-    auto width = infix.size() + left.width() + right.width();
+    auto width = infix.size() + left.width() + right.width() + 2;
     if (width < target_exp_width && left.v.size() == 1 && right.v.size() == 1) {
-      return Value{{left.v[0] + infix + right.v[0]}, precedence};
+      return Value{{cat(left.v[0], " ", infix, " ", right.v[0])}, precedence};
     } else {
-      Value bin { {}, precedence };
+      Value bin{{}, precedence};
       std::move(left.v.begin(), left.v.end(), std::back_inserter(bin.v));
+      bin.v.back().append(" ", 1);
       bin.v.back().append(infix.data(), infix.size());
-      if (indent_right) IndentValue(right, indent_amount, {});
+      if (indent_right) {
+        IndentValue(right, indent_amount, {});
+      }
       std::move(right.v.begin(), right.v.end(), std::back_inserter(bin.v));
       return bin;
     }
   }
 
-  Value WrapNAry(std::vector<Value>& args, string_view prefix,
-                 string_view postfix, Precedence precedence) {
+  Value WrapNAry(std::vector<Value>& args,
+                 string_view prefix,
+                 string_view postfix,
+                 Precedence precedence) {
     size_t total_width = 0;
     size_t max_width = 0;
     bool multiline = false;
@@ -187,18 +195,21 @@ struct Decompiler {
       return Value{{std::move(s)}, precedence};
     } else {
       // Multi-line.
-      Value ml { {}, precedence };
+      Value ml{{}, precedence};
       auto ident_with_name = max_width + prefix.size() < target_exp_width;
       size_t i = 0;
       for (auto& child : args) {
         IndentValue(child, ident_with_name ? prefix.size() : indent_amount,
-                    !i && ident_with_name ? prefix : string_view {});
-        if (i < args.size() - 1) child.v.back() += ",";
-        std::move(child.v.begin(), child.v.end(),
-                  std::back_inserter(ml.v));
+                    !i && ident_with_name ? prefix : string_view{});
+        if (i < args.size() - 1) {
+          child.v.back() += ",";
+        }
+        std::move(child.v.begin(), child.v.end(), std::back_inserter(ml.v));
         i++;
       }
-      if (!ident_with_name) ml.v.insert(ml.v.begin(), std::string(prefix));
+      if (!ident_with_name) {
+        ml.v.insert(ml.v.begin(), std::string(prefix));
+      }
       ml.v.back() += postfix;
       return ml;
     }
@@ -209,12 +220,15 @@ struct Decompiler {
     return name[0] == '$' ? name.substr(1) : name;
   }
 
-  template<ExprType T> Value Get(const VarExpr<T>& ve) {
+  template <ExprType T>
+  Value Get(const VarExpr<T>& ve) {
     return Value{{std::string(VarName(ve.var.name()))}, Precedence::Atomic};
   }
 
-  template<ExprType T> Value Set(Value& child, const VarExpr<T>& ve) {
-    return WrapChild(child, VarName(ve.var.name()) + " = ", "", Precedence::Assign);
+  template <ExprType T>
+  Value Set(Value& child, const VarExpr<T>& ve) {
+    return WrapChild(child, VarName(ve.var.name()) + " = ", "",
+                     Precedence::Assign);
   }
 
   std::string TempVarName(Index n) {
@@ -230,17 +244,25 @@ struct Decompiler {
                struc.empty() ? GetDecompTypeName(t) : struc);
   }
 
-  bool ConstIntVal(const Expr* e, uint64_t &dest) {
+  bool ConstIntVal(const Expr* e, uint64_tdest) {
     dest = 0;
-    if (!e || e->type() != ExprType::Const) return false;
+    if (!e || e->type() != ExprType::Const) {
+      return false;
+    }
     auto& c = cast<ConstExpr>(e)->const_;
-    if (c.type() != Type::I32 && c.type() != Type::I64) return false;
+    if (c.type() != Type::I32 && c.type() != Type::I64) {
+      return false;
+    }
     dest = c.type() == Type::I32 ? c.u32() : c.u64();
     return true;
   }
 
-  void LoadStore(Value &val, const Node& addr_exp, uint64_t offset,
-                  Opcode opc, Address align, Type op_type) {
+  void LoadStore(Value& val,
+                 const Node& addr_exp,
+                 uint64_t offset,
+                 Opcode opc,
+                 Address align,
+                 Type op_type) {
     bool append_type = true;
     auto access = lst.GenAccess(offset, addr_exp);
     if (!access.empty()) {
@@ -267,11 +289,10 @@ struct Decompiler {
         uint64_t dat_base;
         if (dat->offset.size() == 1 &&
             ConstIntVal(&dat->offset.front(), dat_base) &&
-            abs_base >= dat_base &&
-            abs_base < dat_base + dat->data.size()) {
+            abs_base >= dat_base && abs_base < dat_base + dat->data.size()) {
           // We are inside the range of this data segment!
           // Turn expression into data_name[index]
-          val = Value { { dat->name }, Precedence::Atomic };
+          val = Value{{dat->name}, Precedence::Atomic};
           // The new offset is from the start of the data segment, instead of
           // whatever it was.. this may be a different value from both the
           // original const and offset!
@@ -284,8 +305,8 @@ struct Decompiler {
     // cases, but the spec doesn't guarantee it, so we must
     // have a backup syntax.
     auto index = offset % align == 0
-                ? std::to_string(offset / align)
-                : cat(std::to_string(offset), "@", std::to_string(align));
+                     ? std::to_string(offset / align)
+                     : cat(std::to_string(offset), "@", std::to_string(align));
     // Detect the very common case of (base + (index << 2))[0]:int etc.
     // so we can instead do base[index]:int
     // TODO: (index << 2) on the left of + occurs also.
@@ -295,12 +316,10 @@ struct Decompiler {
     if (addr_exp.etype == ExprType::Binary) {
       auto& pe = *cast<BinaryExpr>(addr_exp.e);
       auto& shift_exp = addr_exp.children[1];
-      if (pe.opcode == Opcode::I32Add &&
-          shift_exp.etype == ExprType::Binary) {
+      if (pe.opcode == Opcode::I32Add && shift_exp.etype == ExprType::Binary) {
         auto& se = *cast<BinaryExpr>(shift_exp.e);
         auto& const_exp = shift_exp.children[1];
-        if (se.opcode == Opcode::I32Shl &&
-            const_exp.etype == ExprType::Const) {
+        if (se.opcode == Opcode::I32Shl && const_exp.etype == ExprType::Const) {
           auto& ce = *cast<ConstExpr>(const_exp.e);
           if (ce.const_.type() == Type::I32 &&
               (1ULL << ce.const_.u32()) == align) {
@@ -326,9 +345,8 @@ struct Decompiler {
     BracketIfNeeded(val, Precedence::Indexing);
     val.v.back() += cat("[", index, "]");
     if (append_type) {
-      val.v.back() +=
-        cat(":", GetDecompTypeName(GetMemoryType(op_type, opc)),
-            lst.GenAlign(align, opc));
+      val.v.back() += cat(":", GetDecompTypeName(GetMemoryType(op_type, opc)),
+                          lst.GenAlign(align, opc));
     }
     val.precedence = Precedence::Indexing;
   }
@@ -343,20 +361,24 @@ struct Decompiler {
       case NodeType::FlushToVars: {
         std::string decls = "let ";
         for (Index i = 0; i < n.u.var_count; i++) {
-          if (i) decls += ", ";
+          if (i) {
+            decls += ", ";
+          }
           decls += TempVarName(n.u.var_start + i);
         }
         decls += " = ";
         return WrapNAry(args, decls, "", Precedence::Assign);
       }
       case NodeType::FlushedVar: {
-        return Value { { TempVarName(n.u.var_start) }, Precedence::Atomic };
+        return Value{{TempVarName(n.u.var_start)}, Precedence::Atomic};
       }
       case NodeType::Statements: {
-        Value stats { {}, Precedence::None };
+        Value stats{{}, Precedence::None};
         for (size_t i = 0; i < n.children.size(); i++) {
           auto& s = args[i].v.back();
-          if (s.back() != '}' && s.back() != ':') s += ';';
+          if (s.back() != '}' && s.back() != ':') {
+            s += ';';
+          }
           std::move(args[i].v.begin(), args[i].v.end(),
                     std::back_inserter(stats.v));
         }
@@ -367,10 +389,9 @@ struct Decompiler {
       }
       case NodeType::Decl: {
         cur_ast->vars_defined[n.u.var->name()].defined = true;
-        return Value{
-            {"var " + LocalDecl(std::string(n.u.var->name()),
-                                cur_func->GetLocalType(*n.u.var))},
-            Precedence::None};
+        return Value{{"var " + LocalDecl(std::string(n.u.var->name()),
+                                         cur_func->GetLocalType(*n.u.var))},
+                     Precedence::None};
       }
       case NodeType::DeclInit: {
         if (cur_ast->vars_defined[n.u.var->name()].defined) {
@@ -378,13 +399,12 @@ struct Decompiler {
           return WrapChild(args[0], cat(VarName(n.u.var->name()), " = "), "",
                            Precedence::None);
         } else {
-          return WrapChild(
-              args[0],
-              cat("var ",
-                  LocalDecl(std::string(n.u.var->name()),
-                            cur_func->GetLocalType(*n.u.var)),
-                  " = "),
-              "", Precedence::None);
+          return WrapChild(args[0],
+                           cat("var ",
+                               LocalDecl(std::string(n.u.var->name()),
+                                         cur_func->GetLocalType(*n.u.var)),
+                               " = "),
+                           "", Precedence::None);
         }
       }
       case NodeType::Expr:
@@ -450,16 +470,16 @@ struct Decompiler {
         } else if (opcs == "<<" || opcs == ">>") {
           prec = Precedence::Shift;
         }
-        return WrapBinary(args, cat(" ", opcs, " "), false, prec);
+        return WrapBinary(args, opcs, false, prec);
       }
       case ExprType::Compare: {
         auto& ce = *cast<CompareExpr>(n.e);
-         return WrapBinary(args, cat(" ", OpcodeToToken(ce.opcode), " "), false,
-                           Precedence::Equal);
+        return WrapBinary(args, OpcodeToToken(ce.opcode), false,
+                          Precedence::Equal);
       }
       case ExprType::Unary: {
         auto& ue = *cast<UnaryExpr>(n.e);
-        //BracketIfNeeded(stack.back());
+        // BracketIfNeeded(stack.back());
         // TODO: also version without () depending on precedence.
         return WrapChild(args[0], OpcodeToToken(ue.opcode) + "(", ")",
                          Precedence::Atomic);
@@ -474,11 +494,11 @@ struct Decompiler {
         auto& se = *cast<StoreExpr>(n.e);
         LoadStore(args[0], n.children[0], se.offset, se.opcode, se.align,
                   se.opcode.GetParamType2());
-        return WrapBinary(args, " = ", true, Precedence::Assign);
+        return WrapBinary(args, "=", true, Precedence::Assign);
       }
       case ExprType::If: {
         auto ife = cast<IfExpr>(n.e);
-        Value *elsep = nullptr;
+        Valueelsep = nullptr;
         if (!ife->false_.empty()) {
           elsep = &args[2];
         }
@@ -500,7 +520,8 @@ struct Decompiler {
           if (elsep) {
             ifs.v.push_back("} else {");
             IndentValue(*elsep, indent_amount, {});
-            std::move(elsep->v.begin(), elsep->v.end(), std::back_inserter(ifs.v));
+            std::move(elsep->v.begin(), elsep->v.end(),
+                      std::back_inserter(ifs.v));
           }
           ifs.v.push_back("}");
           ifs.precedence = Precedence::If;
@@ -515,14 +536,13 @@ struct Decompiler {
       case ExprType::Block: {
         auto& val = args[0];
         val.v.push_back(
-              cat("label ", VarName(cast<BlockExpr>(n.e)->block.label), ":"));
+            cat("label ", VarName(cast<BlockExpr>(n.e)->block.label), ":"));
         // If this block is part of a larger statement scope, it doesn't
         // need its own indenting, but if its part of an exp we wrap it in {}.
-        if (parent && parent->ntype != NodeType::Statements
-                   && parent->etype != ExprType::Block
-                   && parent->etype != ExprType::Loop
-                   && (parent->etype != ExprType::If ||
-                       &parent->children[0] == &n)) {
+        if (parent && parent->ntype != NodeType::Statements &&
+            parent->etype != ExprType::Block &&
+            parent->etype != ExprType::Loop &&
+            (parent->etype != ExprType::If || &parent->children[0] == &n)) {
           IndentValue(val, indent_amount, {});
           val.v.insert(val.v.begin(), "{");
           val.v.push_back("}");
@@ -548,8 +568,8 @@ struct Decompiler {
       case ExprType::BrIf: {
         auto bie = cast<BrIfExpr>(n.e);
         auto jmp = n.u.lt == LabelType::Loop ? "continue" : "goto";
-        return WrapChild(args[0], "if (", cat(") ", jmp, " ",
-                                              VarName(bie->var.name())),
+        return WrapChild(args[0], "if (",
+                         cat(") ", jmp, " ", VarName(bie->var.name())),
                          Precedence::None);
       }
       case ExprType::Return: {
@@ -575,7 +595,7 @@ struct Decompiler {
       case ExprType::BrTable: {
         auto bte = cast<BrTableExpr>(n.e);
         std::string ts = "br_table[";
-        for (auto &v : bte->targets) {
+        for (autov : bte->targets) {
           ts += VarName(v.name());
           ts += ", ";
         }
@@ -658,7 +678,7 @@ struct Decompiler {
     return is_import;
   }
 
-  std::string InitExp(const ExprList &el) {
+  std::string InitExp(const ExprListel) {
     assert(!el.empty());
     AST ast(mc, nullptr);
     ast.Construct(el, 1, 0, false);
@@ -668,7 +688,7 @@ struct Decompiler {
   }
 
   // FIXME: Merge with WatWriter::WriteQuotedData somehow.
-  std::string BinaryToString(const std::vector<uint8_t> &in) {
+  std::string BinaryToString(const std::vector<uint8_t>in) {
     std::string s = "\"";
     size_t line_start = 0;
     static const char s_hexdigits[] = "0123456789abcdef";
@@ -744,10 +764,12 @@ struct Decompiler {
 
     // Data.
     for (auto dat : mc.module.data_segments) {
-      s += cat("data ", dat->name, "(offset: ", InitExp(dat->offset), ") = ");
+      s += cat("data ", dat->name, "(offset: ", InitExp(dat->offset), ") =");
       auto ds = BinaryToString(dat->data);
       if (ds.size() > target_exp_width / 2) {
         s += "\n";
+      } else {
+        s += " ";
       }
       s += ds;
       s += ";\n";
index 89bfe78d15792381c02883c1ea8e98f1350a5235..e52a8215d01f7105f9a7dba5bdedf478220ab96f 100644 (file)
@@ -24,8 +24,7 @@ namespace wabt {
 struct Module;
 class Stream;
 
-struct DecompileOptions {
-};
+struct DecompileOptions {};
 
 void RenameAll(Module&);
 
index cd2ed91261135cc343dfcd601ae505656b02209a..7d28a8f95f51f1f6e572eb7c3dbaa05146533761 100644 (file)
@@ -18,8 +18,8 @@
 #define WABT_ERROR_FORMATTER_H_
 
 #include <cstdio>
-#include <string>
 #include <memory>
+#include <string>
 
 #include "src/color.h"
 #include "src/error.h"
index b50400c4bd329eb176ed3901397e0936699378f4..d346f3b77652f9c98a71ab61671323dae2090dc5 100644 (file)
@@ -378,7 +378,6 @@ Result ExprVisitor::HandleDefaultState(Expr* expr) {
       CHECK_RESULT(delegate_->OnStoreExpr(cast<StoreExpr>(expr)));
       break;
 
-
     case ExprType::Throw:
       CHECK_RESULT(delegate_->OnThrowExpr(cast<ThrowExpr>(expr)));
       break;
index 9d7878e18b68c9d567f95ef9dc55104966d3e60f..9a8cb7a4ca3010ef925d884259f701c8987c193a 100644 (file)
@@ -48,8 +48,8 @@ void Features::UpdateDependencies() {
   }
 
   // Reference types requires bulk memory.
-  if (reference_types_enabled_) {
-    bulk_memory_enabled_ = true;
+  if (!bulk_memory_enabled_) {
+    reference_types_enabled_ = false;
   }
 }
 
index 4a85f6f2922227a13e92a15aca1965d0fcb4f9f0..cecab3e6a2ab3c2311c9707bea7e916f602fcde5 100644 (file)
@@ -26,13 +26,14 @@ WABT_FEATURE(exceptions,          "exceptions",              false,   "Experimen
 WABT_FEATURE(mutable_globals,     "mutable-globals",         true,    "Import/export mutable globals")
 WABT_FEATURE(sat_float_to_int,    "saturating-float-to-int", true,    "Saturating float-to-int operators")
 WABT_FEATURE(sign_extension,      "sign-extension",          true,    "Sign-extension operators")
-WABT_FEATURE(simd,                "simd",                    false,   "SIMD support")
+WABT_FEATURE(simd,                "simd",                    true,    "SIMD support")
 WABT_FEATURE(threads,             "threads",                 false,   "Threading support")
 WABT_FEATURE(function_references, "function-references",     false,   "Typed function references")
 WABT_FEATURE(multi_value,         "multi-value",             true,    "Multi-value")
 WABT_FEATURE(tail_call,           "tail-call",               false,   "Tail-call support")
-WABT_FEATURE(bulk_memory,         "bulk-memory",             false,   "Bulk-memory operations")
-WABT_FEATURE(reference_types,     "reference-types",         false,   "Reference types (externref)")
+WABT_FEATURE(bulk_memory,         "bulk-memory",             true,    "Bulk-memory operations")
+WABT_FEATURE(reference_types,     "reference-types",         true,    "Reference types (externref)")
 WABT_FEATURE(annotations,         "annotations",             false,   "Custom annotation syntax")
 WABT_FEATURE(gc,                  "gc",                      false,   "Garbage collection")
 WABT_FEATURE(memory64,            "memory64",                false,   "64-bit memory")
+WABT_FEATURE(multi_memory,        "multi-memory",            false,   "Multi-memory")
index 5f99f0e84c2d06aa21a3f297fa53d64044176518..35f136c3fec8903e298a64f0f0ff74f53060f9ab 100644 (file)
@@ -52,9 +52,7 @@ class NameGenerator : public ExprVisitor::DelegateNop {
                     std::string* out_str);
 
   // Like GenerateName, but only generates a name if |out_str| is empty.
-  void MaybeGenerateName(const char* prefix,
-                         Index index,
-                         std::string* out_str);
+  void MaybeGenerateName(const char* prefix, Index index, std::string* out_str);
 
   // Generate a name via GenerateName and bind it to the given binding hash. If
   // the name already exists, the name will be disambiguated until it can be
@@ -108,8 +106,7 @@ class NameGenerator : public ExprVisitor::DelegateNop {
   NameOpts opts_;
 };
 
-NameGenerator::NameGenerator(NameOpts opts)
-  : visitor_(this), opts_(opts) {}
+NameGenerator::NameGenerator(NameOpts opts) : visitor_(this), opts_(opts) {}
 
 // static
 bool NameGenerator::HasName(const std::string& str) {
index 53a996f5aabec11f6ffa3bd362219af319b264fc..25f4d84fe9f014a8e53390d5df9ec5fd16b4ebbc 100644 (file)
@@ -48,9 +48,16 @@ SegmentMode ToSegmentMode(uint8_t flags) {
   }
 }
 
+// This is only used to distinguish try blocks and all other blocks,
+// so there are only two kinds.
+enum class LabelKind { Block, Try };
+
 struct Label {
+  LabelKind kind;
   Istream::Offset offset;
   Istream::Offset fixup_offset;
+  // Only needs to be set for try blocks.
+  u32 handler_desc_index;
 };
 
 struct FixupMap {
@@ -67,6 +74,7 @@ struct FixupMap {
 class BinaryReaderInterp : public BinaryReaderNop {
  public:
   BinaryReaderInterp(ModuleDesc* module,
+                     string_view filename,
                      Errors* errors,
                      const Features& features);
 
@@ -106,6 +114,11 @@ class BinaryReaderInterp : public BinaryReaderNop {
                         Index global_index,
                         Type type,
                         bool mutable_) override;
+  Result OnImportTag(Index import_index,
+                     string_view module_name,
+                     string_view field_name,
+                     Index tag_index,
+                     Index sig_index) override;
 
   Result OnFunctionCount(Index count) override;
   Result OnFunction(Index index, Index sig_index) override;
@@ -120,8 +133,12 @@ class BinaryReaderInterp : public BinaryReaderNop {
 
   Result OnGlobalCount(Index count) override;
   Result BeginGlobal(Index index, Type type, bool mutable_) override;
+  Result BeginGlobalInitExpr(Index index) override;
   Result EndGlobalInitExpr(Index index) override;
 
+  Result OnTagCount(Index count) override;
+  Result OnTagType(Index index, Index sig_index) override;
+
   Result OnExport(Index index,
                   ExternalKind kind,
                   Index item_index,
@@ -162,6 +179,9 @@ class BinaryReaderInterp : public BinaryReaderNop {
                        Index default_target_depth) override;
   Result OnCallExpr(Index func_index) override;
   Result OnCallIndirectExpr(Index sig_index, Index table_index) override;
+  Result OnCatchExpr(Index tag_index) override;
+  Result OnCatchAllExpr() override;
+  Result OnDelegateExpr(Index depth) override;
   Result OnReturnCallExpr(Index func_index) override;
   Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override;
   Result OnCompareExpr(Opcode opcode) override;
@@ -178,25 +198,28 @@ class BinaryReaderInterp : public BinaryReaderNop {
   Result OnI64ConstExpr(uint64_t value) override;
   Result OnIfExpr(Type sig_type) override;
   Result OnLoadExpr(Opcode opcode,
+                    Index memidx,
                     Address alignment_log2,
                     Address offset) override;
   Result OnLocalGetExpr(Index local_index) override;
   Result OnLocalSetExpr(Index local_index) override;
   Result OnLocalTeeExpr(Index local_index) override;
   Result OnLoopExpr(Type sig_type) override;
-  Result OnMemoryCopyExpr() override;
+  Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) override;
   Result OnDataDropExpr(Index segment_index) override;
-  Result OnMemoryGrowExpr() override;
-  Result OnMemoryFillExpr() override;
-  Result OnMemoryInitExpr(Index segment_index) override;
-  Result OnMemorySizeExpr() override;
+  Result OnMemoryGrowExpr(Index memidx) override;
+  Result OnMemoryFillExpr(Index memidx) override;
+  Result OnMemoryInitExpr(Index segment_index, Index memidx) override;
+  Result OnMemorySizeExpr(Index memidx) override;
   Result OnRefFuncExpr(Index func_index) override;
   Result OnRefNullExpr(Type type) override;
   Result OnRefIsNullExpr() override;
   Result OnNopExpr() override;
+  Result OnRethrowExpr(Index depth) override;
   Result OnReturnExpr() override;
   Result OnSelectExpr(Index result_count, Type* result_types) override;
   Result OnStoreExpr(Opcode opcode,
+                     Index memidx,
                      Address alignment_log2,
                      Address offset) override;
   Result OnUnaryExpr(Opcode opcode) override;
@@ -209,14 +232,18 @@ class BinaryReaderInterp : public BinaryReaderNop {
   Result OnElemDropExpr(Index segment_index) override;
   Result OnTableInitExpr(Index segment_index, Index table_index) override;
   Result OnTernaryExpr(Opcode opcode) override;
+  Result OnThrowExpr(Index tag_index) override;
+  Result OnTryExpr(Type sig_type) override;
   Result OnUnreachableExpr() override;
   Result EndFunctionBody(Index index) override;
   Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) override;
   Result OnSimdLoadLaneExpr(Opcode opcode,
+                            Index memidx,
                             Address alignment_log2,
                             Address offset,
                             uint64_t value) override;
   Result OnSimdStoreLaneExpr(Opcode opcode,
+                             Index memidx,
                              Address alignment_log2,
                              Address offset,
                              uint64_t value) override;
@@ -232,6 +259,7 @@ class BinaryReaderInterp : public BinaryReaderNop {
   Result BeginElemSegment(Index index,
                           Index table_index,
                           uint8_t flags) override;
+  Result BeginElemSegmentInitExpr(Index index) override;
   Result EndElemSegmentInitExpr(Index index) override;
   Result OnElemSegmentElemType(Index index, Type elem_type) override;
   Result OnElemSegmentElemExprCount(Index index, Index count) override;
@@ -240,6 +268,7 @@ class BinaryReaderInterp : public BinaryReaderNop {
                                        Index func_index) override;
 
   Result OnDataCount(Index count) override;
+  Result BeginDataSegmentInitExpr(Index index) override;
   Result EndDataSegmentInitExpr(Index index) override;
   Result BeginDataSegment(Index index,
                           Index memory_index,
@@ -248,20 +277,15 @@ class BinaryReaderInterp : public BinaryReaderNop {
                            const void* data,
                            Address size) override;
 
-  Result OnInitExprF32ConstExpr(Index index, uint32_t value) override;
-  Result OnInitExprF64ConstExpr(Index index, uint64_t value) override;
-  Result OnInitExprV128ConstExpr(Index index, v128 value) override;
-  Result OnInitExprGlobalGetExpr(Index index, Index global_index) override;
-  Result OnInitExprI32ConstExpr(Index index, uint32_t value) override;
-  Result OnInitExprI64ConstExpr(Index index, uint64_t value) override;
-  Result OnInitExprRefNull(Index index, Type type) override;
-  Result OnInitExprRefFunc(Index index, Index func_index) override;
-
  private:
+  Location GetLocation() const;
   Label* GetLabel(Index depth);
+  Label* GetNearestTryLabel(Index depth);
   Label* TopLabel();
-  void PushLabel(Istream::Offset offset = Istream::kInvalidOffset,
-                 Istream::Offset fixup_offset = Istream::kInvalidOffset);
+  void PushLabel(LabelKind label = LabelKind::Block,
+                 Istream::Offset offset = Istream::kInvalidOffset,
+                 Istream::Offset fixup_offset = Istream::kInvalidOffset,
+                 u32 handler_desc_index = kInvalidIndex);
   void PopLabel();
 
   void PrintError(const char* format, ...);
@@ -277,7 +301,13 @@ class BinaryReaderInterp : public BinaryReaderNop {
                                     Index keep_extra,
                                     Index* out_drop_count,
                                     Index* out_keep_count);
-  void EmitBr(Index depth, Index drop_count, Index keep_count);
+  Result BeginInitExpr(Type type);
+  Result EndInitExpr();
+
+  void EmitBr(Index depth,
+              Index drop_count,
+              Index keep_count,
+              Index catch_drop_count);
   void FixupTopLabel();
   u32 GetFuncOffset(Index func_index);
 
@@ -296,6 +326,7 @@ class BinaryReaderInterp : public BinaryReaderNop {
   FixupMap depth_fixups_;
   FixupMap func_fixups_;
 
+  bool reading_init_expr_ = false;
   InitExpr init_expr_;
   u32 local_decl_count_;
   u32 local_count_;
@@ -307,14 +338,15 @@ class BinaryReaderInterp : public BinaryReaderNop {
   std::vector<TagType> tag_types_;        // Includes imported and defined.
 
   static const Index kMemoryIndex0 = 0;
-
-  // TODO: Use this in all locations below, for now. In the future we'll want
-  // to use the real locations.
-  static const Location loc;
+  string_view filename_;
 };
 
-// static
-const Location BinaryReaderInterp::loc{kInvalidOffset};
+Location BinaryReaderInterp::GetLocation() const {
+  Location loc;
+  loc.filename = filename_;
+  loc.offset = state->offset;
+  return loc;
+}
 
 void FixupMap::Clear() {
   map.clear();
@@ -336,18 +368,30 @@ void FixupMap::Resolve(Istream& istream, Index index) {
 }
 
 BinaryReaderInterp::BinaryReaderInterp(ModuleDesc* module,
+                                       string_view filename,
                                        Errors* errors,
                                        const Features& features)
     : errors_(errors),
       module_(*module),
       istream_(module->istream),
-      validator_(errors, ValidateOptions(features)) {}
+      validator_(errors, ValidateOptions(features)),
+      filename_(filename) {}
 
 Label* BinaryReaderInterp::GetLabel(Index depth) {
   assert(depth < label_stack_.size());
   return &label_stack_[label_stack_.size() - depth - 1];
 }
 
+Label* BinaryReaderInterp::GetNearestTryLabel(Index depth) {
+  for (size_t i = depth; i < label_stack_.size(); i++) {
+    Label* label = &label_stack_[label_stack_.size() - i - 1];
+    if (label->kind == LabelKind::Try) {
+      return label;
+    }
+  }
+  return nullptr;
+}
+
 Label* BinaryReaderInterp::TopLabel() {
   return GetLabel(0);
 }
@@ -404,8 +448,10 @@ Result BinaryReaderInterp::GetReturnCallDropKeepCount(const FuncType& func_type,
 
 void BinaryReaderInterp::EmitBr(Index depth,
                                 Index drop_count,
-                                Index keep_count) {
+                                Index keep_count,
+                                Index catch_drop_count) {
   istream_.EmitDropKeep(drop_count, keep_count);
+  istream_.EmitCatchDrop(catch_drop_count);
   Istream::Offset offset = GetLabel(depth)->offset;
   istream_.Emit(Opcode::Br);
   if (offset == Istream::kInvalidOffset) {
@@ -449,8 +495,8 @@ Result BinaryReaderInterp::OnFuncType(Index index,
                                       Type* param_types,
                                       Index result_count,
                                       Type* result_types) {
-  CHECK_RESULT(validator_.OnFuncType(loc, param_count, param_types,
-                                     result_count, result_types));
+  CHECK_RESULT(validator_.OnFuncType(GetLocation(), param_count, param_types,
+                                     result_count, result_types, index));
   module_.func_types.push_back(FuncType(ToInterp(param_count, param_types),
                                         ToInterp(result_count, result_types)));
   return Result::Ok;
@@ -461,7 +507,7 @@ Result BinaryReaderInterp::OnImportFunc(Index import_index,
                                         string_view field_name,
                                         Index func_index,
                                         Index sig_index) {
-  CHECK_RESULT(validator_.OnFunction(loc, Var(sig_index)));
+  CHECK_RESULT(validator_.OnFunction(GetLocation(), Var(sig_index)));
   FuncType& func_type = module_.func_types[sig_index];
   module_.imports.push_back(ImportDesc{ImportType(
       module_name.to_string(), field_name.to_string(), func_type.Clone())});
@@ -475,7 +521,7 @@ Result BinaryReaderInterp::OnImportTable(Index import_index,
                                          Index table_index,
                                          Type elem_type,
                                          const Limits* elem_limits) {
-  CHECK_RESULT(validator_.OnTable(loc, elem_type, *elem_limits));
+  CHECK_RESULT(validator_.OnTable(GetLocation(), elem_type, *elem_limits));
   TableType table_type{elem_type, *elem_limits};
   module_.imports.push_back(ImportDesc{ImportType(
       module_name.to_string(), field_name.to_string(), table_type.Clone())});
@@ -488,7 +534,7 @@ Result BinaryReaderInterp::OnImportMemory(Index import_index,
                                           string_view field_name,
                                           Index memory_index,
                                           const Limits* page_limits) {
-  CHECK_RESULT(validator_.OnMemory(loc, *page_limits));
+  CHECK_RESULT(validator_.OnMemory(GetLocation(), *page_limits));
   MemoryType memory_type{*page_limits};
   module_.imports.push_back(ImportDesc{ImportType(
       module_name.to_string(), field_name.to_string(), memory_type.Clone())});
@@ -502,7 +548,7 @@ Result BinaryReaderInterp::OnImportGlobal(Index import_index,
                                           Index global_index,
                                           Type type,
                                           bool mutable_) {
-  CHECK_RESULT(validator_.OnGlobalImport(loc, type, mutable_));
+  CHECK_RESULT(validator_.OnGlobalImport(GetLocation(), type, mutable_));
   GlobalType global_type{type, ToMutability(mutable_)};
   module_.imports.push_back(ImportDesc{ImportType(
       module_name.to_string(), field_name.to_string(), global_type.Clone())});
@@ -510,15 +556,29 @@ Result BinaryReaderInterp::OnImportGlobal(Index import_index,
   return Result::Ok;
 }
 
+Result BinaryReaderInterp::OnImportTag(Index import_index,
+                                       string_view module_name,
+                                       string_view field_name,
+                                       Index tag_index,
+                                       Index sig_index) {
+  CHECK_RESULT(validator_.OnTag(GetLocation(), Var(sig_index)));
+  FuncType& func_type = module_.func_types[sig_index];
+  TagType tag_type{TagAttr::Exception, func_type.params};
+  module_.imports.push_back(ImportDesc{ImportType(
+      module_name.to_string(), field_name.to_string(), tag_type.Clone())});
+  tag_types_.push_back(tag_type);
+  return Result::Ok;
+}
+
 Result BinaryReaderInterp::OnFunctionCount(Index count) {
   module_.funcs.reserve(count);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnFunction(Index index, Index sig_index) {
-  CHECK_RESULT(validator_.OnFunction(loc, Var(sig_index)));
+  CHECK_RESULT(validator_.OnFunction(GetLocation(), Var(sig_index)));
   FuncType& func_type = module_.func_types[sig_index];
-  module_.funcs.push_back(FuncDesc{func_type, {}, 0});
+  module_.funcs.push_back(FuncDesc{func_type, {}, Istream::kInvalidOffset, {}});
   func_types_.push_back(func_type);
   return Result::Ok;
 }
@@ -531,7 +591,7 @@ Result BinaryReaderInterp::OnTableCount(Index count) {
 Result BinaryReaderInterp::OnTable(Index index,
                                    Type elem_type,
                                    const Limits* elem_limits) {
-  CHECK_RESULT(validator_.OnTable(loc, elem_type, *elem_limits));
+  CHECK_RESULT(validator_.OnTable(GetLocation(), elem_type, *elem_limits));
   TableType table_type{elem_type, *elem_limits};
   module_.tables.push_back(TableDesc{table_type});
   table_types_.push_back(table_type);
@@ -544,7 +604,7 @@ Result BinaryReaderInterp::OnMemoryCount(Index count) {
 }
 
 Result BinaryReaderInterp::OnMemory(Index index, const Limits* limits) {
-  CHECK_RESULT(validator_.OnMemory(loc, *limits));
+  CHECK_RESULT(validator_.OnMemory(GetLocation(), *limits));
   MemoryType memory_type{*limits};
   module_.memories.push_back(MemoryDesc{memory_type});
   memory_types_.push_back(memory_type);
@@ -557,7 +617,7 @@ Result BinaryReaderInterp::OnGlobalCount(Index count) {
 }
 
 Result BinaryReaderInterp::BeginGlobal(Index index, Type type, bool mutable_) {
-  CHECK_RESULT(validator_.OnGlobal(loc, type, mutable_));
+  CHECK_RESULT(validator_.OnGlobal(GetLocation(), type, mutable_));
   GlobalType global_type{type, ToMutability(mutable_)};
   module_.globals.push_back(GlobalDesc{global_type, InitExpr{}});
   global_types_.push_back(global_type);
@@ -565,101 +625,44 @@ Result BinaryReaderInterp::BeginGlobal(Index index, Type type, bool mutable_) {
   return Result::Ok;
 }
 
-Result BinaryReaderInterp::EndGlobalInitExpr(Index index) {
-  switch (init_expr_.kind) {
-    case InitExprKind::I32:
-      CHECK_RESULT(validator_.OnGlobalInitExpr_Const(loc, ValueType::I32));
-      break;
-
-    case InitExprKind::I64:
-      CHECK_RESULT(validator_.OnGlobalInitExpr_Const(loc, ValueType::I64));
-      break;
-
-    case InitExprKind::F32:
-      CHECK_RESULT(validator_.OnGlobalInitExpr_Const(loc, ValueType::F32));
-      break;
-
-    case InitExprKind::F64:
-      CHECK_RESULT(validator_.OnGlobalInitExpr_Const(loc, ValueType::F64));
-      break;
-
-    case InitExprKind::V128:
-      CHECK_RESULT(validator_.OnGlobalInitExpr_Const(loc, ValueType::V128));
-      break;
-
-    case InitExprKind::GlobalGet:
-      CHECK_RESULT(
-          validator_.OnGlobalInitExpr_GlobalGet(loc, Var(init_expr_.index_)));
-      break;
-
-    case InitExprKind::RefNull:
-      CHECK_RESULT(validator_.OnGlobalInitExpr_RefNull(loc, init_expr_.type_));
-      break;
-
-    case InitExprKind::RefFunc:
-      CHECK_RESULT(
-          validator_.OnGlobalInitExpr_RefFunc(loc, Var(init_expr_.index_)));
-      break;
-
-    default:
-      CHECK_RESULT(validator_.OnGlobalInitExpr_Other(loc));
-      break;
-  }
-
-  GlobalDesc& global = module_.globals.back();
-  global.init = init_expr_;
-  return Result::Ok;
-}
-
-Result BinaryReaderInterp::OnInitExprF32ConstExpr(Index index,
-                                                  uint32_t value_bits) {
-  init_expr_.kind = InitExprKind::F32;
-  init_expr_.f32_ = Bitcast<f32>(value_bits);
-  return Result::Ok;
-}
-
-Result BinaryReaderInterp::OnInitExprF64ConstExpr(Index index,
-                                                  uint64_t value_bits) {
-  init_expr_.kind = InitExprKind::F64;
-  init_expr_.f64_ = Bitcast<f64>(value_bits);
-  return Result::Ok;
-}
-
-Result BinaryReaderInterp::OnInitExprV128ConstExpr(Index index,
-                                                   v128 value_bits) {
-  init_expr_.kind = InitExprKind::V128;
-  init_expr_.v128_ = Bitcast<v128>(value_bits);
-  return Result::Ok;
+Result BinaryReaderInterp::BeginGlobalInitExpr(Index index) {
+  GlobalType type = global_types_[index];
+  return BeginInitExpr(type.type);
 }
 
-Result BinaryReaderInterp::OnInitExprGlobalGetExpr(Index index,
-                                                   Index global_index) {
-  init_expr_.kind = InitExprKind::GlobalGet;
-  init_expr_.index_ = global_index;
+Result BinaryReaderInterp::EndInitExpr() {
+  assert(reading_init_expr_);
+  reading_init_expr_ = false;
+  CHECK_RESULT(validator_.EndInitExpr());
   return Result::Ok;
 }
 
-Result BinaryReaderInterp::OnInitExprI32ConstExpr(Index index, uint32_t value) {
-  init_expr_.kind = InitExprKind::I32;
-  init_expr_.i32_ = value;
+Result BinaryReaderInterp::BeginInitExpr(Type type) {
+  assert(!reading_init_expr_);
+  reading_init_expr_ = true;
+  init_expr_.kind = InitExprKind::None;
+  CHECK_RESULT(validator_.BeginInitExpr(GetLocation(), type));
   return Result::Ok;
 }
 
-Result BinaryReaderInterp::OnInitExprI64ConstExpr(Index index, uint64_t value) {
-  init_expr_.kind = InitExprKind::I64;
-  init_expr_.i64_ = value;
+Result BinaryReaderInterp::EndGlobalInitExpr(Index index) {
+  CHECK_RESULT(EndInitExpr());
+  GlobalDesc& global = module_.globals.back();
+  global.init = init_expr_;
   return Result::Ok;
 }
 
-Result BinaryReaderInterp::OnInitExprRefNull(Index index, Type type) {
-  init_expr_.kind = InitExprKind::RefNull;
-  init_expr_.type_ = type;
+Result BinaryReaderInterp::OnTagCount(Index count) {
+  module_.tags.reserve(count);
   return Result::Ok;
 }
 
-Result BinaryReaderInterp::OnInitExprRefFunc(Index index, Index func_index) {
-  init_expr_.kind = InitExprKind::RefFunc;
-  init_expr_.index_ = func_index;
+Result BinaryReaderInterp::OnTagType(Index index, Index sig_index) {
+  CHECK_RESULT(validator_.OnTag(GetLocation(), Var(sig_index)));
+  FuncType& func_type = module_.func_types[sig_index];
+  TagType tag_type{TagAttr::Exception, func_type.params};
+  module_.tags.push_back(TagDesc{tag_type});
+  tag_types_.push_back(tag_type);
   return Result::Ok;
 }
 
@@ -667,7 +670,7 @@ Result BinaryReaderInterp::OnExport(Index index,
                                     ExternalKind kind,
                                     Index item_index,
                                     string_view name) {
-  CHECK_RESULT(validator_.OnExport(loc, kind, Var(item_index), name));
+  CHECK_RESULT(validator_.OnExport(GetLocation(), kind, Var(item_index), name));
 
   std::unique_ptr<ExternType> type;
   switch (kind) {
@@ -683,7 +686,7 @@ Result BinaryReaderInterp::OnExport(Index index,
 }
 
 Result BinaryReaderInterp::OnStartFunction(Index func_index) {
-  CHECK_RESULT(validator_.OnStart(loc, Var(func_index)));
+  CHECK_RESULT(validator_.OnStart(GetLocation(), Var(func_index)));
   module_.starts.push_back(StartDesc{func_index});
   return Result::Ok;
 }
@@ -697,7 +700,7 @@ Result BinaryReaderInterp::BeginElemSegment(Index index,
                                             Index table_index,
                                             uint8_t flags) {
   auto mode = ToSegmentMode(flags);
-  CHECK_RESULT(validator_.OnElemSegment(loc, Var(table_index), mode));
+  CHECK_RESULT(validator_.OnElemSegment(GetLocation(), Var(table_index), mode));
 
   ElemDesc desc;
   desc.type = ValueType::Void;  // Initialized later in OnElemSegmentElemType.
@@ -708,22 +711,12 @@ Result BinaryReaderInterp::BeginElemSegment(Index index,
   return Result::Ok;
 }
 
-Result BinaryReaderInterp::EndElemSegmentInitExpr(Index index) {
-  switch (init_expr_.kind) {
-    case InitExprKind::I32:
-      CHECK_RESULT(validator_.OnElemSegmentInitExpr_Const(loc, ValueType::I32));
-      break;
-
-    case InitExprKind::GlobalGet:
-      CHECK_RESULT(validator_.OnElemSegmentInitExpr_GlobalGet(
-          loc, Var(init_expr_.index_)));
-      break;
-
-    default:
-      CHECK_RESULT(validator_.OnElemSegmentInitExpr_Other(loc));
-      break;
-  }
+Result BinaryReaderInterp::BeginElemSegmentInitExpr(Index index) {
+  return BeginInitExpr(Type::I32);
+}
 
+Result BinaryReaderInterp::EndElemSegmentInitExpr(Index index) {
+  CHECK_RESULT(EndInitExpr());
   ElemDesc& elem = module_.elems.back();
   elem.offset = init_expr_;
   return Result::Ok;
@@ -745,7 +738,7 @@ Result BinaryReaderInterp::OnElemSegmentElemExprCount(Index index,
 
 Result BinaryReaderInterp::OnElemSegmentElemExpr_RefNull(Index segment_index,
                                                          Type type) {
-  CHECK_RESULT(validator_.OnElemSegmentElemExpr_RefNull(loc, type));
+  CHECK_RESULT(validator_.OnElemSegmentElemExpr_RefNull(GetLocation(), type));
   ElemDesc& elem = module_.elems.back();
   elem.elements.push_back(ElemExpr{ElemKind::RefNull, 0});
   return Result::Ok;
@@ -753,7 +746,8 @@ Result BinaryReaderInterp::OnElemSegmentElemExpr_RefNull(Index segment_index,
 
 Result BinaryReaderInterp::OnElemSegmentElemExpr_RefFunc(Index segment_index,
                                                          Index func_index) {
-  CHECK_RESULT(validator_.OnElemSegmentElemExpr_RefFunc(loc, Var(func_index)));
+  CHECK_RESULT(
+      validator_.OnElemSegmentElemExpr_RefFunc(GetLocation(), Var(func_index)));
   ElemDesc& elem = module_.elems.back();
   elem.elements.push_back(ElemExpr{ElemKind::RefFunc, func_index});
   return Result::Ok;
@@ -765,26 +759,13 @@ Result BinaryReaderInterp::OnDataCount(Index count) {
   return Result::Ok;
 }
 
-Result BinaryReaderInterp::EndDataSegmentInitExpr(Index index) {
-  switch (init_expr_.kind) {
-    case InitExprKind::I32:
-      CHECK_RESULT(validator_.OnDataSegmentInitExpr_Const(loc, ValueType::I32));
-      break;
-
-    case InitExprKind::I64:
-      CHECK_RESULT(validator_.OnDataSegmentInitExpr_Const(loc, ValueType::I64));
-      break;
-
-    case InitExprKind::GlobalGet:
-      CHECK_RESULT(validator_.OnDataSegmentInitExpr_GlobalGet(
-          loc, Var(init_expr_.index_)));
-      break;
-
-    default:
-      CHECK_RESULT(validator_.OnDataSegmentInitExpr_Other(loc));
-      break;
-  }
+Result BinaryReaderInterp::BeginDataSegmentInitExpr(Index index) {
+  MemoryType t = memory_types_[0];
+  return BeginInitExpr(t.limits.is_64 ? Type::I64 : Type::I32);
+}
 
+Result BinaryReaderInterp::EndDataSegmentInitExpr(Index index) {
+  CHECK_RESULT(EndInitExpr());
   DataDesc& data = module_.datas.back();
   data.offset = init_expr_;
   return Result::Ok;
@@ -794,7 +775,8 @@ Result BinaryReaderInterp::BeginDataSegment(Index index,
                                             Index memory_index,
                                             uint8_t flags) {
   auto mode = ToSegmentMode(flags);
-  CHECK_RESULT(validator_.OnDataSegment(loc, Var(memory_index), mode));
+  CHECK_RESULT(
+      validator_.OnDataSegment(GetLocation(), Var(memory_index), mode));
 
   DataDesc desc;
   desc.mode = mode;
@@ -815,9 +797,11 @@ Result BinaryReaderInterp::OnDataSegmentData(Index index,
   return Result::Ok;
 }
 
-void BinaryReaderInterp::PushLabel(Istream::Offset offset,
-                                   Istream::Offset fixup_offset) {
-  label_stack_.push_back(Label{offset, fixup_offset});
+void BinaryReaderInterp::PushLabel(LabelKind kind,
+                                   Istream::Offset offset,
+                                   Istream::Offset fixup_offset,
+                                   u32 handler_desc_index) {
+  label_stack_.push_back(Label{kind, offset, fixup_offset, handler_desc_index});
 }
 
 void BinaryReaderInterp::PopLabel() {
@@ -834,10 +818,21 @@ Result BinaryReaderInterp::BeginFunctionBody(Index index, Offset size) {
 
   func_fixups_.Resolve(istream_, defined_index);
 
-  CHECK_RESULT(validator_.BeginFunctionBody(loc, index));
+  CHECK_RESULT(validator_.BeginFunctionBody(GetLocation(), index));
 
   // Push implicit func label (equivalent to return).
-  PushLabel();
+  // With exception handling it acts as a catch-less try block, which is
+  // needed to support delegating to the caller of a function using the
+  // try-delegate instruction.
+  PushLabel(LabelKind::Try, Istream::kInvalidOffset, Istream::kInvalidOffset,
+            func_->handlers.size());
+  func_->handlers.push_back(HandlerDesc{HandlerKind::Catch,
+                                        istream_.end(),
+                                        Istream::kInvalidOffset,
+                                        {},
+                                        {Istream::kInvalidOffset},
+                                        static_cast<u32>(func_->locals.size()),
+                                        0});
   return Result::Ok;
 }
 
@@ -845,7 +840,7 @@ Result BinaryReaderInterp::EndFunctionBody(Index index) {
   FixupTopLabel();
   Index drop_count, keep_count;
   CHECK_RESULT(GetReturnDropKeepCount(&drop_count, &keep_count));
-  CHECK_RESULT(validator_.EndFunctionBody(loc));
+  CHECK_RESULT(validator_.EndFunctionBody(GetLocation()));
   istream_.EmitDropKeep(drop_count, keep_count);
   istream_.Emit(Opcode::Return);
   PopLabel();
@@ -862,7 +857,7 @@ Result BinaryReaderInterp::OnLocalDeclCount(Index count) {
 Result BinaryReaderInterp::OnLocalDecl(Index decl_index,
                                        Index count,
                                        Type type) {
-  CHECK_RESULT(validator_.OnLocalDecl(loc, count, type));
+  CHECK_RESULT(validator_.OnLocalDecl(GetLocation(), count, type));
 
   local_count_ += count;
   func_->locals.push_back(LocalDesc{type, count, local_count_});
@@ -878,7 +873,7 @@ Index BinaryReaderInterp::num_func_imports() const {
 }
 
 Result BinaryReaderInterp::OnOpcode(Opcode opcode) {
-  if (func_ == nullptr || label_stack_.empty()) {
+  if ((func_ == nullptr || label_stack_.empty()) && !reading_init_expr_) {
     PrintError("Unexpected instruction after end of function");
     return Result::Error;
   }
@@ -886,19 +881,19 @@ Result BinaryReaderInterp::OnOpcode(Opcode opcode) {
 }
 
 Result BinaryReaderInterp::OnUnaryExpr(Opcode opcode) {
-  CHECK_RESULT(validator_.OnUnary(loc, opcode));
+  CHECK_RESULT(validator_.OnUnary(GetLocation(), opcode));
   istream_.Emit(opcode);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnTernaryExpr(Opcode opcode) {
-  CHECK_RESULT(validator_.OnTernary(loc, opcode));
+  CHECK_RESULT(validator_.OnTernary(GetLocation(), opcode));
   istream_.Emit(opcode);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnSimdLaneOpExpr(Opcode opcode, uint64_t value) {
-  CHECK_RESULT(validator_.OnSimdLaneOp(loc, opcode, value));
+  CHECK_RESULT(validator_.OnSimdLaneOp(GetLocation(), opcode, value));
   istream_.Emit(opcode, static_cast<u8>(value));
   return Result::Ok;
 }
@@ -908,26 +903,29 @@ uint32_t GetAlignment(Address alignment_log2) {
 }
 
 Result BinaryReaderInterp::OnSimdLoadLaneExpr(Opcode opcode,
+                                              Index memidx,
                                               Address alignment_log2,
                                               Address offset,
                                               uint64_t value) {
-  CHECK_RESULT(validator_.OnSimdLoadLane(loc, opcode, GetAlignment(alignment_log2), value));
-  istream_.Emit(opcode, kMemoryIndex0, offset, static_cast<u8>(value));
+  CHECK_RESULT(validator_.OnSimdLoadLane(GetLocation(), opcode,
+                                         GetAlignment(alignment_log2), value));
+  istream_.Emit(opcode, memidx, offset, static_cast<u8>(value));
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnSimdStoreLaneExpr(Opcode opcode,
-                                              Address alignment_log2,
-                                              Address offset,
-                                              uint64_t value) {
-  CHECK_RESULT(validator_.OnSimdStoreLane(loc, opcode,
+                                               Index memidx,
+                                               Address alignment_log2,
+                                               Address offset,
+                                               uint64_t value) {
+  CHECK_RESULT(validator_.OnSimdStoreLane(GetLocation(), opcode,
                                           GetAlignment(alignment_log2), value));
-  istream_.Emit(opcode, kMemoryIndex0, offset, static_cast<u8>(value));
+  istream_.Emit(opcode, memidx, offset, static_cast<u8>(value));
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnSimdShuffleOpExpr(Opcode opcode, v128 value) {
-  CHECK_RESULT(validator_.OnSimdShuffleOp(loc, opcode, value));
+  CHECK_RESULT(validator_.OnSimdShuffleOp(GetLocation(), opcode, value));
   istream_.Emit(opcode, value);
   return Result::Ok;
 }
@@ -935,7 +933,8 @@ Result BinaryReaderInterp::OnSimdShuffleOpExpr(Opcode opcode, v128 value) {
 Result BinaryReaderInterp::OnLoadSplatExpr(Opcode opcode,
                                            Address align_log2,
                                            Address offset) {
-  CHECK_RESULT(validator_.OnLoadSplat(loc, opcode, GetAlignment(align_log2)));
+  CHECK_RESULT(
+      validator_.OnLoadSplat(GetLocation(), opcode, GetAlignment(align_log2)));
   istream_.Emit(opcode, kMemoryIndex0, offset);
   return Result::Ok;
 }
@@ -943,7 +942,8 @@ Result BinaryReaderInterp::OnLoadSplatExpr(Opcode opcode,
 Result BinaryReaderInterp::OnLoadZeroExpr(Opcode opcode,
                                           Address align_log2,
                                           Address offset) {
-  CHECK_RESULT(validator_.OnLoadZero(loc, opcode, GetAlignment(align_log2)));
+  CHECK_RESULT(
+      validator_.OnLoadZero(GetLocation(), opcode, GetAlignment(align_log2)));
   istream_.Emit(opcode, kMemoryIndex0, offset);
   return Result::Ok;
 }
@@ -951,7 +951,8 @@ Result BinaryReaderInterp::OnLoadZeroExpr(Opcode opcode,
 Result BinaryReaderInterp::OnAtomicLoadExpr(Opcode opcode,
                                             Address align_log2,
                                             Address offset) {
-  CHECK_RESULT(validator_.OnAtomicLoad(loc, opcode, GetAlignment(align_log2)));
+  CHECK_RESULT(
+      validator_.OnAtomicLoad(GetLocation(), opcode, GetAlignment(align_log2)));
   istream_.Emit(opcode, kMemoryIndex0, offset);
   return Result::Ok;
 }
@@ -959,7 +960,8 @@ Result BinaryReaderInterp::OnAtomicLoadExpr(Opcode opcode,
 Result BinaryReaderInterp::OnAtomicStoreExpr(Opcode opcode,
                                              Address align_log2,
                                              Address offset) {
-  CHECK_RESULT(validator_.OnAtomicStore(loc, opcode, GetAlignment(align_log2)));
+  CHECK_RESULT(validator_.OnAtomicStore(GetLocation(), opcode,
+                                        GetAlignment(align_log2)));
   istream_.Emit(opcode, kMemoryIndex0, offset);
   return Result::Ok;
 }
@@ -967,7 +969,8 @@ Result BinaryReaderInterp::OnAtomicStoreExpr(Opcode opcode,
 Result BinaryReaderInterp::OnAtomicRmwExpr(Opcode opcode,
                                            Address align_log2,
                                            Address offset) {
-  CHECK_RESULT(validator_.OnAtomicRmw(loc, opcode, GetAlignment(align_log2)));
+  CHECK_RESULT(
+      validator_.OnAtomicRmw(GetLocation(), opcode, GetAlignment(align_log2)));
   istream_.Emit(opcode, kMemoryIndex0, offset);
   return Result::Ok;
 }
@@ -975,40 +978,40 @@ Result BinaryReaderInterp::OnAtomicRmwExpr(Opcode opcode,
 Result BinaryReaderInterp::OnAtomicRmwCmpxchgExpr(Opcode opcode,
                                                   Address align_log2,
                                                   Address offset) {
-  CHECK_RESULT(
-      validator_.OnAtomicRmwCmpxchg(loc, opcode, GetAlignment(align_log2)));
+  CHECK_RESULT(validator_.OnAtomicRmwCmpxchg(GetLocation(), opcode,
+                                             GetAlignment(align_log2)));
   istream_.Emit(opcode, kMemoryIndex0, offset);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnBinaryExpr(Opcode opcode) {
-  CHECK_RESULT(validator_.OnBinary(loc, opcode));
+  CHECK_RESULT(validator_.OnBinary(GetLocation(), opcode));
   istream_.Emit(opcode);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnBlockExpr(Type sig_type) {
-  CHECK_RESULT(validator_.OnBlock(loc, sig_type));
+  CHECK_RESULT(validator_.OnBlock(GetLocation(), sig_type));
   PushLabel();
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnLoopExpr(Type sig_type) {
-  CHECK_RESULT(validator_.OnLoop(loc, sig_type));
-  PushLabel(istream_.end());
+  CHECK_RESULT(validator_.OnLoop(GetLocation(), sig_type));
+  PushLabel(LabelKind::Block, istream_.end());
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnIfExpr(Type sig_type) {
-  CHECK_RESULT(validator_.OnIf(loc, sig_type));
+  CHECK_RESULT(validator_.OnIf(GetLocation(), sig_type));
   istream_.Emit(Opcode::InterpBrUnless);
   auto fixup = istream_.EmitFixupU32();
-  PushLabel(Istream::kInvalidOffset, fixup);
+  PushLabel(LabelKind::Block, Istream::kInvalidOffset, fixup);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnElseExpr() {
-  CHECK_RESULT(validator_.OnElse(loc));
+  CHECK_RESULT(validator_.OnElse(GetLocation()));
   Label* label = TopLabel();
   Istream::Offset fixup_cond_offset = label->fixup_offset;
   istream_.Emit(Opcode::Br);
@@ -1018,12 +1021,24 @@ Result BinaryReaderInterp::OnElseExpr() {
 }
 
 Result BinaryReaderInterp::OnEndExpr() {
+  if (reading_init_expr_ || label_stack_.size() == 1) {
+    return Result::Ok;
+  }
   SharedValidator::Label* label;
   CHECK_RESULT(validator_.GetLabel(0, &label));
   LabelType label_type = label->label_type;
-  CHECK_RESULT(validator_.OnEnd(loc));
+  CHECK_RESULT(validator_.OnEnd(GetLocation()));
   if (label_type == LabelType::If || label_type == LabelType::Else) {
     istream_.ResolveFixupU32(TopLabel()->fixup_offset);
+  } else if (label_type == LabelType::Try) {
+    // Catch-less try blocks need to fill in the handler description
+    // so that it can trigger an exception rethrow when it's reached.
+    Label* local_label = TopLabel();
+    HandlerDesc& desc = func_->handlers[local_label->handler_desc_index];
+    desc.try_end_offset = istream_.end();
+    assert(desc.catches.size() == 0);
+  } else if (label_type == LabelType::Catch) {
+    istream_.EmitCatchDrop(1);
   }
   FixupTopLabel();
   PopLabel();
@@ -1031,21 +1046,23 @@ Result BinaryReaderInterp::OnEndExpr() {
 }
 
 Result BinaryReaderInterp::OnBrExpr(Index depth) {
-  Index drop_count, keep_count;
+  Index drop_count, keep_count, catch_drop_count;
   CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count));
-  CHECK_RESULT(validator_.OnBr(loc, Var(depth)));
-  EmitBr(depth, drop_count, keep_count);
+  CHECK_RESULT(validator_.GetCatchCount(depth, &catch_drop_count));
+  CHECK_RESULT(validator_.OnBr(GetLocation(), Var(depth)));
+  EmitBr(depth, drop_count, keep_count, catch_drop_count);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnBrIfExpr(Index depth) {
-  Index drop_count, keep_count;
-  CHECK_RESULT(validator_.OnBrIf(loc, Var(depth)));
+  Index drop_count, keep_count, catch_drop_count;
+  CHECK_RESULT(validator_.OnBrIf(GetLocation(), Var(depth)));
   CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count));
+  CHECK_RESULT(validator_.GetCatchCount(depth, &catch_drop_count));
   // Flip the br_if so if <cond> is true it can drop values from the stack.
   istream_.Emit(Opcode::InterpBrUnless);
   auto fixup = istream_.EmitFixupU32();
-  EmitBr(depth, drop_count, keep_count);
+  EmitBr(depth, drop_count, keep_count, catch_drop_count);
   istream_.ResolveFixupU32(fixup);
   return Result::Ok;
 }
@@ -1053,32 +1070,38 @@ Result BinaryReaderInterp::OnBrIfExpr(Index depth) {
 Result BinaryReaderInterp::OnBrTableExpr(Index num_targets,
                                          Index* target_depths,
                                          Index default_target_depth) {
-  CHECK_RESULT(validator_.BeginBrTable(loc));
-  Index drop_count, keep_count;
+  CHECK_RESULT(validator_.BeginBrTable(GetLocation()));
+  Index drop_count, keep_count, catch_drop_count;
   istream_.Emit(Opcode::BrTable, num_targets);
 
   for (Index i = 0; i < num_targets; ++i) {
     Index depth = target_depths[i];
-    CHECK_RESULT(validator_.OnBrTableTarget(loc, Var(depth)));
+    CHECK_RESULT(validator_.OnBrTableTarget(GetLocation(), Var(depth)));
     CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count));
+    CHECK_RESULT(validator_.GetCatchCount(depth, &catch_drop_count));
     // Emit DropKeep directly (instead of using EmitDropKeep) so the
-    // instruction has a fixed size.
+    // instruction has a fixed size. Same for CatchDrop as well.
     istream_.Emit(Opcode::InterpDropKeep, drop_count, keep_count);
-    EmitBr(depth, 0, 0);
+    istream_.Emit(Opcode::InterpCatchDrop, catch_drop_count);
+    EmitBr(depth, 0, 0, 0);
   }
-  CHECK_RESULT(validator_.OnBrTableTarget(loc, Var(default_target_depth)));
+  CHECK_RESULT(
+      validator_.OnBrTableTarget(GetLocation(), Var(default_target_depth)));
   CHECK_RESULT(
       GetBrDropKeepCount(default_target_depth, &drop_count, &keep_count));
+  CHECK_RESULT(
+      validator_.GetCatchCount(default_target_depth, &catch_drop_count));
   // The default case doesn't need a fixed size, since it is never jumped over.
   istream_.EmitDropKeep(drop_count, keep_count);
-  EmitBr(default_target_depth, 0, 0);
+  istream_.Emit(Opcode::InterpCatchDrop, catch_drop_count);
+  EmitBr(default_target_depth, 0, 0, 0);
 
-  CHECK_RESULT(validator_.EndBrTable(loc));
+  CHECK_RESULT(validator_.EndBrTable(GetLocation()));
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnCallExpr(Index func_index) {
-  CHECK_RESULT(validator_.OnCall(loc, Var(func_index)));
+  CHECK_RESULT(validator_.OnCall(GetLocation(), Var(func_index)));
 
   if (func_index >= num_func_imports()) {
     istream_.Emit(Opcode::Call, func_index);
@@ -1091,8 +1114,8 @@ Result BinaryReaderInterp::OnCallExpr(Index func_index) {
 
 Result BinaryReaderInterp::OnCallIndirectExpr(Index sig_index,
                                               Index table_index) {
-  CHECK_RESULT(
-      validator_.OnCallIndirect(loc, Var(sig_index), Var(table_index)));
+  CHECK_RESULT(validator_.OnCallIndirect(GetLocation(), Var(sig_index),
+                                         Var(table_index)));
   istream_.Emit(Opcode::CallIndirect, table_index, sig_index);
   return Result::Ok;
 }
@@ -1100,16 +1123,23 @@ Result BinaryReaderInterp::OnCallIndirectExpr(Index sig_index,
 Result BinaryReaderInterp::OnReturnCallExpr(Index func_index) {
   FuncType& func_type = func_types_[func_index];
 
-  Index drop_count, keep_count;
+  Index drop_count, keep_count, catch_drop_count;
   CHECK_RESULT(
       GetReturnCallDropKeepCount(func_type, 0, &drop_count, &keep_count));
+  CHECK_RESULT(
+      validator_.GetCatchCount(label_stack_.size() - 1, &catch_drop_count));
   // The validator must be run after we get the drop/keep counts, since it
   // will change the type stack.
-  CHECK_RESULT(validator_.OnReturnCall(loc, Var(func_index)));
+  CHECK_RESULT(validator_.OnReturnCall(GetLocation(), Var(func_index)));
   istream_.EmitDropKeep(drop_count, keep_count);
+  istream_.EmitCatchDrop(catch_drop_count);
 
   if (func_index >= num_func_imports()) {
-    istream_.Emit(Opcode::Br, GetFuncOffset(func_index));
+    istream_.Emit(Opcode::InterpAdjustFrameForReturnCall, func_index);
+    istream_.Emit(Opcode::Br);
+    // We emit this separately to ensure that the fixup generated by
+    // GetFuncOffset comes after the Br opcode.
+    istream_.Emit(GetFuncOffset(func_index));
   } else {
     istream_.Emit(Opcode::InterpCallImport, func_index);
     istream_.Emit(Opcode::Return);
@@ -1122,75 +1152,108 @@ Result BinaryReaderInterp::OnReturnCallIndirectExpr(Index sig_index,
                                                     Index table_index) {
   FuncType& func_type = module_.func_types[sig_index];
 
-  Index drop_count, keep_count;
+  Index drop_count, keep_count, catch_drop_count;
   // +1 to include the index of the function.
   CHECK_RESULT(
       GetReturnCallDropKeepCount(func_type, +1, &drop_count, &keep_count));
+  CHECK_RESULT(
+      validator_.GetCatchCount(label_stack_.size() - 1, &catch_drop_count));
   // The validator must be run after we get the drop/keep counts, since it
   // changes the type stack.
-  CHECK_RESULT(
-      validator_.OnReturnCallIndirect(loc, Var(sig_index), Var(table_index)));
+  CHECK_RESULT(validator_.OnReturnCallIndirect(GetLocation(), Var(sig_index),
+                                               Var(table_index)));
   istream_.EmitDropKeep(drop_count, keep_count);
+  istream_.EmitCatchDrop(catch_drop_count);
   istream_.Emit(Opcode::ReturnCallIndirect, table_index, sig_index);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnCompareExpr(Opcode opcode) {
-  CHECK_RESULT(validator_.OnCompare(loc, opcode));
+  CHECK_RESULT(validator_.OnCompare(GetLocation(), opcode));
   istream_.Emit(opcode);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnConvertExpr(Opcode opcode) {
-  CHECK_RESULT(validator_.OnConvert(loc, opcode));
+  CHECK_RESULT(validator_.OnConvert(GetLocation(), opcode));
   istream_.Emit(opcode);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnDropExpr() {
-  CHECK_RESULT(validator_.OnDrop(loc));
+  CHECK_RESULT(validator_.OnDrop(GetLocation()));
   istream_.Emit(Opcode::Drop);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnI32ConstExpr(uint32_t value) {
-  CHECK_RESULT(validator_.OnConst(loc, Type::I32));
+  CHECK_RESULT(validator_.OnConst(GetLocation(), Type::I32));
+  if (reading_init_expr_) {
+    init_expr_.kind = InitExprKind::I32;
+    init_expr_.i32_ = value;
+    return Result::Ok;
+  }
   istream_.Emit(Opcode::I32Const, value);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnI64ConstExpr(uint64_t value) {
-  CHECK_RESULT(validator_.OnConst(loc, Type::I64));
+  CHECK_RESULT(validator_.OnConst(GetLocation(), Type::I64));
+  if (reading_init_expr_) {
+    init_expr_.kind = InitExprKind::I64;
+    init_expr_.i64_ = value;
+    return Result::Ok;
+  }
   istream_.Emit(Opcode::I64Const, value);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnF32ConstExpr(uint32_t value_bits) {
-  CHECK_RESULT(validator_.OnConst(loc, Type::F32));
+  CHECK_RESULT(validator_.OnConst(GetLocation(), Type::F32));
+  if (reading_init_expr_) {
+    init_expr_.kind = InitExprKind::F32;
+    init_expr_.f32_ = Bitcast<f32>(value_bits);
+    return Result::Ok;
+  }
   istream_.Emit(Opcode::F32Const, value_bits);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnF64ConstExpr(uint64_t value_bits) {
-  CHECK_RESULT(validator_.OnConst(loc, Type::F64));
+  CHECK_RESULT(validator_.OnConst(GetLocation(), Type::F64));
+  if (reading_init_expr_) {
+    init_expr_.kind = InitExprKind::F64;
+    init_expr_.f64_ = Bitcast<f64>(value_bits);
+    return Result::Ok;
+  }
   istream_.Emit(Opcode::F64Const, value_bits);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnV128ConstExpr(v128 value_bits) {
-  CHECK_RESULT(validator_.OnConst(loc, Type::V128));
+  CHECK_RESULT(validator_.OnConst(GetLocation(), Type::V128));
+  if (reading_init_expr_) {
+    init_expr_.kind = InitExprKind::V128;
+    init_expr_.v128_ = Bitcast<v128>(value_bits);
+    return Result::Ok;
+  }
   istream_.Emit(Opcode::V128Const, value_bits);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnGlobalGetExpr(Index global_index) {
-  CHECK_RESULT(validator_.OnGlobalGet(loc, Var(global_index)));
+  CHECK_RESULT(validator_.OnGlobalGet(GetLocation(), Var(global_index)));
+  if (reading_init_expr_) {
+    init_expr_.kind = InitExprKind::GlobalGet;
+    init_expr_.index_ = global_index;
+    return Result::Ok;
+  }
   istream_.Emit(Opcode::GlobalGet, global_index);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnGlobalSetExpr(Index global_index) {
-  CHECK_RESULT(validator_.OnGlobalSet(loc, Var(global_index)));
+  CHECK_RESULT(validator_.OnGlobalSet(GetLocation(), Var(global_index)));
   istream_.Emit(Opcode::GlobalSet, global_index);
   return Result::Ok;
 }
@@ -1205,7 +1268,7 @@ Result BinaryReaderInterp::OnLocalGetExpr(Index local_index) {
   // will update the type stack size. We need the index to be relative to the
   // old stack size.
   Index translated_local_index = TranslateLocalIndex(local_index);
-  CHECK_RESULT(validator_.OnLocalGet(loc, Var(local_index)));
+  CHECK_RESULT(validator_.OnLocalGet(GetLocation(), Var(local_index)));
   istream_.Emit(Opcode::LocalGet, translated_local_index);
   return Result::Ok;
 }
@@ -1213,104 +1276,121 @@ Result BinaryReaderInterp::OnLocalGetExpr(Index local_index) {
 Result BinaryReaderInterp::OnLocalSetExpr(Index local_index) {
   // See comment in OnLocalGetExpr above.
   Index translated_local_index = TranslateLocalIndex(local_index);
-  CHECK_RESULT(validator_.OnLocalSet(loc, Var(local_index)));
+  CHECK_RESULT(validator_.OnLocalSet(GetLocation(), Var(local_index)));
   istream_.Emit(Opcode::LocalSet, translated_local_index);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnLocalTeeExpr(Index local_index) {
-  CHECK_RESULT(validator_.OnLocalTee(loc, Var(local_index)));
+  CHECK_RESULT(validator_.OnLocalTee(GetLocation(), Var(local_index)));
   istream_.Emit(Opcode::LocalTee, TranslateLocalIndex(local_index));
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnLoadExpr(Opcode opcode,
+                                      Index memidx,
                                       Address align_log2,
                                       Address offset) {
-  CHECK_RESULT(validator_.OnLoad(loc, opcode, GetAlignment(align_log2)));
-  istream_.Emit(opcode, kMemoryIndex0, offset);
+  CHECK_RESULT(validator_.OnLoad(GetLocation(), opcode, Var(memidx),
+                                 GetAlignment(align_log2)));
+  istream_.Emit(opcode, memidx, offset);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnStoreExpr(Opcode opcode,
+                                       Index memidx,
                                        Address align_log2,
                                        Address offset) {
-  CHECK_RESULT(validator_.OnStore(loc, opcode, GetAlignment(align_log2)));
-  istream_.Emit(opcode, kMemoryIndex0, offset);
+  CHECK_RESULT(validator_.OnStore(GetLocation(), opcode, Var(memidx),
+                                  GetAlignment(align_log2)));
+  istream_.Emit(opcode, memidx, offset);
   return Result::Ok;
 }
 
-Result BinaryReaderInterp::OnMemoryGrowExpr() {
-  CHECK_RESULT(validator_.OnMemoryGrow(loc));
-  istream_.Emit(Opcode::MemoryGrow, kMemoryIndex0);
+Result BinaryReaderInterp::OnMemoryGrowExpr(Index memidx) {
+  CHECK_RESULT(validator_.OnMemoryGrow(GetLocation(), Var(memidx)));
+  istream_.Emit(Opcode::MemoryGrow, memidx);
   return Result::Ok;
 }
 
-Result BinaryReaderInterp::OnMemorySizeExpr() {
-  CHECK_RESULT(validator_.OnMemorySize(loc));
-  istream_.Emit(Opcode::MemorySize, kMemoryIndex0);
+Result BinaryReaderInterp::OnMemorySizeExpr(Index memidx) {
+  CHECK_RESULT(validator_.OnMemorySize(GetLocation(), Var(memidx)));
+  istream_.Emit(Opcode::MemorySize, memidx);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnTableGrowExpr(Index table_index) {
-  CHECK_RESULT(validator_.OnTableGrow(loc, Var(table_index)));
+  CHECK_RESULT(validator_.OnTableGrow(GetLocation(), Var(table_index)));
   istream_.Emit(Opcode::TableGrow, table_index);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnTableSizeExpr(Index table_index) {
-  CHECK_RESULT(validator_.OnTableSize(loc, Var(table_index)));
+  CHECK_RESULT(validator_.OnTableSize(GetLocation(), Var(table_index)));
   istream_.Emit(Opcode::TableSize, table_index);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnTableFillExpr(Index table_index) {
-  CHECK_RESULT(validator_.OnTableFill(loc, Var(table_index)));
+  CHECK_RESULT(validator_.OnTableFill(GetLocation(), Var(table_index)));
   istream_.Emit(Opcode::TableFill, table_index);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnRefFuncExpr(Index func_index) {
-  CHECK_RESULT(validator_.OnRefFunc(loc, Var(func_index)));
+  CHECK_RESULT(validator_.OnRefFunc(GetLocation(), Var(func_index)));
+  if (reading_init_expr_) {
+    init_expr_.kind = InitExprKind::RefFunc;
+    init_expr_.index_ = func_index;
+    return Result::Ok;
+  }
   istream_.Emit(Opcode::RefFunc, func_index);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnRefNullExpr(Type type) {
-  CHECK_RESULT(validator_.OnRefNull(loc, type));
+  CHECK_RESULT(validator_.OnRefNull(GetLocation(), type));
+  if (reading_init_expr_) {
+    init_expr_.kind = InitExprKind::RefNull;
+    init_expr_.type_ = type;
+    return Result::Ok;
+  }
   istream_.Emit(Opcode::RefNull);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnRefIsNullExpr() {
-  CHECK_RESULT(validator_.OnRefIsNull(loc));
+  CHECK_RESULT(validator_.OnRefIsNull(GetLocation()));
   istream_.Emit(Opcode::RefIsNull);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnNopExpr() {
-  CHECK_RESULT(validator_.OnNop(loc));
+  CHECK_RESULT(validator_.OnNop(GetLocation()));
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnReturnExpr() {
-  Index drop_count, keep_count;
+  Index drop_count, keep_count, catch_drop_count;
   CHECK_RESULT(GetReturnDropKeepCount(&drop_count, &keep_count));
-  CHECK_RESULT(validator_.OnReturn(loc));
+  CHECK_RESULT(
+      validator_.GetCatchCount(label_stack_.size() - 1, &catch_drop_count));
+  CHECK_RESULT(validator_.OnReturn(GetLocation()));
   istream_.EmitDropKeep(drop_count, keep_count);
+  istream_.EmitCatchDrop(catch_drop_count);
   istream_.Emit(Opcode::Return);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnSelectExpr(Index result_count,
                                         Type* result_types) {
-  CHECK_RESULT(validator_.OnSelect(loc, result_count, result_types));
+  CHECK_RESULT(validator_.OnSelect(GetLocation(), result_count, result_types));
   istream_.Emit(Opcode::Select);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnUnreachableExpr() {
-  CHECK_RESULT(validator_.OnUnreachable(loc));
+  CHECK_RESULT(validator_.OnUnreachable(GetLocation()));
   istream_.Emit(Opcode::Unreachable);
   return Result::Ok;
 }
@@ -1318,13 +1398,14 @@ Result BinaryReaderInterp::OnUnreachableExpr() {
 Result BinaryReaderInterp::OnAtomicWaitExpr(Opcode opcode,
                                             Address align_log2,
                                             Address offset) {
-  CHECK_RESULT(validator_.OnAtomicWait(loc, opcode, GetAlignment(align_log2)));
+  CHECK_RESULT(
+      validator_.OnAtomicWait(GetLocation(), opcode, GetAlignment(align_log2)));
   istream_.Emit(opcode, kMemoryIndex0, offset);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnAtomicFenceExpr(uint32_t consistency_model) {
-  CHECK_RESULT(validator_.OnAtomicFence(loc, consistency_model));
+  CHECK_RESULT(validator_.OnAtomicFence(GetLocation(), consistency_model));
   istream_.Emit(Opcode::AtomicFence, consistency_model);
   return Result::Ok;
 }
@@ -1332,76 +1413,185 @@ Result BinaryReaderInterp::OnAtomicFenceExpr(uint32_t consistency_model) {
 Result BinaryReaderInterp::OnAtomicNotifyExpr(Opcode opcode,
                                               Address align_log2,
                                               Address offset) {
-  CHECK_RESULT(
-      validator_.OnAtomicNotify(loc, opcode, GetAlignment(align_log2)));
+  CHECK_RESULT(validator_.OnAtomicNotify(GetLocation(), opcode,
+                                         GetAlignment(align_log2)));
   istream_.Emit(opcode, kMemoryIndex0, offset);
   return Result::Ok;
 }
 
-Result BinaryReaderInterp::OnMemoryCopyExpr() {
-  CHECK_RESULT(validator_.OnMemoryCopy(loc));
-  istream_.Emit(Opcode::MemoryCopy, kMemoryIndex0, kMemoryIndex0);
+Result BinaryReaderInterp::OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) {
+  CHECK_RESULT(
+      validator_.OnMemoryCopy(GetLocation(), Var(srcmemidx), Var(destmemidx)));
+  istream_.Emit(Opcode::MemoryCopy, srcmemidx, destmemidx);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnDataDropExpr(Index segment_index) {
-  CHECK_RESULT(validator_.OnDataDrop(loc, Var(segment_index)));
+  CHECK_RESULT(validator_.OnDataDrop(GetLocation(), Var(segment_index)));
   istream_.Emit(Opcode::DataDrop, segment_index);
   return Result::Ok;
 }
 
-Result BinaryReaderInterp::OnMemoryFillExpr() {
-  CHECK_RESULT(validator_.OnMemoryFill(loc));
-  istream_.Emit(Opcode::MemoryFill, kMemoryIndex0);
+Result BinaryReaderInterp::OnMemoryFillExpr(Index memidx) {
+  CHECK_RESULT(validator_.OnMemoryFill(GetLocation(), Var(memidx)));
+  istream_.Emit(Opcode::MemoryFill, memidx);
   return Result::Ok;
 }
 
-Result BinaryReaderInterp::OnMemoryInitExpr(Index segment_index) {
-  CHECK_RESULT(validator_.OnMemoryInit(loc, Var(segment_index)));
-  istream_.Emit(Opcode::MemoryInit, kMemoryIndex0, segment_index);
+Result BinaryReaderInterp::OnMemoryInitExpr(Index segment_index, Index memidx) {
+  CHECK_RESULT(
+      validator_.OnMemoryInit(GetLocation(), Var(segment_index), Var(memidx)));
+  istream_.Emit(Opcode::MemoryInit, memidx, segment_index);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnTableGetExpr(Index table_index) {
-  CHECK_RESULT(validator_.OnTableGet(loc, Var(table_index)));
+  CHECK_RESULT(validator_.OnTableGet(GetLocation(), Var(table_index)));
   istream_.Emit(Opcode::TableGet, table_index);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnTableSetExpr(Index table_index) {
-  CHECK_RESULT(validator_.OnTableSet(loc, Var(table_index)));
+  CHECK_RESULT(validator_.OnTableSet(GetLocation(), Var(table_index)));
   istream_.Emit(Opcode::TableSet, table_index);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnTableCopyExpr(Index dst_index, Index src_index) {
-  CHECK_RESULT(validator_.OnTableCopy(loc, Var(dst_index), Var(src_index)));
+  CHECK_RESULT(
+      validator_.OnTableCopy(GetLocation(), Var(dst_index), Var(src_index)));
   istream_.Emit(Opcode::TableCopy, dst_index, src_index);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnElemDropExpr(Index segment_index) {
-  CHECK_RESULT(validator_.OnElemDrop(loc, Var(segment_index)));
+  CHECK_RESULT(validator_.OnElemDrop(GetLocation(), Var(segment_index)));
   istream_.Emit(Opcode::ElemDrop, segment_index);
   return Result::Ok;
 }
 
 Result BinaryReaderInterp::OnTableInitExpr(Index segment_index,
                                            Index table_index) {
-  CHECK_RESULT(
-      validator_.OnTableInit(loc, Var(segment_index), Var(table_index)));
+  CHECK_RESULT(validator_.OnTableInit(GetLocation(), Var(segment_index),
+                                      Var(table_index)));
   istream_.Emit(Opcode::TableInit, table_index, segment_index);
   return Result::Ok;
 }
 
+Result BinaryReaderInterp::OnThrowExpr(Index tag_index) {
+  CHECK_RESULT(validator_.OnThrow(GetLocation(), Var(tag_index)));
+  istream_.Emit(Opcode::Throw, tag_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnRethrowExpr(Index depth) {
+  Index catch_depth;
+  CHECK_RESULT(validator_.OnRethrow(GetLocation(), Var(depth)));
+  CHECK_RESULT(validator_.GetCatchCount(depth, &catch_depth));
+  // The rethrow opcode takes an index into the exception stack rather than
+  // the number of catch nestings, so we subtract one here.
+  istream_.Emit(Opcode::Rethrow, catch_depth - 1);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnTryExpr(Type sig_type) {
+  u32 exn_stack_height;
+  CHECK_RESULT(
+      validator_.GetCatchCount(label_stack_.size() - 1, &exn_stack_height));
+  u32 value_stack_height = validator_.type_stack_size();
+  CHECK_RESULT(validator_.OnTry(GetLocation(), sig_type));
+  // Push a label that tracks mapping of exn -> catch
+  PushLabel(LabelKind::Try, Istream::kInvalidOffset, Istream::kInvalidOffset,
+            func_->handlers.size());
+  func_->handlers.push_back(HandlerDesc{HandlerKind::Catch,
+                                        istream_.end(),
+                                        Istream::kInvalidOffset,
+                                        {},
+                                        {Istream::kInvalidOffset},
+                                        value_stack_height,
+                                        exn_stack_height});
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnCatchExpr(Index tag_index) {
+  CHECK_RESULT(validator_.OnCatch(GetLocation(), Var(tag_index), false));
+  Label* label = TopLabel();
+  HandlerDesc& desc = func_->handlers[label->handler_desc_index];
+  desc.kind = HandlerKind::Catch;
+  // Drop the previous block's exception if it was a catch.
+  if (label->kind == LabelKind::Block) {
+    istream_.EmitCatchDrop(1);
+  }
+  // Jump to the end of the block at the end of the previous try or catch.
+  Istream::Offset offset = label->offset;
+  istream_.Emit(Opcode::Br);
+  assert(offset == Istream::kInvalidOffset);
+  depth_fixups_.Append(label_stack_.size() - 1, istream_.end());
+  istream_.Emit(offset);
+  // The offset is only set after the first catch block, as the offset range
+  // should only cover the try block itself.
+  if (desc.try_end_offset == Istream::kInvalidOffset) {
+    desc.try_end_offset = istream_.end();
+  }
+  // The label kind is switched to Block from Try in order to distinguish
+  // catch blocks from try blocks. This is used to ensure that a try-delegate
+  // inside this catch will not delegate to the catch, and instead find outer
+  // try blocks to use as a delegate target.
+  label->kind = LabelKind::Block;
+  desc.catches.push_back(CatchDesc{tag_index, istream_.end()});
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnCatchAllExpr() {
+  CHECK_RESULT(validator_.OnCatch(GetLocation(), Var(), true));
+  Label* label = TopLabel();
+  HandlerDesc& desc = func_->handlers[label->handler_desc_index];
+  desc.kind = HandlerKind::Catch;
+  if (label->kind == LabelKind::Block) {
+    istream_.EmitCatchDrop(1);
+  }
+  Istream::Offset offset = label->offset;
+  istream_.Emit(Opcode::Br);
+  assert(offset == Istream::kInvalidOffset);
+  depth_fixups_.Append(label_stack_.size() - 1, istream_.end());
+  istream_.Emit(offset);
+  if (desc.try_end_offset == Istream::kInvalidOffset) {
+    desc.try_end_offset = istream_.end();
+  }
+  label->kind = LabelKind::Block;
+  desc.catch_all_offset = istream_.end();
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnDelegateExpr(Index depth) {
+  CHECK_RESULT(validator_.OnDelegate(GetLocation(), Var(depth)));
+  Label* label = TopLabel();
+  assert(label->kind == LabelKind::Try);
+  HandlerDesc& desc = func_->handlers[label->handler_desc_index];
+  desc.kind = HandlerKind::Delegate;
+  Istream::Offset offset = label->offset;
+  istream_.Emit(Opcode::Br);
+  assert(offset == Istream::kInvalidOffset);
+  depth_fixups_.Append(label_stack_.size() - 1, istream_.end());
+  istream_.Emit(offset);
+  desc.try_end_offset = istream_.end();
+  Label* target_label = GetNearestTryLabel(depth + 1);
+  assert(target_label);
+  desc.delegate_handler_index = target_label->handler_desc_index;
+  FixupTopLabel();
+  PopLabel();
+  return Result::Ok;
+}
+
 }  // namespace
 
-Result ReadBinaryInterp(const void* data,
+Result ReadBinaryInterp(string_view filename,
+                        const void* data,
                         size_t size,
                         const ReadBinaryOptions& options,
                         Errors* errors,
                         ModuleDesc* out_module) {
-  BinaryReaderInterp reader(out_module, errors, options.features);
+  BinaryReaderInterp reader(out_module, filename, errors, options.features);
   return ReadBinary(data, size, &reader, options);
 }
 
index 0197e9aaa09eae5741ebc7dc2de99d18197969d0..82b946e797d373f36ae61144b724a77f81ab8bbb 100644 (file)
@@ -27,7 +27,8 @@ struct ReadBinaryOptions;
 
 namespace interp {
 
-Result ReadBinaryInterp(const void* data,
+Result ReadBinaryInterp(string_view filename,
+                        const void* data,
                         size_t size,
                         const ReadBinaryOptions& options,
                         Errors*,
index 4acccc0ba0da3cbe990fede17f043697c97dd039..49d856621e7401a3e126c1648edc930ed3dc0172 100644 (file)
@@ -127,10 +127,16 @@ inline ExportType& ExportType::operator=(const ExportType& other) {
 //// Frame ////
 inline Frame::Frame(Ref func,
                     u32 values,
+                    u32 exceptions,
                     u32 offset,
                     Instance* inst,
                     Module* mod)
-    : func(func), values(values), offset(offset), inst(inst), mod(mod) {}
+    : func(func),
+      values(values),
+      exceptions(exceptions),
+      offset(offset),
+      inst(inst),
+      mod(mod) {}
 
 //// FreeList ////
 template <typename T>
@@ -255,7 +261,7 @@ RefPtr<T>::RefPtr(const RefPtr<U>& other)
 
 template <typename T>
 template <typename U>
-RefPtr<T>& RefPtr<T>::operator=(const RefPtr<U>& other){
+RefPtr<T>& RefPtr<T>::operator=(const RefPtr<U>& other) {
   obj_ = other.obj_;
   store_ = other.store_;
   root_index_ = store_ ? store_->CopyRoot(other.root_index_) : 0;
@@ -360,7 +366,8 @@ template <> inline bool HasType<f32>(ValueType type) { return type == ValueType:
 template <> inline bool HasType<f64>(ValueType type) { return type == ValueType::F64; }
 template <> inline bool HasType<Ref>(ValueType type) { return IsReference(type); }
 
-template <typename T> void RequireType(ValueType type) {
+template <typename T>
+void RequireType(ValueType type) {
   assert(HasType<T>(type));
 }
 
@@ -460,6 +467,10 @@ inline const Features& Store::features() const {
   return features_;
 }
 
+inline std::set<Thread*>& Store::threads() {
+  return threads_;
+}
+
 //// Object ////
 // static
 inline bool Object::classof(const Object* obj) {
@@ -524,6 +535,25 @@ inline std::string Trap::message() const {
   return message_;
 }
 
+//// Exception ////
+// static
+inline bool Exception::classof(const Object* obj) {
+  return obj->kind() == skind;
+}
+
+// static
+inline Exception::Ptr Exception::New(Store& store, Ref tag, Values& args) {
+  return store.Alloc<Exception>(store, tag, args);
+}
+
+inline Ref Exception::tag() const {
+  return tag_;
+}
+
+inline Values& Exception::args() {
+  return args_;
+}
+
 //// Extern ////
 // static
 inline bool Extern::classof(const Object* obj) {
@@ -634,10 +664,8 @@ inline Memory::Ptr Memory::New(interp::Store& store, MemoryType type) {
 
 inline bool Memory::IsValidAccess(u64 offset, u64 addend, u64 size) const {
   // FIXME: make this faster.
-  return offset <= data_.size() &&
-         addend <= data_.size() &&
-         size <= data_.size() &&
-         offset + addend + size <= data_.size();
+  return offset <= data_.size() && addend <= data_.size() &&
+         size <= data_.size() && offset + addend + size <= data_.size();
 }
 
 inline bool Memory::IsValidAtomicAccess(u64 offset,
@@ -652,7 +680,8 @@ Result Memory::Load(u64 offset, u64 addend, T* out) const {
   if (!IsValidAccess(offset, addend, sizeof(T))) {
     return Result::Error;
   }
-  wabt::MemcpyEndianAware(out, data_.data(), sizeof(T), data_.size(), 0, offset + addend, sizeof(T));
+  wabt::MemcpyEndianAware(out, data_.data(), sizeof(T), data_.size(), 0,
+                          offset + addend, sizeof(T));
   return Result::Ok;
 }
 
@@ -660,7 +689,8 @@ template <typename T>
 T WABT_VECTORCALL Memory::UnsafeLoad(u64 offset, u64 addend) const {
   assert(IsValidAccess(offset, addend, sizeof(T)));
   T val;
-  wabt::MemcpyEndianAware(&val, data_.data(), sizeof(T), data_.size(), 0, offset + addend, sizeof(T));
+  wabt::MemcpyEndianAware(&val, data_.data(), sizeof(T), data_.size(), 0,
+                          offset + addend, sizeof(T));
   return val;
 }
 
@@ -669,7 +699,8 @@ Result WABT_VECTORCALL Memory::Store(u64 offset, u64 addend, T val) {
   if (!IsValidAccess(offset, addend, sizeof(T))) {
     return Result::Error;
   }
-  wabt::MemcpyEndianAware(data_.data(), &val, data_.size(), sizeof(T), offset + addend, 0, sizeof(T));
+  wabt::MemcpyEndianAware(data_.data(), &val, data_.size(), sizeof(T),
+                          offset + addend, 0, sizeof(T));
   return Result::Ok;
 }
 
@@ -678,7 +709,8 @@ Result Memory::AtomicLoad(u64 offset, u64 addend, T* out) const {
   if (!IsValidAtomicAccess(offset, addend, sizeof(T))) {
     return Result::Error;
   }
-  wabt::MemcpyEndianAware(out, data_.data(), sizeof(T), data_.size(), 0, offset + addend, sizeof(T));
+  wabt::MemcpyEndianAware(out, data_.data(), sizeof(T), data_.size(), 0,
+                          offset + addend, sizeof(T));
   return Result::Ok;
 }
 
@@ -687,7 +719,8 @@ Result Memory::AtomicStore(u64 offset, u64 addend, T val) {
   if (!IsValidAtomicAccess(offset, addend, sizeof(T))) {
     return Result::Error;
   }
-  wabt::MemcpyEndianAware(data_.data(), &val, data_.size(), sizeof(T), offset + addend, 0, sizeof(T));
+  wabt::MemcpyEndianAware(data_.data(), &val, data_.size(), sizeof(T),
+                          offset + addend, 0, sizeof(T));
   return Result::Ok;
 }
 
@@ -909,16 +942,6 @@ inline std::vector<DataSegment>& Instance::datas() {
 }
 
 //// Thread ////
-// static
-inline bool Thread::classof(const Object* obj) {
-  return obj->kind() == skind;
-}
-
-// static
-inline Thread::Ptr Thread::New(Store& store, const Options& options) {
-  return store.Alloc<Thread>(store, options);
-}
-
 inline Store& Thread::store() {
   return store_;
 }
index 25716b27454b20139676260f3b166ccf0beb9a2a..444a5ee598dcc1a901ec791c9d3f0342877b764d 100644 (file)
@@ -211,17 +211,19 @@ inline f64 WABT_VECTORCALL FloatAbs(f64 val) {
 template <>
 inline f32 WABT_VECTORCALL FloatCopysign(f32 lhs, f32 rhs) {
   return _mm_cvtss_f32(
-    _mm_or_ps(
-      _mm_and_ps(_mm_set1_ps(lhs), _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff))),
-      _mm_and_ps(_mm_set1_ps(rhs), _mm_castsi128_ps(_mm_set1_epi32(0x80000000)))));
+      _mm_or_ps(_mm_and_ps(_mm_set1_ps(lhs),
+                           _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff))),
+                _mm_and_ps(_mm_set1_ps(rhs),
+                           _mm_castsi128_ps(_mm_set1_epi32(0x80000000)))));
 }
 
 template <>
 inline f64 WABT_VECTORCALL FloatCopysign(f64 lhs, f64 rhs) {
-  return _mm_cvtsd_f64(
-    _mm_or_pd(
-      _mm_and_pd(_mm_set1_pd(lhs), _mm_castsi128_pd(_mm_set1_epi64x(0x7fffffffffffffffull))),
-      _mm_and_pd(_mm_set1_pd(rhs), _mm_castsi128_pd(_mm_set1_epi64x(0x8000000000000000ull)))));
+  return _mm_cvtsd_f64(_mm_or_pd(
+      _mm_and_pd(_mm_set1_pd(lhs),
+                 _mm_castsi128_pd(_mm_set1_epi64x(0x7fffffffffffffffull))),
+      _mm_and_pd(_mm_set1_pd(rhs),
+                 _mm_castsi128_pd(_mm_set1_epi64x(0x8000000000000000ull)))));
 }
 
 #else
index 001b2d900548d38d8c721b32cc3fc00847a50043..82895e672aac86d304f99e2ae873b7494c4a2d34 100644 (file)
@@ -55,6 +55,7 @@ std::string TypedValueToString(const TypedValue& tv) {
     case Type::ExternRef:
       return StringPrintf("externref:%" PRIzd, tv.value.Get<Ref>().index);
 
+    case Type::Reference:
     case Type::Func:
     case Type::Struct:
     case Type::Array:
index d05b34de2c2d81946f786c337d7bb7ef39b7724b..bc94abc26011a67e53ae1538f50b48f88b9d71aa 100644 (file)
@@ -47,4 +47,4 @@ void WriteCall(Stream* stream,
 }  // namespace interp
 }  // namespace wabt
 
-#endif // WABT_INTERP_UTIL_H_
+#endif  // WABT_INTERP_UTIL_H_
index 15d71250c75c8fccd41bad86fd49502849001dd3..61b6f71d064972b1426c5625dbadc024d055b6dc 100644 (file)
@@ -92,13 +92,13 @@ typedef struct __wasi_fdstat_t {
 static_assert(sizeof(__wasi_fdstat_t) == 24, "witx calculated size");
 static_assert(alignof(__wasi_fdstat_t) == 8, "witx calculated align");
 static_assert(offsetof(__wasi_fdstat_t, fs_filetype) == 0,
-               "witx calculated offset");
+              "witx calculated offset");
 static_assert(offsetof(__wasi_fdstat_t, fs_flags) == 2,
-               "witx calculated offset");
+              "witx calculated offset");
 static_assert(offsetof(__wasi_fdstat_t, fs_rights_base) == 8,
-               "witx calculated offset");
+              "witx calculated offset");
 static_assert(offsetof(__wasi_fdstat_t, fs_rights_inheriting) == 16,
-               "witx calculated offset");
+              "witx calculated offset");
 
 struct __wasi_iovec_t {
   __wasi_ptr_t buf;
@@ -141,17 +141,17 @@ static_assert(alignof(__wasi_filestat_t) == 8, "witx calculated align");
 static_assert(offsetof(__wasi_filestat_t, dev) == 0, "witx calculated offset");
 static_assert(offsetof(__wasi_filestat_t, ino) == 8, "witx calculated offset");
 static_assert(offsetof(__wasi_filestat_t, filetype) == 16,
-               "witx calculated offset");
+              "witx calculated offset");
 static_assert(offsetof(__wasi_filestat_t, nlink) == 24,
-               "witx calculated offset");
+              "witx calculated offset");
 static_assert(offsetof(__wasi_filestat_t, size) == 32,
-               "witx calculated offset");
+              "witx calculated offset");
 static_assert(offsetof(__wasi_filestat_t, atim) == 40,
-               "witx calculated offset");
+              "witx calculated offset");
 static_assert(offsetof(__wasi_filestat_t, mtim) == 48,
-               "witx calculated offset");
+              "witx calculated offset");
 static_assert(offsetof(__wasi_filestat_t, ctim) == 56,
-               "witx calculated offset");
+              "witx calculated offset");
 
 #define __WASI_ERRNO_SUCCESS (UINT16_C(0))
 #define __WASI_ERRNO_NOENT (UINT16_C(44))
@@ -194,8 +194,8 @@ class WasiInstance {
      *                                      __wasi_timestamp_t *time)
      */
     __wasi_timestamp_t t;
-    results[0].Set<u32>(
-        uvwasi_clock_time_get(uvwasi, params[0].Get<u32>(), params[1].Get<u64>(), &t));
+    results[0].Set<u32>(uvwasi_clock_time_get(uvwasi, params[0].Get<u32>(),
+                                              params[1].Get<u64>(), &t));
     uint32_t time_ptr = params[2].Get<u32>();
     CHECK_RESULT(writeValue<__wasi_timestamp_t>(t, time_ptr, trap));
     return Result::Ok;
@@ -231,9 +231,9 @@ class WasiInstance {
       trace_stream->Writef("path_open : %s\n", path);
     }
     uvwasi_fd_t outfd;
-    results[0].Set<u32>(
-        uvwasi_path_open(uvwasi, dirfd, dirflags, path, path_len, oflags,
-                         fs_rights_base, fs_rights_inherting, fs_flags, &outfd));
+    results[0].Set<u32>(uvwasi_path_open(
+        uvwasi, dirfd, dirflags, path, path_len, oflags, fs_rights_base,
+        fs_rights_inherting, fs_flags, &outfd));
     if (trace_stream) {
       trace_stream->Writef("path_open -> %d\n", results[0].Get<u32>());
     }
@@ -268,8 +268,8 @@ class WasiInstance {
         filestat_ptr, sizeof(__wasi_filestat_t), &filestat, trap));
     uvwasi_serdes_write_filestat_t(filestat, 0, &buf);
     if (trace_stream) {
-      trace_stream->Writef("path_filestat_get -> size=%" PRIu64 " %d\n", buf.st_size,
-                           results[0].Get<u32>());
+      trace_stream->Writef("path_filestat_get -> size=%" PRIu64 " %d\n",
+                           buf.st_size, results[0].Get<u32>());
     }
     return Result::Ok;
   }
@@ -395,8 +395,8 @@ class WasiInstance {
         filestat_ptr, sizeof(__wasi_filestat_t), &filestat, trap));
     uvwasi_serdes_write_filestat_t(filestat, 0, &buf);
     if (trace_stream) {
-      trace_stream->Writef("fd_filestat_get -> size=%" PRIu64 " %d\n", buf.st_size,
-                           results[0].Get<u32>());
+      trace_stream->Writef("fd_filestat_get -> size=%" PRIu64 " %d\n",
+                           buf.st_size, results[0].Get<u32>());
     }
     return Result::Ok;
   }
@@ -477,7 +477,8 @@ class WasiInstance {
           reinterpret_cast<const uint8_t**>(&iovs[i].buf), trap));
     }
     __wasi_ptr_t* out_addr;
-    CHECK_RESULT(getMemPtr<__wasi_ptr_t>(params[3].Get<u32>(), 1, &out_addr, trap));
+    CHECK_RESULT(
+        getMemPtr<__wasi_ptr_t>(params[3].Get<u32>(), 1, &out_addr, trap));
     results[0].Set<u32>(
         uvwasi_fd_write(uvwasi, fd, iovs.data(), iovs.size(), out_addr));
     return Result::Ok;
@@ -537,7 +538,8 @@ class WasiInstance {
     uvwasi_size_t environ_buf_size;
     uvwasi_environ_sizes_get(uvwasi, &environc, &environ_buf_size);
     CHECK_RESULT(writeValue<uint32_t>(environc, params[0].Get<u32>(), trap));
-    CHECK_RESULT(writeValue<uint32_t>(environ_buf_size, params[1].Get<u32>(), trap));
+    CHECK_RESULT(
+        writeValue<uint32_t>(environ_buf_size, params[1].Get<u32>(), trap));
     if (trace_stream) {
       trace_stream->Writef("environ_sizes_get -> %d %d\n", environc,
                            environ_buf_size);
@@ -573,7 +575,8 @@ class WasiInstance {
     uvwasi_size_t arg_buf_size;
     uvwasi_args_sizes_get(uvwasi, &argc, &arg_buf_size);
     CHECK_RESULT(writeValue<uint32_t>(argc, params[0].Get<u32>(), trap));
-    CHECK_RESULT(writeValue<uint32_t>(arg_buf_size, params[1].Get<u32>(), trap));
+    CHECK_RESULT(
+        writeValue<uint32_t>(arg_buf_size, params[1].Get<u32>(), trap));
     if (trace_stream) {
       trace_stream->Writef("args_sizes_get -> %d %d\n", argc, arg_buf_size);
     }
index 2edc17d9ab9ba77bf154a788e3d1061497cc096b..bc3ba157103ca0c12abba1e213f57058fc15d559 100644 (file)
@@ -48,7 +48,7 @@ static std::unique_ptr<FileStream> s_stdout_stream;
 static ValueType ToWabtValueType(wasm_valkind_t);
 static wasm_valkind_t FromWabtValueType(ValueType);
 
-static wasm_externkind_t FromWabtExternKind(ExternKind );
+static wasm_externkind_t FromWabtExternKind(ExternKind);
 
 static ValueTypes ToWabtValueTypes(const wasm_valtype_vec_t* types);
 static void FromWabtValueTypes(const ValueTypes&, wasm_valtype_vec_t* out);
@@ -81,17 +81,17 @@ struct wasm_valtype_t {
 struct wasm_externtype_t {
   static std::unique_ptr<wasm_externtype_t> New(std::unique_ptr<ExternType>);
 
-  std::unique_ptr<wasm_externtype_t> Clone() const {
-    return New(I->Clone());
-  }
+  std::unique_ptr<wasm_externtype_t> Clone() const { return New(I->Clone()); }
 
   virtual ~wasm_externtype_t() {}
 
   wasm_externtype_t(const wasm_externtype_t& other) = delete;
-  wasm_externtype_t& operator=(const wasm_externtype_t& other)  = delete;
+  wasm_externtype_t& operator=(const wasm_externtype_t& other) = delete;
 
   template <typename T>
-  T* As() const { return cast<T>(I.get()); }
+  T* As() const {
+    return cast<T>(I.get());
+  }
 
   std::unique_ptr<ExternType> I;
 
@@ -251,7 +251,9 @@ struct wasm_ref_t {
   wasm_ref_t(RefPtr<Object> ptr) : I(ptr) {}
 
   template <typename T>
-  T* As() const { return cast<T>(I.get()); }
+  T* As() const {
+    return cast<T>(I.get());
+  }
 
   RefPtr<Object> I;
 };
@@ -285,9 +287,7 @@ struct wasm_module_t : wasm_ref_t {
     return *this;
   }
 
-  ~wasm_module_t() {
-    wasm_byte_vec_delete(&binary);
-  }
+  ~wasm_module_t() { wasm_byte_vec_delete(&binary); }
   // TODO: This is used for wasm_module_serialize/wasm_module_deserialize.
   // Currently the standard wasm binary bytes are cached here, but it would be
   // better to have a serialization of ModuleDesc instead.
@@ -537,21 +537,21 @@ static void print_sig(const FuncType& sig) {
 #ifndef NDEBUG
   fprintf(stderr, "(");
   bool first = true;
-  for (auto Type : sig.params) {
+  for (auto type : sig.params) {
     if (!first) {
       fprintf(stderr, ", ");
     }
     first = false;
-    fprintf(stderr, "%s", Type.GetName());
+    fprintf(stderr, "%s", type.GetName().c_str());
   }
   fprintf(stderr, ") -> (");
   first = true;
-  for (auto Type : sig.results) {
+  for (auto type : sig.results) {
     if (!first) {
       fprintf(stderr, ", ");
     }
     first = false;
-    fprintf(stderr, "%s", Type.GetName());
+    fprintf(stderr, "%s", type.GetName().c_str());
   }
   fprintf(stderr, ")\n");
 #endif
@@ -637,8 +637,8 @@ own wasm_module_t* wasm_module_new(wasm_store_t* store,
                                    const wasm_byte_vec_t* binary) {
   Errors errors;
   ModuleDesc module_desc;
-  if (Failed(ReadBinaryInterp(binary->data, binary->size, GetOptions(), &errors,
-                              &module_desc))) {
+  if (Failed(ReadBinaryInterp("<internal>", binary->data, binary->size,
+                              GetOptions(), &errors, &module_desc))) {
     FormatErrorsToFile(errors, Location::Type::Binary);
     return nullptr;
   }
index 05a40bd407d310d45565a9d825dbc312d5aa8690..bd9fbb2ccdc12da8f847cdf69d758d1f35df9988 100644 (file)
@@ -31,7 +31,7 @@ const char* GetName(Mutability mut) {
   return kNames[int(mut)];
 }
 
-const char* GetName(ValueType type) {
+const std::string GetName(ValueType type) {
   return type.GetName();
 }
 
@@ -105,9 +105,9 @@ Result Match(const TableType& expected,
              const TableType& actual,
              std::string* out_msg) {
   if (expected.element != actual.element) {
-    *out_msg =
-        StringPrintf("type mismatch in imported table, expected %s but got %s.",
-                     GetName(expected.element), GetName(actual.element));
+    *out_msg = StringPrintf(
+        "type mismatch in imported table, expected %s but got %s.",
+        GetName(expected.element).c_str(), GetName(actual.element).c_str());
     return Result::Error;
   }
 
@@ -149,7 +149,7 @@ Result Match(const GlobalType& expected,
        !TypesMatch(expected.type, actual.type))) {
     *out_msg = StringPrintf(
         "type mismatch in imported global, expected %s but got %s.",
-        GetName(expected.type), GetName(actual.type));
+        GetName(expected.type).c_str(), GetName(actual.type).c_str());
     return Result::Error;
   }
 
@@ -164,7 +164,12 @@ std::unique_ptr<ExternType> TagType::Clone() const {
 Result Match(const TagType& expected,
              const TagType& actual,
              std::string* out_msg) {
-  // TODO signature
+  if (expected.signature != actual.signature) {
+    if (out_msg) {
+      *out_msg = "signature mismatch in imported tag";
+    }
+    return Result::Error;
+  }
   return Result::Ok;
 }
 
@@ -251,6 +256,10 @@ void Store::Collect() {
     }
   }
 
+  for (auto thread : threads_) {
+    thread->Mark();
+  }
+
   // TODO: better GC algo.
   // Loop through all newly marked objects and mark their referents.
   std::vector<bool> all_marked(object_count, false);
@@ -279,7 +288,7 @@ void Store::Mark(Ref ref) {
 }
 
 void Store::Mark(const RefVec& refs) {
-  for (auto&& ref: refs) {
+  for (auto&& ref : refs) {
     Mark(ref);
   }
 }
@@ -313,6 +322,21 @@ void Trap::Mark(Store& store) {
   }
 }
 
+//// Exception ////
+Exception::Exception(Store& store, Ref tag, Values& args)
+    : Object(skind), tag_(tag), args_(args) {}
+
+void Exception::Mark(Store& store) {
+  Tag::Ptr tag(store, tag_);
+  store.Mark(tag_);
+  ValueTypes params = tag->type().signature;
+  for (size_t i = 0; i < params.size(); i++) {
+    if (params[i].IsRef()) {
+      store.Mark(args_[i].Get<Ref>());
+    }
+  }
+}
+
 //// Extern ////
 template <typename T>
 Result Extern::MatchImpl(Store& store,
@@ -346,10 +370,8 @@ Result Func::Call(Store& store,
                   Values& results,
                   Trap::Ptr* out_trap,
                   Stream* trace_stream) {
-  Thread::Options options;
-  options.trace_stream = trace_stream;
-  Thread::Ptr thread = Thread::New(store, options);
-  return DoCall(*thread, params, results, out_trap);
+  Thread thread(store, trace_stream);
+  return DoCall(thread, params, results, out_trap);
 }
 
 Result Func::Call(Thread& thread,
@@ -386,6 +408,11 @@ Result DefinedFunc::DoCall(Thread& thread,
   result = thread.Run(out_trap);
   if (result == RunResult::Trap) {
     return Result::Error;
+  } else if (result == RunResult::Exception) {
+    // While this is not actually a trap, it is a convenient way
+    // to report an uncaught exception.
+    *out_trap = Trap::New(thread.store(), "uncaught exception");
+    return Result::Error;
   }
   thread.PopValues(type_.results, &results);
   return Result::Ok;
@@ -456,6 +483,9 @@ Result Table::Grow(Store& store, u32 count, Ref ref) {
   u32 new_size;
   if (store.HasValueType(ref, type_.element) &&
       CanGrow<u32>(type_.limits, old_size, count, &new_size)) {
+    // Grow the limits of the table too, so that if it is used as an
+    // import to another module its new size is honored.
+    type_.limits.initial += count;
     elements_.resize(new_size);
     Fill(store, old_size, ref, new_size - old_size);
     return Result::Ok;
@@ -464,8 +494,7 @@ Result Table::Grow(Store& store, u32 count, Ref ref) {
 }
 
 Result Table::Fill(Store& store, u32 offset, Ref ref, u32 size) {
-  if (IsValidRange(offset, size) &&
-      store.HasValueType(ref, type_.element)) {
+  if (IsValidRange(offset, size) && store.HasValueType(ref, type_.element)) {
     std::fill(elements_.begin() + offset, elements_.begin() + offset + size,
               ref);
     return Result::Ok;
@@ -529,6 +558,9 @@ Result Memory::Match(class Store& store,
 Result Memory::Grow(u64 count) {
   u64 new_pages;
   if (CanGrow<u64>(type_.limits, pages_, count, &new_pages)) {
+    // Grow the limits of the memory too, so that if it is used as an
+    // import to another module its new size is honored.
+    type_.limits.initial += count;
 #if WABT_BIG_ENDIAN
     auto old_size = data_.size();
 #endif
@@ -700,11 +732,11 @@ bool DataSegment::IsValidRange(u64 offset, u64 size) const {
 //// Module ////
 Module::Module(Store&, ModuleDesc desc)
     : Object(skind), desc_(std::move(desc)) {
-  for (auto&& import: desc_.imports) {
+  for (auto&& import : desc_.imports) {
     import_types_.emplace_back(import.type);
   }
 
-  for (auto&& export_: desc_.exports) {
+  for (auto&& export_ : desc_.exports) {
     export_types_.emplace_back(export_.type);
   }
 }
@@ -790,7 +822,7 @@ Instance::Ptr Instance::Instantiate(Store& store,
   }
 
   // Exports.
-  for (auto&& desc : mod->desc().exports){
+  for (auto&& desc : mod->desc().exports) {
     Ref ref;
     switch (desc.type.type->kind) {
       case ExternKind::Func:   ref = inst->funcs_[desc.index]; break;
@@ -864,12 +896,11 @@ Instance::Ptr Instance::Instantiate(Store& store,
 
         if (Failed(result)) {
           *out_trap = Trap::New(
-              store,
-              StringPrintf("out of bounds memory access: data segment is "
-                           "out of bounds: [%" PRIu64 ", %" PRIu64
-                           ") >= max value %"
-                           PRIu64, offset, offset + segment.size(),
-                           memory->ByteSize()));
+              store, StringPrintf(
+                         "out of bounds memory access: data segment is "
+                         "out of bounds: [%" PRIu64 ", %" PRIu64
+                         ") >= max value %" PRIu64,
+                         offset, offset + segment.size(), memory->ByteSize()));
           return {};
         }
       } else if (desc.mode == SegmentMode::Declared) {
@@ -905,23 +936,30 @@ void Instance::Mark(Store& store) {
 }
 
 //// Thread ////
-Thread::Thread(Store& store, const Options& options)
-    : Object(skind), store_(store) {
+Thread::Thread(Store& store, Stream* trace_stream)
+    : store_(store), trace_stream_(trace_stream) {
+  store.threads().insert(this);
+
+  Thread::Options options;
   frames_.reserve(options.call_stack_size);
   values_.reserve(options.value_stack_size);
-  trace_stream_ = options.trace_stream;
-  if (options.trace_stream) {
+  if (trace_stream) {
     trace_source_ = MakeUnique<TraceSource>(this);
   }
 }
 
-void Thread::Mark(Store& store) {
+Thread::~Thread() {
+  store_.threads().erase(this);
+}
+
+void Thread::Mark() {
   for (auto&& frame : frames_) {
-    frame.Mark(store);
+    frame.Mark(store_);
   }
-  for (auto index: refs_) {
-    store.Mark(values_[index].Get<Ref>());
+  for (auto index : refs_) {
+    store_.Mark(values_[index].Get<Ref>());
   }
+  store_.Mark(exceptions_);
 }
 
 void Thread::PushValues(const ValueTypes& types, const Values& values) {
@@ -949,7 +987,8 @@ Instance* Thread::GetCallerInstance() {
 
 RunResult Thread::PushCall(Ref func, u32 offset, Trap::Ptr* out_trap) {
   TRAP_IF(frames_.size() == frames_.capacity(), "call stack exhausted");
-  frames_.emplace_back(func, values_.size(), offset, inst_, mod_);
+  frames_.emplace_back(func, values_.size(), exceptions_.size(), offset, inst_,
+                       mod_);
   return RunResult::Ok;
 }
 
@@ -957,8 +996,8 @@ RunResult Thread::PushCall(const DefinedFunc& func, Trap::Ptr* out_trap) {
   TRAP_IF(frames_.size() == frames_.capacity(), "call stack exhausted");
   inst_ = store_.UnsafeGet<Instance>(func.instance()).get();
   mod_ = store_.UnsafeGet<Module>(inst_->module()).get();
-  frames_.emplace_back(func.self(), values_.size(), func.desc().code_offset,
-                       inst_, mod_);
+  frames_.emplace_back(func.self(), values_.size(), exceptions_.size(),
+                       func.desc().code_offset, inst_, mod_);
   return RunResult::Ok;
 }
 
@@ -966,11 +1005,15 @@ RunResult Thread::PushCall(const HostFunc& func, Trap::Ptr* out_trap) {
   TRAP_IF(frames_.size() == frames_.capacity(), "call stack exhausted");
   inst_ = nullptr;
   mod_ = nullptr;
-  frames_.emplace_back(func.self(), values_.size(), 0, inst_, mod_);
+  frames_.emplace_back(func.self(), values_.size(), exceptions_.size(), 0,
+                       inst_, mod_);
   return RunResult::Ok;
 }
 
 RunResult Thread::PopCall() {
+  // Sanity check that the exception stack was popped correctly.
+  assert(frames_.back().exceptions == exceptions_.size());
+
   frames_.pop_back();
   if (frames_.empty()) {
     return RunResult::Return;
@@ -1011,7 +1054,7 @@ RunResult Thread::Run(Trap::Ptr* out_trap) {
 
 RunResult Thread::Run(int num_instructions, Trap::Ptr* out_trap) {
   DefinedFunc::Ptr func{store_, frames_.back().func};
-  for (;num_instructions > 0; --num_instructions) {
+  for (; num_instructions > 0; --num_instructions) {
     auto result = StepInternal(out_trap);
     if (result != RunResult::Ok) {
       return result;
@@ -1408,6 +1451,24 @@ RunResult Thread::StepInternal(Trap::Ptr* out_trap) {
       break;
     }
 
+    case O::InterpCatchDrop: {
+      auto drop = instr.imm_u32;
+      for (u32 i = 0; i < drop; i++) {
+        exceptions_.pop_back();
+      }
+      break;
+    }
+
+    // This operation adjusts the function reference of the reused frame
+    // after a return_call. This ensures the correct exception handlers are
+    // used for the call.
+    case O::InterpAdjustFrameForReturnCall: {
+      Ref new_func_ref = inst_->funcs()[instr.imm_u32];
+      Frame& current_frame = frames_.back();
+      current_frame.func = new_func_ref;
+      break;
+    }
+
     case O::I32TruncSatF32S: return DoUnop(IntTruncSat<s32, f32>);
     case O::I32TruncSatF32U: return DoUnop(IntTruncSat<u32, f32>);
     case O::I32TruncSatF64S: return DoUnop(IntTruncSat<s32, f64>);
@@ -1780,6 +1841,22 @@ RunResult Thread::StepInternal(Trap::Ptr* out_trap) {
     case O::I64AtomicRmw16CmpxchgU: return DoAtomicRmwCmpxchg<u64, u16>(instr, out_trap);
     case O::I64AtomicRmw32CmpxchgU: return DoAtomicRmwCmpxchg<u64, u32>(instr, out_trap);
 
+    case O::Throw: {
+      u32 tag_index = instr.imm_u32;
+      Values params;
+      Ref tag_ref = inst_->tags()[tag_index];
+      Tag::Ptr tag{store_, tag_ref};
+      PopValues(tag->type().signature, &params);
+      Exception::Ptr exn = Exception::New(store_, tag_ref, params);
+      return DoThrow(exn);
+    }
+    case O::Rethrow: {
+      u32 exn_index = instr.imm_u32;
+      Exception::Ptr exn{store_,
+                         exceptions_[exceptions_.size() - exn_index - 1]};
+      return DoThrow(exn);
+    }
+
     // The following opcodes are either never generated or should never be
     // executed.
     case O::Nop:
@@ -1796,8 +1873,6 @@ RunResult Thread::StepInternal(Trap::Ptr* out_trap) {
     case O::Catch:
     case O::CatchAll:
     case O::Delegate:
-    case O::Throw:
-    case O::Rethrow:
     case O::InterpData:
     case O::Invalid:
       WABT_UNREACHABLE;
@@ -2238,8 +2313,7 @@ RunResult Thread::DoSimdShuffle(Instr instr) {
   auto lhs = Pop<S>();
   S result;
   for (u8 i = 0; i < S::lanes; ++i) {
-    result[i] =
-        sel[i] < S::lanes ? lhs[sel[i]] : rhs[sel[i] - S::lanes];
+    result[i] = sel[i] < S::lanes ? lhs[sel[i]] : rhs[sel[i] - S::lanes];
   }
   Push(result);
   return RunResult::Ok;
@@ -2309,7 +2383,7 @@ RunResult Thread::DoSimdExtaddPairwise() {
   using U = typename S::LaneType;
   for (u8 i = 0; i < S::lanes; ++i) {
     u8 laneidx = i * 2;
-    result[i] = U(val[laneidx]) + U(val[laneidx+1]);
+    result[i] = U(val[laneidx]) + U(val[laneidx + 1]);
   }
   Push(result);
   return RunResult::Ok;
@@ -2324,7 +2398,7 @@ RunResult Thread::DoSimdDot() {
   for (u8 i = 0; i < S::lanes; ++i) {
     u8 laneidx = i * 2;
     SL lo = SL(lhs[laneidx]) * SL(rhs[laneidx]);
-    SL hi = SL(lhs[laneidx+1]) * SL(rhs[laneidx+1]);
+    SL hi = SL(lhs[laneidx + 1]) * SL(rhs[laneidx + 1]);
     result[i] = Add(lo, hi);
   }
   Push(result);
@@ -2384,6 +2458,96 @@ RunResult Thread::DoAtomicRmwCmpxchg(Instr instr, Trap::Ptr* out_trap) {
   return RunResult::Ok;
 }
 
+RunResult Thread::DoThrow(Exception::Ptr exn) {
+  Istream::Offset target_offset = Istream::kInvalidOffset;
+  u32 target_values, target_exceptions;
+  Tag::Ptr exn_tag{store_, exn->tag()};
+  bool popped_frame = false;
+  bool had_catch_all = false;
+
+  // DoThrow is responsible for unwinding the stack at the point at which an
+  // exception is thrown, and also branching to the appropriate catch within
+  // the target try-catch. In a compiler, the tag dispatch might be done in
+  // generated code in a landing pad, but this is easier for the interpreter.
+  while (!frames_.empty()) {
+    const Frame& frame = frames_.back();
+    DefinedFunc::Ptr func{store_, frame.func};
+    u32 pc = frame.offset;
+    auto handlers = func->desc().handlers;
+
+    // We iterate in reverse order, in order to traverse handlers from most
+    // specific (pushed last) to least specific within a nested stack of
+    // try-catch blocks.
+    auto iter = handlers.rbegin();
+    while (iter != handlers.rend()) {
+      const HandlerDesc& handler = *iter;
+      if (pc >= handler.try_start_offset && pc < handler.try_end_offset) {
+        // For a try-delegate, skip part of the traversal by directly going
+        // up to an outer handler specified by the delegate depth.
+        if (handler.kind == HandlerKind::Delegate) {
+          // Subtract one as we're trying to get a reverse iterator that is
+          // offset by `delegate_handler_index` from the first item.
+          iter = handlers.rend() - handler.delegate_handler_index - 1;
+          continue;
+        }
+        // Otherwise, check for a matching catch tag or catch_all.
+        for (auto _catch : handler.catches) {
+          // Here we have to be careful to use the target frame's instance
+          // to look up the tag rather than the throw's instance.
+          Ref catch_tag_ref = frame.inst->tags()[_catch.tag_index];
+          Tag::Ptr catch_tag{store_, catch_tag_ref};
+          if (exn_tag == catch_tag) {
+            target_offset = _catch.offset;
+            target_values = (*iter).values;
+            target_exceptions = (*iter).exceptions;
+            goto found_handler;
+          }
+        }
+        if (handler.catch_all_offset != Istream::kInvalidOffset) {
+          target_offset = handler.catch_all_offset;
+          target_values = (*iter).values;
+          target_exceptions = (*iter).exceptions;
+          had_catch_all = true;
+          goto found_handler;
+        }
+      }
+      iter++;
+    }
+    frames_.pop_back();
+    popped_frame = true;
+  }
+
+  // If the call frames are empty now, the exception is uncaught.
+  assert(frames_.empty());
+  return RunResult::Exception;
+
+found_handler:
+  assert(target_offset != Istream::kInvalidOffset);
+
+  Frame& target_frame = frames_.back();
+  // If the throw crosses call frames, we need to reset the state to that
+  // call frame's values. The stack heights may need to be offset by the
+  // handler's heights as we may be jumping into the middle of the function
+  // code after some stack height changes.
+  if (popped_frame) {
+    inst_ = target_frame.inst;
+    mod_ = target_frame.mod;
+  }
+  values_.resize(target_frame.values + target_values);
+  exceptions_.resize(target_frame.exceptions + target_exceptions);
+  // Jump to the handler.
+  target_frame.offset = target_offset;
+  // When an exception is caught, it needs to be tracked in a stack
+  // to allow for rethrows. This stack is popped on leaving the try-catch
+  // or by control instructions such as `br`.
+  exceptions_.push_back(exn.ref());
+  // Also push exception payload values if applicable.
+  if (!had_catch_all) {
+    PushValues(exn_tag->type().signature, exn->args());
+  }
+  return RunResult::Ok;
+}
+
 Thread::TraceSource::TraceSource(Thread* thread) : thread_(thread) {}
 
 std::string Thread::TraceSource::Header(Istream::Offset offset) {
@@ -2406,8 +2570,8 @@ std::string Thread::TraceSource::Pick(Index index, Instr instr) {
     }
   }
   auto type = index > num_operands
-    ? Type(ValueType::Void)
-    : instr.op.GetParamType(num_operands - index + 1);
+                  ? Type(ValueType::Void)
+                  : instr.op.GetParamType(num_operands - index + 1);
   if (type == ValueType::Void) {
     // Void should never be displayed normally; we only expect to see it when
     // the stack may have different a different type. This is likely to occur
index 328f3b71ac7e925b1b66bcc2b50d217ae2566899..270228f568f02d9c9414e48b78288e6864a45995 100644 (file)
@@ -20,6 +20,7 @@
 #include <cstdint>
 #include <functional>
 #include <memory>
+#include <set>
 #include <string>
 #include <type_traits>
 #include <vector>
@@ -44,7 +45,8 @@ class ElemSegment;
 class Module;
 class Instance;
 class Thread;
-template <typename T> class RefPtr;
+template <typename T>
+class RefPtr;
 
 using s8 = int8_t;
 using u8 = uint8_t;
@@ -63,8 +65,10 @@ using Buffer = std::vector<u8>;
 using ValueType = wabt::Type;
 using ValueTypes = std::vector<ValueType>;
 
-template <typename T> bool HasType(ValueType);
-template <typename T> void RequireType(ValueType);
+template <typename T>
+bool HasType(ValueType);
+template <typename T>
+void RequireType(ValueType);
 bool IsReference(ValueType);
 bool TypesMatch(ValueType expected, ValueType actual);
 
@@ -78,6 +82,7 @@ enum class ObjectKind {
   Null,
   Foreign,
   Trap,
+  Exception,
   DefinedFunc,
   HostFunc,
   Table,
@@ -86,11 +91,10 @@ enum class ObjectKind {
   Tag,
   Module,
   Instance,
-  Thread,
 };
 
 const char* GetName(Mutability);
-const char* GetName(ValueType);
+const std::string GetName(ValueType);
 const char* GetName(ExternKind);
 const char* GetName(ObjectKind);
 
@@ -141,13 +145,13 @@ struct Simd {
 
   inline T& operator[](u8 idx) {
 #if WABT_BIG_ENDIAN
-    idx = (~idx) & (L-1);
+    idx = (~idx) & (L - 1);
 #endif
     return v[idx];
   }
   inline T operator[](u8 idx) const {
 #if WABT_BIG_ENDIAN
-    idx = (~idx) & (L-1);
+    idx = (~idx) & (L - 1);
 #endif
     return v[idx];
   }
@@ -305,6 +309,32 @@ struct LocalDesc {
   u32 end;
 };
 
+// Metadata for representing exception handlers associated with a function's
+// code. This is needed to look up exceptions from call frames from interpreter
+// instructions.
+struct CatchDesc {
+  Index tag_index;
+  u32 offset;
+};
+
+// Handlers for a catch-less `try` or `try-catch` block are included in the
+// Catch kind. `try-delegate` instructions create a Delegate handler.
+enum class HandlerKind { Catch, Delegate };
+
+struct HandlerDesc {
+  HandlerKind kind;
+  u32 try_start_offset;
+  u32 try_end_offset;
+  std::vector<CatchDesc> catches;
+  union {
+    u32 catch_all_offset;
+    u32 delegate_handler_index;
+  };
+  // Local stack heights at the handler site that need to be restored.
+  u32 values;
+  u32 exceptions;
+};
+
 struct FuncDesc {
   // Includes params.
   ValueType GetLocalType(Index) const;
@@ -312,6 +342,7 @@ struct FuncDesc {
   FuncType type;
   std::vector<LocalDesc> locals;
   u32 code_offset;
+  std::vector<HandlerDesc> handlers;
 };
 
 struct TableDesc {
@@ -378,13 +409,19 @@ struct ModuleDesc {
 //// Runtime ////
 
 struct Frame {
-  explicit Frame(Ref func, u32 values, u32 offset, Instance*, Module*);
+  explicit Frame(Ref func,
+                 u32 values,
+                 u32 exceptions,
+                 u32 offset,
+                 Instance*,
+                 Module*);
 
   void Mark(Store&);
 
   Ref func;
-  u32 values;  // Height of the value stack at this activation.
-  u32 offset;  // Istream offset; either the return PC, or the current PC.
+  u32 values;      // Height of the value stack at this activation.
+  u32 exceptions;  // Height of the exception stack at this activation.
+  u32 offset;      // Istream offset; either the return PC, or the current PC.
 
   // Cached for convenience. Both are null if func is a HostFunc.
   Instance* inst;
@@ -405,8 +442,8 @@ class FreeList {
   const T& Get(Index) const;
   T& Get(Index);
 
-  Index size() const;  // 1 greater than the maximum index.
-  Index count() const; // The number of used elements.
+  Index size() const;   // 1 greater than the maximum index.
+  Index count() const;  // The number of used elements.
 
  private:
   // TODO: Optimize memory layout? We could probably store all of this
@@ -461,12 +498,17 @@ class Store {
   ObjectList::Index object_count() const;
 
   const Features& features() const;
+  void setFeatures(const Features& features) { features_ = features; }
+
+  std::set<Thread*>& threads();
 
  private:
   template <typename T>
   friend class RefPtr;
 
   Features features_;
+  // This set contains the currently active Thread objects.
+  std::set<Thread*> threads_;
   ObjectList objects_;
   RootList roots_;
   std::vector<bool> marks_;
@@ -646,6 +688,27 @@ class Trap : public Object {
   std::vector<Frame> trace_;
 };
 
+class Exception : public Object {
+ public:
+  static bool classof(const Object* obj);
+  static const ObjectKind skind = ObjectKind::Exception;
+  static const char* GetTypeName() { return "Exception"; }
+  using Ptr = RefPtr<Exception>;
+
+  static Exception::Ptr New(Store&, Ref tag, Values& args);
+
+  Ref tag() const;
+  Values& args();
+
+ private:
+  friend Store;
+  explicit Exception(Store&, Ref, Values&);
+  void Mark(Store&) override;
+
+  Ref tag_;
+  Values args_;
+};
+
 class Extern : public Object {
  public:
   static bool classof(const Object* obj);
@@ -1024,17 +1087,11 @@ enum class RunResult {
   Ok,
   Return,
   Trap,
+  Exception,
 };
 
-// TODO: Kinda weird to have a thread as an object, but it makes reference
-// marking simpler.
-class Thread : public Object {
+class Thread {
  public:
-  static bool classof(const Object* obj);
-  static const ObjectKind skind = ObjectKind::Thread;
-  static const char* GetTypeName() { return "Thread"; }
-  using Ptr = RefPtr<Thread>;
-
   struct Options {
     static const u32 kDefaultValueStackSize = 64 * 1024 / sizeof(Value);
     static const u32 kDefaultCallStackSize = 64 * 1024 / sizeof(Frame);
@@ -1044,13 +1101,15 @@ class Thread : public Object {
     Stream* trace_stream = nullptr;
   };
 
-  static Thread::Ptr New(Store&, const Options&);
+  Thread(Store& store, Stream* trace_stream = nullptr);
+  ~Thread();
 
   RunResult Run(Trap::Ptr* out_trap);
   RunResult Run(int num_instructions, Trap::Ptr* out_trap);
   RunResult Step(Trap::Ptr* out_trap);
 
   Store& store();
+  void Mark();
 
   Instance* GetCallerInstance();
 
@@ -1060,9 +1119,6 @@ class Thread : public Object {
 
   struct TraceSource;
 
-  explicit Thread(Store&, const Options&);
-  void Mark(Store&) override;
-
   RunResult PushCall(Ref func, u32 offset, Trap::Ptr* out_trap);
   RunResult PushCall(const DefinedFunc&, Trap::Ptr* out_trap);
   RunResult PushCall(const HostFunc&, Trap::Ptr* out_trap);
@@ -1182,12 +1238,18 @@ class Thread : public Object {
   template <typename T, typename V = T>
   RunResult DoAtomicRmwCmpxchg(Instr, Trap::Ptr* out_trap);
 
+  RunResult DoThrow(Exception::Ptr exn_ref);
+
   RunResult StepInternal(Trap::Ptr* out_trap);
 
   std::vector<Frame> frames_;
   std::vector<Value> values_;
   std::vector<u32> refs_;  // Index into values_.
 
+  // Exception handling requires tracking a separate stack of caught
+  // exceptions for catch blocks.
+  RefVec exceptions_;
+
   // Cached for convenience.
   Store& store_;
   Instance* inst_ = nullptr;
index 10a103b3cceb919f5cd2e16e7074314946e9f745..7ef276885c6294b08b67996c8eb1041ead7167cd 100644 (file)
@@ -86,6 +86,12 @@ void Istream::EmitDropKeep(u32 drop, u32 keep) {
   }
 }
 
+void Istream::EmitCatchDrop(u32 drop) {
+  if (drop > 0) {
+    Emit(Opcode::InterpCatchDrop, drop);
+  }
+}
+
 Istream::Offset Istream::EmitFixupU32() {
   auto result = end();
   EmitInternal(kInvalidOffset);
@@ -493,6 +499,8 @@ Instr Istream::Read(Offset* offset) const {
     case Opcode::DataDrop:
     case Opcode::ElemDrop:
     case Opcode::RefFunc:
+    case Opcode::Throw:
+    case Opcode::Rethrow:
       // Index immediate, 0 operands.
       instr.kind = InstrKind::Imm_Index_Op_0;
       instr.imm_u32 = ReadAt<u32>(offset);
@@ -685,6 +693,8 @@ Instr Istream::Read(Offset* offset) const {
     case Opcode::AtomicFence:
     case Opcode::I32Const:
     case Opcode::InterpAlloca:
+    case Opcode::InterpCatchDrop:
+    case Opcode::InterpAdjustFrameForReturnCall:
       // i32/f32 immediate, 0 operands.
       instr.kind = InstrKind::Imm_I32_Op_0;
       instr.imm_u32 = ReadAt<u32>(offset);
@@ -762,8 +772,6 @@ Instr Istream::Read(Offset* offset) const {
     case Opcode::InterpData:
     case Opcode::Invalid:
     case Opcode::Loop:
-    case Opcode::Rethrow:
-    case Opcode::Throw:
     case Opcode::Try:
     case Opcode::ReturnCall:
       // Not used.
@@ -857,7 +865,7 @@ Istream::Offset Istream::Trace(Stream* stream,
       break;
 
     case InstrKind::Imm_Index_Op_N:
-      stream->Writef(" $%u\n", instr.imm_u32); // TODO param/result count?
+      stream->Writef(" $%u\n", instr.imm_u32);  // TODO param/result count?
       break;
 
     case InstrKind::Imm_Index_Index_Op_3:
@@ -891,9 +899,10 @@ Istream::Offset Istream::Trace(Stream* stream,
       break;
 
     case InstrKind::Imm_Index_Offset_Lane_Op_2:
-      stream->Writef(" $%u:%s+$%u, %s (Lane imm: $%u)\n", instr.imm_u32x2_u8.fst,
-                     source->Pick(2, instr).c_str(), instr.imm_u32x2_u8.snd,
-                     source->Pick(1, instr).c_str(), instr.imm_u32x2_u8.idx);
+      stream->Writef(" $%u:%s+$%u, %s (Lane imm: $%u)\n",
+                     instr.imm_u32x2_u8.fst, source->Pick(2, instr).c_str(),
+                     instr.imm_u32x2_u8.snd, source->Pick(1, instr).c_str(),
+                     instr.imm_u32x2_u8.idx);
       break;
 
     case InstrKind::Imm_I32_Op_0:
index 614a942d345e5d2441753f2d9bce8976c4da575b..d671e14b697ba706ebfa0abdbd92d2031130212e 100644 (file)
@@ -18,8 +18,8 @@
 #define WABT_INTERP_ISTREAM_H_
 
 #include <cstdint>
-#include <vector>
 #include <string>
+#include <vector>
 
 #include "src/common.h"
 #include "src/opcode.h"
@@ -43,32 +43,32 @@ using ValueType = wabt::Type;
 // simplify instruction decoding, disassembling, and tracing. There is an
 // example of an instruction that uses this encoding on the right.
 enum class InstrKind {
-  Imm_0_Op_0,             // Nop
-  Imm_0_Op_1,             // i32.eqz
-  Imm_0_Op_2,             // i32.add
-  Imm_0_Op_3,             // select
-  Imm_Jump_Op_0,          // br
-  Imm_Jump_Op_1,          // br_if
-  Imm_Index_Op_0,         // global.get
-  Imm_Index_Op_1,         // global.set
-  Imm_Index_Op_2,         // table.set
-  Imm_Index_Op_3,         // memory.fill
-  Imm_Index_Op_N,         // call
-  Imm_Index_Index_Op_3,   // memory.init
-  Imm_Index_Index_Op_N,   // call_indirect
-  Imm_Index_Offset_Op_1,  // i32.load
-  Imm_Index_Offset_Op_2,  // i32.store
-  Imm_Index_Offset_Op_3,  // i32.atomic.rmw.cmpxchg
-  Imm_Index_Offset_Lane_Op_2, // v128.load8_lane
-  Imm_I32_Op_0,           // i32.const
-  Imm_I64_Op_0,           // i64.const
-  Imm_F32_Op_0,           // f32.const
-  Imm_F64_Op_0,           // f64.const
-  Imm_I32_I32_Op_0,       // drop_keep
-  Imm_I8_Op_1,            // i32x4.extract_lane
-  Imm_I8_Op_2,            // i32x4.replace_lane
-  Imm_V128_Op_0,          // v128.const
-  Imm_V128_Op_2,          // i8x16.shuffle
+  Imm_0_Op_0,                  // Nop
+  Imm_0_Op_1,                  // i32.eqz
+  Imm_0_Op_2,                  // i32.add
+  Imm_0_Op_3,                  // select
+  Imm_Jump_Op_0,               // br
+  Imm_Jump_Op_1,               // br_if
+  Imm_Index_Op_0,              // global.get
+  Imm_Index_Op_1,              // global.set
+  Imm_Index_Op_2,              // table.set
+  Imm_Index_Op_3,              // memory.fill
+  Imm_Index_Op_N,              // call
+  Imm_Index_Index_Op_3,        // memory.init
+  Imm_Index_Index_Op_N,        // call_indirect
+  Imm_Index_Offset_Op_1,       // i32.load
+  Imm_Index_Offset_Op_2,       // i32.store
+  Imm_Index_Offset_Op_3,       // i32.atomic.rmw.cmpxchg
+  Imm_Index_Offset_Lane_Op_2,  // v128.load8_lane
+  Imm_I32_Op_0,                // i32.const
+  Imm_I64_Op_0,                // i64.const
+  Imm_F32_Op_0,                // f32.const
+  Imm_F64_Op_0,                // f64.const
+  Imm_I32_I32_Op_0,            // drop_keep
+  Imm_I8_Op_1,                 // i32x4.extract_lane
+  Imm_I8_Op_2,                 // i32x4.replace_lane
+  Imm_V128_Op_0,               // v128.const
+  Imm_V128_Op_2,               // i8x16.shuffle
 };
 
 struct Instr {
@@ -81,8 +81,13 @@ struct Instr {
     u64 imm_u64;
     f64 imm_f64;
     v128 imm_v128;
-    struct { u32 fst, snd; } imm_u32x2;
-    struct { u32 fst, snd; u8 idx; } imm_u32x2_u8;
+    struct {
+      u32 fst, snd;
+    } imm_u32x2;
+    struct {
+      u32 fst, snd;
+      u8 idx;
+    } imm_u32x2_u8;
   };
 };
 
@@ -91,14 +96,15 @@ class Istream {
   using SerializedOpcode = u32;  // TODO: change to u16
   using Offset = u32;
   static const Offset kInvalidOffset = ~0;
-  // Each br_table entry is made up of two instructions:
+  // Each br_table entry is made up of three instructions:
   //
   //   interp_drop_keep $drop $keep
+  //   interp_catch_drop $catches
   //   br $label
   //
   // Each opcode is a SerializedOpcode, and each immediate is a u32.
   static const Offset kBrTableEntrySize =
-      sizeof(SerializedOpcode) * 2 + 3 * sizeof(u32);
+      sizeof(SerializedOpcode) * 3 + 4 * sizeof(u32);
 
   // Emit API.
   void Emit(u32);
@@ -110,6 +116,7 @@ class Istream {
   void Emit(Opcode::Enum, u32, u32);
   void Emit(Opcode::Enum, u32, u32, u8);
   void EmitDropKeep(u32 drop, u32 keep);
+  void EmitCatchDrop(u32 drop);
 
   Offset EmitFixupU32();
   void ResolveFixupU32(Offset);
@@ -140,7 +147,7 @@ class Istream {
 
   Offset Trace(Stream*, Offset, TraceSource*) const;
 
-private:
+ private:
   template <typename T>
   void WABT_VECTORCALL EmitAt(Offset, T val);
   template <typename T>
index 7d9611a74a4febead82c9223c428b46aa654a2ac..74161561371f7fc524928c0b4d582285a8db944c 100644 (file)
@@ -320,8 +320,8 @@ inline typename intrusive_list<T>::iterator intrusive_list<T>::end() noexcept {
 }
 
 template <typename T>
-inline typename intrusive_list<T>::const_iterator intrusive_list<T>::end() const
-    noexcept {
+inline typename intrusive_list<T>::const_iterator intrusive_list<T>::end()
+    const noexcept {
   return const_iterator(*this, nullptr);
 }
 
@@ -374,8 +374,8 @@ intrusive_list<T>::crend() const noexcept {
 }
 
 template <typename T>
-inline typename intrusive_list<T>::size_type intrusive_list<T>::size() const
-    noexcept {
+inline typename intrusive_list<T>::size_type intrusive_list<T>::size()
+    const noexcept {
   return size_;
 }
 
index 9b664611885dd47ea1d65205c5e22908e2c64c9b..959f093739b7c23974b9003e7e8015d02e46f6de 100644 (file)
@@ -30,8 +30,8 @@
 #include "src/cast.h"
 #include "src/common.h"
 #include "src/expr-visitor.h"
-#include "src/ir.h"
 #include "src/ir-util.h"
+#include "src/ir.h"
 #include "src/literal.h"
 #include "src/stream.h"
 
@@ -102,53 +102,52 @@ ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const {
     case ExprType::Binary:
     case ExprType::Compare:
     case ExprType::TableGrow:
-      return { 2, 1 };
+      return {2, 1};
 
     case ExprType::AtomicStore:
     case ExprType::Store:
     case ExprType::TableSet:
-      return { 2, 0 };
+      return {2, 0};
 
     case ExprType::Block:
-      return { 0, cast<BlockExpr>(&expr)->block.decl.sig.GetNumResults() };
+      return {0, cast<BlockExpr>(&expr)->block.decl.sig.GetNumResults()};
 
     case ExprType::Br:
-      return { GetLabelArity(cast<BrExpr>(&expr)->var), 1, true };
+      return {GetLabelArity(cast<BrExpr>(&expr)->var), 1, true};
 
     case ExprType::BrIf: {
       Index arity = GetLabelArity(cast<BrIfExpr>(&expr)->var);
-      return { arity + 1, arity };
+      return {arity + 1, arity};
     }
 
     case ExprType::BrTable:
-      return { GetLabelArity(cast<BrTableExpr>(&expr)->default_target) + 1, 1,
-               true };
+      return {GetLabelArity(cast<BrTableExpr>(&expr)->default_target) + 1, 1,
+              true};
 
     case ExprType::Call: {
       const Var& var = cast<CallExpr>(&expr)->var;
-      return { GetFuncParamCount(var), GetFuncResultCount(var) };
+      return {GetFuncParamCount(var), GetFuncResultCount(var)};
     }
 
     case ExprType::ReturnCall: {
       const Var& var = cast<ReturnCallExpr>(&expr)->var;
-      return { GetFuncParamCount(var), GetFuncResultCount(var), true };
+      return {GetFuncParamCount(var), GetFuncResultCount(var), true};
     }
 
     case ExprType::CallIndirect: {
       const auto* ci_expr = cast<CallIndirectExpr>(&expr);
-      return { ci_expr->decl.GetNumParams() + 1,
-               ci_expr->decl.GetNumResults() };
+      return {ci_expr->decl.GetNumParams() + 1, ci_expr->decl.GetNumResults()};
     }
 
     case ExprType::CallRef: {
       const Var& var = cast<CallRefExpr>(&expr)->function_type_index;
-      return { GetFuncParamCount(var) + 1, GetFuncResultCount(var) };
+      return {GetFuncParamCount(var) + 1, GetFuncResultCount(var)};
     }
 
     case ExprType::ReturnCallIndirect: {
       const auto* rci_expr = cast<ReturnCallIndirectExpr>(&expr);
-      return { rci_expr->decl.GetNumParams() + 1,
-               rci_expr->decl.GetNumResults(), true };
+      return {rci_expr->decl.GetNumParams() + 1, rci_expr->decl.GetNumResults(),
+              true};
     }
 
     case ExprType::Const:
@@ -158,15 +157,15 @@ ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const {
     case ExprType::TableSize:
     case ExprType::RefNull:
     case ExprType::RefFunc:
-      return { 0, 1 };
+      return {0, 1};
 
     case ExprType::Unreachable:
-      return { 0, 1, true };
+      return {0, 1, true};
 
     case ExprType::DataDrop:
     case ExprType::ElemDrop:
     case ExprType::AtomicFence:
-      return { 0, 0 };
+      return {0, 0};
 
     case ExprType::MemoryInit:
     case ExprType::TableInit:
@@ -174,7 +173,7 @@ ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const {
     case ExprType::MemoryCopy:
     case ExprType::TableCopy:
     case ExprType::TableFill:
-      return { 3, 0 };
+      return {3, 0};
 
     case ExprType::AtomicLoad:
     case ExprType::Convert:
@@ -186,34 +185,33 @@ ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const {
     case ExprType::RefIsNull:
     case ExprType::LoadSplat:
     case ExprType::LoadZero:
-      return { 1, 1 };
+      return {1, 1};
 
     case ExprType::Drop:
     case ExprType::GlobalSet:
     case ExprType::LocalSet:
-      return { 1, 0 };
+      return {1, 0};
 
     case ExprType::If:
-      return { 1, cast<IfExpr>(&expr)->true_.decl.sig.GetNumResults() };
+      return {1, cast<IfExpr>(&expr)->true_.decl.sig.GetNumResults()};
 
     case ExprType::Loop:
-      return { 0, cast<LoopExpr>(&expr)->block.decl.sig.GetNumResults() };
+      return {0, cast<LoopExpr>(&expr)->block.decl.sig.GetNumResults()};
 
     case ExprType::Nop:
-      return { 0, 0 };
+      return {0, 0};
 
     case ExprType::Return:
-      return
-        { static_cast<Index>(current_func_->decl.sig.result_types.size()), 1,
-          true };
+      return {static_cast<Index>(current_func_->decl.sig.result_types.size()),
+              1, true};
 
     case ExprType::Rethrow:
-      return { 0, 0, true };
+      return {0, 0, true};
 
     case ExprType::AtomicRmwCmpxchg:
     case ExprType::AtomicWait:
     case ExprType::Select:
-      return { 3, 1 };
+      return {3, 1};
 
     case ExprType::Throw: {
       auto throw_ = cast<ThrowExpr>(&expr);
@@ -221,14 +219,14 @@ ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const {
       if (Tag* tag = module.GetTag(throw_->var)) {
         operand_count = tag->decl.sig.param_types.size();
       }
-      return { operand_count, 0, true };
+      return {operand_count, 0, true};
     }
 
     case ExprType::Try:
-      return { 0, cast<TryExpr>(&expr)->block.decl.sig.GetNumResults() };
+      return {0, cast<TryExpr>(&expr)->block.decl.sig.GetNumResults()};
 
     case ExprType::Ternary:
-      return { 3, 1 };
+      return {3, 1};
 
     case ExprType::SimdLaneOp: {
       const Opcode opcode = cast<SimdLaneOpExpr>(&expr)->opcode;
@@ -241,7 +239,7 @@ ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const {
         case Opcode::I64X2ExtractLane:
         case Opcode::F32X4ExtractLane:
         case Opcode::F64X2ExtractLane:
-          return { 1, 1 };
+          return {1, 1};
 
         case Opcode::I8X16ReplaceLane:
         case Opcode::I16X8ReplaceLane:
@@ -249,23 +247,23 @@ ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const {
         case Opcode::I64X2ReplaceLane:
         case Opcode::F32X4ReplaceLane:
         case Opcode::F64X2ReplaceLane:
-          return { 2, 1 };
+          return {2, 1};
 
         default:
           fprintf(stderr, "Invalid Opcode for expr type: %s\n",
                   GetExprTypeName(expr));
           assert(0);
-          return { 0, 0 };
+          return {0, 0};
       }
     }
 
     case ExprType::SimdLoadLane:
     case ExprType::SimdStoreLane: {
-      return { 2, 1 };
+      return {2, 1};
     }
 
     case ExprType::SimdShuffleOp:
-      return { 2, 1 };
+      return {2, 1};
   }
 
   WABT_UNREACHABLE;
index 226e81aad9ab1a4ae1b9445b3a93aa372f6ffb6a..db9cf5b48615fba5ad8f3484db7166bf52290a0d 100644 (file)
@@ -39,7 +39,7 @@ struct Label {
 };
 
 struct ModuleContext {
-  ModuleContext(const Module &module) : module(module) {}
+  ModuleContext(const Modulemodule) : module(module) {}
 
   Index GetLabelStackSize() const { return label_stack_.size(); }
   const Label* GetLabel(const Var& var) const;
@@ -61,11 +61,12 @@ struct ModuleContext {
     Index nreturns;
     bool unreachable;
     Arities(Index na, Index nr, bool ur = false)
-      : nargs(na), nreturns(nr), unreachable(ur) {}
+        : nargs(na), nreturns(nr), unreachable(ur) {}
   };
   Arities GetExprArity(const Expr& expr) const;
 
-  const Module &module;
+  const Module& module;
+
  private:
   const Func* current_func_ = nullptr;
   std::vector<Label> label_stack_;
index ddfd490de2fdc6b52eee06559baf07252c36fc33..3af9568530fedacfa8852c5316a52e97dc6986de 100644 (file)
 namespace {
 
 const char* ExprTypeName[] = {
-  "AtomicFence",
-  "AtomicLoad",
-  "AtomicRmw",
-  "AtomicRmwCmpxchg",
-  "AtomicStore",
-  "AtomicNotify",
-  "AtomicWait",
-  "Binary",
-  "Block",
-  "Br",
-  "BrIf",
-  "BrTable",
-  "Call",
-  "CallIndirect",
-  "CallRef",
-  "Compare",
-  "Const",
-  "Convert",
-  "Drop",
-  "GlobalGet",
-  "GlobalSet",
-  "If",
-  "Load",
-  "LocalGet",
-  "LocalSet",
-  "LocalTee",
-  "Loop",
-  "MemoryCopy",
-  "DataDrop",
-  "MemoryFill",
-  "MemoryGrow",
-  "MemoryInit",
-  "MemorySize",
-  "Nop",
-  "RefIsNull",
-  "RefFunc",
-  "RefNull",
-  "Rethrow",
-  "Return",
-  "ReturnCall",
-  "ReturnCallIndirect",
-  "Select",
-  "SimdLaneOp",
-  "SimdLoadLane",
-  "SimdStoreLane",
-  "SimdShuffleOp",
-  "LoadSplat",
-  "LoadZero",
-  "Store",
-  "TableCopy",
-  "ElemDrop",
-  "TableInit",
-  "TableGet",
-  "TableGrow",
-  "TableSize",
-  "TableSet",
-  "TableFill",
-  "Ternary",
-  "Throw",
-  "Try",
-  "Unary",
-  "Unreachable",
+    "AtomicFence",
+    "AtomicLoad",
+    "AtomicRmw",
+    "AtomicRmwCmpxchg",
+    "AtomicStore",
+    "AtomicNotify",
+    "AtomicWait",
+    "Binary",
+    "Block",
+    "Br",
+    "BrIf",
+    "BrTable",
+    "Call",
+    "CallIndirect",
+    "CallRef",
+    "Compare",
+    "Const",
+    "Convert",
+    "Drop",
+    "GlobalGet",
+    "GlobalSet",
+    "If",
+    "Load",
+    "LocalGet",
+    "LocalSet",
+    "LocalTee",
+    "Loop",
+    "MemoryCopy",
+    "DataDrop",
+    "MemoryFill",
+    "MemoryGrow",
+    "MemoryInit",
+    "MemorySize",
+    "Nop",
+    "RefIsNull",
+    "RefFunc",
+    "RefNull",
+    "Rethrow",
+    "Return",
+    "ReturnCall",
+    "ReturnCallIndirect",
+    "Select",
+    "SimdLaneOp",
+    "SimdLoadLane",
+    "SimdStoreLane",
+    "SimdShuffleOp",
+    "LoadSplat",
+    "LoadZero",
+    "Store",
+    "TableCopy",
+    "ElemDrop",
+    "TableInit",
+    "TableGet",
+    "TableGrow",
+    "TableSize",
+    "TableSet",
+    "TableFill",
+    "Ternary",
+    "Throw",
+    "Try",
+    "Unary",
+    "Unreachable",
 };
 
 }  // end of anonymous namespace
@@ -197,7 +197,7 @@ Index LocalTypes::size() const {
 
 Type LocalTypes::operator[](Index i) const {
   Index count = 0;
-  for (auto decl: decls_) {
+  for (auto decl : decls_) {
     if (i < count + decl.second) {
       return decl.first;
     }
@@ -664,11 +664,12 @@ uint8_t ElemSegment::GetFlags(const Module* module) const {
       break;
   }
 
-  all_ref_func = all_ref_func &&
-                 std::all_of(elem_exprs.begin(), elem_exprs.end(),
-                             [](const ElemExpr& elem_expr) {
-                               return elem_expr.kind == ElemExprKind::RefFunc;
-                             });
+  all_ref_func =
+      all_ref_func &&
+      std::all_of(elem_exprs.begin(), elem_exprs.end(),
+                  [](const ExprList& elem_expr) {
+                    return elem_expr.front().type() == ExprType::RefFunc;
+                  });
   if (!all_ref_func) {
     flags |= SegUseElemExprs;
   }
@@ -691,5 +692,4 @@ uint8_t DataSegment::GetFlags(const Module* module) const {
   return flags;
 }
 
-
 }  // namespace wabt
index 3c63128456f90de7e277f0ba8d4fbd79cebeefe4..eee59a321c4b32977c52b593fd3792b0eb427251 100644 (file)
@@ -53,8 +53,14 @@ struct Var {
   bool is_index() const { return type_ == VarType::Index; }
   bool is_name() const { return type_ == VarType::Name; }
 
-  Index index() const { assert(is_index()); return index_; }
-  const std::string& name() const { assert(is_name()); return name_; }
+  Index index() const {
+    assert(is_index());
+    return index_;
+  }
+  const std::string& name() const {
+    assert(is_name());
+    return name_;
+  }
 
   void set_index(Index);
   void set_name(std::string&&);
@@ -95,7 +101,10 @@ struct Const {
   }
 
   Type type() const { return type_; }
-  Type lane_type() const { assert(type_ == Type::V128); return lane_type_; }
+  Type lane_type() const {
+    assert(type_ == Type::V128);
+    return lane_type_;
+  }
 
   int lane_count() const {
     switch (lane_type()) {
@@ -117,7 +126,9 @@ struct Const {
   v128 vec128() const { return data_; }
 
   template <typename T>
-  T v128_lane(int lane) const { return data_.To<T>(lane); }
+  T v128_lane(int lane) const {
+    return data_.To<T>(lane);
+  }
 
   void set_u32(uint32_t x) { From(Type::I32, x); }
   void set_u64(uint64_t x) { From(Type::I64, x); }
@@ -132,11 +143,17 @@ struct Const {
   void set_v128_f64(int lane, uint64_t x) { set_v128_lane(lane, Type::F64, x); }
 
   // Only used for expectations. (e.g. wast assertions)
-  void set_f32(ExpectedNan nan) { set_f32(0); set_expected_nan(0, nan); }
-  void set_f64(ExpectedNan nan) { set_f64(0); set_expected_nan(0, nan); }
-  void set_funcref()            { From<uintptr_t>(Type::FuncRef, 0); }
+  void set_f32(ExpectedNan nan) {
+    set_f32(0);
+    set_expected_nan(0, nan);
+  }
+  void set_f64(ExpectedNan nan) {
+    set_f64(0);
+    set_expected_nan(0, nan);
+  }
+  void set_funcref() { From<uintptr_t>(Type::FuncRef, 0); }
   void set_externref(uintptr_t x) { From(Type::ExternRef, x); }
-  void set_null(Type type)      { From<uintptr_t>(type, kRefNullBits); }
+  void set_null(Type type) { From<uintptr_t>(type, kRefNullBits); }
 
   bool is_expected_nan(int lane = 0) const {
     return expected_nan(lane) != ExpectedNan::None;
@@ -178,7 +195,7 @@ struct Const {
   }
 
   Type type_;
-  Type lane_type_;    // Only valid if type_ == Type::V128.
+  Type lane_type_;  // Only valid if type_ == Type::V128.
   v128 data_;
   ExpectedNan nan_[4];
 };
@@ -188,6 +205,13 @@ struct FuncSignature {
   TypeVector param_types;
   TypeVector result_types;
 
+  // Some types can have names, for example (ref $foo) has type $foo.
+  // So to use this type we need to translate its name into
+  // a proper index from the module type section.
+  // This is the mapping from parameter/result index to its name.
+  std::unordered_map<uint32_t, std::string> param_type_names;
+  std::unordered_map<uint32_t, std::string> result_type_names;
+
   Index GetNumParams() const { return param_types.size(); }
   Index GetNumResults() const { return result_types.size(); }
   Type GetParamType(Index index) const { return param_types[index]; }
@@ -378,11 +402,7 @@ struct Catch {
 };
 typedef std::vector<Catch> CatchVector;
 
-enum class TryKind {
-  Plain,
-  Catch,
-  Delegate
-};
+enum class TryKind { Plain, Catch, Delegate };
 
 class Expr : public intrusive_list_base<Expr> {
  public:
@@ -411,15 +431,40 @@ class ExprMixin : public Expr {
   explicit ExprMixin(const Location& loc = Location()) : Expr(TypeEnum, loc) {}
 };
 
+template <ExprType TypeEnum>
+class MemoryExpr : public ExprMixin<TypeEnum> {
+ public:
+  MemoryExpr(Var memidx, const Location& loc = Location())
+      : ExprMixin<TypeEnum>(loc), memidx(memidx) {}
+
+  Var memidx;
+};
+
+template <ExprType TypeEnum>
+class MemoryBinaryExpr : public ExprMixin<TypeEnum> {
+ public:
+  MemoryBinaryExpr(Var srcmemidx,
+                   Var destmemidx,
+                   const Location& loc = Location())
+      : ExprMixin<TypeEnum>(loc),
+        srcmemidx(srcmemidx),
+        destmemidx(destmemidx) {}
+
+  Var srcmemidx;
+  Var destmemidx;
+};
+
 typedef ExprMixin<ExprType::Drop> DropExpr;
-typedef ExprMixin<ExprType::MemoryGrow> MemoryGrowExpr;
-typedef ExprMixin<ExprType::MemorySize> MemorySizeExpr;
-typedef ExprMixin<ExprType::MemoryCopy> MemoryCopyExpr;
-typedef ExprMixin<ExprType::MemoryFill> MemoryFillExpr;
 typedef ExprMixin<ExprType::Nop> NopExpr;
 typedef ExprMixin<ExprType::Return> ReturnExpr;
 typedef ExprMixin<ExprType::Unreachable> UnreachableExpr;
 
+typedef MemoryExpr<ExprType::MemoryGrow> MemoryGrowExpr;
+typedef MemoryExpr<ExprType::MemorySize> MemorySizeExpr;
+typedef MemoryExpr<ExprType::MemoryFill> MemoryFillExpr;
+
+typedef MemoryBinaryExpr<ExprType::MemoryCopy> MemoryCopyExpr;
+
 template <ExprType TypeEnum>
 class RefTypeExpr : public ExprMixin<TypeEnum> {
  public:
@@ -456,35 +501,41 @@ class SimdLaneOpExpr : public ExprMixin<ExprType::SimdLaneOp> {
   uint64_t val;
 };
 
-class SimdLoadLaneExpr : public OpcodeExpr<ExprType::SimdLoadLane> {
+class SimdLoadLaneExpr : public MemoryExpr<ExprType::SimdLoadLane> {
  public:
   SimdLoadLaneExpr(Opcode opcode,
+                   Var memidx,
                    Address align,
                    Address offset,
                    uint64_t val,
                    const Location& loc = Location())
-      : OpcodeExpr<ExprType::SimdLoadLane>(opcode, loc),
+      : MemoryExpr<ExprType::SimdLoadLane>(memidx, loc),
+        opcode(opcode),
         align(align),
         offset(offset),
         val(val) {}
 
+  Opcode opcode;
   Address align;
   Address offset;
   uint64_t val;
 };
 
-class SimdStoreLaneExpr : public OpcodeExpr<ExprType::SimdStoreLane> {
+class SimdStoreLaneExpr : public MemoryExpr<ExprType::SimdStoreLane> {
  public:
   SimdStoreLaneExpr(Opcode opcode,
+                    Var memidx,
                     Address align,
                     Address offset,
                     uint64_t val,
                     const Location& loc = Location())
-      : OpcodeExpr<ExprType::SimdStoreLane>(opcode, loc),
+      : MemoryExpr<ExprType::SimdStoreLane>(memidx, loc),
+        opcode(opcode),
         align(align),
         offset(offset),
         val(val) {}
 
+  Opcode opcode;
   Address align;
   Address offset;
   uint64_t val;
@@ -508,6 +559,15 @@ class VarExpr : public ExprMixin<TypeEnum> {
   Var var;
 };
 
+template <ExprType TypeEnum>
+class MemoryVarExpr : public MemoryExpr<TypeEnum> {
+ public:
+  MemoryVarExpr(const Var& var, Var memidx, const Location& loc = Location())
+      : MemoryExpr<TypeEnum>(memidx, loc), var(var) {}
+
+  Var var;
+};
+
 typedef VarExpr<ExprType::Br> BrExpr;
 typedef VarExpr<ExprType::BrIf> BrIfExpr;
 typedef VarExpr<ExprType::Call> CallExpr;
@@ -521,7 +581,6 @@ typedef VarExpr<ExprType::ReturnCall> ReturnCallExpr;
 typedef VarExpr<ExprType::Throw> ThrowExpr;
 typedef VarExpr<ExprType::Rethrow> RethrowExpr;
 
-typedef VarExpr<ExprType::MemoryInit> MemoryInitExpr;
 typedef VarExpr<ExprType::DataDrop> DataDropExpr;
 typedef VarExpr<ExprType::ElemDrop> ElemDropExpr;
 typedef VarExpr<ExprType::TableGet> TableGetExpr;
@@ -530,6 +589,8 @@ typedef VarExpr<ExprType::TableGrow> TableGrowExpr;
 typedef VarExpr<ExprType::TableSize> TableSizeExpr;
 typedef VarExpr<ExprType::TableFill> TableFillExpr;
 
+typedef MemoryVarExpr<ExprType::MemoryInit> MemoryInitExpr;
+
 class SelectExpr : public ExprMixin<ExprType::Select> {
  public:
   SelectExpr(TypeVector type, const Location& loc = Location())
@@ -572,7 +633,7 @@ class CallIndirectExpr : public ExprMixin<ExprType::CallIndirect> {
 
 class ReturnCallIndirectExpr : public ExprMixin<ExprType::ReturnCallIndirect> {
  public:
-  explicit ReturnCallIndirectExpr(const Location &loc = Location())
+  explicit ReturnCallIndirectExpr(const Locationloc = Location())
       : ExprMixin<ExprType::ReturnCallIndirect>(loc) {}
 
   FuncDeclaration decl;
@@ -581,7 +642,7 @@ class ReturnCallIndirectExpr : public ExprMixin<ExprType::ReturnCallIndirect> {
 
 class CallRefExpr : public ExprMixin<ExprType::CallRef> {
  public:
-  explicit CallRefExpr(const Location &loc = Location())
+  explicit CallRefExpr(const Locationloc = Location())
       : ExprMixin<ExprType::CallRef>(loc) {}
 
   // This field is setup only during Validate phase,
@@ -657,8 +718,27 @@ class LoadStoreExpr : public ExprMixin<TypeEnum> {
   Address offset;
 };
 
-typedef LoadStoreExpr<ExprType::Load> LoadExpr;
-typedef LoadStoreExpr<ExprType::Store> StoreExpr;
+template <ExprType TypeEnum>
+class MemoryLoadStoreExpr : public MemoryExpr<TypeEnum> {
+ public:
+  MemoryLoadStoreExpr(Opcode opcode,
+                      Var memidx,
+                      Address align,
+                      Address offset,
+                      const Location& loc = Location())
+      : MemoryExpr<TypeEnum>(memidx, loc),
+        opcode(opcode),
+        align(align),
+        offset(offset) {}
+
+  Opcode opcode;
+  Address align;
+  Address offset;
+};
+
+typedef MemoryLoadStoreExpr<ExprType::Load> LoadExpr;
+typedef MemoryLoadStoreExpr<ExprType::Store> StoreExpr;
+
 typedef LoadStoreExpr<ExprType::AtomicLoad> AtomicLoadExpr;
 typedef LoadStoreExpr<ExprType::AtomicStore> AtomicStoreExpr;
 typedef LoadStoreExpr<ExprType::AtomicRmw> AtomicRmwExpr;
@@ -786,22 +866,7 @@ struct Table {
   Type elem_type;
 };
 
-enum class ElemExprKind {
-  RefNull,
-  RefFunc,
-};
-
-struct ElemExpr {
-  ElemExpr() : kind(ElemExprKind::RefNull), type(Type::FuncRef) {}
-  explicit ElemExpr(Var var) : kind(ElemExprKind::RefFunc), var(var) {}
-  explicit ElemExpr(Type type) : kind(ElemExprKind::RefNull), type(type) {}
-
-  ElemExprKind kind;
-  Var var;    // Only used when kind == RefFunc.
-  Type type;  // Only used when kind == RefNull
-};
-
-typedef std::vector<ElemExpr> ElemExprVector;
+typedef std::vector<ExprList> ExprListVector;
 
 struct ElemSegment {
   explicit ElemSegment(string_view name) : name(name.to_string()) {}
@@ -812,7 +877,7 @@ struct ElemSegment {
   Var table_var;
   Type elem_type;
   ExprList offset;
-  ElemExprVector elem_exprs;
+  ExprListVector elem_exprs;
 };
 
 struct Memory {
@@ -1250,9 +1315,10 @@ enum class CommandType {
   AssertReturn,
   AssertTrap,
   AssertExhaustion,
+  AssertException,
 
   First = Module,
-  Last = AssertExhaustion,
+  Last = AssertException,
 };
 static const int kCommandTypeCount = WABT_ENUM_COUNT(CommandType);
 
@@ -1329,6 +1395,12 @@ typedef AssertModuleCommand<CommandType::AssertUnlinkable>
 typedef AssertModuleCommand<CommandType::AssertUninstantiable>
     AssertUninstantiableCommand;
 
+class AssertExceptionCommand
+    : public CommandMixin<CommandType::AssertException> {
+ public:
+  ActionPtr action;
+};
+
 typedef std::unique_ptr<Command> CommandPtr;
 typedef std::vector<CommandPtr> CommandPtrVector;
 
index 1ff631ba4d81986d1f4b2a935c8791c518df9c77..4927304b4528a3def2dba51e4380604414dc7165 100644 (file)
@@ -18,6 +18,7 @@ struct TokenInfo {
 };
 %%
 array, Type::Array, TokenType::Array
+assert_exception, TokenType::AssertException
 assert_exhaustion, TokenType::AssertExhaustion
 assert_invalid, TokenType::AssertInvalid
 assert_malformed, TokenType::AssertMalformed
@@ -35,7 +36,6 @@ call_ref, TokenType::CallRef, Opcode::CallRef
 call, TokenType::Call, Opcode::Call
 catch, TokenType::Catch, Opcode::Catch
 catch_all, TokenType::CatchAll, Opcode::CatchAll
-current_memory, TokenType::MemorySize, Opcode::MemorySize
 data.drop, TokenType::DataDrop, Opcode::DataDrop
 data, TokenType::Data
 declare, TokenType::Declare
@@ -173,7 +173,6 @@ get, TokenType::Get
 global.get, TokenType::GlobalGet, Opcode::GlobalGet
 global.set, TokenType::GlobalSet, Opcode::GlobalSet
 global, TokenType::Global
-grow_memory, TokenType::MemoryGrow, Opcode::MemoryGrow
 i16x8.abs, TokenType::Unary, Opcode::I16X8Abs
 i16x8.add_sat_s, TokenType::Binary, Opcode::I16X8AddSatS
 i16x8.add_sat_u, TokenType::Binary, Opcode::I16X8AddSatU
@@ -531,6 +530,7 @@ nop, TokenType::Nop, Opcode::Nop
 offset, TokenType::Offset
 output, TokenType::Output
 param, TokenType::Param
+ref, TokenType::Ref
 quote, TokenType::Quote
 ref.extern, TokenType::RefExtern
 ref.func, TokenType::RefFunc, Opcode::RefFunc
@@ -586,46 +586,3 @@ v128.store32_lane, TokenType::SimdStoreLane, Opcode::V128Store32Lane
 v128.store64_lane, TokenType::SimdStoreLane, Opcode::V128Store64Lane
 i8x16.shuffle, TokenType::SimdShuffleOp, Opcode::I8X16Shuffle
 i8x16.swizzle, TokenType::Binary, Opcode::I8X16Swizzle
-# Deprecated names.
-atomic.notify, TokenType::AtomicNotify, Opcode::MemoryAtomicNotify
-i32.atomic.wait, TokenType::AtomicWait, Opcode::MemoryAtomicWait32
-i64.atomic.wait, TokenType::AtomicWait, Opcode::MemoryAtomicWait64
-anyfunc, Type::FuncRef
-f32.convert_s/i32, TokenType::Convert, Opcode::F32ConvertI32S
-f32.convert_s/i64, TokenType::Convert, Opcode::F32ConvertI64S
-f32.convert_u/i32, TokenType::Convert, Opcode::F32ConvertI32U
-f32.convert_u/i64, TokenType::Convert, Opcode::F32ConvertI64U
-f32.demote/f64, TokenType::Convert, Opcode::F32DemoteF64
-f32.reinterpret/i32, TokenType::Convert, Opcode::F32ReinterpretI32
-f64.convert_s/i32, TokenType::Convert, Opcode::F64ConvertI32S
-f64.convert_s/i64, TokenType::Convert, Opcode::F64ConvertI64S
-f64.convert_u/i32, TokenType::Convert, Opcode::F64ConvertI32U
-f64.convert_u/i64, TokenType::Convert, Opcode::F64ConvertI64U
-f64.promote/f32, TokenType::Convert, Opcode::F64PromoteF32
-f64.reinterpret/i64, TokenType::Convert, Opcode::F64ReinterpretI64
-get_global, TokenType::GlobalGet, Opcode::GlobalGet
-get_local, TokenType::LocalGet, Opcode::LocalGet
-i32.reinterpret/f32, TokenType::Convert, Opcode::I32ReinterpretF32
-i32.trunc_s/f32, TokenType::Convert, Opcode::I32TruncF32S
-i32.trunc_s/f64, TokenType::Convert, Opcode::I32TruncF64S
-i32.trunc_s:sat/f32, TokenType::Convert, Opcode::I32TruncSatF32S
-i32.trunc_s:sat/f64, TokenType::Convert, Opcode::I32TruncSatF64S
-i32.trunc_u/f32, TokenType::Convert, Opcode::I32TruncF32U
-i32.trunc_u/f64, TokenType::Convert, Opcode::I32TruncF64U
-i32.trunc_u:sat/f32, TokenType::Convert, Opcode::I32TruncSatF32U
-i32.trunc_u:sat/f64, TokenType::Convert, Opcode::I32TruncSatF64U
-i32.wrap/i64, TokenType::Convert, Opcode::I32WrapI64
-i64.extend_s/i32, TokenType::Convert, Opcode::I64ExtendI32S
-i64.extend_u/i32, TokenType::Convert, Opcode::I64ExtendI32U
-i64.reinterpret/f64, TokenType::Convert, Opcode::I64ReinterpretF64
-i64.trunc_s/f32, TokenType::Convert, Opcode::I64TruncF32S
-i64.trunc_s/f64, TokenType::Convert, Opcode::I64TruncF64S
-i64.trunc_s:sat/f32, TokenType::Convert, Opcode::I64TruncSatF32S
-i64.trunc_s:sat/f64, TokenType::Convert, Opcode::I64TruncSatF64S
-i64.trunc_u/f32, TokenType::Convert, Opcode::I64TruncF32U
-i64.trunc_u/f64, TokenType::Convert, Opcode::I64TruncF64U
-i64.trunc_u:sat/f32, TokenType::Convert, Opcode::I64TruncSatF32U
-i64.trunc_u:sat/f64, TokenType::Convert, Opcode::I64TruncSatF64U
-set_global, TokenType::GlobalSet, Opcode::GlobalSet
-set_local, TokenType::LocalSet, Opcode::LocalSet
-tee_local, TokenType::LocalTee, Opcode::LocalTee
index 0061772e2debfb7b0a7567443aac736953cf6747..615d8cb59a8a5d5dbe55ca2eda7df3352b557bf6 100644 (file)
@@ -649,7 +649,9 @@ Result ParseInt64(const char* s,
 namespace {
 uint32_t AddWithCarry(uint32_t x, uint32_t y, uint32_t* carry) {
   // Increments *carry if the addition overflows, otherwise leaves carry alone.
-  if ((0xffffffff - x) < y) ++*carry;
+  if ((0xffffffff - x) < y) {
+    ++*carry;
+  }
   return x + y;
 }
 
@@ -674,11 +676,9 @@ void Mul10(v128* v) {
   v->set_u32(2, AddWithCarry(v->u32(2), carry_into_v2, &carry_into_v3));
   v->set_u32(3, v->u32(3) * 10 + carry_into_v3);
 }
-}
+}  // namespace
 
-Result ParseUint128(const char* s,
-                    const char* end,
-                    v128* out) {
+Result ParseUint128(const char* s, const char* end, v128* out) {
   if (s == end) {
     return Result::Error;
   }
@@ -801,7 +801,7 @@ void WriteUint128(char* buffer, size_t size, v128 bits) {
 
     for (int i = 3; i != 0; --i) {
       digits = remainder / 10;
-      remainder = ((remainder - digits * 10) << 32) + bits.u32(i-1);
+      remainder = ((remainder - digits * 10) << 32) + bits.u32(i - 1);
       bits.set_u32(i, digits);
     }
 
@@ -822,8 +822,7 @@ void WriteUint128(char* buffer, size_t size, v128 bits) {
     len = size - 1;
   }
   std::reverse_copy(reversed_buffer + truncated_tail,
-                    reversed_buffer + len + truncated_tail,
-                    buffer);
+                    reversed_buffer + len + truncated_tail, buffer);
   buffer[len] = '\0';
 }
 
index b223e161dabd7ba40e8f07e049bbaab2151411bc..3adb478d4bdf4755fbff99a8a52ace065d0a6dd7 100644 (file)
@@ -17,8 +17,8 @@
 #ifndef WABT_OPCODE_CODE_TABLE_H_
 #define WABT_OPCODE_CODE_TABLE_H_
 
-#include <stdlib.h>
 #include <stdint.h>
+#include <stdlib.h>
 
 #ifdef __cplusplus
 extern "C" {
index 6a70eb4fab02d172b51a53286e3d55fe9763aafd..cfa23f1d49f9c4b02293a4cfdd834558cfb51fdb 100644 (file)
@@ -33,7 +33,7 @@ Opcode::Info Opcode::infos_[] = {
 };
 
 #define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
-                    text, decomp)                                                     \
+                    text, decomp)                                             \
   /* static */ Opcode Opcode::Name##_Opcode(Opcode::Name);
 #include "src/opcode.def"
 #undef WABT_OPCODE
index e5335d74ce2bbd3340abd0ccc585972d5f00fc13..9005418ed1c6c6ca32765a82047d6a8d32cb7975 100644 (file)
@@ -231,6 +231,8 @@ WABT_OPCODE(___,  I32,  ___,  ___,  0,  0,    0xe1, InterpBrUnless, "br_unless",
 WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xe2, InterpCallImport, "call_import", "")
 WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xe3, InterpData, "data", "")
 WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xe4, InterpDropKeep, "drop_keep", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xe5, InterpCatchDrop, "catch_drop", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xe6, InterpAdjustFrameForReturnCall, "adjust_frame_for_return_call", "")
 
 /* Saturating float-to-int opcodes (--enable-saturating-float-to-int) */
 WABT_OPCODE(I32,  F32,  ___,  ___,  0,  0xfc, 0x00, I32TruncSatF32S, "i32.trunc_sat_f32_s", "")
@@ -242,7 +244,7 @@ WABT_OPCODE(I64,  F32,  ___,  ___,  0,  0xfc, 0x05, I64TruncSatF32U, "i64.trunc_
 WABT_OPCODE(I64,  F64,  ___,  ___,  0,  0xfc, 0x06, I64TruncSatF64S, "i64.trunc_sat_f64_s", "")
 WABT_OPCODE(I64,  F64,  ___,  ___,  0,  0xfc, 0x07, I64TruncSatF64U, "i64.trunc_sat_f64_u", "")
 
-/* Bulk-memory (--enable-bulk-memory) */
+/* Bulk-memory */
 WABT_OPCODE(___, I32,  I32,  I32,  0,  0xfc, 0x08, MemoryInit, "memory.init", "")
 WABT_OPCODE(___, ___,  ___,  ___,  0,  0xfc, 0x09, DataDrop, "data.drop", "")
 WABT_OPCODE(___, I32,  I32,  I32,  0,  0xfc, 0x0a, MemoryCopy,"memory.copy", "")
@@ -251,7 +253,7 @@ WABT_OPCODE(___, I32,  I32,  I32,  0,  0xfc, 0x0c, TableInit, "table.init", "")
 WABT_OPCODE(___, ___,  ___,  ___,  0,  0xfc, 0x0d, ElemDrop, "elem.drop", "")
 WABT_OPCODE(___, I32,  I32,  I32,  0,  0xfc, 0x0e, TableCopy, "table.copy", "")
 
-/* Reference types (--enable-reference-types) */
+/* Reference types */
 WABT_OPCODE(___,  I32,  ___,  ___,  0,  0,    0x25, TableGet, "table.get", "")
 WABT_OPCODE(___,  I32,  ___,  ___,  0,  0,    0x26, TableSet, "table.set", "")
 WABT_OPCODE(___,  ___,  I32,  ___,  0,  0xfc, 0x0f, TableGrow, "table.grow", "")
@@ -261,7 +263,7 @@ WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xd0, RefNull, "ref.null", "")
 WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xd1, RefIsNull, "ref.is_null", "")
 WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xd2, RefFunc, "ref.func", "")
 
-/* Simd opcodes (--enable-simd) */
+/* Simd opcodes */
 WABT_OPCODE(V128, I32,  ___,  ___,  16, 0xfd, 0x00, V128Load,  "v128.load", "")
 WABT_OPCODE(V128, I32,   ___, ___,  8,  0xfd, 0x01, V128Load8X8S, "v128.load8x8_s", "")
 WABT_OPCODE(V128, I32,   ___, ___,  8,  0xfd, 0x02, V128Load8X8U, "v128.load8x8_u", "")
index 94cd4cb8f6df754c74b31413d9e653a95445d46a..486af52a6f6a601da6e626c8ec0d6c3f1555741b 100644 (file)
@@ -20,8 +20,8 @@
 #include <vector>
 
 #include "src/common.h"
-#include "src/opcode-code-table.h"
 #include "src/leb128.h"
+#include "src/opcode-code-table.h"
 
 namespace wabt {
 
@@ -176,7 +176,6 @@ inline Opcode Opcode::FromCode(uint8_t prefix, uint32_t code) {
   return Opcode(EncodeInvalidOpcode(prefix_code));
 }
 
-
 }  // namespace wabt
 
 #endif  // WABT_OPCODE_H_
index d6a38ae8d9fdcf535f5768252dbab012f0959f9a..cf11d4589127afbe5e9ee8a2147f771467ec6288 100644 (file)
@@ -50,7 +50,6 @@ OptionParser::OptionParser(const char* program_name, const char* description)
     : program_name_(program_name),
       description_(description),
       on_error_([this](const std::string& message) { DefaultError(message); }) {
-
   // Add common options
   AddOption("help", "Print this help message", [this]() {
     PrintHelp();
index 9f1f68ed8c53b86942bc246c92204e715bb5552a..2d8ec4e161450ff080c93c7174b7dbb5d796f756 100644 (file)
@@ -1,6 +1,6 @@
 /* C++ code produced by gperf version 3.1 */
 /* Command-line: gperf -m 50 -L C++ -N InWordSet -E -t -c --output-file=src/prebuilt/lexer-keywords.cc src/lexer-keywords.txt  */
-/* Computed positions: -k'1,3,5-9,11-14,16-19,23,$' */
+/* Computed positions: -k'1,3,5-8,10,12,15,17-19,23,$' */
 
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
       && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@@ -48,7 +48,7 @@ struct TokenInfo {
     Opcode opcode;
   };
 };
-/* maximum key range = 2613, duplicates = 0 */
+/* maximum key range = 2358, duplicates = 0 */
 
 class Perfect_Hash
 {
@@ -63,32 +63,32 @@ Perfect_Hash::hash (const char *str, size_t len)
 {
   static unsigned short asso_values[] =
     {
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632,   12,  111, 2632,   60,
-         8,   44,    7,  294,  126,  601,  359,  575,   17, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632,    8,   30,   67,   24,   77,
-        27,   13,    7,  561,  624,   10,   13,   25,   40,    8,
-         9,   53,  353,  537,  140,    7,    7,    9,  162,  131,
-       317,  751,   95, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632, 2632,
-      2632, 2632, 2632, 2632, 2632, 2632, 2632
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380,   13, 2380, 2380,  540,
+       325,    4,  181,    3,  173,  368,  142, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380,   34,    4,    6,  776,   40,
+        31,    9,  621,    3,  399,  214,    5,    8,    5,  126,
+        25,   75,  471,  396,   20,    5,   17,    3,  626,  356,
+        58,  515,  271, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380, 2380,
+      2380, 2380, 2380, 2380, 2380, 2380, 2380
     };
   unsigned int hval = len;
 
@@ -107,28 +107,22 @@ Perfect_Hash::hash (const char *str, size_t len)
         hval += asso_values[static_cast<unsigned char>(str[17])];
       /*FALLTHROUGH*/
       case 17:
-        hval += asso_values[static_cast<unsigned char>(str[16]+1)];
+        hval += asso_values[static_cast<unsigned char>(str[16])];
       /*FALLTHROUGH*/
       case 16:
-        hval += asso_values[static_cast<unsigned char>(str[15])];
-      /*FALLTHROUGH*/
       case 15:
-      case 14:
-        hval += asso_values[static_cast<unsigned char>(str[13])];
+        hval += asso_values[static_cast<unsigned char>(str[14])];
       /*FALLTHROUGH*/
+      case 14:
       case 13:
-        hval += asso_values[static_cast<unsigned char>(str[12])];
-      /*FALLTHROUGH*/
       case 12:
         hval += asso_values[static_cast<unsigned char>(str[11])];
       /*FALLTHROUGH*/
       case 11:
-        hval += asso_values[static_cast<unsigned char>(str[10])];
-      /*FALLTHROUGH*/
       case 10:
-      case 9:
-        hval += asso_values[static_cast<unsigned char>(str[8])];
+        hval += asso_values[static_cast<unsigned char>(str[9])];
       /*FALLTHROUGH*/
+      case 9:
       case 8:
         hval += asso_values[static_cast<unsigned char>(str[7])];
       /*FALLTHROUGH*/
@@ -139,15 +133,15 @@ Perfect_Hash::hash (const char *str, size_t len)
         hval += asso_values[static_cast<unsigned char>(str[5])];
       /*FALLTHROUGH*/
       case 5:
-        hval += asso_values[static_cast<unsigned char>(str[4]+1)];
+        hval += asso_values[static_cast<unsigned char>(str[4])];
       /*FALLTHROUGH*/
       case 4:
       case 3:
-        hval += asso_values[static_cast<unsigned char>(str[2])];
+        hval += asso_values[static_cast<unsigned char>(str[2]+1)];
       /*FALLTHROUGH*/
       case 2:
       case 1:
-        hval += asso_values[static_cast<unsigned char>(str[0])];
+        hval += asso_values[static_cast<unsigned char>(str[0]+1)];
         break;
     }
   return hval + asso_values[static_cast<unsigned char>(str[len - 1])];
@@ -158,1610 +152,1516 @@ Perfect_Hash::InWordSet (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 611,
+      TOTAL_KEYWORDS = 569,
       MIN_WORD_LENGTH = 2,
       MAX_WORD_LENGTH = 29,
-      MIN_HASH_VALUE = 19,
-      MAX_HASH_VALUE = 2631
+      MIN_HASH_VALUE = 22,
+      MAX_HASH_VALUE = 2379
     };
 
   static struct TokenInfo wordlist[] =
     {
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""},
-#line 507 "src/lexer-keywords.txt"
-      {"if", TokenType::If, Opcode::If},
       {""}, {""}, {""}, {""},
-#line 140 "src/lexer-keywords.txt"
-      {"f64", Type::F64},
-#line 527 "src/lexer-keywords.txt"
-      {"mut", TokenType::Mut},
-#line 82 "src/lexer-keywords.txt"
-      {"f32", Type::F32},
-#line 439 "src/lexer-keywords.txt"
-      {"i64", Type::I64},
-      {""},
-#line 301 "src/lexer-keywords.txt"
-      {"i32", Type::I32},
-      {""}, {""}, {""},
-#line 557 "src/lexer-keywords.txt"
-      {"then", TokenType::Then},
-      {""},
-#line 511 "src/lexer-keywords.txt"
-      {"item", TokenType::Item},
+#line 40 "src/lexer-keywords.txt"
+      {"data", TokenType::Data},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""},
-#line 47 "src/lexer-keywords.txt"
-      {"else", TokenType::Else, Opcode::Else},
-#line 46 "src/lexer-keywords.txt"
-      {"elem", TokenType::Elem},
-      {""}, {""}, {""},
+#line 123 "src/lexer-keywords.txt"
+      {"f64.ge", TokenType::Compare, Opcode::F64Ge},
+#line 66 "src/lexer-keywords.txt"
+      {"f32.ge", TokenType::Compare, Opcode::F32Ge},
+#line 125 "src/lexer-keywords.txt"
+      {"f64.le", TokenType::Compare, Opcode::F64Le},
+#line 68 "src/lexer-keywords.txt"
+      {"f32.le", TokenType::Compare, Opcode::F32Le},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""},
+#line 526 "src/lexer-keywords.txt"
+      {"mut", TokenType::Mut},
+#line 124 "src/lexer-keywords.txt"
+      {"f64.gt", TokenType::Compare, Opcode::F64Gt},
+#line 67 "src/lexer-keywords.txt"
+      {"f32.gt", TokenType::Compare, Opcode::F32Gt},
 #line 127 "src/lexer-keywords.txt"
       {"f64.lt", TokenType::Compare, Opcode::F64Lt},
 #line 70 "src/lexer-keywords.txt"
       {"f32.lt", TokenType::Compare, Opcode::F32Lt},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 50 "src/lexer-keywords.txt"
-      {"extern", Type::ExternRef, TokenType::Extern},
+#line 132 "src/lexer-keywords.txt"
+      {"f64.neg", TokenType::Unary, Opcode::F64Neg},
+#line 75 "src/lexer-keywords.txt"
+      {"f32.neg", TokenType::Unary, Opcode::F32Neg},
+#line 133 "src/lexer-keywords.txt"
+      {"f64.ne", TokenType::Compare, Opcode::F64Ne},
+#line 76 "src/lexer-keywords.txt"
+      {"f32.ne", TokenType::Compare, Opcode::F32Ne},
+#line 414 "src/lexer-keywords.txt"
+      {"i64.ne", TokenType::Compare, Opcode::I64Ne},
+#line 277 "src/lexer-keywords.txt"
+      {"i32.ne", TokenType::Compare, Opcode::I32Ne},
+#line 538 "src/lexer-keywords.txt"
+      {"ref.null", TokenType::RefNull, Opcode::RefNull},
+      {""}, {""},
+#line 33 "src/lexer-keywords.txt"
+      {"br", TokenType::Br, Opcode::Br},
+#line 525 "src/lexer-keywords.txt"
+      {"module", TokenType::Module},
       {""}, {""},
-#line 125 "src/lexer-keywords.txt"
-      {"f64.le", TokenType::Compare, Opcode::F64Le},
-#line 68 "src/lexer-keywords.txt"
-      {"f32.le", TokenType::Compare, Opcode::F32Le},
 #line 556 "src/lexer-keywords.txt"
       {"table", TokenType::Table},
-#line 170 "src/lexer-keywords.txt"
-      {"funcref", Type::FuncRef},
-#line 129 "src/lexer-keywords.txt"
-      {"f64.min", TokenType::Binary, Opcode::F64Min},
-#line 72 "src/lexer-keywords.txt"
-      {"f32.min", TokenType::Binary, Opcode::F32Min},
-      {""}, {""},
+#line 540 "src/lexer-keywords.txt"
+      {"result", TokenType::Result},
+#line 399 "src/lexer-keywords.txt"
+      {"i64.ge_u", TokenType::Compare, Opcode::I64GeU},
+#line 264 "src/lexer-keywords.txt"
+      {"i32.ge_u", TokenType::Compare, Opcode::I32GeU},
+#line 403 "src/lexer-keywords.txt"
+      {"i64.le_u", TokenType::Compare, Opcode::I64LeU},
+#line 268 "src/lexer-keywords.txt"
+      {"i32.le_u", TokenType::Compare, Opcode::I32LeU},
+#line 398 "src/lexer-keywords.txt"
+      {"i64.ge_s", TokenType::Compare, Opcode::I64GeS},
+#line 263 "src/lexer-keywords.txt"
+      {"i32.ge_s", TokenType::Compare, Opcode::I32GeS},
+#line 402 "src/lexer-keywords.txt"
+      {"i64.le_s", TokenType::Compare, Opcode::I64LeS},
+#line 267 "src/lexer-keywords.txt"
+      {"i32.le_s", TokenType::Compare, Opcode::I32LeS},
+#line 401 "src/lexer-keywords.txt"
+      {"i64.gt_u", TokenType::Compare, Opcode::I64GtU},
+#line 266 "src/lexer-keywords.txt"
+      {"i32.gt_u", TokenType::Compare, Opcode::I32GtU},
 #line 412 "src/lexer-keywords.txt"
-      {"i64.lt_s", TokenType::Compare, Opcode::I64LtS},
+      {"i64.lt_u", TokenType::Compare, Opcode::I64LtU},
 #line 275 "src/lexer-keywords.txt"
+      {"i32.lt_u", TokenType::Compare, Opcode::I32LtU},
+#line 400 "src/lexer-keywords.txt"
+      {"i64.gt_s", TokenType::Compare, Opcode::I64GtS},
+#line 265 "src/lexer-keywords.txt"
+      {"i32.gt_s", TokenType::Compare, Opcode::I32GtS},
+#line 411 "src/lexer-keywords.txt"
+      {"i64.lt_s", TokenType::Compare, Opcode::I64LtS},
+#line 274 "src/lexer-keywords.txt"
       {"i32.lt_s", TokenType::Compare, Opcode::I32LtS},
+#line 544 "src/lexer-keywords.txt"
+      {"return", TokenType::Return, Opcode::Return},
       {""},
-#line 169 "src/lexer-keywords.txt"
-      {"field", TokenType::Field},
-#line 413 "src/lexer-keywords.txt"
-      {"i64.lt_u", TokenType::Compare, Opcode::I64LtU},
-#line 276 "src/lexer-keywords.txt"
-      {"i32.lt_u", TokenType::Compare, Opcode::I32LtU},
-#line 403 "src/lexer-keywords.txt"
-      {"i64.le_s", TokenType::Compare, Opcode::I64LeS},
-#line 268 "src/lexer-keywords.txt"
-      {"i32.le_s", TokenType::Compare, Opcode::I32LeS},
-#line 48 "src/lexer-keywords.txt"
-      {"end", TokenType::End, Opcode::End},
-#line 168 "src/lexer-keywords.txt"
-      {"f64x2", TokenType::F64X2},
-#line 404 "src/lexer-keywords.txt"
-      {"i64.le_u", TokenType::Compare, Opcode::I64LeU},
-#line 269 "src/lexer-keywords.txt"
-      {"i32.le_u", TokenType::Compare, Opcode::I32LeU},
-#line 469 "src/lexer-keywords.txt"
-      {"i64x2", TokenType::I64X2},
-#line 526 "src/lexer-keywords.txt"
-      {"module", TokenType::Module},
-#line 419 "src/lexer-keywords.txt"
-      {"i64.rem_s", TokenType::Binary, Opcode::I64RemS},
-#line 282 "src/lexer-keywords.txt"
-      {"i32.rem_s", TokenType::Binary, Opcode::I32RemS},
-      {""}, {""},
-#line 420 "src/lexer-keywords.txt"
-      {"i64.rem_u", TokenType::Binary, Opcode::I64RemU},
-#line 283 "src/lexer-keywords.txt"
-      {"i32.rem_u", TokenType::Binary, Opcode::I32RemU},
 #line 43 "src/lexer-keywords.txt"
       {"do", TokenType::Do},
-#line 111 "src/lexer-keywords.txt"
-      {"f64.abs", TokenType::Unary, Opcode::F64Abs},
-#line 53 "src/lexer-keywords.txt"
-      {"f32.abs", TokenType::Unary, Opcode::F32Abs},
-#line 138 "src/lexer-keywords.txt"
-      {"f64.sub", TokenType::Binary, Opcode::F64Sub},
-#line 80 "src/lexer-keywords.txt"
-      {"f32.sub", TokenType::Binary, Opcode::F32Sub},
-#line 531 "src/lexer-keywords.txt"
-      {"offset", TokenType::Offset},
-#line 430 "src/lexer-keywords.txt"
-      {"i64.sub", TokenType::Binary, Opcode::I64Sub},
-#line 292 "src/lexer-keywords.txt"
-      {"i32.sub", TokenType::Binary, Opcode::I32Sub},
-      {""}, {""}, {""},
+      {""}, {""}, {""}, {""},
+#line 41 "src/lexer-keywords.txt"
+      {"declare", TokenType::Declare},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 131 "src/lexer-keywords.txt"
+      {"f64.nearest", TokenType::Unary, Opcode::F64Nearest},
+#line 74 "src/lexer-keywords.txt"
+      {"f32.nearest", TokenType::Unary, Opcode::F32Nearest},
+      {""},
+#line 548 "src/lexer-keywords.txt"
+      {"struct", Type::Struct, TokenType::Struct},
+#line 551 "src/lexer-keywords.txt"
+      {"table.get", TokenType::TableGet, Opcode::TableGet},
+      {""},
 #line 554 "src/lexer-keywords.txt"
       {"table.set", TokenType::TableSet, Opcode::TableSet},
-#line 545 "src/lexer-keywords.txt"
-      {"select", TokenType::Select, Opcode::Select},
-#line 547 "src/lexer-keywords.txt"
-      {"start", TokenType::Start},
-#line 553 "src/lexer-keywords.txt"
-      {"table.init", TokenType::TableInit, Opcode::TableInit},
+      {""}, {""},
+#line 349 "src/lexer-keywords.txt"
+      {"i64.and", TokenType::Binary, Opcode::I64And},
+#line 226 "src/lexer-keywords.txt"
+      {"i32.and", TokenType::Binary, Opcode::I32And},
+      {""}, {""},
+#line 112 "src/lexer-keywords.txt"
+      {"f64.add", TokenType::Binary, Opcode::F64Add},
+#line 54 "src/lexer-keywords.txt"
+      {"f32.add", TokenType::Binary, Opcode::F32Add},
+#line 348 "src/lexer-keywords.txt"
+      {"i64.add", TokenType::Binary, Opcode::I64Add},
+#line 225 "src/lexer-keywords.txt"
+      {"i32.add", TokenType::Binary, Opcode::I32Add},
+      {""}, {""}, {""}, {""},
+#line 139 "src/lexer-keywords.txt"
+      {"f64.trunc", TokenType::Unary, Opcode::F64Trunc},
+#line 81 "src/lexer-keywords.txt"
+      {"f32.trunc", TokenType::Unary, Opcode::F32Trunc},
 #line 171 "src/lexer-keywords.txt"
       {"func", Type::FuncRef, TokenType::Func},
-      {""},
-#line 133 "src/lexer-keywords.txt"
-      {"f64.ne", TokenType::Compare, Opcode::F64Ne},
-#line 76 "src/lexer-keywords.txt"
-      {"f32.ne", TokenType::Compare, Opcode::F32Ne},
-      {""},
+      {""}, {""}, {""}, {""}, {""}, {""},
 #line 415 "src/lexer-keywords.txt"
-      {"i64.ne", TokenType::Compare, Opcode::I64Ne},
+      {"i64.or", TokenType::Binary, Opcode::I64Or},
 #line 278 "src/lexer-keywords.txt"
-      {"i32.ne", TokenType::Compare, Opcode::I32Ne},
-      {""},
-#line 40 "src/lexer-keywords.txt"
-      {"data", TokenType::Data},
-      {""}, {""}, {""}, {""}, {""},
-#line 350 "src/lexer-keywords.txt"
-      {"i64.and", TokenType::Binary, Opcode::I64And},
-#line 227 "src/lexer-keywords.txt"
-      {"i32.and", TokenType::Binary, Opcode::I32And},
-#line 157 "src/lexer-keywords.txt"
-      {"f64x2.ne", TokenType::Compare, Opcode::F64X2Ne},
+      {"i32.or", TokenType::Binary, Opcode::I32Or},
       {""},
-#line 153 "src/lexer-keywords.txt"
-      {"f64x2.min", TokenType::Binary, Opcode::F64X2Min},
-#line 446 "src/lexer-keywords.txt"
-      {"i64x2.ne", TokenType::Binary, Opcode::I64X2Ne},
+#line 431 "src/lexer-keywords.txt"
+      {"i64.trunc_f32_u", TokenType::Convert, Opcode::I64TruncF32U},
+#line 293 "src/lexer-keywords.txt"
+      {"i32.trunc_f32_u", TokenType::Convert, Opcode::I32TruncF32U},
       {""}, {""},
+#line 430 "src/lexer-keywords.txt"
+      {"i64.trunc_f32_s", TokenType::Convert, Opcode::I64TruncF32S},
+#line 292 "src/lexer-keywords.txt"
+      {"i32.trunc_f32_s", TokenType::Convert, Opcode::I32TruncF32S},
+#line 420 "src/lexer-keywords.txt"
+      {"i64.rotl", TokenType::Binary, Opcode::I64Rotl},
+#line 283 "src/lexer-keywords.txt"
+      {"i32.rotl", TokenType::Binary, Opcode::I32Rotl},
+      {""},
+#line 137 "src/lexer-keywords.txt"
+      {"f64.store", TokenType::Store, Opcode::F64Store},
+#line 79 "src/lexer-keywords.txt"
+      {"f32.store", TokenType::Store, Opcode::F32Store},
+#line 428 "src/lexer-keywords.txt"
+      {"i64.store", TokenType::Store, Opcode::I64Store},
+#line 290 "src/lexer-keywords.txt"
+      {"i32.store", TokenType::Store, Opcode::I32Store},
+      {""}, {""}, {""},
+#line 543 "src/lexer-keywords.txt"
+      {"return_call", TokenType::ReturnCall, Opcode::ReturnCall},
+      {""}, {""}, {""},
 #line 130 "src/lexer-keywords.txt"
       {"f64.mul", TokenType::Binary, Opcode::F64Mul},
 #line 73 "src/lexer-keywords.txt"
       {"f32.mul", TokenType::Binary, Opcode::F32Mul},
-      {""},
-#line 414 "src/lexer-keywords.txt"
+#line 413 "src/lexer-keywords.txt"
       {"i64.mul", TokenType::Binary, Opcode::I64Mul},
-#line 277 "src/lexer-keywords.txt"
+#line 276 "src/lexer-keywords.txt"
       {"i32.mul", TokenType::Binary, Opcode::I32Mul},
-      {""}, {""},
-#line 112 "src/lexer-keywords.txt"
-      {"f64.add", TokenType::Binary, Opcode::F64Add},
-#line 54 "src/lexer-keywords.txt"
-      {"f32.add", TokenType::Binary, Opcode::F32Add},
-      {""},
-#line 349 "src/lexer-keywords.txt"
-      {"i64.add", TokenType::Binary, Opcode::I64Add},
-#line 226 "src/lexer-keywords.txt"
-      {"i32.add", TokenType::Binary, Opcode::I32Add},
+      {""}, {""}, {""}, {""}, {""},
+#line 535 "src/lexer-keywords.txt"
+      {"ref.extern", TokenType::RefExtern},
+#line 126 "src/lexer-keywords.txt"
+      {"f64.load", TokenType::Load, Opcode::F64Load},
+#line 69 "src/lexer-keywords.txt"
+      {"f32.load", TokenType::Load, Opcode::F32Load},
+#line 410 "src/lexer-keywords.txt"
+      {"i64.load", TokenType::Load, Opcode::I64Load},
+#line 273 "src/lexer-keywords.txt"
+      {"i32.load", TokenType::Load, Opcode::I32Load},
+#line 36 "src/lexer-keywords.txt"
+      {"call", TokenType::Call, Opcode::Call},
       {""},
-#line 151 "src/lexer-keywords.txt"
-      {"f64x2.lt", TokenType::Compare, Opcode::F64X2Lt},
+#line 421 "src/lexer-keywords.txt"
+      {"i64.rotr", TokenType::Binary, Opcode::I64Rotr},
+#line 284 "src/lexer-keywords.txt"
+      {"i32.rotr", TokenType::Binary, Opcode::I32Rotr},
+      {""}, {""},
+#line 514 "src/lexer-keywords.txt"
+      {"local", TokenType::Local},
+#line 409 "src/lexer-keywords.txt"
+      {"i64.load8_u", TokenType::Load, Opcode::I64Load8U},
+#line 272 "src/lexer-keywords.txt"
+      {"i32.load8_u", TokenType::Load, Opcode::I32Load8U},
+#line 408 "src/lexer-keywords.txt"
+      {"i64.load8_s", TokenType::Load, Opcode::I64Load8S},
+#line 271 "src/lexer-keywords.txt"
+      {"i32.load8_s", TokenType::Load, Opcode::I32Load8S},
 #line 114 "src/lexer-keywords.txt"
       {"f64.const", TokenType::Const, Opcode::F64Const},
 #line 56 "src/lexer-keywords.txt"
       {"f32.const", TokenType::Const, Opcode::F32Const},
-      {""},
-#line 388 "src/lexer-keywords.txt"
+#line 387 "src/lexer-keywords.txt"
       {"i64.const", TokenType::Const, Opcode::I64Const},
-#line 256 "src/lexer-keywords.txt"
+#line 255 "src/lexer-keywords.txt"
       {"i32.const", TokenType::Const, Opcode::I32Const},
       {""}, {""}, {""},
-#line 546 "src/lexer-keywords.txt"
-      {"shared", TokenType::Shared},
-      {""},
-#line 163 "src/lexer-keywords.txt"
-      {"f64x2.sub", TokenType::Binary, Opcode::F64X2Sub},
-#line 150 "src/lexer-keywords.txt"
-      {"f64x2.le", TokenType::Compare, Opcode::F64X2Le},
-#line 447 "src/lexer-keywords.txt"
-      {"i64x2.lt_s", TokenType::Binary, Opcode::I64X2LtS},
-#line 464 "src/lexer-keywords.txt"
-      {"i64x2.sub", TokenType::Binary, Opcode::I64X2Sub},
-#line 29 "src/lexer-keywords.txt"
-      {"block", TokenType::Block, Opcode::Block},
-      {""}, {""}, {""},
-#line 449 "src/lexer-keywords.txt"
-      {"i64x2.le_s", TokenType::Binary, Opcode::I64X2LeS},
-#line 113 "src/lexer-keywords.txt"
-      {"f64.ceil", TokenType::Unary, Opcode::F64Ceil},
-#line 55 "src/lexer-keywords.txt"
-      {"f32.ceil", TokenType::Unary, Opcode::F32Ceil},
-#line 31 "src/lexer-keywords.txt"
-      {"br_table", TokenType::BrTable, Opcode::BrTable},
-      {""}, {""},
-#line 550 "src/lexer-keywords.txt"
-      {"table.fill", TokenType::TableFill, Opcode::TableFill},
-      {""}, {""}, {""},
-#line 35 "src/lexer-keywords.txt"
-      {"call", TokenType::Call, Opcode::Call},
-      {""}, {""}, {""}, {""},
-#line 32 "src/lexer-keywords.txt"
-      {"br", TokenType::Br, Opcode::Br},
-      {""}, {""}, {""},
-#line 515 "src/lexer-keywords.txt"
-      {"local", TokenType::Local},
+#line 395 "src/lexer-keywords.txt"
+      {"i64.extend8_s", TokenType::Unary, Opcode::I64Extend8S},
+#line 262 "src/lexer-keywords.txt"
+      {"i32.extend8_s", TokenType::Unary, Opcode::I32Extend8S},
       {""},
-#line 421 "src/lexer-keywords.txt"
-      {"i64.rotl", TokenType::Binary, Opcode::I64Rotl},
-#line 284 "src/lexer-keywords.txt"
-      {"i32.rotl", TokenType::Binary, Opcode::I32Rotl},
+#line 42 "src/lexer-keywords.txt"
+      {"delegate", TokenType::Delegate},
+#line 469 "src/lexer-keywords.txt"
+      {"i64.xor", TokenType::Binary, Opcode::I64Xor},
+#line 347 "src/lexer-keywords.txt"
+      {"i32.xor", TokenType::Binary, Opcode::I32Xor},
+#line 140 "src/lexer-keywords.txt"
+      {"f64", Type::F64},
       {""},
-#line 540 "src/lexer-keywords.txt"
-      {"result", TokenType::Result},
-#line 154 "src/lexer-keywords.txt"
-      {"f64x2.mul", TokenType::Binary, Opcode::F64X2Mul},
+#line 438 "src/lexer-keywords.txt"
+      {"i64", Type::I64},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 419 "src/lexer-keywords.txt"
+      {"i64.rem_u", TokenType::Binary, Opcode::I64RemU},
+#line 282 "src/lexer-keywords.txt"
+      {"i32.rem_u", TokenType::Binary, Opcode::I32RemU},
+#line 418 "src/lexer-keywords.txt"
+      {"i64.rem_s", TokenType::Binary, Opcode::I64RemS},
+#line 281 "src/lexer-keywords.txt"
+      {"i32.rem_s", TokenType::Binary, Opcode::I32RemS},
+#line 511 "src/lexer-keywords.txt"
+      {"local.get", TokenType::LocalGet, Opcode::LocalGet},
       {""},
-#line 544 "src/lexer-keywords.txt"
-      {"return", TokenType::Return, Opcode::Return},
-#line 444 "src/lexer-keywords.txt"
-      {"i64x2.mul", TokenType::Binary, Opcode::I64X2Mul},
-#line 513 "src/lexer-keywords.txt"
+#line 512 "src/lexer-keywords.txt"
       {"local.set", TokenType::LocalSet, Opcode::LocalSet},
       {""}, {""}, {""},
-#line 141 "src/lexer-keywords.txt"
-      {"f64x2.abs", TokenType::Unary, Opcode::F64X2Abs},
-#line 555 "src/lexer-keywords.txt"
-      {"table.size", TokenType::TableSize, Opcode::TableSize},
-      {""},
-#line 451 "src/lexer-keywords.txt"
-      {"i64x2.abs", TokenType::Unary, Opcode::I64X2Abs},
-      {""}, {""}, {""}, {""},
-#line 514 "src/lexer-keywords.txt"
+#line 513 "src/lexer-keywords.txt"
       {"local.tee", TokenType::LocalTee, Opcode::LocalTee},
-      {""},
-#line 548 "src/lexer-keywords.txt"
-      {"struct", Type::Struct, TokenType::Struct},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 126 "src/lexer-keywords.txt"
-      {"f64.load", TokenType::Load, Opcode::F64Load},
-#line 69 "src/lexer-keywords.txt"
-      {"f32.load", TokenType::Load, Opcode::F32Load},
-#line 155 "src/lexer-keywords.txt"
-      {"f64x2.nearest", TokenType::Unary, Opcode::F64X2Nearest},
-#line 411 "src/lexer-keywords.txt"
-      {"i64.load", TokenType::Load, Opcode::I64Load},
-#line 274 "src/lexer-keywords.txt"
-      {"i32.load", TokenType::Load, Opcode::I32Load},
       {""}, {""}, {""},
-#line 51 "src/lexer-keywords.txt"
-      {"externref", Type::ExternRef},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 143 "src/lexer-keywords.txt"
-      {"f64x2.ceil", TokenType::Unary, Opcode::F64X2Ceil},
+#line 545 "src/lexer-keywords.txt"
+      {"select", TokenType::Select, Opcode::Select},
       {""}, {""}, {""}, {""}, {""}, {""},
-#line 142 "src/lexer-keywords.txt"
-      {"f64x2.add", TokenType::Binary, Opcode::F64X2Add},
-      {""}, {""},
-#line 440 "src/lexer-keywords.txt"
-      {"i64x2.add", TokenType::Binary, Opcode::I64X2Add},
-      {""}, {""},
-#line 390 "src/lexer-keywords.txt"
-      {"i64.div_s", TokenType::Binary, Opcode::I64DivS},
-#line 258 "src/lexer-keywords.txt"
-      {"i32.div_s", TokenType::Binary, Opcode::I32DivS},
-      {""}, {""},
-#line 391 "src/lexer-keywords.txt"
-      {"i64.div_u", TokenType::Binary, Opcode::I64DivU},
-#line 259 "src/lexer-keywords.txt"
-      {"i32.div_u", TokenType::Binary, Opcode::I32DivU},
+#line 92 "src/lexer-keywords.txt"
+      {"f32x4.ge", TokenType::Compare, Opcode::F32X4Ge},
+#line 309 "src/lexer-keywords.txt"
+      {"i32x4.ge_u", TokenType::Compare, Opcode::I32X4GeU},
+#line 94 "src/lexer-keywords.txt"
+      {"f32x4.le", TokenType::Compare, Opcode::F32X4Le},
+#line 313 "src/lexer-keywords.txt"
+      {"i32x4.le_u", TokenType::Compare, Opcode::I32X4LeU},
       {""},
-#line 386 "src/lexer-keywords.txt"
-      {"i64.atomic.store", TokenType::AtomicStore, Opcode::I64AtomicStore},
-#line 254 "src/lexer-keywords.txt"
-      {"i32.atomic.store", TokenType::AtomicStore, Opcode::I32AtomicStore},
-#line 532 "src/lexer-keywords.txt"
-      {"output", TokenType::Output},
+#line 308 "src/lexer-keywords.txt"
+      {"i32x4.ge_s", TokenType::Compare, Opcode::I32X4GeS},
       {""},
-#line 510 "src/lexer-keywords.txt"
-      {"invoke", TokenType::Invoke},
-      {""}, {""}, {""},
-#line 389 "src/lexer-keywords.txt"
-      {"i64.ctz", TokenType::Unary, Opcode::I64Ctz},
-#line 257 "src/lexer-keywords.txt"
-      {"i32.ctz", TokenType::Unary, Opcode::I32Ctz},
-#line 407 "src/lexer-keywords.txt"
-      {"i64.load32_s", TokenType::Load, Opcode::I64Load32S},
-#line 454 "src/lexer-keywords.txt"
-      {"i64x2.bitmask", TokenType::Unary, Opcode::I64X2Bitmask},
-#line 384 "src/lexer-keywords.txt"
-      {"i64.atomic.store32", TokenType::AtomicStore, Opcode::I64AtomicStore32},
+#line 312 "src/lexer-keywords.txt"
+      {"i32x4.le_s", TokenType::Compare, Opcode::I32X4LeS},
       {""},
-#line 408 "src/lexer-keywords.txt"
-      {"i64.load32_u", TokenType::Load, Opcode::I64Load32U},
+#line 311 "src/lexer-keywords.txt"
+      {"i32x4.gt_u", TokenType::Compare, Opcode::I32X4GtU},
       {""},
-#line 137 "src/lexer-keywords.txt"
-      {"f64.store", TokenType::Store, Opcode::F64Store},
-#line 79 "src/lexer-keywords.txt"
-      {"f32.store", TokenType::Store, Opcode::F32Store},
+#line 317 "src/lexer-keywords.txt"
+      {"i32x4.lt_u", TokenType::Compare, Opcode::I32X4LtU},
       {""},
-#line 429 "src/lexer-keywords.txt"
-      {"i64.store", TokenType::Store, Opcode::I64Store},
-#line 291 "src/lexer-keywords.txt"
-      {"i32.store", TokenType::Store, Opcode::I32Store},
-      {""}, {""}, {""},
-#line 427 "src/lexer-keywords.txt"
-      {"i64.store32", TokenType::Store, Opcode::I64Store32},
+#line 310 "src/lexer-keywords.txt"
+      {"i32x4.gt_s", TokenType::Compare, Opcode::I32X4GtS},
       {""},
-#line 405 "src/lexer-keywords.txt"
-      {"i64.load16_s", TokenType::Load, Opcode::I64Load16S},
-#line 270 "src/lexer-keywords.txt"
-      {"i32.load16_s", TokenType::Load, Opcode::I32Load16S},
-      {""}, {""},
-#line 406 "src/lexer-keywords.txt"
-      {"i64.load16_u", TokenType::Load, Opcode::I64Load16U},
-#line 271 "src/lexer-keywords.txt"
-      {"i32.load16_u", TokenType::Load, Opcode::I32Load16U},
-      {""}, {""}, {""}, {""}, {""}, {""},
-#line 62 "src/lexer-keywords.txt"
-      {"f32.demote_f64", TokenType::Convert, Opcode::F32DemoteF64},
+#line 316 "src/lexer-keywords.txt"
+      {"i32x4.lt_s", TokenType::Compare, Opcode::I32X4LtS},
+#line 93 "src/lexer-keywords.txt"
+      {"f32x4.gt", TokenType::Compare, Opcode::F32X4Gt},
+#line 100 "src/lexer-keywords.txt"
+      {"f32x4.neg", TokenType::Unary, Opcode::F32X4Neg},
+#line 95 "src/lexer-keywords.txt"
+      {"f32x4.lt", TokenType::Compare, Opcode::F32X4Lt},
+#line 324 "src/lexer-keywords.txt"
+      {"i32x4.neg", TokenType::Unary, Opcode::I32X4Neg},
       {""}, {""},
-#line 387 "src/lexer-keywords.txt"
-      {"i64.clz", TokenType::Unary, Opcode::I64Clz},
-#line 255 "src/lexer-keywords.txt"
-      {"i32.clz", TokenType::Unary, Opcode::I32Clz},
-      {""},
-#line 537 "src/lexer-keywords.txt"
-      {"ref.is_null", TokenType::RefIsNull, Opcode::RefIsNull},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""},
-#line 37 "src/lexer-keywords.txt"
-      {"catch_all", TokenType::CatchAll, Opcode::CatchAll},
+#line 101 "src/lexer-keywords.txt"
+      {"f32x4.ne", TokenType::Compare, Opcode::F32X4Ne},
       {""},
-#line 22 "src/lexer-keywords.txt"
-      {"assert_invalid", TokenType::AssertInvalid},
-#line 41 "src/lexer-keywords.txt"
-      {"declare", TokenType::Declare},
-#line 26 "src/lexer-keywords.txt"
-      {"assert_unlinkable", TokenType::AssertUnlinkable},
-      {""}, {""}, {""}, {""}, {""},
-#line 630 "src/lexer-keywords.txt"
-      {"set_local", TokenType::LocalSet, Opcode::LocalSet},
-      {""}, {""}, {""}, {""}, {""},
-#line 631 "src/lexer-keywords.txt"
-      {"tee_local", TokenType::LocalTee, Opcode::LocalTee},
-      {""}, {""}, {""}, {""}, {""},
-#line 33 "src/lexer-keywords.txt"
-      {"call_indirect", TokenType::CallIndirect, Opcode::CallIndirect},
-#line 110 "src/lexer-keywords.txt"
-      {"f32x4", TokenType::F32X4},
-#line 34 "src/lexer-keywords.txt"
-      {"call_ref", TokenType::CallRef, Opcode::CallRef},
+#line 325 "src/lexer-keywords.txt"
+      {"i32x4.ne", TokenType::Compare, Opcode::I32X4Ne},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 128 "src/lexer-keywords.txt"
+      {"f64.max", TokenType::Binary, Opcode::F64Max},
+#line 71 "src/lexer-keywords.txt"
+      {"f32.max", TokenType::Binary, Opcode::F32Max},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 85 "src/lexer-keywords.txt"
+      {"f32x4.ceil", TokenType::Unary, Opcode::F32X4Ceil},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 84 "src/lexer-keywords.txt"
+      {"f32x4.add", TokenType::Binary, Opcode::F32X4Add},
       {""},
-#line 339 "src/lexer-keywords.txt"
-      {"i32x4", TokenType::I32X4},
-#line 131 "src/lexer-keywords.txt"
-      {"f64.nearest", TokenType::Unary, Opcode::F64Nearest},
-#line 74 "src/lexer-keywords.txt"
-      {"f32.nearest", TokenType::Unary, Opcode::F32Nearest},
+#line 303 "src/lexer-keywords.txt"
+      {"i32x4.add", TokenType::Binary, Opcode::I32X4Add},
       {""}, {""}, {""}, {""}, {""}, {""},
-#line 354 "src/lexer-keywords.txt"
+#line 113 "src/lexer-keywords.txt"
+      {"f64.ceil", TokenType::Unary, Opcode::F64Ceil},
+#line 55 "src/lexer-keywords.txt"
+      {"f32.ceil", TokenType::Unary, Opcode::F32Ceil},
+      {""},
+#line 99 "src/lexer-keywords.txt"
+      {"f32x4.nearest", TokenType::Unary, Opcode::F32X4Nearest},
+#line 304 "src/lexer-keywords.txt"
+      {"i32x4.all_true", TokenType::Unary, Opcode::I32X4AllTrue},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 433 "src/lexer-keywords.txt"
+      {"i64.trunc_f64_u", TokenType::Convert, Opcode::I64TruncF64U},
+#line 295 "src/lexer-keywords.txt"
+      {"i32.trunc_f64_u", TokenType::Convert, Opcode::I32TruncF64U},
+#line 542 "src/lexer-keywords.txt"
+      {"return_call_indirect", TokenType::ReturnCallIndirect, Opcode::ReturnCallIndirect},
+      {""},
+#line 432 "src/lexer-keywords.txt"
+      {"i64.trunc_f64_s", TokenType::Convert, Opcode::I64TruncF64S},
+#line 294 "src/lexer-keywords.txt"
+      {"i32.trunc_f64_s", TokenType::Convert, Opcode::I32TruncF64S},
+#line 537 "src/lexer-keywords.txt"
+      {"ref.is_null", TokenType::RefIsNull, Opcode::RefIsNull},
+      {""}, {""}, {""}, {""},
+#line 555 "src/lexer-keywords.txt"
+      {"table.size", TokenType::TableSize, Opcode::TableSize},
+      {""},
+#line 108 "src/lexer-keywords.txt"
+      {"f32x4.trunc", TokenType::Unary, Opcode::F32X4Trunc},
+      {""},
+#line 405 "src/lexer-keywords.txt"
+      {"i64.load16_u", TokenType::Load, Opcode::I64Load16U},
+#line 270 "src/lexer-keywords.txt"
+      {"i32.load16_u", TokenType::Load, Opcode::I32Load16U},
+      {""}, {""},
+#line 404 "src/lexer-keywords.txt"
+      {"i64.load16_s", TokenType::Load, Opcode::I64Load16S},
+#line 269 "src/lexer-keywords.txt"
+      {"i32.load16_s", TokenType::Load, Opcode::I32Load16S},
+#line 385 "src/lexer-keywords.txt"
+      {"i64.atomic.store", TokenType::AtomicStore, Opcode::I64AtomicStore},
+#line 253 "src/lexer-keywords.txt"
+      {"i32.atomic.store", TokenType::AtomicStore, Opcode::I32AtomicStore},
+#line 393 "src/lexer-keywords.txt"
+      {"i64.extend16_s", TokenType::Unary, Opcode::I64Extend16S},
+#line 261 "src/lexer-keywords.txt"
+      {"i32.extend16_s", TokenType::Unary, Opcode::I32Extend16S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 82 "src/lexer-keywords.txt"
+      {"f32", Type::F32},
+      {""},
+#line 300 "src/lexer-keywords.txt"
+      {"i32", Type::I32},
+      {""}, {""}, {""},
+#line 104 "src/lexer-keywords.txt"
+      {"f32x4.replace_lane", TokenType::SimdLaneOp, Opcode::F32X4ReplaceLane},
+#line 365 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32SubU},
+#line 326 "src/lexer-keywords.txt"
+      {"i32x4.replace_lane", TokenType::SimdLaneOp, Opcode::I32X4ReplaceLane},
+#line 98 "src/lexer-keywords.txt"
+      {"f32x4.mul", TokenType::Binary, Opcode::F32X4Mul},
+      {""},
+#line 323 "src/lexer-keywords.txt"
+      {"i32x4.mul", TokenType::Binary, Opcode::I32X4Mul},
+      {""},
+#line 553 "src/lexer-keywords.txt"
+      {"table.init", TokenType::TableInit, Opcode::TableInit},
+      {""}, {""}, {""}, {""}, {""},
+#line 353 "src/lexer-keywords.txt"
       {"i64.atomic.load", TokenType::AtomicLoad, Opcode::I64AtomicLoad},
-#line 230 "src/lexer-keywords.txt"
+#line 229 "src/lexer-keywords.txt"
       {"i32.atomic.load", TokenType::AtomicLoad, Opcode::I32AtomicLoad},
-      {""}, {""},
-#line 538 "src/lexer-keywords.txt"
-      {"ref.null", TokenType::RefNull, Opcode::RefNull},
       {""}, {""}, {""}, {""}, {""}, {""},
-#line 139 "src/lexer-keywords.txt"
-      {"f64.trunc", TokenType::Unary, Opcode::F64Trunc},
-#line 81 "src/lexer-keywords.txt"
-      {"f32.trunc", TokenType::Unary, Opcode::F32Trunc},
-      {""}, {""}, {""}, {""},
-#line 431 "src/lexer-keywords.txt"
-      {"i64.trunc_f32_s", TokenType::Convert, Opcode::I64TruncF32S},
-#line 293 "src/lexer-keywords.txt"
-      {"i32.trunc_f32_s", TokenType::Convert, Opcode::I32TruncF32S},
-#line 432 "src/lexer-keywords.txt"
-      {"i64.trunc_f32_u", TokenType::Convert, Opcode::I64TruncF32U},
-#line 294 "src/lexer-keywords.txt"
-      {"i32.trunc_f32_u", TokenType::Convert, Opcode::I32TruncF32U},
+#line 378 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I64AtomicRmwOr},
+#line 247 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I32AtomicRmwOr},
+      {""},
+#line 362 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AndU},
+#line 352 "src/lexer-keywords.txt"
+      {"i64.atomic.load8_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad8U},
+#line 228 "src/lexer-keywords.txt"
+      {"i32.atomic.load8_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad8U},
       {""}, {""}, {""},
-#line 27 "src/lexer-keywords.txt"
-      {"atomic.fence", TokenType::AtomicFence, Opcode::AtomicFence},
+#line 361 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AddU},
+      {""},
+#line 148 "src/lexer-keywords.txt"
+      {"f64x2.ge", TokenType::Compare, Opcode::F64X2Ge},
+#line 110 "src/lexer-keywords.txt"
+      {"f32x4", TokenType::F32X4},
+#line 150 "src/lexer-keywords.txt"
+      {"f64x2.le", TokenType::Compare, Opcode::F64X2Le},
+#line 338 "src/lexer-keywords.txt"
+      {"i32x4", TokenType::I32X4},
+      {""},
+#line 449 "src/lexer-keywords.txt"
+      {"i64x2.ge_s", TokenType::Binary, Opcode::I64X2GeS},
+      {""},
+#line 448 "src/lexer-keywords.txt"
+      {"i64x2.le_s", TokenType::Binary, Opcode::I64X2LeS},
+      {""}, {""},
+#line 319 "src/lexer-keywords.txt"
+      {"i32x4.max_u", TokenType::Binary, Opcode::I32X4MaxU},
+      {""},
+#line 318 "src/lexer-keywords.txt"
+      {"i32x4.max_s", TokenType::Binary, Opcode::I32X4MaxS},
+#line 447 "src/lexer-keywords.txt"
+      {"i64x2.gt_s", TokenType::Binary, Opcode::I64X2GtS},
+      {""},
+#line 446 "src/lexer-keywords.txt"
+      {"i64x2.lt_s", TokenType::Binary, Opcode::I64X2LtS},
+#line 149 "src/lexer-keywords.txt"
+      {"f64x2.gt", TokenType::Compare, Opcode::F64X2Gt},
+#line 156 "src/lexer-keywords.txt"
+      {"f64x2.neg", TokenType::Unary, Opcode::F64X2Neg},
+#line 151 "src/lexer-keywords.txt"
+      {"f64x2.lt", TokenType::Compare, Opcode::F64X2Lt},
+#line 451 "src/lexer-keywords.txt"
+      {"i64x2.neg", TokenType::Unary, Opcode::I64X2Neg},
+#line 509 "src/lexer-keywords.txt"
+      {"invoke", TokenType::Invoke},
+#line 90 "src/lexer-keywords.txt"
+      {"f32x4.extract_lane", TokenType::SimdLaneOp, Opcode::F32X4ExtractLane},
+#line 157 "src/lexer-keywords.txt"
+      {"f64x2.ne", TokenType::Compare, Opcode::F64X2Ne},
+#line 307 "src/lexer-keywords.txt"
+      {"i32x4.extract_lane", TokenType::SimdLaneOp, Opcode::I32X4ExtractLane},
+#line 445 "src/lexer-keywords.txt"
+      {"i64x2.ne", TokenType::Binary, Opcode::I64X2Ne},
+      {""},
+#line 397 "src/lexer-keywords.txt"
+      {"i64.extend_i32_u", TokenType::Convert, Opcode::I64ExtendI32U},
+#line 96 "src/lexer-keywords.txt"
+      {"f32x4.max", TokenType::Binary, Opcode::F32X4Max},
+#line 396 "src/lexer-keywords.txt"
+      {"i64.extend_i32_s", TokenType::Convert, Opcode::I64ExtendI32S},
+      {""},
+#line 129 "src/lexer-keywords.txt"
+      {"f64.min", TokenType::Binary, Opcode::F64Min},
+#line 72 "src/lexer-keywords.txt"
+      {"f32.min", TokenType::Binary, Opcode::F32Min},
       {""}, {""}, {""},
-#line 592 "src/lexer-keywords.txt"
-      {"i64.atomic.wait", TokenType::AtomicWait, Opcode::MemoryAtomicWait64},
-#line 591 "src/lexer-keywords.txt"
-      {"i32.atomic.wait", TokenType::AtomicWait, Opcode::MemoryAtomicWait32},
+#line 49 "src/lexer-keywords.txt"
+      {"tag", TokenType::Tag},
       {""},
-#line 101 "src/lexer-keywords.txt"
-      {"f32x4.ne", TokenType::Compare, Opcode::F32X4Ne},
-#line 567 "src/lexer-keywords.txt"
-      {"v128.not", TokenType::Unary, Opcode::V128Not},
-#line 97 "src/lexer-keywords.txt"
-      {"f32x4.min", TokenType::Binary, Opcode::F32X4Min},
-#line 326 "src/lexer-keywords.txt"
-      {"i32x4.ne", TokenType::Compare, Opcode::I32X4Ne},
-#line 120 "src/lexer-keywords.txt"
-      {"f64.div", TokenType::Binary, Opcode::F64Div},
-#line 63 "src/lexer-keywords.txt"
-      {"f32.div", TokenType::Binary, Opcode::F32Div},
+#line 376 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.and", TokenType::AtomicRmw, Opcode::I64AtomicRmwAnd},
+#line 245 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.and", TokenType::AtomicRmw, Opcode::I32AtomicRmwAnd},
+#line 560 "src/lexer-keywords.txt"
+      {"type", TokenType::Type},
+#line 143 "src/lexer-keywords.txt"
+      {"f64x2.ceil", TokenType::Unary, Opcode::F64X2Ceil},
       {""}, {""},
+#line 375 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I64AtomicRmwAdd},
+#line 244 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I32AtomicRmwAdd},
+      {""},
+#line 427 "src/lexer-keywords.txt"
+      {"i64.store8", TokenType::Store, Opcode::I64Store8},
+#line 289 "src/lexer-keywords.txt"
+      {"i32.store8", TokenType::Store, Opcode::I32Store8},
+#line 142 "src/lexer-keywords.txt"
+      {"f64x2.add", TokenType::Binary, Opcode::F64X2Add},
+#line 172 "src/lexer-keywords.txt"
+      {"get", TokenType::Get},
+#line 439 "src/lexer-keywords.txt"
+      {"i64x2.add", TokenType::Binary, Opcode::I64X2Add},
+      {""}, {""}, {""}, {""},
+#line 364 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32OrU},
 #line 422 "src/lexer-keywords.txt"
-      {"i64.rotr", TokenType::Binary, Opcode::I64Rotr},
+      {"i64.shl", TokenType::Binary, Opcode::I64Shl},
 #line 285 "src/lexer-keywords.txt"
-      {"i32.rotr", TokenType::Binary, Opcode::I32Rotr},
-      {""}, {""},
-#line 321 "src/lexer-keywords.txt"
-      {"i32x4.min_s", TokenType::Binary, Opcode::I32X4MinS},
-#line 560 "src/lexer-keywords.txt"
-      {"type", TokenType::Type},
+      {"i32.shl", TokenType::Binary, Opcode::I32Shl},
       {""}, {""},
-#line 322 "src/lexer-keywords.txt"
-      {"i32x4.min_u", TokenType::Binary, Opcode::I32X4MinU},
-#line 598 "src/lexer-keywords.txt"
-      {"f32.demote/f64", TokenType::Convert, Opcode::F32DemoteF64},
+#line 155 "src/lexer-keywords.txt"
+      {"f64x2.nearest", TokenType::Unary, Opcode::F64X2Nearest},
+#line 452 "src/lexer-keywords.txt"
+      {"i64x2.all_true", TokenType::Unary, Opcode::I64X2AllTrue},
       {""},
-#line 95 "src/lexer-keywords.txt"
-      {"f32x4.lt", TokenType::Compare, Opcode::F32X4Lt},
-#line 509 "src/lexer-keywords.txt"
-      {"input", TokenType::Input},
+#line 366 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XchgU},
       {""},
-#line 115 "src/lexer-keywords.txt"
-      {"f64.convert_i32_s", TokenType::Convert, Opcode::F64ConvertI32S},
-#line 57 "src/lexer-keywords.txt"
-      {"f32.convert_i32_s", TokenType::Convert, Opcode::F32ConvertI32S},
-      {""}, {""},
+#line 381 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I64AtomicRmwXor},
+#line 250 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I32AtomicRmwXor},
 #line 508 "src/lexer-keywords.txt"
-      {"import", TokenType::Import},
+      {"input", TokenType::Input},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
 #line 164 "src/lexer-keywords.txt"
       {"f64x2.trunc", TokenType::Unary, Opcode::F64X2Trunc},
-      {""},
-#line 52 "src/lexer-keywords.txt"
-      {"export", TokenType::Export},
-#line 107 "src/lexer-keywords.txt"
-      {"f32x4.sub", TokenType::Binary, Opcode::F32X4Sub},
-#line 94 "src/lexer-keywords.txt"
-      {"f32x4.le", TokenType::Compare, Opcode::F32X4Le},
-#line 317 "src/lexer-keywords.txt"
-      {"i32x4.lt_s", TokenType::Compare, Opcode::I32X4LtS},
-#line 332 "src/lexer-keywords.txt"
-      {"i32x4.sub", TokenType::Binary, Opcode::I32X4Sub},
-#line 318 "src/lexer-keywords.txt"
-      {"i32x4.lt_u", TokenType::Compare, Opcode::I32X4LtU},
       {""}, {""}, {""},
-#line 313 "src/lexer-keywords.txt"
-      {"i32x4.le_s", TokenType::Compare, Opcode::I32X4LeS},
+#line 507 "src/lexer-keywords.txt"
+      {"import", TokenType::Import},
+      {""}, {""}, {""},
+#line 426 "src/lexer-keywords.txt"
+      {"i64.store32", TokenType::Store, Opcode::I64Store32},
       {""},
-#line 314 "src/lexer-keywords.txt"
-      {"i32x4.le_u", TokenType::Compare, Opcode::I32X4LeU},
+#line 367 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XorU},
+#line 407 "src/lexer-keywords.txt"
+      {"i64.load32_u", TokenType::Load, Opcode::I64Load32U},
+#line 136 "src/lexer-keywords.txt"
+      {"f64.sqrt", TokenType::Unary, Opcode::F64Sqrt},
+#line 78 "src/lexer-keywords.txt"
+      {"f32.sqrt", TokenType::Unary, Opcode::F32Sqrt},
       {""},
-#line 543 "src/lexer-keywords.txt"
-      {"return_call", TokenType::ReturnCall, Opcode::ReturnCall},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 453 "src/lexer-keywords.txt"
-      {"i64x2.all_true", TokenType::Unary, Opcode::I64X2AllTrue},
+#line 406 "src/lexer-keywords.txt"
+      {"i64.load32_s", TokenType::Load, Opcode::I64Load32S},
       {""},
-#line 562 "src/lexer-keywords.txt"
-      {"v128.andnot", TokenType::Binary, Opcode::V128Andnot},
 #line 563 "src/lexer-keywords.txt"
       {"v128.and", TokenType::Binary, Opcode::V128And},
-#line 529 "src/lexer-keywords.txt"
-      {"nan:canonical", TokenType::NanCanonical},
-      {""}, {""}, {""},
-#line 352 "src/lexer-keywords.txt"
-      {"i64.atomic.load32_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad32U},
-      {""}, {""},
-#line 98 "src/lexer-keywords.txt"
-      {"f32x4.mul", TokenType::Binary, Opcode::F32X4Mul},
       {""},
-#line 24 "src/lexer-keywords.txt"
-      {"assert_return", TokenType::AssertReturn},
-#line 324 "src/lexer-keywords.txt"
-      {"i32x4.mul", TokenType::Binary, Opcode::I32X4Mul},
-#line 433 "src/lexer-keywords.txt"
-      {"i64.trunc_f64_s", TokenType::Convert, Opcode::I64TruncF64S},
-#line 295 "src/lexer-keywords.txt"
-      {"i32.trunc_f64_s", TokenType::Convert, Opcode::I32TruncF64S},
-#line 434 "src/lexer-keywords.txt"
-      {"i64.trunc_f64_u", TokenType::Convert, Opcode::I64TruncF64U},
-#line 296 "src/lexer-keywords.txt"
-      {"i32.trunc_f64_u", TokenType::Convert, Opcode::I32TruncF64U},
-#line 83 "src/lexer-keywords.txt"
-      {"f32x4.abs", TokenType::Unary, Opcode::F32X4Abs},
+#line 394 "src/lexer-keywords.txt"
+      {"i64.extend32_s", TokenType::Unary, Opcode::I64Extend32S},
       {""},
-#line 44 "src/lexer-keywords.txt"
-      {"drop", TokenType::Drop, Opcode::Drop},
-#line 303 "src/lexer-keywords.txt"
-      {"i32x4.abs", TokenType::Unary, Opcode::I32X4Abs},
+#line 424 "src/lexer-keywords.txt"
+      {"i64.shr_u", TokenType::Binary, Opcode::I64ShrU},
+#line 287 "src/lexer-keywords.txt"
+      {"i32.shr_u", TokenType::Binary, Opcode::I32ShrU},
+#line 423 "src/lexer-keywords.txt"
+      {"i64.shr_s", TokenType::Binary, Opcode::I64ShrS},
+#line 286 "src/lexer-keywords.txt"
+      {"i32.shr_s", TokenType::Binary, Opcode::I32ShrS},
       {""},
-#line 144 "src/lexer-keywords.txt"
-      {"f64x2.div", TokenType::Binary, Opcode::F64X2Div},
-      {""}, {""}, {""},
-#line 565 "src/lexer-keywords.txt"
-      {"v128.const", TokenType::Const, Opcode::V128Const},
-      {""}, {""}, {""}, {""},
-#line 23 "src/lexer-keywords.txt"
-      {"assert_malformed", TokenType::AssertMalformed},
-#line 516 "src/lexer-keywords.txt"
-      {"loop", TokenType::Loop, Opcode::Loop},
-      {""}, {""},
-#line 621 "src/lexer-keywords.txt"
-      {"i64.trunc_s/f32", TokenType::Convert, Opcode::I64TruncF32S},
-#line 609 "src/lexer-keywords.txt"
-      {"i32.trunc_s/f32", TokenType::Convert, Opcode::I32TruncF32S},
-#line 625 "src/lexer-keywords.txt"
-      {"i64.trunc_u/f32", TokenType::Convert, Opcode::I64TruncF32U},
-#line 613 "src/lexer-keywords.txt"
-      {"i32.trunc_u/f32", TokenType::Convert, Opcode::I32TruncF32U},
-#line 99 "src/lexer-keywords.txt"
-      {"f32x4.nearest", TokenType::Unary, Opcode::F32X4Nearest},
-#line 395 "src/lexer-keywords.txt"
-      {"i64.extend32_s", TokenType::Unary, Opcode::I64Extend32S},
+#line 539 "src/lexer-keywords.txt"
+      {"register", TokenType::Register},
+#line 160 "src/lexer-keywords.txt"
+      {"f64x2.replace_lane", TokenType::SimdLaneOp, Opcode::F64X2ReplaceLane},
       {""},
-#line 159 "src/lexer-keywords.txt"
-      {"f64x2.pmin", TokenType::Binary, Opcode::F64X2PMin},
-#line 147 "src/lexer-keywords.txt"
-      {"f64x2.floor", TokenType::Unary, Opcode::F64X2Floor},
-      {""}, {""}, {""}, {""}, {""}, {""},
-#line 117 "src/lexer-keywords.txt"
-      {"f64.convert_i64_s", TokenType::Convert, Opcode::F64ConvertI64S},
-#line 59 "src/lexer-keywords.txt"
-      {"f32.convert_i64_s", TokenType::Convert, Opcode::F32ConvertI64S},
-#line 397 "src/lexer-keywords.txt"
-      {"i64.extend_i32_s", TokenType::Convert, Opcode::I64ExtendI32S},
-#line 85 "src/lexer-keywords.txt"
-      {"f32x4.ceil", TokenType::Unary, Opcode::F32X4Ceil},
+#line 458 "src/lexer-keywords.txt"
+      {"i64x2.replace_lane", TokenType::SimdLaneOp, Opcode::I64X2ReplaceLane},
+#line 154 "src/lexer-keywords.txt"
+      {"f64x2.mul", TokenType::Binary, Opcode::F64X2Mul},
+      {""},
+#line 443 "src/lexer-keywords.txt"
+      {"i64x2.mul", TokenType::Binary, Opcode::I64X2Mul},
       {""}, {""},
-#line 398 "src/lexer-keywords.txt"
-      {"i64.extend_i32_u", TokenType::Convert, Opcode::I64ExtendI32U},
+#line 38 "src/lexer-keywords.txt"
+      {"catch_all", TokenType::CatchAll, Opcode::CatchAll},
+      {""}, {""},
+#line 568 "src/lexer-keywords.txt"
+      {"v128.or", TokenType::Binary, Opcode::V128Or},
+      {""}, {""},
+#line 572 "src/lexer-keywords.txt"
+      {"v128.store", TokenType::Store, Opcode::V128Store},
+#line 566 "src/lexer-keywords.txt"
+      {"v128.load", TokenType::Load, Opcode::V128Load},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 573 "src/lexer-keywords.txt"
+      {"v128", Type::V128},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 534 "src/lexer-keywords.txt"
+      {"quote", TokenType::Quote},
+#line 567 "src/lexer-keywords.txt"
+      {"v128.not", TokenType::Unary, Opcode::V128Not},
       {""},
-#line 541 "src/lexer-keywords.txt"
-      {"rethrow", TokenType::Rethrow, Opcode::Rethrow},
+#line 531 "src/lexer-keywords.txt"
+      {"output", TokenType::Output},
+      {""}, {""},
+#line 369 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AndU},
+#line 238 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AndU},
       {""},
-#line 84 "src/lexer-keywords.txt"
-      {"f32x4.add", TokenType::Binary, Opcode::F32X4Add},
-#line 435 "src/lexer-keywords.txt"
-      {"i64.trunc_sat_f32_s", TokenType::Convert, Opcode::I64TruncSatF32S},
-#line 297 "src/lexer-keywords.txt"
-      {"i32.trunc_sat_f32_s", TokenType::Convert, Opcode::I32TruncSatF32S},
-#line 304 "src/lexer-keywords.txt"
-      {"i32x4.add", TokenType::Binary, Opcode::I32X4Add},
+#line 530 "src/lexer-keywords.txt"
+      {"offset", TokenType::Offset},
+      {""}, {""},
+#line 368 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AddU},
+#line 237 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AddU},
+      {""}, {""}, {""}, {""},
+#line 30 "src/lexer-keywords.txt"
+      {"block", TokenType::Block, Opcode::Block},
       {""},
-#line 436 "src/lexer-keywords.txt"
-      {"i64.trunc_sat_f32_u", TokenType::Convert, Opcode::I64TruncSatF32U},
-#line 298 "src/lexer-keywords.txt"
-      {"i32.trunc_sat_f32_u", TokenType::Convert, Opcode::I32TruncSatF32U},
+#line 528 "src/lexer-keywords.txt"
+      {"nan:canonical", TokenType::NanCanonical},
       {""}, {""},
-#line 564 "src/lexer-keywords.txt"
-      {"v128.bitselect", TokenType::Ternary, Opcode::V128BitSelect},
+#line 146 "src/lexer-keywords.txt"
+      {"f64x2.extract_lane", TokenType::SimdLaneOp, Opcode::F64X2ExtractLane},
+#line 562 "src/lexer-keywords.txt"
+      {"v128.andnot", TokenType::Binary, Opcode::V128Andnot},
+#line 440 "src/lexer-keywords.txt"
+      {"i64x2.extract_lane", TokenType::SimdLaneOp, Opcode::I64X2ExtractLane},
+#line 350 "src/lexer-keywords.txt"
+      {"i64.atomic.load16_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad16U},
+#line 227 "src/lexer-keywords.txt"
+      {"i32.atomic.load16_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad16U},
+#line 442 "src/lexer-keywords.txt"
+      {"v128.load32x2_u", TokenType::Load, Opcode::V128Load32X2U},
+#line 152 "src/lexer-keywords.txt"
+      {"f64x2.max", TokenType::Binary, Opcode::F64X2Max},
+      {""}, {""},
+#line 441 "src/lexer-keywords.txt"
+      {"v128.load32x2_s", TokenType::Load, Opcode::V128Load32X2S},
+#line 581 "src/lexer-keywords.txt"
+      {"v128.load32_lane", TokenType::SimdLoadLane, Opcode::V128Load32Lane},
+      {""}, {""}, {""},
+#line 34 "src/lexer-keywords.txt"
+      {"call_indirect", TokenType::CallIndirect, Opcode::CallIndirect},
       {""},
-#line 383 "src/lexer-keywords.txt"
-      {"i64.atomic.store16", TokenType::AtomicStore, Opcode::I64AtomicStore16},
-#line 252 "src/lexer-keywords.txt"
-      {"i32.atomic.store16", TokenType::AtomicStore, Opcode::I32AtomicStore16},
+#line 576 "src/lexer-keywords.txt"
+      {"v128.load32_splat", TokenType::Load, Opcode::V128Load32Splat},
+#line 574 "src/lexer-keywords.txt"
+      {"v128.xor", TokenType::Binary, Opcode::V128Xor},
       {""},
-#line 373 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw8.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8SubU},
-#line 242 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw8.sub_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8SubU},
+#line 187 "src/lexer-keywords.txt"
+      {"i16x8.ge_u", TokenType::Compare, Opcode::I16X8GeU},
+#line 565 "src/lexer-keywords.txt"
+      {"v128.const", TokenType::Const, Opcode::V128Const},
+#line 191 "src/lexer-keywords.txt"
+      {"i16x8.le_u", TokenType::Compare, Opcode::I16X8LeU},
+      {""},
+#line 186 "src/lexer-keywords.txt"
+      {"i16x8.ge_s", TokenType::Compare, Opcode::I16X8GeS},
+      {""},
+#line 190 "src/lexer-keywords.txt"
+      {"i16x8.le_s", TokenType::Compare, Opcode::I16X8LeS},
+#line 583 "src/lexer-keywords.txt"
+      {"v128.store8_lane", TokenType::SimdStoreLane, Opcode::V128Store8Lane},
+#line 189 "src/lexer-keywords.txt"
+      {"i16x8.gt_u", TokenType::Compare, Opcode::I16X8GtU},
       {""},
-#line 161 "src/lexer-keywords.txt"
-      {"f64x2.splat", TokenType::Unary, Opcode::F64X2Splat},
-      {""}, {""},
-#line 463 "src/lexer-keywords.txt"
-      {"i64x2.splat", TokenType::Unary, Opcode::I64X2Splat},
+#line 195 "src/lexer-keywords.txt"
+      {"i16x8.lt_u", TokenType::Compare, Opcode::I16X8LtU},
       {""},
-#line 426 "src/lexer-keywords.txt"
-      {"i64.store16", TokenType::Store, Opcode::I64Store16},
-#line 289 "src/lexer-keywords.txt"
-      {"i32.store16", TokenType::Store, Opcode::I32Store16},
-#line 306 "src/lexer-keywords.txt"
-      {"i32x4.bitmask", TokenType::Unary, Opcode::I32X4Bitmask},
+#line 188 "src/lexer-keywords.txt"
+      {"i16x8.gt_s", TokenType::Compare, Opcode::I16X8GtS},
       {""},
-#line 566 "src/lexer-keywords.txt"
-      {"v128.load", TokenType::Load, Opcode::V128Load},
+#line 194 "src/lexer-keywords.txt"
+      {"i16x8.lt_s", TokenType::Compare, Opcode::I16X8LtS},
+      {""}, {""}, {""},
+#line 203 "src/lexer-keywords.txt"
+      {"i16x8.neg", TokenType::Unary, Opcode::I16X8Neg},
+#line 97 "src/lexer-keywords.txt"
+      {"f32x4.min", TokenType::Binary, Opcode::F32X4Min},
+      {""}, {""}, {""},
+#line 205 "src/lexer-keywords.txt"
+      {"i16x8.ne", TokenType::Compare, Opcode::I16X8Ne},
       {""}, {""}, {""}, {""}, {""}, {""},
-#line 572 "src/lexer-keywords.txt"
-      {"v128.store", TokenType::Store, Opcode::V128Store},
-#line 370 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AndU},
-#line 239 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AndU},
+#line 371 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8OrU},
+#line 240 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8OrU},
+      {""}, {""}, {""},
+#line 321 "src/lexer-keywords.txt"
+      {"i32x4.min_u", TokenType::Binary, Opcode::I32X4MinU},
       {""},
-#line 533 "src/lexer-keywords.txt"
-      {"param", TokenType::Param},
-#line 542 "src/lexer-keywords.txt"
-      {"return_call_indirect", TokenType::ReturnCallIndirect, Opcode::ReturnCallIndirect},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 600 "src/lexer-keywords.txt"
-      {"f64.convert_s/i32", TokenType::Convert, Opcode::F64ConvertI32S},
-#line 594 "src/lexer-keywords.txt"
-      {"f32.convert_s/i32", TokenType::Convert, Opcode::F32ConvertI32S},
-#line 602 "src/lexer-keywords.txt"
-      {"f64.convert_u/i32", TokenType::Convert, Opcode::F64ConvertI32U},
-#line 596 "src/lexer-keywords.txt"
-      {"f32.convert_u/i32", TokenType::Convert, Opcode::F32ConvertI32U},
-      {""}, {""},
-#line 369 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AddU},
-#line 238 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AddU},
+#line 320 "src/lexer-keywords.txt"
+      {"i32x4.min_s", TokenType::Binary, Opcode::I32X4MinS},
+      {""}, {""}, {""},
+#line 212 "src/lexer-keywords.txt"
+      {"i16x8.sub_sat_u", TokenType::Binary, Opcode::I16X8SubSatU},
+#line 384 "src/lexer-keywords.txt"
+      {"i64.atomic.store8", TokenType::AtomicStore, Opcode::I64AtomicStore8},
+#line 252 "src/lexer-keywords.txt"
+      {"i32.atomic.store8", TokenType::AtomicStore, Opcode::I32AtomicStore8},
       {""},
-#line 573 "src/lexer-keywords.txt"
-      {"v128", Type::V128},
-#line 622 "src/lexer-keywords.txt"
-      {"i64.trunc_s/f64", TokenType::Convert, Opcode::I64TruncF64S},
-#line 610 "src/lexer-keywords.txt"
-      {"i32.trunc_s/f64", TokenType::Convert, Opcode::I32TruncF64S},
-#line 626 "src/lexer-keywords.txt"
-      {"i64.trunc_u/f64", TokenType::Convert, Opcode::I64TruncF64U},
-#line 614 "src/lexer-keywords.txt"
-      {"i32.trunc_u/f64", TokenType::Convert, Opcode::I32TruncF64U},
-#line 618 "src/lexer-keywords.txt"
-      {"i64.extend_s/i32", TokenType::Convert, Opcode::I64ExtendI32S},
-      {""},
-#line 619 "src/lexer-keywords.txt"
-      {"i64.extend_u/i32", TokenType::Convert, Opcode::I64ExtendI32U},
-      {""}, {""},
-#line 116 "src/lexer-keywords.txt"
-      {"f64.convert_i32_u", TokenType::Convert, Opcode::F64ConvertI32U},
-#line 58 "src/lexer-keywords.txt"
-      {"f32.convert_i32_u", TokenType::Convert, Opcode::F32ConvertI32U},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 211 "src/lexer-keywords.txt"
+      {"i16x8.sub_sat_s", TokenType::Binary, Opcode::I16X8SubSatS},
+#line 386 "src/lexer-keywords.txt"
+      {"i64.clz", TokenType::Unary, Opcode::I64Clz},
+#line 254 "src/lexer-keywords.txt"
+      {"i32.clz", TokenType::Unary, Opcode::I32Clz},
+#line 527 "src/lexer-keywords.txt"
+      {"nan:arithmetic", TokenType::NanArithmetic},
+#line 179 "src/lexer-keywords.txt"
+      {"i16x8.add", TokenType::Binary, Opcode::I16X8Add},
       {""}, {""},
-#line 409 "src/lexer-keywords.txt"
-      {"i64.load8_s", TokenType::Load, Opcode::I64Load8S},
-#line 272 "src/lexer-keywords.txt"
-      {"i32.load8_s", TokenType::Load, Opcode::I32Load8S},
+#line 570 "src/lexer-keywords.txt"
+      {"v128.load32_zero", TokenType::Load, Opcode::V128Load32Zero},
       {""}, {""},
-#line 410 "src/lexer-keywords.txt"
-      {"i64.load8_u", TokenType::Load, Opcode::I64Load8U},
-#line 273 "src/lexer-keywords.txt"
-      {"i32.load8_u", TokenType::Load, Opcode::I32Load8U},
-#line 376 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I64AtomicRmwAdd},
-#line 245 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I32AtomicRmwAdd},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""},
-#line 366 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw32.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32SubU},
+#line 374 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XorU},
+#line 243 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XorU},
       {""},
-#line 172 "src/lexer-keywords.txt"
-      {"get", TokenType::Get},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 388 "src/lexer-keywords.txt"
+      {"i64.ctz", TokenType::Unary, Opcode::I64Ctz},
+#line 256 "src/lexer-keywords.txt"
+      {"i32.ctz", TokenType::Unary, Opcode::I32Ctz},
+#line 180 "src/lexer-keywords.txt"
+      {"i16x8.all_true", TokenType::Unary, Opcode::I16X8AllTrue},
       {""}, {""}, {""}, {""},
-#line 394 "src/lexer-keywords.txt"
-      {"i64.extend16_s", TokenType::Unary, Opcode::I64Extend16S},
-#line 262 "src/lexer-keywords.txt"
-      {"i32.extend16_s", TokenType::Unary, Opcode::I32Extend16S},
-      {""}, {""}, {""}, {""}, {""}, {""},
-#line 558 "src/lexer-keywords.txt"
-      {"throw", TokenType::Throw, Opcode::Throw},
+#line 327 "src/lexer-keywords.txt"
+      {"i32x4.shl", TokenType::Binary, Opcode::I32X4Shl},
+      {""}, {""}, {""}, {""},
+#line 178 "src/lexer-keywords.txt"
+      {"i16x8.add_sat_u", TokenType::Binary, Opcode::I16X8AddSatU},
       {""},
-#line 377 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw.and", TokenType::AtomicRmw, Opcode::I64AtomicRmwAnd},
-#line 246 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw.and", TokenType::AtomicRmw, Opcode::I32AtomicRmwAnd},
+#line 506 "src/lexer-keywords.txt"
+      {"if", TokenType::If, Opcode::If},
       {""},
-#line 30 "src/lexer-keywords.txt"
-      {"br_if", TokenType::BrIf, Opcode::BrIf},
-#line 428 "src/lexer-keywords.txt"
-      {"i64.store8", TokenType::Store, Opcode::I64Store8},
-#line 290 "src/lexer-keywords.txt"
-      {"i32.store8", TokenType::Store, Opcode::I32Store8},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 534 "src/lexer-keywords.txt"
-      {"quote", TokenType::Quote},
-      {""}, {""}, {""}, {""},
+#line 177 "src/lexer-keywords.txt"
+      {"i16x8.add_sat_s", TokenType::Binary, Opcode::I16X8AddSatS},
+#line 39 "src/lexer-keywords.txt"
+      {"data.drop", TokenType::DataDrop, Opcode::DataDrop},
+#line 533 "src/lexer-keywords.txt"
+      {"ref", TokenType::Ref},
+      {""}, {""}, {""}, {""}, {""}, {""},
 #line 579 "src/lexer-keywords.txt"
       {"v128.load8_lane", TokenType::SimdLoadLane, Opcode::V128Load8Lane},
-#line 568 "src/lexer-keywords.txt"
-      {"v128.or", TokenType::Binary, Opcode::V128Or},
-      {""}, {""}, {""},
-#line 118 "src/lexer-keywords.txt"
-      {"f64.convert_i64_u", TokenType::Convert, Opcode::F64ConvertI64U},
-#line 60 "src/lexer-keywords.txt"
-      {"f32.convert_i64_u", TokenType::Convert, Opcode::F32ConvertI64U},
-#line 379 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I64AtomicRmwOr},
-#line 248 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I32AtomicRmwOr},
-      {""}, {""}, {""},
-#line 582 "src/lexer-keywords.txt"
-      {"v128.load64_lane", TokenType::SimdLoadLane, Opcode::V128Load64Lane},
-#line 581 "src/lexer-keywords.txt"
-      {"v128.load32_lane", TokenType::SimdLoadLane, Opcode::V128Load32Lane},
-#line 585 "src/lexer-keywords.txt"
-      {"v128.store32_lane", TokenType::SimdStoreLane, Opcode::V128Store32Lane},
-      {""},
-#line 363 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw32.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AndU},
       {""}, {""}, {""}, {""}, {""},
-#line 108 "src/lexer-keywords.txt"
-      {"f32x4.trunc", TokenType::Unary, Opcode::F32X4Trunc},
-      {""}, {""},
-#line 380 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I64AtomicRmwSub},
-#line 249 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I32AtomicRmwSub},
-#line 551 "src/lexer-keywords.txt"
-      {"table.get", TokenType::TableGet, Opcode::TableGet},
-#line 21 "src/lexer-keywords.txt"
-      {"assert_exhaustion", TokenType::AssertExhaustion},
+#line 578 "src/lexer-keywords.txt"
+      {"v128.load8_splat", TokenType::Load, Opcode::V128Load8Splat},
+#line 106 "src/lexer-keywords.txt"
+      {"f32x4.sqrt", TokenType::Unary, Opcode::F32X4Sqrt},
+      {""}, {""}, {""}, {""},
+#line 47 "src/lexer-keywords.txt"
+      {"else", TokenType::Else, Opcode::Else},
       {""},
-#line 535 "src/lexer-keywords.txt"
-      {"ref.extern", TokenType::RefExtern},
-      {""}, {""},
-#line 149 "src/lexer-keywords.txt"
-      {"f64x2.gt", TokenType::Compare, Opcode::F64X2Gt},
-#line 362 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw32.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AddU},
+#line 557 "src/lexer-keywords.txt"
+      {"then", TokenType::Then},
       {""},
-#line 416 "src/lexer-keywords.txt"
-      {"i64.or", TokenType::Binary, Opcode::I64Or},
-#line 279 "src/lexer-keywords.txt"
-      {"i32.or", TokenType::Binary, Opcode::I32Or},
-#line 124 "src/lexer-keywords.txt"
-      {"f64.gt", TokenType::Compare, Opcode::F64Gt},
-#line 67 "src/lexer-keywords.txt"
-      {"f32.gt", TokenType::Compare, Opcode::F32Gt},
-      {""}, {""}, {""}, {""}, {""},
-#line 148 "src/lexer-keywords.txt"
-      {"f64x2.ge", TokenType::Compare, Opcode::F64X2Ge},
-#line 448 "src/lexer-keywords.txt"
-      {"i64x2.gt_s", TokenType::Binary, Opcode::I64X2GtS},
-#line 305 "src/lexer-keywords.txt"
-      {"i32x4.all_true", TokenType::Unary, Opcode::I32X4AllTrue},
-      {""}, {""},
-#line 123 "src/lexer-keywords.txt"
-      {"f64.ge", TokenType::Compare, Opcode::F64Ge},
-#line 66 "src/lexer-keywords.txt"
-      {"f32.ge", TokenType::Compare, Opcode::F32Ge},
-#line 450 "src/lexer-keywords.txt"
-      {"i64x2.ge_s", TokenType::Binary, Opcode::I64X2GeS},
-      {""}, {""}, {""}, {""}, {""},
-#line 401 "src/lexer-keywords.txt"
-      {"i64.gt_s", TokenType::Compare, Opcode::I64GtS},
-#line 266 "src/lexer-keywords.txt"
-      {"i32.gt_s", TokenType::Compare, Opcode::I32GtS},
-      {""}, {""},
-#line 402 "src/lexer-keywords.txt"
-      {"i64.gt_u", TokenType::Compare, Opcode::I64GtU},
-#line 267 "src/lexer-keywords.txt"
-      {"i32.gt_u", TokenType::Compare, Opcode::I32GtU},
-#line 399 "src/lexer-keywords.txt"
-      {"i64.ge_s", TokenType::Compare, Opcode::I64GeS},
-#line 264 "src/lexer-keywords.txt"
-      {"i32.ge_s", TokenType::Compare, Opcode::I32GeS},
-      {""}, {""},
-#line 400 "src/lexer-keywords.txt"
-      {"i64.ge_u", TokenType::Compare, Opcode::I64GeU},
-#line 265 "src/lexer-keywords.txt"
-      {"i32.ge_u", TokenType::Compare, Opcode::I32GeU},
+#line 329 "src/lexer-keywords.txt"
+      {"i32x4.shr_u", TokenType::Binary, Opcode::I32X4ShrU},
       {""},
-#line 88 "src/lexer-keywords.txt"
-      {"f32x4.div", TokenType::Binary, Opcode::F32X4Div},
+#line 328 "src/lexer-keywords.txt"
+      {"i32x4.shr_s", TokenType::Binary, Opcode::I32X4ShrS},
+#line 532 "src/lexer-keywords.txt"
+      {"param", TokenType::Param},
       {""}, {""},
-#line 359 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw16.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16SubU},
-#line 235 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw16.sub_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16SubU},
+#line 168 "src/lexer-keywords.txt"
+      {"f64x2", TokenType::F64X2},
+#line 220 "src/lexer-keywords.txt"
+      {"i16x8", TokenType::I16X8},
+#line 468 "src/lexer-keywords.txt"
+      {"i64x2", TokenType::I64X2},
+#line 48 "src/lexer-keywords.txt"
+      {"end", TokenType::End, Opcode::End},
+      {""}, {""}, {""},
+#line 206 "src/lexer-keywords.txt"
+      {"i16x8.replace_lane", TokenType::SimdLaneOp, Opcode::I16X8ReplaceLane},
+      {""}, {""},
+#line 200 "src/lexer-keywords.txt"
+      {"i16x8.mul", TokenType::Binary, Opcode::I16X8Mul},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""},
+#line 169 "src/lexer-keywords.txt"
+      {"field", TokenType::Field},
+#line 351 "src/lexer-keywords.txt"
+      {"i64.atomic.load32_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad32U},
+#line 584 "src/lexer-keywords.txt"
+      {"v128.store16_lane", TokenType::SimdStoreLane, Opcode::V128Store16Lane},
       {""}, {""}, {""}, {""}, {""}, {""},
-#line 103 "src/lexer-keywords.txt"
-      {"f32x4.pmin", TokenType::Binary, Opcode::F32X4PMin},
-#line 91 "src/lexer-keywords.txt"
-      {"f32x4.floor", TokenType::Unary, Opcode::F32X4Floor},
-#line 571 "src/lexer-keywords.txt"
-      {"v128.load64_zero", TokenType::Load, Opcode::V128Load64Zero},
-#line 570 "src/lexer-keywords.txt"
-      {"v128.load32_zero", TokenType::Load, Opcode::V128Load32Zero},
+#line 50 "src/lexer-keywords.txt"
+      {"extern", Type::ExternRef, TokenType::Extern},
 #line 586 "src/lexer-keywords.txt"
       {"v128.store64_lane", TokenType::SimdStoreLane, Opcode::V128Store64Lane},
-#line 353 "src/lexer-keywords.txt"
-      {"i64.atomic.load8_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad8U},
-#line 229 "src/lexer-keywords.txt"
-      {"i32.atomic.load8_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad8U},
-#line 530 "src/lexer-keywords.txt"
-      {"nop", TokenType::Nop, Opcode::Nop},
-      {""},
-#line 136 "src/lexer-keywords.txt"
-      {"f64.sqrt", TokenType::Unary, Opcode::F64Sqrt},
-#line 78 "src/lexer-keywords.txt"
-      {"f32.sqrt", TokenType::Unary, Opcode::F32Sqrt},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 197 "src/lexer-keywords.txt"
+      {"i16x8.max_u", TokenType::Binary, Opcode::I16X8MaxU},
       {""},
-#line 36 "src/lexer-keywords.txt"
-      {"catch", TokenType::Catch, Opcode::Catch},
-#line 175 "src/lexer-keywords.txt"
-      {"global", TokenType::Global},
-      {""}, {""},
-#line 174 "src/lexer-keywords.txt"
-      {"global.set", TokenType::GlobalSet, Opcode::GlobalSet},
-      {""}, {""},
-#line 146 "src/lexer-keywords.txt"
-      {"f64x2.extract_lane", TokenType::SimdLaneOp, Opcode::F64X2ExtractLane},
-#line 128 "src/lexer-keywords.txt"
-      {"f64.max", TokenType::Binary, Opcode::F64Max},
-#line 71 "src/lexer-keywords.txt"
-      {"f32.max", TokenType::Binary, Opcode::F32Max},
-#line 441 "src/lexer-keywords.txt"
-      {"i64x2.extract_lane", TokenType::SimdLaneOp, Opcode::I64X2ExtractLane},
-#line 512 "src/lexer-keywords.txt"
-      {"local.get", TokenType::LocalGet, Opcode::LocalGet},
-#line 423 "src/lexer-keywords.txt"
-      {"i64.shl", TokenType::Binary, Opcode::I64Shl},
-#line 286 "src/lexer-keywords.txt"
-      {"i32.shl", TokenType::Binary, Opcode::I32Shl},
-      {""}, {""}, {""}, {""},
-#line 319 "src/lexer-keywords.txt"
-      {"i32x4.max_s", TokenType::Binary, Opcode::I32X4MaxS},
-      {""}, {""}, {""},
-#line 320 "src/lexer-keywords.txt"
-      {"i32x4.max_u", TokenType::Binary, Opcode::I32X4MaxU},
+#line 196 "src/lexer-keywords.txt"
+      {"i16x8.max_s", TokenType::Binary, Opcode::I16X8MaxS},
 #line 105 "src/lexer-keywords.txt"
       {"f32x4.splat", TokenType::Unary, Opcode::F32X4Splat},
       {""},
-#line 455 "src/lexer-keywords.txt"
-      {"i64x2.extend_low_i32x4_s", TokenType::Unary, Opcode::I64X2ExtendLowI32X4S},
-#line 331 "src/lexer-keywords.txt"
+#line 330 "src/lexer-keywords.txt"
       {"i32x4.splat", TokenType::Unary, Opcode::I32X4Splat},
-#line 457 "src/lexer-keywords.txt"
-      {"i64x2.extend_low_i32x4_u", TokenType::Unary, Opcode::I64X2ExtendLowI32X4U},
-#line 580 "src/lexer-keywords.txt"
-      {"v128.load16_lane", TokenType::SimdLoadLane, Opcode::V128Load16Lane},
-#line 365 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw32.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32OrU},
+      {""}, {""},
+#line 582 "src/lexer-keywords.txt"
+      {"v128.load64_lane", TokenType::SimdLoadLane, Opcode::V128Load64Lane},
       {""},
-#line 356 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AndU},
-#line 232 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AndU},
+#line 153 "src/lexer-keywords.txt"
+      {"f64x2.min", TokenType::Binary, Opcode::F64X2Min},
+      {""}, {""}, {""},
+#line 577 "src/lexer-keywords.txt"
+      {"v128.load64_splat", TokenType::Load, Opcode::V128Load64Splat},
       {""}, {""},
-#line 393 "src/lexer-keywords.txt"
-      {"i64.eqz", TokenType::Convert, Opcode::I64Eqz},
-#line 261 "src/lexer-keywords.txt"
-      {"i32.eqz", TokenType::Convert, Opcode::I32Eqz},
+#line 558 "src/lexer-keywords.txt"
+      {"throw", TokenType::Throw, Opcode::Throw},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 481 "src/lexer-keywords.txt"
+      {"i8x16.ge_u", TokenType::Compare, Opcode::I8X16GeU},
       {""},
-#line 465 "src/lexer-keywords.txt"
-      {"i64x2.extmul_low_i32x4_s", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4S},
+#line 485 "src/lexer-keywords.txt"
+      {"i8x16.le_u", TokenType::Compare, Opcode::I8X16LeU},
       {""},
-#line 467 "src/lexer-keywords.txt"
-      {"i64x2.extmul_low_i32x4_u", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4U},
-#line 396 "src/lexer-keywords.txt"
-      {"i64.extend8_s", TokenType::Unary, Opcode::I64Extend8S},
-#line 263 "src/lexer-keywords.txt"
-      {"i32.extend8_s", TokenType::Unary, Opcode::I32Extend8S},
-#line 206 "src/lexer-keywords.txt"
-      {"i16x8.ne", TokenType::Compare, Opcode::I16X8Ne},
+#line 480 "src/lexer-keywords.txt"
+      {"i8x16.ge_s", TokenType::Compare, Opcode::I8X16GeS},
       {""},
-#line 584 "src/lexer-keywords.txt"
-      {"v128.store16_lane", TokenType::SimdStoreLane, Opcode::V128Store16Lane},
+#line 484 "src/lexer-keywords.txt"
+      {"i8x16.le_s", TokenType::Compare, Opcode::I8X16LeS},
+      {""},
+#line 483 "src/lexer-keywords.txt"
+      {"i8x16.gt_u", TokenType::Compare, Opcode::I8X16GtU},
+      {""},
+#line 487 "src/lexer-keywords.txt"
+      {"i8x16.lt_u", TokenType::Compare, Opcode::I8X16LtU},
+#line 536 "src/lexer-keywords.txt"
+      {"ref.func", TokenType::RefFunc, Opcode::RefFunc},
+#line 482 "src/lexer-keywords.txt"
+      {"i8x16.gt_s", TokenType::Compare, Opcode::I8X16GtS},
+      {""},
+#line 486 "src/lexer-keywords.txt"
+      {"i8x16.lt_s", TokenType::Compare, Opcode::I8X16LtS},
       {""}, {""},
-#line 162 "src/lexer-keywords.txt"
-      {"f64x2.sqrt", TokenType::Unary, Opcode::F64X2Sqrt},
-#line 355 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AddU},
-#line 231 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AddU},
+#line 185 "src/lexer-keywords.txt"
+      {"i16x8.extract_lane_u", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneU},
+#line 494 "src/lexer-keywords.txt"
+      {"i8x16.neg", TokenType::Unary, Opcode::I8X16Neg},
+#line 184 "src/lexer-keywords.txt"
+      {"i16x8.extract_lane_s", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneS},
+      {""}, {""},
+#line 510 "src/lexer-keywords.txt"
+      {"item", TokenType::Item},
+#line 496 "src/lexer-keywords.txt"
+      {"i8x16.ne", TokenType::Compare, Opcode::I8X16Ne},
+      {""}, {""},
+#line 193 "src/lexer-keywords.txt"
+      {"v128.load8x8_u", TokenType::Load, Opcode::V128Load8X8U},
       {""},
-#line 199 "src/lexer-keywords.txt"
-      {"i16x8.min_s", TokenType::Binary, Opcode::I16X8MinS},
-      {""}, {""}, {""},
-#line 200 "src/lexer-keywords.txt"
-      {"i16x8.min_u", TokenType::Binary, Opcode::I16X8MinU},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 152 "src/lexer-keywords.txt"
-      {"f64x2.max", TokenType::Binary, Opcode::F64X2Max},
-      {""}, {""}, {""}, {""},
-#line 460 "src/lexer-keywords.txt"
+#line 192 "src/lexer-keywords.txt"
+      {"v128.load8x8_s", TokenType::Load, Opcode::V128Load8X8S},
+      {""},
+#line 459 "src/lexer-keywords.txt"
       {"i64x2.shl", TokenType::Binary, Opcode::I64X2Shl},
+      {""}, {""}, {""}, {""},
+#line 380 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I64AtomicRmwXchg},
+#line 249 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I32AtomicRmwXchg},
+      {""}, {""}, {""}, {""},
+#line 503 "src/lexer-keywords.txt"
+      {"i8x16.sub_sat_u", TokenType::Binary, Opcode::I8X16SubSatU},
       {""},
-#line 195 "src/lexer-keywords.txt"
-      {"i16x8.lt_s", TokenType::Compare, Opcode::I16X8LtS},
-#line 214 "src/lexer-keywords.txt"
-      {"i16x8.sub", TokenType::Binary, Opcode::I16X8Sub},
-#line 196 "src/lexer-keywords.txt"
-      {"i16x8.lt_u", TokenType::Compare, Opcode::I16X8LtU},
+#line 571 "src/lexer-keywords.txt"
+      {"v128.load64_zero", TokenType::Load, Opcode::V128Load64Zero},
       {""},
-#line 42 "src/lexer-keywords.txt"
-      {"delegate", TokenType::Delegate},
+#line 502 "src/lexer-keywords.txt"
+      {"i8x16.sub_sat_s", TokenType::Binary, Opcode::I8X16SubSatS},
+      {""}, {""}, {""},
+#line 473 "src/lexer-keywords.txt"
+      {"i8x16.add", TokenType::Binary, Opcode::I8X16Add},
+      {""}, {""}, {""}, {""}, {""},
+#line 162 "src/lexer-keywords.txt"
+      {"f64x2.sqrt", TokenType::Unary, Opcode::F64X2Sqrt},
+      {""}, {""},
+#line 559 "src/lexer-keywords.txt"
+      {"try", TokenType::Try, Opcode::Try},
       {""},
-#line 191 "src/lexer-keywords.txt"
-      {"i16x8.le_s", TokenType::Compare, Opcode::I16X8LeS},
+#line 474 "src/lexer-keywords.txt"
+      {"i8x16.all_true", TokenType::Unary, Opcode::I8X16AllTrue},
+      {""}, {""}, {""},
+#line 461 "src/lexer-keywords.txt"
+      {"i64x2.shr_u", TokenType::Binary, Opcode::I64X2ShrU},
       {""},
-#line 192 "src/lexer-keywords.txt"
-      {"i16x8.le_u", TokenType::Compare, Opcode::I16X8LeU},
-#line 165 "src/lexer-keywords.txt"
-      {"f64x2.convert_low_i32x4_s", TokenType::Unary, Opcode::F64X2ConvertLowI32X4S},
+#line 460 "src/lexer-keywords.txt"
+      {"i64x2.shr_s", TokenType::Binary, Opcode::I64X2ShrS},
+      {""}, {""}, {""},
+#line 472 "src/lexer-keywords.txt"
+      {"i8x16.add_sat_u", TokenType::Binary, Opcode::I8X16AddSatU},
+#line 111 "src/lexer-keywords.txt"
+      {"f64.abs", TokenType::Unary, Opcode::F64Abs},
+#line 53 "src/lexer-keywords.txt"
+      {"f32.abs", TokenType::Unary, Opcode::F32Abs},
       {""},
-#line 166 "src/lexer-keywords.txt"
-      {"f64x2.convert_low_i32x4_u", TokenType::Unary, Opcode::F64X2ConvertLowI32X4U},
-#line 77 "src/lexer-keywords.txt"
-      {"f32.reinterpret_i32", TokenType::Convert, Opcode::F32ReinterpretI32},
+#line 471 "src/lexer-keywords.txt"
+      {"i8x16.add_sat_s", TokenType::Binary, Opcode::I8X16AddSatS},
+      {""},
+#line 552 "src/lexer-keywords.txt"
+      {"table.grow", TokenType::TableGrow, Opcode::TableGrow},
+#line 122 "src/lexer-keywords.txt"
+      {"f64.floor", TokenType::Unary, Opcode::F64Floor},
+#line 65 "src/lexer-keywords.txt"
+      {"f32.floor", TokenType::Unary, Opcode::F32Floor},
+#line 121 "src/lexer-keywords.txt"
+      {"f64.eq", TokenType::Compare, Opcode::F64Eq},
+#line 64 "src/lexer-keywords.txt"
+      {"f32.eq", TokenType::Compare, Opcode::F32Eq},
+#line 391 "src/lexer-keywords.txt"
+      {"i64.eq", TokenType::Compare, Opcode::I64Eq},
+#line 259 "src/lexer-keywords.txt"
+      {"i32.eq", TokenType::Compare, Opcode::I32Eq},
+      {""}, {""}, {""}, {""}, {""},
+#line 541 "src/lexer-keywords.txt"
+      {"rethrow", TokenType::Rethrow, Opcode::Rethrow},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 547 "src/lexer-keywords.txt"
+      {"start", TokenType::Start},
+      {""}, {""}, {""}, {""},
+#line 37 "src/lexer-keywords.txt"
+      {"catch", TokenType::Catch, Opcode::Catch},
       {""}, {""}, {""},
-#line 437 "src/lexer-keywords.txt"
-      {"i64.trunc_sat_f64_s", TokenType::Convert, Opcode::I64TruncSatF64S},
-#line 299 "src/lexer-keywords.txt"
-      {"i32.trunc_sat_f64_s", TokenType::Convert, Opcode::I32TruncSatF64S},
-      {""}, {""},
-#line 438 "src/lexer-keywords.txt"
-      {"i64.trunc_sat_f64_u", TokenType::Convert, Opcode::I64TruncSatF64U},
-#line 300 "src/lexer-keywords.txt"
-      {"i32.trunc_sat_f64_u", TokenType::Convert, Opcode::I32TruncSatF64U},
-      {""}, {""},
-#line 424 "src/lexer-keywords.txt"
-      {"i64.shr_s", TokenType::Binary, Opcode::I64ShrS},
-#line 287 "src/lexer-keywords.txt"
-      {"i32.shr_s", TokenType::Binary, Opcode::I32ShrS},
+#line 456 "src/lexer-keywords.txt"
+      {"i64x2.extend_low_i32x4_u", TokenType::Unary, Opcode::I64X2ExtendLowI32X4U},
+      {""},
+#line 454 "src/lexer-keywords.txt"
+      {"i64x2.extend_low_i32x4_s", TokenType::Unary, Opcode::I64X2ExtendLowI32X4S},
+      {""},
+#line 585 "src/lexer-keywords.txt"
+      {"v128.store32_lane", TokenType::SimdStoreLane, Opcode::V128Store32Lane},
+#line 497 "src/lexer-keywords.txt"
+      {"i8x16.replace_lane", TokenType::SimdLaneOp, Opcode::I8X16ReplaceLane},
       {""}, {""},
 #line 425 "src/lexer-keywords.txt"
-      {"i64.shr_u", TokenType::Binary, Opcode::I64ShrU},
+      {"i64.store16", TokenType::Store, Opcode::I64Store16},
 #line 288 "src/lexer-keywords.txt"
-      {"i32.shr_u", TokenType::Binary, Opcode::I32ShrU},
-#line 158 "src/lexer-keywords.txt"
-      {"f64x2.pmax", TokenType::Binary, Opcode::F64X2PMax},
+      {"i32.store16", TokenType::Store, Opcode::I32Store16},
       {""}, {""}, {""},
-#line 201 "src/lexer-keywords.txt"
-      {"i16x8.mul", TokenType::Binary, Opcode::I16X8Mul},
-#line 523 "src/lexer-keywords.txt"
-      {"memory.init", TokenType::MemoryInit, Opcode::MemoryInit},
-#line 442 "src/lexer-keywords.txt"
-      {"v128.load32x2_s", TokenType::Load, Opcode::V128Load32X2S},
+#line 161 "src/lexer-keywords.txt"
+      {"f64x2.splat", TokenType::Unary, Opcode::F64X2Splat},
       {""},
-#line 443 "src/lexer-keywords.txt"
-      {"v128.load32x2_u", TokenType::Load, Opcode::V128Load32X2U},
-      {""}, {""}, {""},
-#line 177 "src/lexer-keywords.txt"
-      {"i16x8.abs", TokenType::Unary, Opcode::I16X8Abs},
-      {""}, {""},
-#line 524 "src/lexer-keywords.txt"
-      {"memory.size", TokenType::MemorySize, Opcode::MemorySize},
+#line 462 "src/lexer-keywords.txt"
+      {"i64x2.splat", TokenType::Unary, Opcode::I64X2Splat},
+#line 32 "src/lexer-keywords.txt"
+      {"br_table", TokenType::BrTable, Opcode::BrTable},
+#line 103 "src/lexer-keywords.txt"
+      {"f32x4.pmin", TokenType::Binary, Opcode::F32X4PMin},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""},
-#line 601 "src/lexer-keywords.txt"
-      {"f64.convert_s/i64", TokenType::Convert, Opcode::F64ConvertI64S},
-#line 595 "src/lexer-keywords.txt"
-      {"f32.convert_s/i64", TokenType::Convert, Opcode::F32ConvertI64S},
-#line 603 "src/lexer-keywords.txt"
-      {"f64.convert_u/i64", TokenType::Convert, Opcode::F64ConvertI64U},
-#line 597 "src/lexer-keywords.txt"
-      {"f32.convert_u/i64", TokenType::Convert, Opcode::F32ConvertI64U},
-      {""}, {""}, {""},
-#line 607 "src/lexer-keywords.txt"
-      {"get_local", TokenType::LocalGet, Opcode::LocalGet},
+      {""}, {""},
+#line 546 "src/lexer-keywords.txt"
+      {"shared", TokenType::Shared},
+#line 505 "src/lexer-keywords.txt"
+      {"i8x16", TokenType::I8X16},
       {""}, {""}, {""}, {""}, {""}, {""},
-#line 461 "src/lexer-keywords.txt"
-      {"i64x2.shr_s", TokenType::Binary, Opcode::I64X2ShrS},
 #line 358 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16OrU},
+      {"i64.atomic.rmw16.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16SubU},
 #line 234 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16OrU},
-#line 629 "src/lexer-keywords.txt"
-      {"set_global", TokenType::GlobalSet, Opcode::GlobalSet},
-#line 462 "src/lexer-keywords.txt"
-      {"i64x2.shr_u", TokenType::Binary, Opcode::I64X2ShrU},
-#line 212 "src/lexer-keywords.txt"
-      {"i16x8.sub_sat_s", TokenType::Binary, Opcode::I16X8SubSatS},
+      {"i32.atomic.rmw16.sub_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16SubU},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 489 "src/lexer-keywords.txt"
+      {"i8x16.max_u", TokenType::Binary, Opcode::I8X16MaxU},
       {""},
-#line 213 "src/lexer-keywords.txt"
-      {"i16x8.sub_sat_u", TokenType::Binary, Opcode::I16X8SubSatU},
+#line 488 "src/lexer-keywords.txt"
+      {"i8x16.max_s", TokenType::Binary, Opcode::I8X16MaxS},
       {""}, {""}, {""},
-#line 180 "src/lexer-keywords.txt"
-      {"i16x8.add", TokenType::Binary, Opcode::I16X8Add},
-      {""}, {""}, {""}, {""}, {""},
-#line 135 "src/lexer-keywords.txt"
-      {"f64.reinterpret_i64", TokenType::Convert, Opcode::F64ReinterpretI64},
-      {""},
-#line 536 "src/lexer-keywords.txt"
-      {"ref.func", TokenType::RefFunc, Opcode::RefFunc},
-      {""}, {""}, {""}, {""}, {""},
-#line 521 "src/lexer-keywords.txt"
-      {"memory.fill", TokenType::MemoryFill, Opcode::MemoryFill},
-      {""}, {""}, {""}, {""}, {""},
-#line 134 "src/lexer-keywords.txt"
-      {"f64.promote_f32", TokenType::Convert, Opcode::F64PromoteF32},
-#line 183 "src/lexer-keywords.txt"
-      {"i16x8.bitmask", TokenType::Unary, Opcode::I16X8Bitmask},
-      {""}, {""},
-#line 93 "src/lexer-keywords.txt"
-      {"f32x4.gt", TokenType::Compare, Opcode::F32X4Gt},
-#line 160 "src/lexer-keywords.txt"
-      {"f64x2.replace_lane", TokenType::SimdLaneOp, Opcode::F64X2ReplaceLane},
-#line 578 "src/lexer-keywords.txt"
-      {"v128.load8_splat", TokenType::Load, Opcode::V128Load8Splat},
-      {""},
-#line 459 "src/lexer-keywords.txt"
-      {"i64x2.replace_lane", TokenType::SimdLaneOp, Opcode::I64X2ReplaceLane},
-      {""},
-#line 599 "src/lexer-keywords.txt"
-      {"f32.reinterpret/i32", TokenType::Convert, Opcode::F32ReinterpretI32},
-      {""}, {""}, {""}, {""}, {""},
-#line 92 "src/lexer-keywords.txt"
-      {"f32x4.ge", TokenType::Compare, Opcode::F32X4Ge},
-#line 311 "src/lexer-keywords.txt"
-      {"i32x4.gt_s", TokenType::Compare, Opcode::I32X4GtS},
+#line 175 "src/lexer-keywords.txt"
+      {"global", TokenType::Global},
       {""},
-#line 312 "src/lexer-keywords.txt"
-      {"i32x4.gt_u", TokenType::Compare, Opcode::I32X4GtU},
+#line 523 "src/lexer-keywords.txt"
+      {"memory.size", TokenType::MemorySize, Opcode::MemorySize},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 355 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AndU},
+#line 231 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AndU},
+#line 363 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw32CmpxchgU},
       {""}, {""}, {""},
-#line 309 "src/lexer-keywords.txt"
-      {"i32x4.ge_s", TokenType::Compare, Opcode::I32X4GeS},
+#line 354 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AddU},
+#line 230 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AddU},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 199 "src/lexer-keywords.txt"
+      {"i16x8.min_u", TokenType::Binary, Opcode::I16X8MinU},
       {""},
-#line 310 "src/lexer-keywords.txt"
-      {"i32x4.ge_u", TokenType::Compare, Opcode::I32X4GeU},
-      {""}, {""}, {""}, {""},
-#line 368 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw32.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XorU},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 574 "src/lexer-keywords.txt"
-      {"v128.xor", TokenType::Binary, Opcode::V128Xor},
+#line 198 "src/lexer-keywords.txt"
+      {"i16x8.min_s", TokenType::Binary, Opcode::I16X8MinS},
+      {""},
+#line 550 "src/lexer-keywords.txt"
+      {"table.fill", TokenType::TableFill, Opcode::TableFill},
       {""}, {""}, {""},
-#line 577 "src/lexer-keywords.txt"
-      {"v128.load64_splat", TokenType::Load, Opcode::V128Load64Splat},
-#line 576 "src/lexer-keywords.txt"
-      {"v128.load32_splat", TokenType::Load, Opcode::V128Load32Splat},
-#line 552 "src/lexer-keywords.txt"
-      {"table.grow", TokenType::TableGrow, Opcode::TableGrow},
-      {""}, {""},
-#line 315 "src/lexer-keywords.txt"
-      {"v128.load16x4_s", TokenType::Load, Opcode::V128Load16X4S},
+#line 102 "src/lexer-keywords.txt"
+      {"f32x4.pmax", TokenType::Binary, Opcode::F32X4PMax},
+#line 390 "src/lexer-keywords.txt"
+      {"i64.div_u", TokenType::Binary, Opcode::I64DivU},
+#line 258 "src/lexer-keywords.txt"
+      {"i32.div_u", TokenType::Binary, Opcode::I32DivU},
+#line 389 "src/lexer-keywords.txt"
+      {"i64.div_s", TokenType::Binary, Opcode::I64DivS},
+#line 257 "src/lexer-keywords.txt"
+      {"i32.div_s", TokenType::Binary, Opcode::I32DivS},
+#line 479 "src/lexer-keywords.txt"
+      {"i8x16.extract_lane_u", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneU},
       {""},
-#line 316 "src/lexer-keywords.txt"
-      {"v128.load16x4_u", TokenType::Load, Opcode::V128Load16X4U},
+#line 478 "src/lexer-keywords.txt"
+      {"i8x16.extract_lane_s", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneS},
+#line 466 "src/lexer-keywords.txt"
+      {"i64x2.extmul_low_i32x4_u", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4U},
+#line 91 "src/lexer-keywords.txt"
+      {"f32x4.floor", TokenType::Unary, Opcode::F32X4Floor},
+#line 464 "src/lexer-keywords.txt"
+      {"i64x2.extmul_low_i32x4_s", TokenType::Binary, Opcode::I64X2ExtmulLowI32X4S},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 173 "src/lexer-keywords.txt"
+      {"global.get", TokenType::GlobalGet, Opcode::GlobalGet},
       {""},
-#line 372 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8OrU},
-#line 241 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8OrU},
+#line 174 "src/lexer-keywords.txt"
+      {"global.set", TokenType::GlobalSet, Opcode::GlobalSet},
       {""},
-#line 178 "src/lexer-keywords.txt"
-      {"i16x8.add_sat_s", TokenType::Binary, Opcode::I16X8AddSatS},
+#line 529 "src/lexer-keywords.txt"
+      {"nop", TokenType::Nop, Opcode::Nop},
+#line 207 "src/lexer-keywords.txt"
+      {"i16x8.shl", TokenType::Binary, Opcode::I16X8Shl},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 44 "src/lexer-keywords.txt"
+      {"drop", TokenType::Drop, Opcode::Drop},
+#line 373 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XchgU},
+#line 242 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XchgU},
       {""},
-#line 179 "src/lexer-keywords.txt"
-      {"i16x8.add_sat_u", TokenType::Binary, Opcode::I16X8AddSatU},
-      {""}, {""},
 #line 25 "src/lexer-keywords.txt"
-      {"assert_trap", TokenType::AssertTrap},
-      {""}, {""},
-#line 323 "src/lexer-keywords.txt"
-      {"i32x4.dot_i16x8_s", TokenType::Binary, Opcode::I32X4DotI16X8S},
-#line 367 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw32.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XchgU},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 90 "src/lexer-keywords.txt"
-      {"f32x4.extract_lane", TokenType::SimdLaneOp, Opcode::F32X4ExtractLane},
-      {""},
-#line 497 "src/lexer-keywords.txt"
-      {"i8x16.ne", TokenType::Compare, Opcode::I8X16Ne},
-#line 308 "src/lexer-keywords.txt"
-      {"i32x4.extract_lane", TokenType::SimdLaneOp, Opcode::I32X4ExtractLane},
-      {""}, {""}, {""}, {""},
-#line 605 "src/lexer-keywords.txt"
-      {"f64.reinterpret/i64", TokenType::Convert, Opcode::F64ReinterpretI64},
-      {""}, {""},
-#line 491 "src/lexer-keywords.txt"
-      {"i8x16.min_s", TokenType::Binary, Opcode::I8X16MinS},
-      {""}, {""}, {""},
-#line 492 "src/lexer-keywords.txt"
-      {"i8x16.min_u", TokenType::Binary, Opcode::I8X16MinU},
-#line 351 "src/lexer-keywords.txt"
-      {"i64.atomic.load16_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad16U},
-#line 228 "src/lexer-keywords.txt"
-      {"i32.atomic.load16_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad16U},
-      {""}, {""}, {""},
-#line 561 "src/lexer-keywords.txt"
-      {"unreachable", TokenType::Unreachable, Opcode::Unreachable},
-#line 604 "src/lexer-keywords.txt"
-      {"f64.promote/f32", TokenType::Convert, Opcode::F64PromoteF32},
-#line 583 "src/lexer-keywords.txt"
-      {"v128.store8_lane", TokenType::SimdStoreLane, Opcode::V128Store8Lane},
-      {""}, {""}, {""}, {""}, {""},
-#line 122 "src/lexer-keywords.txt"
-      {"f64.floor", TokenType::Unary, Opcode::F64Floor},
-#line 65 "src/lexer-keywords.txt"
-      {"f32.floor", TokenType::Unary, Opcode::F32Floor},
-#line 487 "src/lexer-keywords.txt"
-      {"i8x16.lt_s", TokenType::Compare, Opcode::I8X16LtS},
-#line 505 "src/lexer-keywords.txt"
-      {"i8x16.sub", TokenType::Binary, Opcode::I8X16Sub},
-#line 488 "src/lexer-keywords.txt"
-      {"i8x16.lt_u", TokenType::Compare, Opcode::I8X16LtU},
-#line 344 "src/lexer-keywords.txt"
-      {"i32x4.extend_low_i16x8_s", TokenType::Unary, Opcode::I32X4ExtendLowI16X8S},
-#line 539 "src/lexer-keywords.txt"
-      {"register", TokenType::Register},
-#line 345 "src/lexer-keywords.txt"
-      {"i32x4.extend_low_i16x8_u", TokenType::Unary, Opcode::I32X4ExtendLowI16X8U},
-#line 485 "src/lexer-keywords.txt"
-      {"i8x16.le_s", TokenType::Compare, Opcode::I8X16LeS},
-      {""},
-#line 486 "src/lexer-keywords.txt"
-      {"i8x16.le_u", TokenType::Compare, Opcode::I8X16LeU},
-#line 528 "src/lexer-keywords.txt"
-      {"nan:arithmetic", TokenType::NanArithmetic},
-#line 106 "src/lexer-keywords.txt"
-      {"f32x4.sqrt", TokenType::Unary, Opcode::F32X4Sqrt},
-      {""}, {""}, {""}, {""}, {""},
-#line 335 "src/lexer-keywords.txt"
-      {"i32x4.extmul_low_i16x8_s", TokenType::Binary, Opcode::I32X4ExtmulLowI16X8S},
+      {"assert_return", TokenType::AssertReturn},
       {""},
-#line 337 "src/lexer-keywords.txt"
-      {"i32x4.extmul_low_i16x8_u", TokenType::Binary, Opcode::I32X4ExtmulLowI16X8U},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 96 "src/lexer-keywords.txt"
-      {"f32x4.max", TokenType::Binary, Opcode::F32X4Max},
-      {""}, {""}, {""}, {""},
-#line 328 "src/lexer-keywords.txt"
-      {"i32x4.shl", TokenType::Binary, Opcode::I32X4Shl},
+#line 569 "src/lexer-keywords.txt"
+      {"v128.any_true", TokenType::Unary, Opcode::V128AnyTrue},
+#line 392 "src/lexer-keywords.txt"
+      {"i64.eqz", TokenType::Convert, Opcode::I64Eqz},
+#line 260 "src/lexer-keywords.txt"
+      {"i32.eqz", TokenType::Convert, Opcode::I32Eqz},
+#line 357 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16OrU},
+#line 233 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16OrU},
       {""}, {""}, {""},
-#line 361 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XorU},
-#line 237 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XorU},
-      {""}, {""}, {""}, {""},
-#line 471 "src/lexer-keywords.txt"
-      {"i8x16.abs", TokenType::Unary, Opcode::I8X16Abs},
-#line 302 "src/lexer-keywords.txt"
-      {"i32.wrap_i64", TokenType::Convert, Opcode::I32WrapI64},
+#line 383 "src/lexer-keywords.txt"
+      {"i64.atomic.store32", TokenType::AtomicStore, Opcode::I64AtomicStore32},
       {""}, {""},
-#line 20 "src/lexer-keywords.txt"
-      {"array", Type::Array, TokenType::Array},
-#line 506 "src/lexer-keywords.txt"
-      {"i8x16", TokenType::I8X16},
+#line 359 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XchgU},
+#line 235 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XchgU},
+#line 437 "src/lexer-keywords.txt"
+      {"i64.trunc_sat_f64_u", TokenType::Convert, Opcode::I64TruncSatF64U},
+#line 299 "src/lexer-keywords.txt"
+      {"i32.trunc_sat_f64_u", TokenType::Convert, Opcode::I32TruncSatF64U},
       {""}, {""},
-#line 575 "src/lexer-keywords.txt"
-      {"v128.load16_splat", TokenType::Load, Opcode::V128Load16Splat},
-#line 417 "src/lexer-keywords.txt"
-      {"i64.popcnt", TokenType::Unary, Opcode::I64Popcnt},
-#line 280 "src/lexer-keywords.txt"
-      {"i32.popcnt", TokenType::Unary, Opcode::I32Popcnt},
+#line 436 "src/lexer-keywords.txt"
+      {"i64.trunc_sat_f64_s", TokenType::Convert, Opcode::I64TruncSatF64S},
+#line 298 "src/lexer-keywords.txt"
+      {"i32.trunc_sat_f64_s", TokenType::Convert, Opcode::I32TruncSatF64S},
+#line 209 "src/lexer-keywords.txt"
+      {"i16x8.shr_u", TokenType::Binary, Opcode::I16X8ShrU},
       {""},
-#line 181 "src/lexer-keywords.txt"
-      {"i16x8.all_true", TokenType::Unary, Opcode::I16X8AllTrue},
+#line 208 "src/lexer-keywords.txt"
+      {"i16x8.shr_s", TokenType::Binary, Opcode::I16X8ShrS},
+      {""}, {""},
+#line 377 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmwCmpxchg},
+#line 246 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmwCmpxchg},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 107 "src/lexer-keywords.txt"
+      {"f32x4.sub", TokenType::Binary, Opcode::F32X4Sub},
       {""},
-#line 86 "src/lexer-keywords.txt"
-      {"f32x4.convert_i32x4_s", TokenType::Unary, Opcode::F32X4ConvertI32X4S},
+#line 331 "src/lexer-keywords.txt"
+      {"i32x4.sub", TokenType::Binary, Opcode::I32X4Sub},
+#line 83 "src/lexer-keywords.txt"
+      {"f32x4.abs", TokenType::Unary, Opcode::F32X4Abs},
       {""},
-#line 87 "src/lexer-keywords.txt"
-      {"f32x4.convert_i32x4_u", TokenType::Unary, Opcode::F32X4ConvertI32X4U},
+#line 302 "src/lexer-keywords.txt"
+      {"i32x4.abs", TokenType::Unary, Opcode::I32X4Abs},
       {""},
-#line 45 "src/lexer-keywords.txt"
-      {"elem.drop", TokenType::ElemDrop, Opcode::ElemDrop},
-      {""}, {""},
-#line 221 "src/lexer-keywords.txt"
-      {"i16x8", TokenType::I16X8},
-#line 102 "src/lexer-keywords.txt"
-      {"f32x4.pmax", TokenType::Binary, Opcode::F32X4PMax},
-      {""}, {""}, {""},
-#line 39 "src/lexer-keywords.txt"
-      {"data.drop", TokenType::DataDrop, Opcode::DataDrop},
+#line 159 "src/lexer-keywords.txt"
+      {"f64x2.pmin", TokenType::Binary, Opcode::F64X2PMin},
       {""},
 #line 360 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XchgU},
+      {"i64.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XorU},
 #line 236 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XchgU},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 503 "src/lexer-keywords.txt"
-      {"i8x16.sub_sat_s", TokenType::Binary, Opcode::I8X16SubSatS},
-      {""},
-#line 504 "src/lexer-keywords.txt"
-      {"i8x16.sub_sat_u", TokenType::Binary, Opcode::I8X16SubSatU},
-      {""}, {""}, {""},
-#line 474 "src/lexer-keywords.txt"
-      {"i8x16.add", TokenType::Binary, Opcode::I8X16Add},
-      {""}, {""}, {""},
-#line 121 "src/lexer-keywords.txt"
-      {"f64.eq", TokenType::Compare, Opcode::F64Eq},
-#line 64 "src/lexer-keywords.txt"
-      {"f32.eq", TokenType::Compare, Opcode::F32Eq},
+      {"i32.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XorU},
+      {""}, {""}, {""}, {""}, {""},
+#line 89 "src/lexer-keywords.txt"
+      {"f32x4.eq", TokenType::Compare, Opcode::F32X4Eq},
       {""},
-#line 392 "src/lexer-keywords.txt"
-      {"i64.eq", TokenType::Compare, Opcode::I64Eq},
-#line 260 "src/lexer-keywords.txt"
-      {"i32.eq", TokenType::Compare, Opcode::I32Eq},
+#line 306 "src/lexer-keywords.txt"
+      {"i32x4.eq", TokenType::Compare, Opcode::I32X4Eq},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 118 "src/lexer-keywords.txt"
+      {"f64.convert_i64_u", TokenType::Convert, Opcode::F64ConvertI64U},
+#line 60 "src/lexer-keywords.txt"
+      {"f32.convert_i64_u", TokenType::Convert, Opcode::F32ConvertI64U},
       {""}, {""},
-#line 470 "src/lexer-keywords.txt"
-      {"i64.xor", TokenType::Binary, Opcode::I64Xor},
-#line 348 "src/lexer-keywords.txt"
-      {"i32.xor", TokenType::Binary, Opcode::I32Xor},
-#line 623 "src/lexer-keywords.txt"
-      {"i64.trunc_s:sat/f32", TokenType::Convert, Opcode::I64TruncSatF32S},
-#line 611 "src/lexer-keywords.txt"
-      {"i32.trunc_s:sat/f32", TokenType::Convert, Opcode::I32TruncSatF32S},
-#line 627 "src/lexer-keywords.txt"
-      {"i64.trunc_u:sat/f32", TokenType::Convert, Opcode::I64TruncSatF32U},
-#line 615 "src/lexer-keywords.txt"
-      {"i32.trunc_u:sat/f32", TokenType::Convert, Opcode::I32TruncSatF32U},
+#line 117 "src/lexer-keywords.txt"
+      {"f64.convert_i64_s", TokenType::Convert, Opcode::F64ConvertI64S},
+#line 59 "src/lexer-keywords.txt"
+      {"f32.convert_i64_s", TokenType::Convert, Opcode::F32ConvertI64S},
+      {""}, {""},
+#line 210 "src/lexer-keywords.txt"
+      {"i16x8.splat", TokenType::Unary, Opcode::I16X8Splat},
       {""}, {""}, {""}, {""},
-#line 477 "src/lexer-keywords.txt"
-      {"i8x16.bitmask", TokenType::Unary, Opcode::I8X16Bitmask},
-#line 167 "src/lexer-keywords.txt"
-      {"f64x2.promote_low_f32x4", TokenType::Unary, Opcode::F64X2PromoteLowF32X4},
-#line 329 "src/lexer-keywords.txt"
-      {"i32x4.shr_s", TokenType::Binary, Opcode::I32X4ShrS},
-      {""}, {""}, {""},
-#line 330 "src/lexer-keywords.txt"
-      {"i32x4.shr_u", TokenType::Binary, Opcode::I32X4ShrU},
+#line 521 "src/lexer-keywords.txt"
+      {"memory.grow", TokenType::MemoryGrow, Opcode::MemoryGrow},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 322 "src/lexer-keywords.txt"
+      {"i32x4.dot_i16x8_s", TokenType::Binary, Opcode::I32X4DotI16X8S},
       {""},
-#line 518 "src/lexer-keywords.txt"
-      {"memory.atomic.wait32", TokenType::AtomicWait, Opcode::MemoryAtomicWait32},
-      {""}, {""}, {""}, {""}, {""},
-#line 49 "src/lexer-keywords.txt"
-      {"tag", TokenType::Tag},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 197 "src/lexer-keywords.txt"
-      {"i16x8.max_s", TokenType::Binary, Opcode::I16X8MaxS},
-      {""}, {""}, {""},
-#line 198 "src/lexer-keywords.txt"
-      {"i16x8.max_u", TokenType::Binary, Opcode::I16X8MaxU},
+#line 522 "src/lexer-keywords.txt"
+      {"memory.init", TokenType::MemoryInit, Opcode::MemoryInit},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""},
-#line 211 "src/lexer-keywords.txt"
-      {"i16x8.splat", TokenType::Unary, Opcode::I16X8Splat},
+#line 158 "src/lexer-keywords.txt"
+      {"f64x2.pmax", TokenType::Binary, Opcode::F64X2PMax},
+      {""}, {""}, {""}, {""},
+#line 515 "src/lexer-keywords.txt"
+      {"loop", TokenType::Loop, Opcode::Loop},
+#line 62 "src/lexer-keywords.txt"
+      {"f32.demote_f64", TokenType::Convert, Opcode::F32DemoteF64},
+      {""}, {""},
+#line 147 "src/lexer-keywords.txt"
+      {"f64x2.floor", TokenType::Unary, Opcode::F64X2Floor},
+#line 52 "src/lexer-keywords.txt"
+      {"export", TokenType::Export},
+#line 315 "src/lexer-keywords.txt"
+      {"v128.load16x4_u", TokenType::Load, Opcode::V128Load16X4U},
+      {""}, {""},
+#line 88 "src/lexer-keywords.txt"
+      {"f32x4.div", TokenType::Binary, Opcode::F32X4Div},
+#line 314 "src/lexer-keywords.txt"
+      {"v128.load16x4_s", TokenType::Load, Opcode::V128Load16X4S},
+#line 580 "src/lexer-keywords.txt"
+      {"v128.load16_lane", TokenType::SimdLoadLane, Opcode::V128Load16Lane},
+      {""}, {""}, {""}, {""},
+#line 109 "src/lexer-keywords.txt"
+      {"f32x4.demote_f64x2_zero", TokenType::Unary, Opcode::F32X4DemoteF64X2Zero},
+#line 575 "src/lexer-keywords.txt"
+      {"v128.load16_splat", TokenType::Load, Opcode::V128Load16Splat},
+      {""}, {""}, {""}, {""},
+#line 491 "src/lexer-keywords.txt"
+      {"i8x16.min_u", TokenType::Binary, Opcode::I8X16MinU},
       {""},
-#line 593 "src/lexer-keywords.txt"
-      {"anyfunc", Type::FuncRef},
+#line 490 "src/lexer-keywords.txt"
+      {"i8x16.min_s", TokenType::Binary, Opcode::I8X16MinS},
       {""}, {""}, {""}, {""}, {""},
-#line 104 "src/lexer-keywords.txt"
-      {"f32x4.replace_lane", TokenType::SimdLaneOp, Opcode::F32X4ReplaceLane},
-      {""},
-#line 617 "src/lexer-keywords.txt"
-      {"i32.wrap/i64", TokenType::Convert, Opcode::I32WrapI64},
-#line 327 "src/lexer-keywords.txt"
-      {"i32x4.replace_lane", TokenType::SimdLaneOp, Opcode::I32X4ReplaceLane},
+#line 370 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw8CmpxchgU},
+#line 239 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw8CmpxchgU},
       {""}, {""},
-#line 385 "src/lexer-keywords.txt"
-      {"i64.atomic.store8", TokenType::AtomicStore, Opcode::I64AtomicStore8},
-#line 253 "src/lexer-keywords.txt"
-      {"i32.atomic.store8", TokenType::AtomicStore, Opcode::I32AtomicStore8},
+#line 524 "src/lexer-keywords.txt"
+      {"memory", TokenType::Memory},
+#line 561 "src/lexer-keywords.txt"
+      {"unreachable", TokenType::Unreachable, Opcode::Unreachable},
       {""},
-#line 145 "src/lexer-keywords.txt"
-      {"f64x2.eq", TokenType::Compare, Opcode::F64X2Eq},
+#line 416 "src/lexer-keywords.txt"
+      {"i64.popcnt", TokenType::Unary, Opcode::I64Popcnt},
+#line 279 "src/lexer-keywords.txt"
+      {"i32.popcnt", TokenType::Unary, Opcode::I32Popcnt},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 435 "src/lexer-keywords.txt"
+      {"i64.trunc_sat_f32_u", TokenType::Convert, Opcode::I64TruncSatF32U},
+#line 297 "src/lexer-keywords.txt"
+      {"i32.trunc_sat_f32_u", TokenType::Convert, Opcode::I32TruncSatF32U},
       {""}, {""},
-#line 445 "src/lexer-keywords.txt"
-      {"i64x2.eq", TokenType::Binary, Opcode::I64X2Eq},
-      {""}, {""}, {""},
-#line 472 "src/lexer-keywords.txt"
-      {"i8x16.add_sat_s", TokenType::Binary, Opcode::I8X16AddSatS},
+#line 434 "src/lexer-keywords.txt"
+      {"i64.trunc_sat_f32_s", TokenType::Convert, Opcode::I64TruncSatF32S},
+#line 296 "src/lexer-keywords.txt"
+      {"i32.trunc_sat_f32_s", TokenType::Convert, Opcode::I32TruncSatF32S},
+#line 498 "src/lexer-keywords.txt"
+      {"i8x16.shl", TokenType::Binary, Opcode::I8X16Shl},
       {""},
-#line 473 "src/lexer-keywords.txt"
-      {"i8x16.add_sat_u", TokenType::Binary, Opcode::I8X16AddSatU},
-      {""}, {""}, {""}, {""}, {""},
-#line 193 "src/lexer-keywords.txt"
-      {"v128.load8x8_s", TokenType::Load, Opcode::V128Load8X8S},
-      {""}, {""}, {""},
-#line 194 "src/lexer-keywords.txt"
-      {"v128.load8x8_u", TokenType::Load, Opcode::V128Load8X8U},
-      {""}, {""}, {""}, {""}, {""},
-#line 624 "src/lexer-keywords.txt"
-      {"i64.trunc_s:sat/f64", TokenType::Convert, Opcode::I64TruncSatF64S},
-#line 612 "src/lexer-keywords.txt"
-      {"i32.trunc_s:sat/f64", TokenType::Convert, Opcode::I32TruncSatF64S},
-#line 628 "src/lexer-keywords.txt"
-      {"i64.trunc_u:sat/f64", TokenType::Convert, Opcode::I64TruncSatF64U},
-#line 616 "src/lexer-keywords.txt"
-      {"i32.trunc_u:sat/f64", TokenType::Convert, Opcode::I32TruncSatF64U},
+#line 24 "src/lexer-keywords.txt"
+      {"assert_malformed", TokenType::AssertMalformed},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""},
-#line 519 "src/lexer-keywords.txt"
-      {"memory.atomic.wait64", TokenType::AtomicWait, Opcode::MemoryAtomicWait64},
       {""},
-#line 132 "src/lexer-keywords.txt"
-      {"f64.neg", TokenType::Unary, Opcode::F64Neg},
-#line 75 "src/lexer-keywords.txt"
-      {"f32.neg", TokenType::Unary, Opcode::F32Neg},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""},
-#line 156 "src/lexer-keywords.txt"
-      {"f64x2.neg", TokenType::Unary, Opcode::F64X2Neg},
-      {""}, {""},
-#line 452 "src/lexer-keywords.txt"
-      {"i64x2.neg", TokenType::Unary, Opcode::I64X2Neg},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 588 "src/lexer-keywords.txt"
-      {"i8x16.swizzle", TokenType::Binary, Opcode::I8X16Swizzle},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 163 "src/lexer-keywords.txt"
+      {"f64x2.sub", TokenType::Binary, Opcode::F64X2Sub},
+      {""},
+#line 463 "src/lexer-keywords.txt"
+      {"i64x2.sub", TokenType::Binary, Opcode::I64X2Sub},
+#line 141 "src/lexer-keywords.txt"
+      {"f64x2.abs", TokenType::Unary, Opcode::F64X2Abs},
       {""},
-#line 364 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw32.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw32CmpxchgU},
+#line 450 "src/lexer-keywords.txt"
+      {"i64x2.abs", TokenType::Unary, Opcode::I64X2Abs},
       {""}, {""}, {""}, {""}, {""}, {""},
 #line 333 "src/lexer-keywords.txt"
-      {"i32x4.extadd_pairwise_i16x8_s", TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8S},
-#line 173 "src/lexer-keywords.txt"
-      {"global.get", TokenType::GlobalGet, Opcode::GlobalGet},
-#line 334 "src/lexer-keywords.txt"
       {"i32x4.extadd_pairwise_i16x8_u", TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8U},
-#line 475 "src/lexer-keywords.txt"
-      {"i8x16.all_true", TokenType::Unary, Opcode::I8X16AllTrue},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""},
-#line 549 "src/lexer-keywords.txt"
-      {"table.copy", TokenType::TableCopy, Opcode::TableCopy},
-      {""}, {""},
-#line 340 "src/lexer-keywords.txt"
-      {"i32x4.trunc_sat_f32x4_s", TokenType::Unary, Opcode::I32X4TruncSatF32X4S},
-      {""}, {""}, {""},
-#line 341 "src/lexer-keywords.txt"
-      {"i32x4.trunc_sat_f32x4_u", TokenType::Unary, Opcode::I32X4TruncSatF32X4U},
-      {""}, {""},
-#line 569 "src/lexer-keywords.txt"
-      {"v128.any_true", TokenType::Unary, Opcode::V128AnyTrue},
+#line 332 "src/lexer-keywords.txt"
+      {"i32x4.extadd_pairwise_i16x8_s", TokenType::Unary, Opcode::I32X4ExtaddPairwiseI16X8S},
+      {""},
+#line 145 "src/lexer-keywords.txt"
+      {"f64x2.eq", TokenType::Compare, Opcode::F64X2Eq},
+      {""},
+#line 444 "src/lexer-keywords.txt"
+      {"i64x2.eq", TokenType::Binary, Opcode::I64X2Eq},
       {""}, {""},
-#line 109 "src/lexer-keywords.txt"
-      {"f32x4.demote_f64x2_zero", TokenType::Unary, Opcode::F32X4DemoteF64X2Zero},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 189 "src/lexer-keywords.txt"
-      {"i16x8.gt_s", TokenType::Compare, Opcode::I16X8GtS},
+#line 500 "src/lexer-keywords.txt"
+      {"i8x16.shr_u", TokenType::Binary, Opcode::I8X16ShrU},
       {""},
-#line 190 "src/lexer-keywords.txt"
-      {"i16x8.gt_u", TokenType::Compare, Opcode::I16X8GtU},
-      {""}, {""}, {""},
-#line 187 "src/lexer-keywords.txt"
-      {"i16x8.ge_s", TokenType::Compare, Opcode::I16X8GeS},
+#line 499 "src/lexer-keywords.txt"
+      {"i8x16.shr_s", TokenType::Binary, Opcode::I8X16ShrS},
+#line 224 "src/lexer-keywords.txt"
+      {"i16x8.extend_low_i8x16_u", TokenType::Unary, Opcode::I16X8ExtendLowI8X16U},
       {""},
-#line 188 "src/lexer-keywords.txt"
-      {"i16x8.ge_u", TokenType::Compare, Opcode::I16X8GeU},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 223 "src/lexer-keywords.txt"
+      {"i16x8.extend_low_i8x16_s", TokenType::Unary, Opcode::I16X8ExtendLowI8X16S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 29 "src/lexer-keywords.txt"
+      {"binary", TokenType::Bin},
+      {""}, {""},
+#line 116 "src/lexer-keywords.txt"
+      {"f64.convert_i32_u", TokenType::Convert, Opcode::F64ConvertI32U},
+#line 58 "src/lexer-keywords.txt"
+      {"f32.convert_i32_u", TokenType::Convert, Opcode::F32ConvertI32U},
+      {""}, {""},
+#line 115 "src/lexer-keywords.txt"
+      {"f64.convert_i32_s", TokenType::Convert, Opcode::F64ConvertI32S},
+#line 57 "src/lexer-keywords.txt"
+      {"f32.convert_i32_s", TokenType::Convert, Opcode::F32ConvertI32S},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""},
-#line 489 "src/lexer-keywords.txt"
-      {"i8x16.max_s", TokenType::Binary, Opcode::I8X16MaxS},
-#line 281 "src/lexer-keywords.txt"
-      {"i32.reinterpret_f32", TokenType::Convert, Opcode::I32ReinterpretF32},
+#line 181 "src/lexer-keywords.txt"
+      {"i16x8.avgr_u", TokenType::Binary, Opcode::I16X8AvgrU},
       {""}, {""},
-#line 490 "src/lexer-keywords.txt"
-      {"i8x16.max_u", TokenType::Binary, Opcode::I8X16MaxU},
-      {""}, {""}, {""},
-#line 502 "src/lexer-keywords.txt"
-      {"i8x16.splat", TokenType::Unary, Opcode::I8X16Splat},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""},
 #line 382 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I64AtomicRmwXor},
+      {"i64.atomic.store16", TokenType::AtomicStore, Opcode::I64AtomicStore16},
 #line 251 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I32AtomicRmwXor},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 185 "src/lexer-keywords.txt"
-      {"i16x8.extract_lane_s", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneS},
-      {""},
-#line 186 "src/lexer-keywords.txt"
-      {"i16x8.extract_lane_u", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneU},
-      {""},
-#line 357 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw16CmpxchgU},
-#line 233 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw16CmpxchgU},
+      {"i32.atomic.store16", TokenType::AtomicStore, Opcode::I32AtomicStore16},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""},
+#line 501 "src/lexer-keywords.txt"
+      {"i8x16.splat", TokenType::Unary, Opcode::I8X16Splat},
       {""}, {""}, {""},
-#line 375 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XorU},
-#line 244 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XorU},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 371 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw8.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw8CmpxchgU},
-#line 240 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw8.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw8CmpxchgU},
+#line 549 "src/lexer-keywords.txt"
+      {"table.copy", TokenType::TableCopy, Opcode::TableCopy},
+      {""}, {""}, {""},
+#line 144 "src/lexer-keywords.txt"
+      {"f64x2.div", TokenType::Binary, Opcode::F64X2Div},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 89 "src/lexer-keywords.txt"
-      {"f32x4.eq", TokenType::Compare, Opcode::F32X4Eq},
-      {""}, {""},
-#line 307 "src/lexer-keywords.txt"
-      {"i32x4.eq", TokenType::Compare, Opcode::I32X4Eq},
-      {""}, {""}, {""}, {""}, {""}, {""},
-#line 606 "src/lexer-keywords.txt"
-      {"get_global", TokenType::GlobalGet, Opcode::GlobalGet},
+#line 344 "src/lexer-keywords.txt"
+      {"i32x4.extend_low_i16x8_u", TokenType::Unary, Opcode::I32X4ExtendLowI16X8U},
+#line 202 "src/lexer-keywords.txt"
+      {"i16x8.narrow_i32x4_u", TokenType::Binary, Opcode::I16X8NarrowI32X4U},
+#line 343 "src/lexer-keywords.txt"
+      {"i32x4.extend_low_i16x8_s", TokenType::Unary, Opcode::I32X4ExtendLowI16X8S},
+#line 201 "src/lexer-keywords.txt"
+      {"i16x8.narrow_i32x4_s", TokenType::Binary, Opcode::I16X8NarrowI32X4S},
       {""}, {""},
-#line 346 "src/lexer-keywords.txt"
-      {"i32x4.trunc_sat_f64x2_s_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2SZero},
+#line 520 "src/lexer-keywords.txt"
+      {"memory.fill", TokenType::MemoryFill, Opcode::MemoryFill},
       {""},
-#line 347 "src/lexer-keywords.txt"
-      {"i32x4.trunc_sat_f64x2_u_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2UZero},
-      {""}, {""}, {""}, {""}, {""},
-#line 418 "src/lexer-keywords.txt"
-      {"i64.reinterpret_f64", TokenType::Convert, Opcode::I64ReinterpretF64},
-      {""}, {""}, {""}, {""}, {""},
-#line 208 "src/lexer-keywords.txt"
-      {"i16x8.shl", TokenType::Binary, Opcode::I16X8Shl},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 372 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8SubU},
+#line 241 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.sub_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8SubU},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 608 "src/lexer-keywords.txt"
-      {"i32.reinterpret/f32", TokenType::Convert, Opcode::I32ReinterpretF32},
+#line 218 "src/lexer-keywords.txt"
+      {"i16x8.extmul_low_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16U},
+      {""},
+#line 216 "src/lexer-keywords.txt"
+      {"i16x8.extmul_low_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16S},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""},
-#line 100 "src/lexer-keywords.txt"
-      {"f32x4.neg", TokenType::Unary, Opcode::F32X4Neg},
-      {""}, {""},
-#line 325 "src/lexer-keywords.txt"
-      {"i32x4.neg", TokenType::Unary, Opcode::I32X4Neg},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 559 "src/lexer-keywords.txt"
-      {"try", TokenType::Try, Opcode::Try},
-      {""}, {""}, {""}, {""}, {""}, {""},
-#line 209 "src/lexer-keywords.txt"
-      {"i16x8.shr_s", TokenType::Binary, Opcode::I16X8ShrS},
+#line 31 "src/lexer-keywords.txt"
+      {"br_if", TokenType::BrIf, Opcode::BrIf},
       {""}, {""}, {""},
-#line 210 "src/lexer-keywords.txt"
-      {"i16x8.shr_u", TokenType::Binary, Opcode::I16X8ShrU},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 525 "src/lexer-keywords.txt"
-      {"memory", TokenType::Memory},
+#line 340 "src/lexer-keywords.txt"
+      {"i32x4.trunc_sat_f32x4_u", TokenType::Unary, Opcode::I32X4TruncSatF32X4U},
+      {""}, {""}, {""},
+#line 339 "src/lexer-keywords.txt"
+      {"i32x4.trunc_sat_f32x4_s", TokenType::Unary, Opcode::I32X4TruncSatF32X4S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""},
+#line 213 "src/lexer-keywords.txt"
+      {"i16x8.sub", TokenType::Binary, Opcode::I16X8Sub},
+      {""}, {""},
+#line 176 "src/lexer-keywords.txt"
+      {"i16x8.abs", TokenType::Unary, Opcode::I16X8Abs},
+#line 336 "src/lexer-keywords.txt"
+      {"i32x4.extmul_low_i16x8_u", TokenType::Binary, Opcode::I32X4ExtmulLowI16X8U},
       {""},
-#line 483 "src/lexer-keywords.txt"
-      {"i8x16.gt_s", TokenType::Compare, Opcode::I8X16GtS},
+#line 334 "src/lexer-keywords.txt"
+      {"i32x4.extmul_low_i16x8_s", TokenType::Binary, Opcode::I32X4ExtmulLowI16X8S},
+#line 51 "src/lexer-keywords.txt"
+      {"externref", Type::ExternRef},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 183 "src/lexer-keywords.txt"
+      {"i16x8.eq", TokenType::Compare, Opcode::I16X8Eq},
+#line 495 "src/lexer-keywords.txt"
+      {"i8x16.popcnt", TokenType::Unary, Opcode::I8X16Popcnt},
+      {""}, {""},
+#line 342 "src/lexer-keywords.txt"
+      {"i32x4.extend_high_i16x8_u", TokenType::Unary, Opcode::I32X4ExtendHighI16X8U},
       {""},
-#line 484 "src/lexer-keywords.txt"
-      {"i8x16.gt_u", TokenType::Compare, Opcode::I8X16GtU},
+#line 341 "src/lexer-keywords.txt"
+      {"i32x4.extend_high_i16x8_s", TokenType::Unary, Opcode::I32X4ExtendHighI16X8S},
+      {""},
+#line 305 "src/lexer-keywords.txt"
+      {"i32x4.bitmask", TokenType::Unary, Opcode::I32X4Bitmask},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""},
+#line 170 "src/lexer-keywords.txt"
+      {"funcref", Type::FuncRef},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 588 "src/lexer-keywords.txt"
+      {"i8x16.swizzle", TokenType::Binary, Opcode::I8X16Swizzle},
       {""}, {""}, {""},
-#line 481 "src/lexer-keywords.txt"
-      {"i8x16.ge_s", TokenType::Compare, Opcode::I8X16GeS},
-#line 620 "src/lexer-keywords.txt"
-      {"i64.reinterpret/f64", TokenType::Convert, Opcode::I64ReinterpretF64},
-#line 482 "src/lexer-keywords.txt"
-      {"i8x16.ge_u", TokenType::Compare, Opcode::I8X16GeU},
-      {""}, {""}, {""}, {""}, {""}, {""},
-#line 28 "src/lexer-keywords.txt"
-      {"binary", TokenType::Bin},
+#line 26 "src/lexer-keywords.txt"
+      {"assert_trap", TokenType::AssertTrap},
       {""}, {""},
-#line 182 "src/lexer-keywords.txt"
-      {"i16x8.avgr_u", TokenType::Binary, Opcode::I16X8AvgrU},
+#line 46 "src/lexer-keywords.txt"
+      {"elem", TokenType::Elem},
+      {""}, {""}, {""},
+#line 475 "src/lexer-keywords.txt"
+      {"i8x16.avgr_u", TokenType::Binary, Opcode::I8X16AvgrU},
       {""}, {""}, {""}, {""}, {""}, {""},
-#line 207 "src/lexer-keywords.txt"
-      {"i16x8.replace_lane", TokenType::SimdLaneOp, Opcode::I16X8ReplaceLane},
+#line 119 "src/lexer-keywords.txt"
+      {"f64.copysign", TokenType::Binary, Opcode::F64Copysign},
+#line 61 "src/lexer-keywords.txt"
+      {"f32.copysign", TokenType::Binary, Opcode::F32Copysign},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""},
+#line 346 "src/lexer-keywords.txt"
+      {"i32x4.trunc_sat_f64x2_u_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2UZero},
+      {""},
+#line 345 "src/lexer-keywords.txt"
+      {"i32x4.trunc_sat_f64x2_s_zero", TokenType::Unary, Opcode::I32X4TruncSatF64X2SZero},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""},
+#line 134 "src/lexer-keywords.txt"
+      {"f64.promote_f32", TokenType::Convert, Opcode::F64PromoteF32},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""},
+#line 564 "src/lexer-keywords.txt"
+      {"v128.bitselect", TokenType::Ternary, Opcode::V128BitSelect},
+      {""}, {""},
+#line 337 "src/lexer-keywords.txt"
+      {"i32x4.extmul_high_i16x8_u", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8U},
+      {""},
+#line 335 "src/lexer-keywords.txt"
+      {"i32x4.extmul_high_i16x8_s", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8S},
+      {""}, {""}, {""}, {""},
+#line 356 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw16CmpxchgU},
+#line 232 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw16CmpxchgU},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 301 "src/lexer-keywords.txt"
+      {"i32.wrap_i64", TokenType::Convert, Opcode::I32WrapI64},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 479 "src/lexer-keywords.txt"
-      {"i8x16.extract_lane_s", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneS},
       {""},
-#line 480 "src/lexer-keywords.txt"
-      {"i8x16.extract_lane_u", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneU},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 499 "src/lexer-keywords.txt"
-      {"i8x16.shl", TokenType::Binary, Opcode::I8X16Shl},
-      {""}, {""}, {""}, {""}, {""},
-#line 587 "src/lexer-keywords.txt"
-      {"i8x16.shuffle", TokenType::SimdShuffleOp, Opcode::I8X16Shuffle},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 35 "src/lexer-keywords.txt"
+      {"call_ref", TokenType::CallRef, Opcode::CallRef},
       {""}, {""}, {""},
 #line 215 "src/lexer-keywords.txt"
-      {"i16x8.extadd_pairwise_i8x16_s", TokenType::Unary, Opcode::I16X8ExtaddPairwiseI8X16S},
-      {""},
-#line 216 "src/lexer-keywords.txt"
       {"i16x8.extadd_pairwise_i8x16_u", TokenType::Unary, Opcode::I16X8ExtaddPairwiseI8X16U},
+      {""},
+#line 214 "src/lexer-keywords.txt"
+      {"i16x8.extadd_pairwise_i8x16_s", TokenType::Unary, Opcode::I16X8ExtaddPairwiseI8X16S},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""},
+#line 453 "src/lexer-keywords.txt"
+      {"i64x2.bitmask", TokenType::Unary, Opcode::I64X2Bitmask},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""},
-#line 456 "src/lexer-keywords.txt"
-      {"i64x2.extend_high_i32x4_s", TokenType::Unary, Opcode::I64X2ExtendHighI32X4S},
       {""},
-#line 458 "src/lexer-keywords.txt"
-      {"i64x2.extend_high_i32x4_u", TokenType::Unary, Opcode::I64X2ExtendHighI32X4U},
-      {""}, {""}, {""}, {""},
-#line 224 "src/lexer-keywords.txt"
-      {"i16x8.extend_low_i8x16_s", TokenType::Unary, Opcode::I16X8ExtendLowI8X16S},
+#line 504 "src/lexer-keywords.txt"
+      {"i8x16.sub", TokenType::Binary, Opcode::I8X16Sub},
+#line 21 "src/lexer-keywords.txt"
+      {"assert_exception", TokenType::AssertException},
       {""},
-#line 225 "src/lexer-keywords.txt"
-      {"i16x8.extend_low_i8x16_u", TokenType::Unary, Opcode::I16X8ExtendLowI8X16U},
+#line 470 "src/lexer-keywords.txt"
+      {"i8x16.abs", TokenType::Unary, Opcode::I8X16Abs},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 120 "src/lexer-keywords.txt"
+      {"f64.div", TokenType::Binary, Opcode::F64Div},
+#line 63 "src/lexer-keywords.txt"
+      {"f32.div", TokenType::Binary, Opcode::F32Div},
       {""}, {""}, {""},
-#line 466 "src/lexer-keywords.txt"
-      {"i64x2.extmul_high_i32x4_s", TokenType::Binary, Opcode::I64X2ExtmulHighI32X4S},
+#line 477 "src/lexer-keywords.txt"
+      {"i8x16.eq", TokenType::Compare, Opcode::I8X16Eq},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 457 "src/lexer-keywords.txt"
+      {"i64x2.extend_high_i32x4_u", TokenType::Unary, Opcode::I64X2ExtendHighI32X4U},
       {""},
-#line 468 "src/lexer-keywords.txt"
-      {"i64x2.extmul_high_i32x4_u", TokenType::Binary, Opcode::I64X2ExtmulHighI32X4U},
+#line 455 "src/lexer-keywords.txt"
+      {"i64x2.extend_high_i32x4_s", TokenType::Unary, Opcode::I64X2ExtendHighI32X4S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""},
-#line 217 "src/lexer-keywords.txt"
-      {"i16x8.extmul_low_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16S},
-      {""},
-#line 219 "src/lexer-keywords.txt"
-      {"i16x8.extmul_low_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulLowI8X16U},
-      {""}, {""}, {""}, {""}, {""},
-#line 496 "src/lexer-keywords.txt"
-      {"i8x16.popcnt", TokenType::Unary, Opcode::I8X16Popcnt},
-      {""},
-#line 500 "src/lexer-keywords.txt"
-      {"i8x16.shr_s", TokenType::Binary, Opcode::I8X16ShrS},
-      {""}, {""}, {""},
-#line 501 "src/lexer-keywords.txt"
-      {"i8x16.shr_u", TokenType::Binary, Opcode::I8X16ShrU},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 378 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmwCmpxchg},
-#line 247 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmwCmpxchg},
+#line 135 "src/lexer-keywords.txt"
+      {"f64.reinterpret_i64", TokenType::Convert, Opcode::F64ReinterpretI64},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 522 "src/lexer-keywords.txt"
-      {"memory.grow", TokenType::MemoryGrow, Opcode::MemoryGrow},
       {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 476 "src/lexer-keywords.txt"
-      {"i8x16.avgr_u", TokenType::Binary, Opcode::I8X16AvgrU},
-      {""}, {""}, {""}, {""}, {""}, {""},
-#line 498 "src/lexer-keywords.txt"
-      {"i8x16.replace_lane", TokenType::SimdLaneOp, Opcode::I8X16ReplaceLane},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""},
-#line 119 "src/lexer-keywords.txt"
-      {"f64.copysign", TokenType::Binary, Opcode::F64Copysign},
-#line 61 "src/lexer-keywords.txt"
-      {"f32.copysign", TokenType::Binary, Opcode::F32Copysign},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 22 "src/lexer-keywords.txt"
+      {"assert_exhaustion", TokenType::AssertExhaustion},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 590 "src/lexer-keywords.txt"
-      {"atomic.notify", TokenType::AtomicNotify, Opcode::MemoryAtomicNotify},
-#line 517 "src/lexer-keywords.txt"
-      {"memory.atomic.notify", TokenType::AtomicNotify, Opcode::MemoryAtomicNotify},
-#line 184 "src/lexer-keywords.txt"
-      {"i16x8.eq", TokenType::Compare, Opcode::I16X8Eq},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 138 "src/lexer-keywords.txt"
+      {"f64.sub", TokenType::Binary, Opcode::F64Sub},
+#line 80 "src/lexer-keywords.txt"
+      {"f32.sub", TokenType::Binary, Opcode::F32Sub},
+#line 429 "src/lexer-keywords.txt"
+      {"i64.sub", TokenType::Binary, Opcode::I64Sub},
+#line 291 "src/lexer-keywords.txt"
+      {"i32.sub", TokenType::Binary, Opcode::I32Sub},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""},
+#line 467 "src/lexer-keywords.txt"
+      {"i64x2.extmul_high_i32x4_u", TokenType::Binary, Opcode::I64X2ExtmulHighI32X4U},
+      {""},
+#line 465 "src/lexer-keywords.txt"
+      {"i64x2.extmul_high_i32x4_s", TokenType::Binary, Opcode::I64X2ExtmulHighI32X4S},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""},
-#line 204 "src/lexer-keywords.txt"
-      {"i16x8.neg", TokenType::Unary, Opcode::I16X8Neg},
+#line 519 "src/lexer-keywords.txt"
+      {"memory.copy", TokenType::MemoryCopy, Opcode::MemoryCopy},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""},
+#line 77 "src/lexer-keywords.txt"
+      {"f32.reinterpret_i32", TokenType::Convert, Opcode::F32ReinterpretI32},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""},
-#line 374 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XchgU},
-#line 243 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XchgU},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 182 "src/lexer-keywords.txt"
+      {"i16x8.bitmask", TokenType::Unary, Opcode::I16X8Bitmask},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""},
-#line 205 "src/lexer-keywords.txt"
+#line 204 "src/lexer-keywords.txt"
       {"i16x8.q15mulr_sat_s", TokenType::Binary, Opcode::I16X8Q15mulrSatS},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""},
-#line 202 "src/lexer-keywords.txt"
-      {"i16x8.narrow_i32x4_s", TokenType::Binary, Opcode::I16X8NarrowI32X4S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 222 "src/lexer-keywords.txt"
+      {"i16x8.extend_high_i8x16_u", TokenType::Unary, Opcode::I16X8ExtendHighI8X16U},
       {""},
-#line 203 "src/lexer-keywords.txt"
-      {"i16x8.narrow_i32x4_u", TokenType::Binary, Opcode::I16X8NarrowI32X4U},
+#line 221 "src/lexer-keywords.txt"
+      {"i16x8.extend_high_i8x16_s", TokenType::Unary, Opcode::I16X8ExtendHighI8X16S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 27 "src/lexer-keywords.txt"
+      {"assert_unlinkable", TokenType::AssertUnlinkable},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""},
-#line 38 "src/lexer-keywords.txt"
-      {"current_memory", TokenType::MemorySize, Opcode::MemorySize},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 23 "src/lexer-keywords.txt"
+      {"assert_invalid", TokenType::AssertInvalid},
+      {""}, {""}, {""},
+#line 587 "src/lexer-keywords.txt"
+      {"i8x16.shuffle", TokenType::SimdShuffleOp, Opcode::I8X16Shuffle},
+      {""}, {""}, {""}, {""}, {""},
+#line 87 "src/lexer-keywords.txt"
+      {"f32x4.convert_i32x4_u", TokenType::Unary, Opcode::F32X4ConvertI32X4U},
+      {""},
+#line 86 "src/lexer-keywords.txt"
+      {"f32x4.convert_i32x4_s", TokenType::Unary, Opcode::F32X4ConvertI32X4S},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""},
+#line 219 "src/lexer-keywords.txt"
+      {"i16x8.extmul_high_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16U},
+      {""},
+#line 217 "src/lexer-keywords.txt"
+      {"i16x8.extmul_high_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16S},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 478 "src/lexer-keywords.txt"
-      {"i8x16.eq", TokenType::Compare, Opcode::I8X16Eq},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 20 "src/lexer-keywords.txt"
+      {"array", Type::Array, TokenType::Array},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""},
-#line 495 "src/lexer-keywords.txt"
-      {"i8x16.neg", TokenType::Unary, Opcode::I8X16Neg},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 517 "src/lexer-keywords.txt"
+      {"memory.atomic.wait32", TokenType::AtomicWait, Opcode::MemoryAtomicWait32},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 476 "src/lexer-keywords.txt"
+      {"i8x16.bitmask", TokenType::Unary, Opcode::I8X16Bitmask},
+      {""}, {""}, {""}, {""}, {""},
+#line 518 "src/lexer-keywords.txt"
+      {"memory.atomic.wait64", TokenType::AtomicWait, Opcode::MemoryAtomicWait64},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 45 "src/lexer-keywords.txt"
+      {"elem.drop", TokenType::ElemDrop, Opcode::ElemDrop},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 379 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I64AtomicRmwSub},
+#line 248 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I32AtomicRmwSub},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""},
+#line 493 "src/lexer-keywords.txt"
+      {"i8x16.narrow_i16x8_u", TokenType::Binary, Opcode::I8X16NarrowI16X8U},
+      {""},
+#line 492 "src/lexer-keywords.txt"
+      {"i8x16.narrow_i16x8_s", TokenType::Binary, Opcode::I8X16NarrowI16X8S},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""},
+#line 166 "src/lexer-keywords.txt"
+      {"f64x2.convert_low_i32x4_u", TokenType::Unary, Opcode::F64X2ConvertLowI32X4U},
+      {""},
+#line 165 "src/lexer-keywords.txt"
+      {"f64x2.convert_low_i32x4_s", TokenType::Unary, Opcode::F64X2ConvertLowI32X4S},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""},
+#line 417 "src/lexer-keywords.txt"
+      {"i64.reinterpret_f64", TokenType::Convert, Opcode::I64ReinterpretF64},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""},
-#line 176 "src/lexer-keywords.txt"
-      {"grow_memory", TokenType::MemoryGrow, Opcode::MemoryGrow},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
@@ -1769,19 +1669,10 @@ Perfect_Hash::InWordSet (const char *str, size_t len)
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""},
-#line 342 "src/lexer-keywords.txt"
-      {"i32x4.extend_high_i16x8_s", TokenType::Unary, Opcode::I32X4ExtendHighI16X8S},
-      {""},
-#line 343 "src/lexer-keywords.txt"
-      {"i32x4.extend_high_i16x8_u", TokenType::Unary, Opcode::I32X4ExtendHighI16X8U},
+      {""}, {""},
+#line 280 "src/lexer-keywords.txt"
+      {"i32.reinterpret_f32", TokenType::Convert, Opcode::I32ReinterpretF32},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""},
-#line 336 "src/lexer-keywords.txt"
-      {"i32x4.extmul_high_i16x8_s", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8S},
-      {""},
-#line 338 "src/lexer-keywords.txt"
-      {"i32x4.extmul_high_i16x8_u", TokenType::Binary, Opcode::I32X4ExtmulHighI16X8U},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
@@ -1793,38 +1684,25 @@ Perfect_Hash::InWordSet (const char *str, size_t len)
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""},
-#line 520 "src/lexer-keywords.txt"
-      {"memory.copy", TokenType::MemoryCopy, Opcode::MemoryCopy},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""},
+#line 28 "src/lexer-keywords.txt"
+      {"atomic.fence", TokenType::AtomicFence, Opcode::AtomicFence},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 222 "src/lexer-keywords.txt"
-      {"i16x8.extend_high_i8x16_s", TokenType::Unary, Opcode::I16X8ExtendHighI8X16S},
-      {""},
-#line 223 "src/lexer-keywords.txt"
-      {"i16x8.extend_high_i8x16_u", TokenType::Unary, Opcode::I16X8ExtendHighI8X16U},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""},
-#line 218 "src/lexer-keywords.txt"
-      {"i16x8.extmul_high_i8x16_s", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16S},
-      {""},
-#line 220 "src/lexer-keywords.txt"
-      {"i16x8.extmul_high_i8x16_u", TokenType::Binary, Opcode::I16X8ExtmulHighI8X16U},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""},
-#line 381 "src/lexer-keywords.txt"
-      {"i64.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I64AtomicRmwXchg},
-#line 250 "src/lexer-keywords.txt"
-      {"i32.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I32AtomicRmwXchg},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 516 "src/lexer-keywords.txt"
+      {"memory.atomic.notify", TokenType::AtomicNotify, Opcode::MemoryAtomicNotify},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
@@ -1833,11 +1711,9 @@ Perfect_Hash::InWordSet (const char *str, size_t len)
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 493 "src/lexer-keywords.txt"
-      {"i8x16.narrow_i16x8_s", TokenType::Binary, Opcode::I8X16NarrowI16X8S},
       {""},
-#line 494 "src/lexer-keywords.txt"
-      {"i8x16.narrow_i16x8_u", TokenType::Binary, Opcode::I8X16NarrowI16X8U}
+#line 167 "src/lexer-keywords.txt"
+      {"f64x2.promote_low_f32x4", TokenType::Unary, Opcode::F64X2PromoteLowF32X4}
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
index 099a8e5754d12b5ff30c02f5f829b346ec2d7b0a..fd555779115b12bd1bca73bd1e368b935e8b1676 100644 (file)
@@ -45,19 +45,24 @@ class NameResolver : public ExprVisitor::DelegateNop {
   Result OnCallIndirectExpr(CallIndirectExpr*) override;
   Result OnCatchExpr(TryExpr*, Catch*) override;
   Result OnDelegateExpr(TryExpr*) override;
-  Result OnReturnCallExpr(ReturnCallExpr *) override;
+  Result OnReturnCallExpr(ReturnCallExpr*) override;
   Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override;
   Result OnGlobalGetExpr(GlobalGetExpr*) override;
   Result OnGlobalSetExpr(GlobalSetExpr*) override;
   Result BeginIfExpr(IfExpr*) override;
   Result EndIfExpr(IfExpr*) override;
+  Result OnLoadExpr(LoadExpr*) override;
   Result OnLocalGetExpr(LocalGetExpr*) override;
   Result OnLocalSetExpr(LocalSetExpr*) override;
   Result OnLocalTeeExpr(LocalTeeExpr*) override;
   Result BeginLoopExpr(LoopExpr*) override;
   Result EndLoopExpr(LoopExpr*) override;
+  Result OnMemoryCopyExpr(MemoryCopyExpr*) override;
   Result OnDataDropExpr(DataDropExpr*) override;
+  Result OnMemoryFillExpr(MemoryFillExpr*) override;
+  Result OnMemoryGrowExpr(MemoryGrowExpr*) override;
   Result OnMemoryInitExpr(MemoryInitExpr*) override;
+  Result OnMemorySizeExpr(MemorySizeExpr*) override;
   Result OnElemDropExpr(ElemDropExpr*) override;
   Result OnTableCopyExpr(TableCopyExpr*) override;
   Result OnTableInitExpr(TableInitExpr*) override;
@@ -67,6 +72,7 @@ class NameResolver : public ExprVisitor::DelegateNop {
   Result OnTableSizeExpr(TableSizeExpr*) override;
   Result OnTableFillExpr(TableFillExpr*) override;
   Result OnRefFuncExpr(RefFuncExpr*) override;
+  Result OnStoreExpr(StoreExpr*) override;
   Result BeginTryExpr(TryExpr*) override;
   Result EndTryExpr(TryExpr*) override;
   Result OnThrowExpr(ThrowExpr*) override;
@@ -111,9 +117,7 @@ class NameResolver : public ExprVisitor::DelegateNop {
 };
 
 NameResolver::NameResolver(Script* script, Errors* errors)
-    : errors_(errors),
-      script_(script),
-      visitor_(this) {}
+    : errors_(errors), script_(script), visitor_(this) {}
 
 }  // end anonymous namespace
 
@@ -321,6 +325,11 @@ Result NameResolver::EndIfExpr(IfExpr* expr) {
   return Result::Ok;
 }
 
+Result NameResolver::OnLoadExpr(LoadExpr* expr) {
+  ResolveMemoryVar(&expr->memidx);
+  return Result::Ok;
+}
+
 Result NameResolver::OnLocalGetExpr(LocalGetExpr* expr) {
   ResolveLocalVar(&expr->var);
   return Result::Ok;
@@ -336,13 +345,35 @@ Result NameResolver::OnLocalTeeExpr(LocalTeeExpr* expr) {
   return Result::Ok;
 }
 
+Result NameResolver::OnMemoryCopyExpr(MemoryCopyExpr* expr) {
+  ResolveMemoryVar(&expr->srcmemidx);
+  ResolveMemoryVar(&expr->destmemidx);
+  return Result::Ok;
+}
+
 Result NameResolver::OnDataDropExpr(DataDropExpr* expr) {
   ResolveDataSegmentVar(&expr->var);
   return Result::Ok;
 }
 
+Result NameResolver::OnMemoryFillExpr(MemoryFillExpr* expr) {
+  ResolveMemoryVar(&expr->memidx);
+  return Result::Ok;
+}
+
+Result NameResolver::OnMemoryGrowExpr(MemoryGrowExpr* expr) {
+  ResolveMemoryVar(&expr->memidx);
+  return Result::Ok;
+}
+
 Result NameResolver::OnMemoryInitExpr(MemoryInitExpr* expr) {
   ResolveDataSegmentVar(&expr->var);
+  ResolveMemoryVar(&expr->memidx);
+  return Result::Ok;
+}
+
+Result NameResolver::OnMemorySizeExpr(MemorySizeExpr* expr) {
+  ResolveMemoryVar(&expr->memidx);
   return Result::Ok;
 }
 
@@ -393,6 +424,11 @@ Result NameResolver::OnRefFuncExpr(RefFuncExpr* expr) {
   return Result::Ok;
 }
 
+Result NameResolver::OnStoreExpr(StoreExpr* expr) {
+  ResolveMemoryVar(&expr->memidx);
+  return Result::Ok;
+}
+
 Result NameResolver::BeginTryExpr(TryExpr* expr) {
   PushLabel(expr->block.label);
   ResolveBlockDeclarationVar(&expr->block.decl);
@@ -488,9 +524,10 @@ void NameResolver::VisitTag(Tag* tag) {
 void NameResolver::VisitElemSegment(ElemSegment* segment) {
   ResolveTableVar(&segment->table_var);
   visitor_.VisitExprList(segment->offset);
-  for (ElemExpr& elem_expr : segment->elem_exprs) {
-    if (elem_expr.kind == ElemExprKind::RefFunc) {
-      ResolveFuncVar(&elem_expr.var);
+  for (ExprList& elem_expr : segment->elem_exprs) {
+    if (elem_expr.size() == 1 &&
+        elem_expr.front().type() == ExprType::RefFunc) {
+      ResolveFuncVar(&cast<RefFuncExpr>(&elem_expr.front())->var);
     }
   }
 }
@@ -544,6 +581,7 @@ void NameResolver::VisitCommand(Command* command) {
     case CommandType::AssertReturn:
     case CommandType::AssertTrap:
     case CommandType::AssertExhaustion:
+    case CommandType::AssertException:
     case CommandType::Register:
       /* Don't resolve a module_var, since it doesn't really behave like other
        * vars. You can't reference a module by index. */
index 51c0edea6e87c1853cb0171d0ba540813004bdce..b61f1dee7dd46822ae7e52a11c871633aa2914be 100644 (file)
@@ -41,22 +41,25 @@ Result WABT_PRINTF_FORMAT(3, 4) SharedValidator::PrintError(const Location& loc,
 }
 
 void SharedValidator::OnTypecheckerError(const char* msg) {
-  PrintError(*expr_loc_, "%s", msg);
+  PrintError(expr_loc_, "%s", msg);
 }
 
 Result SharedValidator::OnFuncType(const Location& loc,
                                    Index param_count,
                                    const Type* param_types,
                                    Index result_count,
-                                   const Type* result_types) {
+                                   const Type* result_types,
+                                   Index type_index) {
   Result result = Result::Ok;
   if (!options_.features.multi_value_enabled() && result_count > 1) {
-    result |=
-        PrintError(loc, "multiple result values not currently supported.");
+    result |= PrintError(loc,
+                         "multiple result values are not supported without "
+                         "multi-value enabled.");
   }
-  func_types_.emplace(num_types_++,
-                      FuncType{ToTypeVector(param_count, param_types),
-                               ToTypeVector(result_count, result_types)});
+  func_types_.emplace(
+      num_types_++,
+      FuncType{ToTypeVector(param_count, param_types),
+               ToTypeVector(result_count, result_types), type_index});
   return result;
 }
 
@@ -133,7 +136,7 @@ Result SharedValidator::OnTable(const Location& loc,
 
 Result SharedValidator::OnMemory(const Location& loc, const Limits& limits) {
   Result result = Result::Ok;
-  if (memories_.size() > 0) {
+  if (memories_.size() > 0 && !options_.features.multi_memory_enabled()) {
     result |= PrintError(loc, "only one memory block allowed");
   }
   result |= CheckLimits(
@@ -176,62 +179,12 @@ Result SharedValidator::CheckType(const Location& loc,
                                   const char* desc) {
   if (Failed(TypeChecker::CheckType(actual, expected))) {
     PrintError(loc, "type mismatch at %s. got %s, expected %s", desc,
-               actual.GetName(), expected.GetName());
+               actual.GetName().c_str(), expected.GetName().c_str());
     return Result::Error;
   }
   return Result::Ok;
 }
 
-Result SharedValidator::OnGlobalInitExpr_Const(const Location& loc,
-                                               Type actual) {
-  return CheckType(loc, actual, globals_.back().type,
-                   "global initializer expression");
-}
-
-Result SharedValidator::OnGlobalInitExpr_GlobalGet(const Location& loc,
-                                                   Var ref_global_var) {
-  Result result = Result::Ok;
-  GlobalType ref_global;
-  CHECK_RESULT(CheckGlobalIndex(ref_global_var, &ref_global));
-
-  if (ref_global_var.index() >= num_imported_globals_) {
-    result |= PrintError(
-        ref_global_var.loc,
-        "initializer expression can only reference an imported global");
-  }
-
-  if (ref_global.mutable_) {
-    result |= PrintError(
-        loc, "initializer expression cannot reference a mutable global");
-  }
-
-  result |= CheckType(loc, ref_global.type, globals_.back().type,
-                      "global initializer expression");
-  return result;
-}
-
-Result SharedValidator::OnGlobalInitExpr_RefNull(const Location& loc,
-                                                 Type type) {
-  return CheckType(loc, type, globals_.back().type,
-                   "global initializer expression");
-}
-
-Result SharedValidator::OnGlobalInitExpr_RefFunc(const Location& loc,
-                                                 Var func_var) {
-  Result result = Result::Ok;
-  result |= CheckFuncIndex(func_var);
-  init_expr_funcs_.push_back(func_var);
-  result |= CheckType(loc, Type::FuncRef, globals_.back().type,
-                      "global initializer expression");
-  return result;
-}
-
-Result SharedValidator::OnGlobalInitExpr_Other(const Location& loc) {
-  return PrintError(
-      loc,
-      "invalid global initializer expression, must be a constant expression");
-}
-
 Result SharedValidator::OnTag(const Location& loc, Var sig_var) {
   Result result = Result::Ok;
   FuncType type;
@@ -310,33 +263,6 @@ void SharedValidator::OnElemSegmentElemType(Type elem_type) {
   elems_.back().element = elem_type;
 }
 
-Result SharedValidator::OnElemSegmentInitExpr_Const(const Location& loc,
-                                                    Type type) {
-  return CheckType(loc, type, Type::I32, "elem segment offset");
-}
-
-Result SharedValidator::OnElemSegmentInitExpr_GlobalGet(const Location& loc,
-                                                        Var global_var) {
-  Result result = Result::Ok;
-  GlobalType ref_global;
-  result |= CheckGlobalIndex(global_var, &ref_global);
-
-  if (ref_global.mutable_) {
-    result |= PrintError(
-        loc, "initializer expression cannot reference a mutable global");
-  }
-
-  result |= CheckType(loc, ref_global.type, Type::I32, "elem segment offset");
-  return result;
-}
-
-Result SharedValidator::OnElemSegmentInitExpr_Other(const Location& loc) {
-  return PrintError(loc,
-                    "invalid elem segment offset, must be a constant "
-                    "expression; either i32.const or "
-                    "global.get.");
-}
-
 Result SharedValidator::OnElemSegmentElemExpr_RefNull(const Location& loc,
                                                       Type type) {
   return CheckType(loc, type, elems_.back().element, "elem expression");
@@ -370,41 +296,12 @@ Result SharedValidator::OnDataSegment(const Location& loc,
   return result;
 }
 
-Result SharedValidator::OnDataSegmentInitExpr_Const(const Location& loc,
-                                                    Type type) {
-  auto required =
-      memories_.empty() ? Type(Type::I32) : memories_[0].limits.IndexType();
-  return CheckType(loc, type, required, "data segment offset");
-}
-
-Result SharedValidator::OnDataSegmentInitExpr_GlobalGet(const Location& loc,
-                                                        Var global_var) {
-  Result result = Result::Ok;
-  GlobalType ref_global;
-  result |= CheckGlobalIndex(global_var, &ref_global);
-
-  if (ref_global.mutable_) {
-    result |= PrintError(
-        loc, "initializer expression cannot reference a mutable global");
-  }
-
-  auto required =
-      memories_.empty() ? Type(Type::I32) : memories_[0].limits.IndexType();
-  result |= CheckType(loc, ref_global.type, required, "data segment offset");
-  return result;
-}
-
-Result SharedValidator::OnDataSegmentInitExpr_Other(const Location& loc) {
-  return PrintError(loc,
-                    "invalid data segment offset, must be a constant "
-                    "expression; either iXX.const or "
-                    "global.get.");
-}
-
 Result SharedValidator::CheckDeclaredFunc(Var func_var) {
   if (declared_funcs_.count(func_var.index()) == 0) {
     return PrintError(func_var.loc,
-                      "function is not declared in any elem sections");
+                      "function %" PRIindex
+                      " is not declared in any elem sections",
+                      func_var.index());
   }
   return Result::Ok;
 }
@@ -414,7 +311,7 @@ Result SharedValidator::EndModule() {
   // mentioned in an elems section.  This can't be done while process the
   // globals because the global section comes before the elem section.
   Result result = Result::Ok;
-  for (Var func_var : init_expr_funcs_) {
+  for (Var func_var : check_declared_funcs_) {
     result |= CheckDeclaredFunc(func_var);
   }
   return result;
@@ -531,9 +428,25 @@ Result SharedValidator::CheckBlockSignature(const Location& loc,
   return result;
 }
 
+Index SharedValidator::GetFunctionTypeIndex(Index func_index) const {
+  assert(func_index < funcs_.size());
+  return funcs_[func_index].type_index;
+}
+
+Result SharedValidator::BeginInitExpr(const Location& loc, Type type) {
+  expr_loc_ = loc;
+  in_init_expr_ = true;
+  return typechecker_.BeginInitExpr(type);
+}
+
+Result SharedValidator::EndInitExpr() {
+  in_init_expr_ = false;
+  return typechecker_.EndInitExpr();
+}
+
 Result SharedValidator::BeginFunctionBody(const Location& loc,
                                           Index func_index) {
-  expr_loc_ = &loc;
+  expr_loc_ = loc;
   locals_.clear();
   if (func_index < funcs_.size()) {
     for (Type type : funcs_[func_index].params) {
@@ -606,9 +519,28 @@ Result SharedValidator::CheckAtomicAlign(const Location& loc,
   return Result::Ok;
 }
 
+static bool ValidInitOpcode(Opcode opcode) {
+  return opcode == Opcode::GlobalGet || opcode == Opcode::I32Const ||
+         opcode == Opcode::I64Const || opcode == Opcode::F32Const ||
+         opcode == Opcode::F64Const || opcode == Opcode::RefFunc ||
+         opcode == Opcode::RefNull;
+}
+
+Result SharedValidator::CheckInstr(Opcode opcode, const Location& loc) {
+  expr_loc_ = loc;
+  if (in_init_expr_ && !ValidInitOpcode(opcode)) {
+    PrintError(loc,
+               "invalid initializer: instruction not valid in initializer "
+               "expression: %s",
+               opcode.GetName());
+    return Result::Error;
+  }
+  return Result::Ok;
+}
+
 Result SharedValidator::OnAtomicFence(const Location& loc,
                                       uint32_t consistency_model) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(Opcode::AtomicFence, loc);
   if (consistency_model != 0) {
     result |= PrintError(
         loc, "unexpected atomic.fence consistency model (expected 0): %u",
@@ -621,9 +553,8 @@ Result SharedValidator::OnAtomicFence(const Location& loc,
 Result SharedValidator::OnAtomicLoad(const Location& loc,
                                      Opcode opcode,
                                      Address alignment) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(opcode, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
   result |= CheckMemoryIndex(Var(0, loc), &mt);
   result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
   result |= typechecker_.OnAtomicLoad(opcode, mt.limits);
@@ -633,9 +564,8 @@ Result SharedValidator::OnAtomicLoad(const Location& loc,
 Result SharedValidator::OnAtomicNotify(const Location& loc,
                                        Opcode opcode,
                                        Address alignment) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(opcode, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
   result |= CheckMemoryIndex(Var(0, loc), &mt);
   result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
   result |= typechecker_.OnAtomicNotify(opcode, mt.limits);
@@ -645,9 +575,8 @@ Result SharedValidator::OnAtomicNotify(const Location& loc,
 Result SharedValidator::OnAtomicRmwCmpxchg(const Location& loc,
                                            Opcode opcode,
                                            Address alignment) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(opcode, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
   result |= CheckMemoryIndex(Var(0, loc), &mt);
   result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
   result |= typechecker_.OnAtomicRmwCmpxchg(opcode, mt.limits);
@@ -657,9 +586,8 @@ Result SharedValidator::OnAtomicRmwCmpxchg(const Location& loc,
 Result SharedValidator::OnAtomicRmw(const Location& loc,
                                     Opcode opcode,
                                     Address alignment) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(opcode, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
   result |= CheckMemoryIndex(Var(0, loc), &mt);
   result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
   result |= typechecker_.OnAtomicRmw(opcode, mt.limits);
@@ -669,9 +597,8 @@ Result SharedValidator::OnAtomicRmw(const Location& loc,
 Result SharedValidator::OnAtomicStore(const Location& loc,
                                       Opcode opcode,
                                       Address alignment) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(opcode, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
   result |= CheckMemoryIndex(Var(0, loc), &mt);
   result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
   result |= typechecker_.OnAtomicStore(opcode, mt.limits);
@@ -681,9 +608,8 @@ Result SharedValidator::OnAtomicStore(const Location& loc,
 Result SharedValidator::OnAtomicWait(const Location& loc,
                                      Opcode opcode,
                                      Address alignment) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(opcode, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
   result |= CheckMemoryIndex(Var(0, loc), &mt);
   result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
   result |= typechecker_.OnAtomicWait(opcode, mt.limits);
@@ -691,16 +617,14 @@ Result SharedValidator::OnAtomicWait(const Location& loc,
 }
 
 Result SharedValidator::OnBinary(const Location& loc, Opcode opcode) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(opcode, loc);
   result |= typechecker_.OnBinary(opcode);
   return result;
 }
 
 Result SharedValidator::OnBlock(const Location& loc, Type sig_type) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(Opcode::Block, loc);
   TypeVector param_types, result_types;
-  expr_loc_ = &loc;
   result |= CheckBlockSignature(loc, Opcode::Block, sig_type, &param_types,
                                 &result_types);
   result |= typechecker_.OnBlock(param_types, result_types);
@@ -708,43 +632,38 @@ Result SharedValidator::OnBlock(const Location& loc, Type sig_type) {
 }
 
 Result SharedValidator::OnBr(const Location& loc, Var depth) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::Br, loc);
   result |= typechecker_.OnBr(depth.index());
   return result;
 }
 
 Result SharedValidator::OnBrIf(const Location& loc, Var depth) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::BrIf, loc);
   result |= typechecker_.OnBrIf(depth.index());
   return result;
 }
 
 Result SharedValidator::BeginBrTable(const Location& loc) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::BrTable, loc);
   result |= typechecker_.BeginBrTable();
   return result;
 }
 
 Result SharedValidator::OnBrTableTarget(const Location& loc, Var depth) {
   Result result = Result::Ok;
-  expr_loc_ = &loc;
+  expr_loc_ = loc;
   result |= typechecker_.OnBrTableTarget(depth.index());
   return result;
 }
 
 Result SharedValidator::EndBrTable(const Location& loc) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::BrTable, loc);
   result |= typechecker_.EndBrTable();
   return result;
 }
 
 Result SharedValidator::OnCall(const Location& loc, Var func_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::Call, loc);
   FuncType func_type;
   result |= CheckFuncIndex(func_var, &func_type);
   result |= typechecker_.OnCall(func_type.params, func_type.results);
@@ -754,8 +673,7 @@ Result SharedValidator::OnCall(const Location& loc, Var func_var) {
 Result SharedValidator::OnCallIndirect(const Location& loc,
                                        Var sig_var,
                                        Var table_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::CallIndirect, loc);
   FuncType func_type;
   result |= CheckFuncTypeIndex(sig_var, &func_type);
   result |= CheckTableIndex(table_var);
@@ -763,11 +681,11 @@ Result SharedValidator::OnCallIndirect(const Location& loc,
   return result;
 }
 
-Result SharedValidator::OnCallRef(const Location& loc, Index* function_type_index) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+Result SharedValidator::OnCallRef(const Location& loc,
+                                  Index* function_type_index) {
+  Result result = CheckInstr(Opcode::CallRef, loc);
   Index func_index;
-  result |= typechecker_.OnFuncRef(&func_index);
+  result |= typechecker_.OnIndexedFuncRef(&func_index);
   if (Failed(result)) {
     return result;
   }
@@ -783,8 +701,7 @@ Result SharedValidator::OnCallRef(const Location& loc, Index* function_type_inde
 Result SharedValidator::OnCatch(const Location& loc,
                                 Var tag_var,
                                 bool is_catch_all) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::Catch, loc);
   if (is_catch_all) {
     TypeVector empty;
     result |= typechecker_.OnCatch(empty);
@@ -797,80 +714,87 @@ Result SharedValidator::OnCatch(const Location& loc,
 }
 
 Result SharedValidator::OnCompare(const Location& loc, Opcode opcode) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(opcode, loc);
   result |= typechecker_.OnCompare(opcode);
   return result;
 }
 
 Result SharedValidator::OnConst(const Location& loc, Type type) {
   Result result = Result::Ok;
-  expr_loc_ = &loc;
+  expr_loc_ = loc;
   result |= typechecker_.OnConst(type);
   return result;
 }
 
 Result SharedValidator::OnConvert(const Location& loc, Opcode opcode) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(opcode, loc);
   result |= typechecker_.OnConvert(opcode);
   return result;
 }
 
 Result SharedValidator::OnDataDrop(const Location& loc, Var segment_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::DataDrop, loc);
   result |= CheckDataSegmentIndex(segment_var);
   result |= typechecker_.OnDataDrop(segment_var.index());
   return result;
 }
 
 Result SharedValidator::OnDelegate(const Location& loc, Var depth) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::Delegate, loc);
   result |= typechecker_.OnDelegate(depth.index());
   return result;
 }
 
 Result SharedValidator::OnDrop(const Location& loc) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::Drop, loc);
   result |= typechecker_.OnDrop();
   return result;
 }
 
 Result SharedValidator::OnElemDrop(const Location& loc, Var segment_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::ElemDrop, loc);
   result |= CheckElemSegmentIndex(segment_var);
   result |= typechecker_.OnElemDrop(segment_var.index());
   return result;
 }
 
 Result SharedValidator::OnElse(const Location& loc) {
+  // Don't call CheckInstr or update expr_loc_ here because if we fail we want
+  // the last expression in the If block to be reported as the error location,
+  // not the else itself.
   Result result = Result::Ok;
   result |= typechecker_.OnElse();
   return result;
 }
 
 Result SharedValidator::OnEnd(const Location& loc) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::End, loc);
   result |= typechecker_.OnEnd();
   return result;
 }
 
 Result SharedValidator::OnGlobalGet(const Location& loc, Var global_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::GlobalGet, loc);
   GlobalType global_type;
   result |= CheckGlobalIndex(global_var, &global_type);
   result |= typechecker_.OnGlobalGet(global_type.type);
+  if (Succeeded(result) && in_init_expr_) {
+    if (global_var.index() >= num_imported_globals_) {
+      result |= PrintError(
+          global_var.loc,
+          "initializer expression can only reference an imported global");
+    }
+    if (global_type.mutable_) {
+      result |= PrintError(
+          loc, "initializer expression cannot reference a mutable global");
+    }
+  }
+
   return result;
 }
 
 Result SharedValidator::OnGlobalSet(const Location& loc, Var global_var) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(Opcode::GlobalSet, loc);
   GlobalType global_type;
   result |= CheckGlobalIndex(global_var, &global_type);
   if (!global_type.mutable_) {
@@ -878,15 +802,13 @@ Result SharedValidator::OnGlobalSet(const Location& loc, Var global_var) {
         loc, "can't global.set on immutable global at index %" PRIindex ".",
         global_var.index());
   }
-  expr_loc_ = &loc;
   result |= typechecker_.OnGlobalSet(global_type.type);
   return result;
 }
 
 Result SharedValidator::OnIf(const Location& loc, Type sig_type) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(Opcode::If, loc);
   TypeVector param_types, result_types;
-  expr_loc_ = &loc;
   result |= CheckBlockSignature(loc, Opcode::If, sig_type, &param_types,
                                 &result_types);
   result |= typechecker_.OnIf(param_types, result_types);
@@ -895,11 +817,11 @@ Result SharedValidator::OnIf(const Location& loc, Type sig_type) {
 
 Result SharedValidator::OnLoad(const Location& loc,
                                Opcode opcode,
+                               Var memidx,
                                Address alignment) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(opcode, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
-  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckMemoryIndex(memidx, &mt);
   result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
   result |= typechecker_.OnLoad(opcode, mt.limits);
   return result;
@@ -908,9 +830,8 @@ Result SharedValidator::OnLoad(const Location& loc,
 Result SharedValidator::OnLoadSplat(const Location& loc,
                                     Opcode opcode,
                                     Address alignment) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(opcode, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
   result |= CheckMemoryIndex(Var(0, loc), &mt);
   result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
   result |= typechecker_.OnLoad(opcode, mt.limits);
@@ -920,9 +841,8 @@ Result SharedValidator::OnLoadSplat(const Location& loc,
 Result SharedValidator::OnLoadZero(const Location& loc,
                                    Opcode opcode,
                                    Address alignment) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(opcode, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
   result |= CheckMemoryIndex(Var(0, loc), &mt);
   result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
   result |= typechecker_.OnLoad(opcode, mt.limits);
@@ -930,125 +850,123 @@ Result SharedValidator::OnLoadZero(const Location& loc,
 }
 
 Result SharedValidator::OnLocalGet(const Location& loc, Var local_var) {
+  CHECK_RESULT(CheckInstr(Opcode::LocalGet, loc));
   Result result = Result::Ok;
   Type type = Type::Any;
-  expr_loc_ = &loc;
   result |= CheckLocalIndex(local_var, &type);
   result |= typechecker_.OnLocalGet(type);
   return result;
 }
 
 Result SharedValidator::OnLocalSet(const Location& loc, Var local_var) {
+  CHECK_RESULT(CheckInstr(Opcode::LocalSet, loc));
   Result result = Result::Ok;
   Type type = Type::Any;
-  expr_loc_ = &loc;
   result |= CheckLocalIndex(local_var, &type);
   result |= typechecker_.OnLocalSet(type);
   return result;
 }
 
 Result SharedValidator::OnLocalTee(const Location& loc, Var local_var) {
+  CHECK_RESULT(CheckInstr(Opcode::LocalTee, loc));
   Result result = Result::Ok;
   Type type = Type::Any;
-  expr_loc_ = &loc;
   result |= CheckLocalIndex(local_var, &type);
   result |= typechecker_.OnLocalTee(type);
   return result;
 }
 
 Result SharedValidator::OnLoop(const Location& loc, Type sig_type) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(Opcode::Loop, loc);
   TypeVector param_types, result_types;
-  expr_loc_ = &loc;
   result |= CheckBlockSignature(loc, Opcode::Loop, sig_type, &param_types,
                                 &result_types);
   result |= typechecker_.OnLoop(param_types, result_types);
   return result;
 }
 
-Result SharedValidator::OnMemoryCopy(const Location& loc) {
-  Result result = Result::Ok;
+Result SharedValidator::OnMemoryCopy(const Location& loc,
+                                     Var srcmemidx,
+                                     Var destmemidx) {
+  Result result = CheckInstr(Opcode::MemoryCopy, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
-  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckMemoryIndex(srcmemidx, &mt);
+  result |= CheckMemoryIndex(destmemidx, &mt);
   result |= typechecker_.OnMemoryCopy(mt.limits);
   return result;
 }
 
-Result SharedValidator::OnMemoryFill(const Location& loc) {
-  Result result = Result::Ok;
+Result SharedValidator::OnMemoryFill(const Location& loc, Var memidx) {
+  Result result = CheckInstr(Opcode::MemoryFill, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
   result |= CheckMemoryIndex(Var(0, loc), &mt);
   result |= typechecker_.OnMemoryFill(mt.limits);
   return result;
 }
 
-Result SharedValidator::OnMemoryGrow(const Location& loc) {
-  Result result = Result::Ok;
+Result SharedValidator::OnMemoryGrow(const Location& loc, Var memidx) {
+  Result result = CheckInstr(Opcode::MemoryGrow, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
-  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckMemoryIndex(memidx, &mt);
   result |= typechecker_.OnMemoryGrow(mt.limits);
   return result;
 }
 
-Result SharedValidator::OnMemoryInit(const Location& loc, Var segment_var) {
-  Result result = Result::Ok;
+Result SharedValidator::OnMemoryInit(const Location& loc,
+                                     Var segment_var,
+                                     Var memidx) {
+  Result result = CheckInstr(Opcode::MemoryInit, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
-  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckMemoryIndex(memidx, &mt);
   result |= CheckDataSegmentIndex(segment_var);
   result |= typechecker_.OnMemoryInit(segment_var.index(), mt.limits);
   return result;
 }
 
-Result SharedValidator::OnMemorySize(const Location& loc) {
-  Result result = Result::Ok;
+Result SharedValidator::OnMemorySize(const Location& loc, Var memidx) {
+  Result result = CheckInstr(Opcode::MemorySize, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
-  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckMemoryIndex(memidx, &mt);
   result |= typechecker_.OnMemorySize(mt.limits);
   return result;
 }
 
 Result SharedValidator::OnNop(const Location& loc) {
-  expr_loc_ = &loc;
-  return Result::Ok;
+  Result result = CheckInstr(Opcode::Nop, loc);
+  return result;
 }
 
 Result SharedValidator::OnRefFunc(const Location& loc, Var func_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
-  result |= CheckDeclaredFunc(func_var);
-  result |= typechecker_.OnRefFuncExpr(func_var.index());
+  Result result = CheckInstr(Opcode::RefFunc, loc);
+  result |= CheckFuncIndex(func_var);
+  if (Succeeded(result)) {
+    check_declared_funcs_.push_back(func_var);
+    Index func_type = GetFunctionTypeIndex(func_var.index());
+    result |= typechecker_.OnRefFuncExpr(func_type);
+  }
   return result;
 }
 
 Result SharedValidator::OnRefIsNull(const Location& loc) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::RefIsNull, loc);
   result |= typechecker_.OnRefIsNullExpr();
   return result;
 }
 
 Result SharedValidator::OnRefNull(const Location& loc, Type type) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::RefNull, loc);
   result |= typechecker_.OnRefNullExpr(type);
   return result;
 }
 
 Result SharedValidator::OnRethrow(const Location& loc, Var depth) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::Rethrow, loc);
   result |= typechecker_.OnRethrow(depth.index());
   return result;
 }
 
 Result SharedValidator::OnReturnCall(const Location& loc, Var func_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::ReturnCall, loc);
   FuncType func_type;
   result |= CheckFuncIndex(func_var, &func_type);
   result |= typechecker_.OnReturnCall(func_type.params, func_type.results);
@@ -1058,8 +976,7 @@ Result SharedValidator::OnReturnCall(const Location& loc, Var func_var) {
 Result SharedValidator::OnReturnCallIndirect(const Location& loc,
                                              Var sig_var,
                                              Var table_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::CallIndirect, loc);
   result |= CheckTableIndex(table_var);
   FuncType func_type;
   result |= CheckFuncTypeIndex(sig_var, &func_type);
@@ -1069,8 +986,7 @@ Result SharedValidator::OnReturnCallIndirect(const Location& loc,
 }
 
 Result SharedValidator::OnReturn(const Location& loc) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::Return, loc);
   result |= typechecker_.OnReturn();
   return result;
 }
@@ -1078,8 +994,7 @@ Result SharedValidator::OnReturn(const Location& loc) {
 Result SharedValidator::OnSelect(const Location& loc,
                                  Index result_count,
                                  Type* result_types) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::Select, loc);
   if (result_count > 1) {
     result |=
         PrintError(loc, "invalid arity in select instruction: %" PRIindex ".",
@@ -1093,19 +1008,17 @@ Result SharedValidator::OnSelect(const Location& loc,
 Result SharedValidator::OnSimdLaneOp(const Location& loc,
                                      Opcode opcode,
                                      uint64_t value) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(opcode, loc);
   result |= typechecker_.OnSimdLaneOp(opcode, value);
   return result;
 }
 
 Result SharedValidator::OnSimdLoadLane(const Location& loc,
-                                     Opcode opcode,
-                                     Address alignment,
-                                     uint64_t value) {
-  Result result = Result::Ok;
+                                       Opcode opcode,
+                                       Address alignment,
+                                       uint64_t value) {
+  Result result = CheckInstr(opcode, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
   result |= CheckMemoryIndex(Var(0, loc), &mt);
   result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
   result |= typechecker_.OnSimdLoadLane(opcode, mt.limits, value);
@@ -1116,9 +1029,8 @@ Result SharedValidator::OnSimdStoreLane(const Location& loc,
                                         Opcode opcode,
                                         Address alignment,
                                         uint64_t value) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(opcode, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
   result |= CheckMemoryIndex(Var(0, loc), &mt);
   result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
   result |= typechecker_.OnSimdStoreLane(opcode, mt.limits, value);
@@ -1128,19 +1040,18 @@ Result SharedValidator::OnSimdStoreLane(const Location& loc,
 Result SharedValidator::OnSimdShuffleOp(const Location& loc,
                                         Opcode opcode,
                                         v128 value) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(opcode, loc);
   result |= typechecker_.OnSimdShuffleOp(opcode, value);
   return result;
 }
 
 Result SharedValidator::OnStore(const Location& loc,
                                 Opcode opcode,
+                                Var memidx,
                                 Address alignment) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(opcode, loc);
   MemoryType mt;
-  expr_loc_ = &loc;
-  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckMemoryIndex(memidx, &mt);
   result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
   result |= typechecker_.OnStore(opcode, mt.limits);
   return result;
@@ -1149,8 +1060,7 @@ Result SharedValidator::OnStore(const Location& loc,
 Result SharedValidator::OnTableCopy(const Location& loc,
                                     Var dst_var,
                                     Var src_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::TableCopy, loc);
   TableType dst_table;
   TableType src_table;
   result |= CheckTableIndex(dst_var, &dst_table);
@@ -1161,8 +1071,7 @@ Result SharedValidator::OnTableCopy(const Location& loc,
 }
 
 Result SharedValidator::OnTableFill(const Location& loc, Var table_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::TableFill, loc);
   TableType table_type;
   result |= CheckTableIndex(table_var, &table_type);
   result |= typechecker_.OnTableFill(table_type.element);
@@ -1170,8 +1079,7 @@ Result SharedValidator::OnTableFill(const Location& loc, Var table_var) {
 }
 
 Result SharedValidator::OnTableGet(const Location& loc, Var table_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::TableGet, loc);
   TableType table_type;
   result |= CheckTableIndex(table_var, &table_type);
   result |= typechecker_.OnTableGet(table_type.element);
@@ -1179,8 +1087,7 @@ Result SharedValidator::OnTableGet(const Location& loc, Var table_var) {
 }
 
 Result SharedValidator::OnTableGrow(const Location& loc, Var table_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::TableGrow, loc);
   TableType table_type;
   result |= CheckTableIndex(table_var, &table_type);
   result |= typechecker_.OnTableGrow(table_type.element);
@@ -1190,8 +1097,7 @@ Result SharedValidator::OnTableGrow(const Location& loc, Var table_var) {
 Result SharedValidator::OnTableInit(const Location& loc,
                                     Var segment_var,
                                     Var table_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::TableInit, loc);
   TableType table_type;
   ElemType elem_type;
   result |= CheckTableIndex(table_var, &table_type);
@@ -1202,8 +1108,7 @@ Result SharedValidator::OnTableInit(const Location& loc,
 }
 
 Result SharedValidator::OnTableSet(const Location& loc, Var table_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::TableSet, loc);
   TableType table_type;
   result |= CheckTableIndex(table_var, &table_type);
   result |= typechecker_.OnTableSet(table_type.element);
@@ -1211,23 +1116,20 @@ Result SharedValidator::OnTableSet(const Location& loc, Var table_var) {
 }
 
 Result SharedValidator::OnTableSize(const Location& loc, Var table_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::TableSize, loc);
   result |= CheckTableIndex(table_var);
   result |= typechecker_.OnTableSize();
   return result;
 }
 
 Result SharedValidator::OnTernary(const Location& loc, Opcode opcode) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(opcode, loc);
   result |= typechecker_.OnTernary(opcode);
   return result;
 }
 
 Result SharedValidator::OnThrow(const Location& loc, Var tag_var) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::Throw, loc);
   TagType tag_type;
   result |= CheckTagIndex(tag_var, &tag_type);
   result |= typechecker_.OnThrow(tag_type.params);
@@ -1235,9 +1137,8 @@ Result SharedValidator::OnThrow(const Location& loc, Var tag_var) {
 }
 
 Result SharedValidator::OnTry(const Location& loc, Type sig_type) {
-  Result result = Result::Ok;
+  Result result = CheckInstr(Opcode::Try, loc);
   TypeVector param_types, result_types;
-  expr_loc_ = &loc;
   result |= CheckBlockSignature(loc, Opcode::Try, sig_type, &param_types,
                                 &result_types);
   result |= typechecker_.OnTry(param_types, result_types);
@@ -1245,15 +1146,13 @@ Result SharedValidator::OnTry(const Location& loc, Type sig_type) {
 }
 
 Result SharedValidator::OnUnary(const Location& loc, Opcode opcode) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(opcode, loc);
   result |= typechecker_.OnUnary(opcode);
   return result;
 }
 
 Result SharedValidator::OnUnreachable(const Location& loc) {
-  Result result = Result::Ok;
-  expr_loc_ = &loc;
+  Result result = CheckInstr(Opcode::Unreachable, loc);
   result |= typechecker_.OnUnreachable();
   return result;
 }
index 415e484eae28981029a2b48c6dc002d0127e7028..0f422a8b9ec44f05ca69e8204a960be1cc7098a9 100644 (file)
@@ -51,6 +51,9 @@ class SharedValidator {
   Result GetLabel(Index depth, Label** out_label) {
     return typechecker_.GetLabel(depth, out_label);
   }
+  Result GetCatchCount(Index depth, Index* out_count) {
+    return typechecker_.GetCatchCount(depth, out_count);
+  }
 
   Result WABT_PRINTF_FORMAT(3, 4)
       PrintError(const Location& loc, const char* fmt, ...);
@@ -65,7 +68,8 @@ class SharedValidator {
                     Index param_count,
                     const Type* param_types,
                     Index result_count,
-                    const Type* result_types);
+                    const Type* result_types,
+                    Index type_index);
   Result OnStructType(const Location&, Index field_count, TypeMut* fields);
   Result OnArrayType(const Location&, TypeMut field);
 
@@ -74,11 +78,6 @@ class SharedValidator {
   Result OnMemory(const Location&, const Limits&);
   Result OnGlobalImport(const Location&, Type type, bool mutable_);
   Result OnGlobal(const Location&, Type type, bool mutable_);
-  Result OnGlobalInitExpr_Const(const Location&, Type);
-  Result OnGlobalInitExpr_GlobalGet(const Location&, Var global_var);
-  Result OnGlobalInitExpr_RefNull(const Location&, Type type);
-  Result OnGlobalInitExpr_RefFunc(const Location&, Var func_var);
-  Result OnGlobalInitExpr_Other(const Location&);
   Result OnTag(const Location&, Var sig_var);
 
   Result OnExport(const Location&,
@@ -90,19 +89,15 @@ class SharedValidator {
 
   Result OnElemSegment(const Location&, Var table_var, SegmentKind);
   void OnElemSegmentElemType(Type elem_type);
-  Result OnElemSegmentInitExpr_Const(const Location&, Type);
-  Result OnElemSegmentInitExpr_GlobalGet(const Location&, Var global_var);
-  Result OnElemSegmentInitExpr_Other(const Location&);
   Result OnElemSegmentElemExpr_RefNull(const Location&, Type type);
   Result OnElemSegmentElemExpr_RefFunc(const Location&, Var func_var);
   Result OnElemSegmentElemExpr_Other(const Location&);
 
   void OnDataCount(Index count);
-
   Result OnDataSegment(const Location&, Var memory_var, SegmentKind);
-  Result OnDataSegmentInitExpr_Const(const Location&, Type);
-  Result OnDataSegmentInitExpr_GlobalGet(const Location&, Var global_var);
-  Result OnDataSegmentInitExpr_Other(const Location&);
+
+  Result BeginInitExpr(const Location&, Type type);
+  Result EndInitExpr();
 
   Result BeginFunctionBody(const Location&, Index func_index);
   Result EndFunctionBody(const Location&);
@@ -138,18 +133,18 @@ class SharedValidator {
   Result OnGlobalGet(const Location&, Var);
   Result OnGlobalSet(const Location&, Var);
   Result OnIf(const Location&, Type sig_type);
-  Result OnLoad(const Location&, Opcode, Address align);
+  Result OnLoad(const Location&, Opcode, Var memidx, Address align);
   Result OnLoadSplat(const Location&, Opcode, Address align);
   Result OnLoadZero(const Location&, Opcode, Address align);
   Result OnLocalGet(const Location&, Var);
   Result OnLocalSet(const Location&, Var);
   Result OnLocalTee(const Location&, Var);
   Result OnLoop(const Location&, Type sig_type);
-  Result OnMemoryCopy(const Location&);
-  Result OnMemoryFill(const Location&);
-  Result OnMemoryGrow(const Location&);
-  Result OnMemoryInit(const Location&, Var segment_var);
-  Result OnMemorySize(const Location&);
+  Result OnMemoryCopy(const Location&, Var srcmemidx, Var destmemidx);
+  Result OnMemoryFill(const Location&, Var memidx);
+  Result OnMemoryGrow(const Location&, Var memidx);
+  Result OnMemoryInit(const Location&, Var segment_var, Var memidx);
+  Result OnMemorySize(const Location&, Var memidx);
   Result OnNop(const Location&);
   Result OnRefFunc(const Location&, Var func_var);
   Result OnRefIsNull(const Location&);
@@ -160,10 +155,16 @@ class SharedValidator {
   Result OnReturn(const Location&);
   Result OnSelect(const Location&, Index result_count, Type* result_types);
   Result OnSimdLaneOp(const Location&, Opcode, uint64_t lane_idx);
-  Result OnSimdLoadLane(const Location&, Opcode, Address align, uint64_t lane_idx);
-  Result OnSimdStoreLane(const Location&, Opcode, Address align, uint64_t lane_idx);
+  Result OnSimdLoadLane(const Location&,
+                        Opcode,
+                        Address align,
+                        uint64_t lane_idx);
+  Result OnSimdStoreLane(const Location&,
+                         Opcode,
+                         Address align,
+                         uint64_t lane_idx);
   Result OnSimdShuffleOp(const Location&, Opcode, v128 lane_idx);
-  Result OnStore(const Location&, Opcode, Address align);
+  Result OnStore(const Location&, Opcode, Var memidx, Address align);
   Result OnTableCopy(const Location&, Var dst_var, Var src_var);
   Result OnTableFill(const Location&, Var table_var);
   Result OnTableGet(const Location&, Var table_var);
@@ -180,11 +181,14 @@ class SharedValidator {
  private:
   struct FuncType {
     FuncType() = default;
-    FuncType(const TypeVector& params, const TypeVector& results)
-        : params(params), results(results) {}
+    FuncType(const TypeVector& params,
+             const TypeVector& results,
+             Index type_index)
+        : params(params), results(results), type_index(type_index) {}
 
     TypeVector params;
     TypeVector results;
+    Index type_index;
   };
 
   struct StructType {
@@ -240,6 +244,7 @@ class SharedValidator {
     Index end;
   };
 
+  Result CheckInstr(Opcode opcode, const Location& loc);
   Result CheckType(const Location&,
                    Type actual,
                    Type expected,
@@ -269,7 +274,9 @@ class SharedValidator {
   Result CheckDataSegmentIndex(Var data_segment_var);
 
   Result CheckAlign(const Location&, Address align, Address natural_align);
-  Result CheckAtomicAlign(const Location&, Address align, Address natural_align);
+  Result CheckAtomicAlign(const Location&,
+                          Address align,
+                          Address natural_align);
 
   Result CheckBlockSignature(const Location&,
                              Opcode,
@@ -277,13 +284,16 @@ class SharedValidator {
                              TypeVector* out_param_types,
                              TypeVector* out_result_types);
 
+  Index GetFunctionTypeIndex(Index func_index) const;
+
   TypeVector ToTypeVector(Index count, const Type* types);
 
   ValidateOptions options_;
   Errors* errors_;
   TypeChecker typechecker_;  // TODO: Move into SharedValidator.
   // Cached for access by OnTypecheckerError.
-  const Location* expr_loc_ = nullptr;
+  Location expr_loc_ = Location(kInvalidOffset);
+  bool in_init_expr_ = false;
 
   Index num_types_ = 0;
   std::map<Index, FuncType> func_types_;
@@ -306,7 +316,7 @@ class SharedValidator {
 
   std::set<std::string> export_names_;  // Used to check for duplicates.
   std::set<Index> declared_funcs_;      // TODO: optimize?
-  std::vector<Var> init_expr_funcs_;
+  std::vector<Var> check_declared_funcs_;
 };
 
 }  // namespace wabt
index e52c51b94a5478e2032d3410982fa38d7b2293c0..cf6d17f2eb5a3f92d1d35893103f2c5ea2645d3c 100644 (file)
@@ -255,7 +255,9 @@ FileStream::~FileStream() {
 }
 
 void FileStream::Flush() {
-  if (file_) fflush(file_);
+  if (file_) {
+    fflush(file_);
+  }
 }
 
 Result FileStream::WriteDataImpl(size_t at, const void* data, size_t size) {
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/string-format.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/string-format.h
new file mode 100644 (file)
index 0000000..642ee11
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2021 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WABT_STRING_FORMAT_H_
+#define WABT_STRING_FORMAT_H_
+
+#include <string>
+#include <vector>
+
+#include "config.h"
+
+#define PRIstringview "%.*s"
+#define WABT_PRINTF_STRING_VIEW_ARG(x) \
+  static_cast<int>((x).length()), (x).data()
+
+#define PRItypecode "%s%#x"
+#define WABT_PRINTF_TYPE_CODE(x) \
+  (static_cast<int32_t>(x) < 0 ? "-" : ""), std::abs(static_cast<int32_t>(x))
+
+#define WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE 128
+#define WABT_SNPRINTF_ALLOCA(buffer, len, format)                          \
+  va_list args;                                                            \
+  va_list args_copy;                                                       \
+  va_start(args, format);                                                  \
+  va_copy(args_copy, args);                                                \
+  char fixed_buf[WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE];                    \
+  char* buffer = fixed_buf;                                                \
+  size_t len = wabt_vsnprintf(fixed_buf, sizeof(fixed_buf), format, args); \
+  va_end(args);                                                            \
+  if (len + 1 > sizeof(fixed_buf)) {                                       \
+    buffer = static_cast<char*>(alloca(len + 1));                          \
+    len = wabt_vsnprintf(buffer, len + 1, format, args_copy);              \
+  }                                                                        \
+  va_end(args_copy)
+
+namespace wabt {
+
+inline std::string WABT_PRINTF_FORMAT(1, 2)
+    StringPrintf(const char* format, ...) {
+  va_list args;
+  va_list args_copy;
+  va_start(args, format);
+  va_copy(args_copy, args);
+  size_t len = wabt_vsnprintf(nullptr, 0, format, args) + 1;  // For \0.
+  std::vector<char> buffer(len);
+  va_end(args);
+  wabt_vsnprintf(buffer.data(), len, format, args_copy);
+  va_end(args_copy);
+  return std::string(buffer.data(), len - 1);
+}
+
+}  // namespace wabt
+
+#endif  // WABT_STRING_FORMAT_H_
index bb32410a8ed42dd61f9d02dfbc46c056c8b6e793..68d2a7a3bd7c107147ab566d29e8aeff93e336af 100644 (file)
@@ -100,8 +100,8 @@ int string_view::compare(size_type pos1,
   return substr(pos1, n1).compare(string_view(s, n2));
 }
 
-string_view::size_type string_view::find(string_view s, size_type pos) const
-    noexcept {
+string_view::size_type string_view::find(string_view s,
+                                         size_type pos) const noexcept {
   pos = std::min(pos, size_);
   const_iterator iter = std::search(begin() + pos, end(), s.begin(), s.end());
   return iter == end() ? npos : iter - begin();
@@ -121,16 +121,16 @@ string_view::size_type string_view::find(const char* s, size_type pos) const {
   return find(string_view(s), pos);
 }
 
-string_view::size_type string_view::rfind(string_view s, size_type pos) const
-    noexcept {
+string_view::size_type string_view::rfind(string_view s,
+                                          size_type pos) const noexcept {
   pos = std::min(std::min(pos, size_ - s.size_) + s.size_, size_);
   reverse_iterator iter = std::search(reverse_iterator(begin() + pos), rend(),
                                       s.rbegin(), s.rend());
   return iter == rend() ? npos : (rend() - iter - s.size_);
 }
 
-string_view::size_type string_view::rfind(char c, size_type pos) const
-    noexcept {
+string_view::size_type string_view::rfind(char c,
+                                          size_type pos) const noexcept {
   return rfind(string_view(&c, 1), pos);
 }
 
@@ -144,17 +144,16 @@ string_view::size_type string_view::rfind(const char* s, size_type pos) const {
   return rfind(string_view(s), pos);
 }
 
-string_view::size_type string_view::find_first_of(string_view s,
-                                                  size_type pos) const
-    noexcept {
+string_view::size_type string_view::find_first_of(string_view s, size_type pos)
+    const noexcept {
   pos = std::min(pos, size_);
   const_iterator iter =
       std::find_first_of(begin() + pos, end(), s.begin(), s.end());
   return iter == end() ? npos : iter - begin();
 }
 
-string_view::size_type string_view::find_first_of(char c, size_type pos) const
-    noexcept {
+string_view::size_type string_view::find_first_of(char c, size_type pos)
+    const noexcept {
   return find_first_of(string_view(&c, 1), pos);
 }
 
@@ -177,8 +176,8 @@ string_view::size_type string_view::find_last_of(string_view s,
   return iter == rend() ? npos : (rend() - iter - 1);
 }
 
-string_view::size_type string_view::find_last_of(char c, size_type pos) const
-    noexcept {
+string_view::size_type string_view::find_last_of(char c,
+                                                 size_type pos) const noexcept {
   return find_last_of(string_view(&c, 1), pos);
 }
 
index 534e675c73473b7bf477d057a0c899c15b726d99..25cff41f77e877dc0d7264c31c053661c342f475 100644 (file)
@@ -110,25 +110,25 @@ class string_view {
   /*constexpr*/ size_type find(char c, size_type pos = 0) const noexcept;
   /*constexpr*/ size_type find(const char* s, size_type pos, size_type n) const;
   /*constexpr*/ size_type find(const char* s, size_type pos = 0) const;
-  /*constexpr*/ size_type rfind(string_view s, size_type pos = npos) const
-      noexcept;
+  /*constexpr*/ size_type rfind(string_view s,
+                                size_type pos = npos) const noexcept;
   /*constexpr*/ size_type rfind(char c, size_type pos = npos) const noexcept;
   /*constexpr*/ size_type rfind(const char* s,
                                 size_type pos,
                                 size_type n) const;
   /*constexpr*/ size_type rfind(const char* s, size_type pos = npos) const;
-  /*constexpr*/ size_type find_first_of(string_view s, size_type pos = 0) const
-      noexcept;
-  /*constexpr*/ size_type find_first_of(char c, size_type pos = 0) const
-      noexcept;
+  /*constexpr*/ size_type find_first_of(string_view s,
+                                        size_type pos = 0) const noexcept;
+  /*constexpr*/ size_type find_first_of(char c,
+                                        size_type pos = 0) const noexcept;
   /*constexpr*/ size_type find_first_of(const char* s,
                                         size_type pos,
                                         size_type n) const;
   /*constexpr*/ size_type find_first_of(const char* s, size_type pos = 0) const;
   /*constexpr*/ size_type find_last_of(string_view s,
                                        size_type pos = npos) const noexcept;
-  /*constexpr*/ size_type find_last_of(char c, size_type pos = npos) const
-      noexcept;
+  /*constexpr*/ size_type find_last_of(char c,
+                                       size_type pos = npos) const noexcept;
   /*constexpr*/ size_type find_last_of(const char* s,
                                        size_type pos,
                                        size_type n) const;
@@ -219,25 +219,28 @@ inline std::string operator+(string_view x, const char* y) {
 
 inline void cat_concatenate(std::string&) {}
 
-template<typename T, typename ...Ts>
+template <typename T, typename... Ts>
 void cat_concatenate(std::string& s, const T& t, const Ts&... args) {
-    s += t;
-    cat_concatenate(s, args...);
+  s += t;
+  cat_concatenate(s, args...);
 }
 
-inline size_t cat_compute_size() { return 0; }
+inline size_t cat_compute_size() {
+  return 0;
+}
 
-template<typename T, typename ...Ts>
+template <typename T, typename... Ts>
 size_t cat_compute_size(const T& t, const Ts&... args) {
-    return string_view(t).size() + cat_compute_size(args...);
+  return string_view(t).size() + cat_compute_size(args...);
 }
 
 // Is able to concatenate any combination of string/string_view/char*
-template<typename ...Ts> std::string cat(const Ts&... args) {
-    std::string s;
-    s.reserve(cat_compute_size(args...));
-    cat_concatenate(s, args...);
-    return s;
+template <typename... Ts>
+std::string cat(const Ts&... args) {
+  std::string s;
+  s.reserve(cat_compute_size(args...));
+  cat_concatenate(s, args...);
+  return s;
 }
 
 inline constexpr string_view::string_view() noexcept
@@ -252,8 +255,8 @@ inline string_view::string_view(const char* str)
 inline constexpr string_view::string_view(const char* str, size_type len)
     : data_(str), size_(len) {}
 
-inline constexpr string_view::const_iterator string_view::begin() const
-    noexcept {
+inline constexpr string_view::const_iterator string_view::begin()
+    const noexcept {
   return data_;
 }
 
@@ -261,18 +264,18 @@ inline constexpr string_view::const_iterator string_view::end() const noexcept {
   return data_ + size_;
 }
 
-inline constexpr string_view::const_iterator string_view::cbegin() const
-    noexcept {
+inline constexpr string_view::const_iterator string_view::cbegin()
+    const noexcept {
   return data_;
 }
 
-inline constexpr string_view::const_iterator string_view::cend() const
-    noexcept {
+inline constexpr string_view::const_iterator string_view::cend()
+    const noexcept {
   return data_ + size_;
 }
 
-inline string_view::const_reverse_iterator string_view::rbegin() const
-    noexcept {
+inline string_view::const_reverse_iterator string_view::rbegin()
+    const noexcept {
   return const_reverse_iterator(end());
 }
 
@@ -280,8 +283,8 @@ inline string_view::const_reverse_iterator string_view::rend() const noexcept {
   return const_reverse_iterator(begin());
 }
 
-inline string_view::const_reverse_iterator string_view::crbegin() const
-    noexcept {
+inline string_view::const_reverse_iterator string_view::crbegin()
+    const noexcept {
   return const_reverse_iterator(cend());
 }
 
@@ -326,8 +329,8 @@ constexpr inline string_view::const_pointer string_view::data() const noexcept {
 }
 
 inline std::ostream& operator<<(std::ostream& os, string_view sv) {
-    os.write(sv.data(), sv.size());
-    return os;
+  os.write(sv.data(), sv.size());
+  return os;
 }
 
 }  // namespace wabt
index a96ccdb7a32e49ef0321682e7f77ff6356366c1d..ee20601367f18d027549338a6af8e2124cd8e4f8 100644 (file)
@@ -16,8 +16,8 @@
 
 #include "gtest/gtest.h"
 
-#include "src/binary-reader.h"
 #include "src/binary-reader-nop.h"
+#include "src/binary-reader.h"
 #include "src/leb128.h"
 #include "src/opcode.h"
 
index 3a77194cadf6ce5dbfa7cc32c09d5a11fd97b737..1ba6b0b1b29cfb164c912db0dc5140d7aea82ef1 100644 (file)
@@ -30,8 +30,8 @@ class InterpTest : public ::testing::Test {
   void ReadModule(const std::vector<u8>& data) {
     Errors errors;
     ReadBinaryOptions options;
-    Result result = ReadBinaryInterp(data.data(), data.size(), options, &errors,
-                                     &module_desc_);
+    Result result = ReadBinaryInterp("<internal>", data.data(), data.size(),
+                                     options, &errors, &module_desc_);
     ASSERT_EQ(Result::Ok, result)
         << FormatErrorsToString(errors, Location::Type::Binary);
   }
@@ -59,7 +59,6 @@ class InterpTest : public ::testing::Test {
   Instance::Ptr inst_;
 };
 
-
 TEST_F(InterpTest, Empty) {
   ASSERT_TRUE(mod_.empty());
   ReadModule({0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00});
@@ -308,18 +307,18 @@ TEST_F(InterpTest, HostFunc_PingPong) {
       0x0b, 0x01, 0x09, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x10, 0x00, 0x0b,
   });
 
-  auto host_func = HostFunc::New(
-      store_, FuncType{{ValueType::I32}, {ValueType::I32}},
-      [&](Thread& thread, const Values& params, Values& results,
-          Trap::Ptr* out_trap) -> Result {
-        auto val = params[0].Get<u32>();
-        if (val < 10) {
-          return GetFuncExport(0)->Call(store_, {Value::Make(val * 2)}, results,
-                                        out_trap);
-        }
-        results[0] = Value::Make(val);
-        return Result::Ok;
-      });
+  auto host_func =
+      HostFunc::New(store_, FuncType{{ValueType::I32}, {ValueType::I32}},
+                    [&](Thread& thread, const Values& params, Values& results,
+                        Trap::Ptr* out_trap) -> Result {
+                      auto val = params[0].Get<u32>();
+                      if (val < 10) {
+                        return GetFuncExport(0)->Call(
+                            store_, {Value::Make(val * 2)}, results, out_trap);
+                      }
+                      results[0] = Value::Make(val);
+                      return Result::Ok;
+                    });
 
   Instantiate({host_func->self()});
 
@@ -328,7 +327,8 @@ TEST_F(InterpTest, HostFunc_PingPong) {
 
   Values results;
   Trap::Ptr trap;
-  Result result = GetFuncExport(0)->Call(store_, {Value::Make(1)}, results, &trap);
+  Result result =
+      GetFuncExport(0)->Call(store_, {Value::Make(1)}, results, &trap);
 
   ASSERT_EQ(Result::Ok, result);
   EXPECT_EQ(1u, results.size());
@@ -346,7 +346,7 @@ TEST_F(InterpTest, HostFunc_PingPong_SameThread) {
       0x0b, 0x01, 0x09, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x10, 0x00, 0x0b,
   });
 
-  auto thread = Thread::New(store_, {});
+  Thread thread(store_);
 
   auto host_func =
       HostFunc::New(store_, FuncType{{ValueType::I32}, {ValueType::I32}},
@@ -368,7 +368,8 @@ TEST_F(InterpTest, HostFunc_PingPong_SameThread) {
 
   Values results;
   Trap::Ptr trap;
-  Result result = GetFuncExport(0)->Call(*thread, {Value::Make(1)}, results, &trap);
+  Result result =
+      GetFuncExport(0)->Call(thread, {Value::Make(1)}, results, &trap);
 
   ASSERT_EQ(Result::Ok, result);
   EXPECT_EQ(1u, results.size());
@@ -411,22 +412,22 @@ TEST_F(InterpTest, Rot13) {
   //   (local $uc i32)
   //
   //   ;; No change if < 'A'.
-  //   (if (i32.lt_u (get_local $c) (i32.const 65))
-  //     (return (get_local $c)))
+  //   (if (i32.lt_u (local.get $c) (i32.const 65))
+  //     (return (local.get $c)))
   //
   //   ;; Clear 5th bit of c, to force uppercase. 0xdf = 0b11011111
-  //   (set_local $uc (i32.and (get_local $c) (i32.const 0xdf)))
+  //   (local.set $uc (i32.and (local.get $c) (i32.const 0xdf)))
   //
   //   ;; In range ['A', 'M'] return |c| + 13.
-  //   (if (i32.le_u (get_local $uc) (i32.const 77))
-  //     (return (i32.add (get_local $c) (i32.const 13))))
+  //   (if (i32.le_u (local.get $uc) (i32.const 77))
+  //     (return (i32.add (local.get $c) (i32.const 13))))
   //
   //   ;; In range ['N', 'Z'] return |c| - 13.
-  //   (if (i32.le_u (get_local $uc) (i32.const 90))
-  //     (return (i32.sub (get_local $c) (i32.const 13))))
+  //   (if (i32.le_u (local.get $uc) (i32.const 90))
+  //     (return (i32.sub (local.get $c) (i32.const 13))))
   //
   //   ;; No change for everything else.
-  //   (return (get_local $c))
+  //   (return (local.get $c))
   // )
   //
   // (func (export "rot13")
@@ -437,27 +438,27 @@ TEST_F(InterpTest, Rot13) {
   //   (call $fill_buf (i32.const 0) (i32.const 1024))
   //
   //   ;; The host returns the size filled.
-  //   (set_local $size)
+  //   (local.set $size)
   //
   //   ;; Loop over all bytes and rot13 them.
   //   (block $exit
   //     (loop $top
   //       ;; if (i >= size) break
-  //       (if (i32.ge_u (get_local $i) (get_local $size)) (br $exit))
+  //       (if (i32.ge_u (local.get $i) (local.get $size)) (br $exit))
   //
   //       ;; mem[i] = rot13c(mem[i])
   //       (i32.store8
-  //         (get_local $i)
+  //         (local.get $i)
   //         (call $rot13c
-  //           (i32.load8_u (get_local $i))))
+  //           (i32.load8_u (local.get $i))))
   //
   //       ;; i++
-  //       (set_local $i (i32.add (get_local $i) (i32.const 1)))
+  //       (local.set $i (i32.add (local.get $i) (i32.const 1)))
   //       (br $top)
   //     )
   //   )
   //
-  //   (call $buf_done (i32.const 0) (get_local $size))
+  //   (call $buf_done (i32.const 0) (local.get $size))
   // )
   ReadModule({
       0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x14, 0x04, 0x60,
@@ -551,9 +552,7 @@ TEST_F(InterpTest, Rot13) {
 
 class InterpGCTest : public InterpTest {
  public:
-  void SetUp() override {
-    before_new = store_.object_count();
-  }
+  void SetUp() override { before_new = store_.object_count(); }
 
   void TearDown() override {
     // Reset instance and module, in case they were allocated.
index bce7a0b8f03d6d788b6262abdc6bdbd913b0ed96..4a309d6ef3cfba88083e88c62986dc7513237844 100644 (file)
@@ -87,8 +87,7 @@ void AssertInt64Equals(uint64_t expected,
   AssertIntEquals(expected, s, ParseInt64, parse_type);
 }
 
-void AssertUint128Equals(v128 expected,
-                         const char* s) {
+void AssertUint128Equals(v128 expected, const char* s) {
   const char* const end = s + strlen(s);
   v128 actual;
   ASSERT_EQ(Result::Ok, ParseUint128(s, end, &actual)) << s;
@@ -474,138 +473,138 @@ TEST(ParseFloat, RoundingSpec) {
     const char* input;
     uint32_t output;
   } kTests[] = {
-    {"+0x1.00000100000000000p-50", 0x26800000},
-    {"-0x1.00000100000000000p-50", 0xa6800000},
-    {"+0x1.00000100000000001p-50", 0x26800001},
-    {"-0x1.00000100000000001p-50", 0xa6800001},
-    {"+0x1.000001fffffffffffp-50", 0x26800001},
-    {"-0x1.000001fffffffffffp-50", 0xa6800001},
-    {"+0x1.00000200000000000p-50", 0x26800001},
-    {"-0x1.00000200000000000p-50", 0xa6800001},
-    {"+0x1.00000200000000001p-50", 0x26800001},
-    {"-0x1.00000200000000001p-50", 0xa6800001},
-    {"+0x1.000002fffffffffffp-50", 0x26800001},
-    {"-0x1.000002fffffffffffp-50", 0xa6800001},
-    {"+0x1.00000300000000000p-50", 0x26800002},
-    {"-0x1.00000300000000000p-50", 0xa6800002},
-    {"+0x1.00000300000000001p-50", 0x26800002},
-    {"-0x1.00000300000000001p-50", 0xa6800002},
-    {"+0x1.000003fffffffffffp-50", 0x26800002},
-    {"-0x1.000003fffffffffffp-50", 0xa6800002},
-    {"+0x1.00000400000000000p-50", 0x26800002},
-    {"-0x1.00000400000000000p-50", 0xa6800002},
-    {"+0x1.00000400000000001p-50", 0x26800002},
-    {"-0x1.00000400000000001p-50", 0xa6800002},
-    {"+0x1.000004fffffffffffp-50", 0x26800002},
-    {"-0x1.000004fffffffffffp-50", 0xa6800002},
-    {"+0x1.00000500000000000p-50", 0x26800002},
-    {"-0x1.00000500000000000p-50", 0xa6800002},
-    {"+0x1.00000500000000001p-50", 0x26800003},
-    {"-0x1.00000500000000001p-50", 0xa6800003},
-    {"+0x4000.004000000p-64", 0x26800000},
-    {"-0x4000.004000000p-64", 0xa6800000},
-    {"+0x4000.004000001p-64", 0x26800001},
-    {"-0x4000.004000001p-64", 0xa6800001},
-    {"+0x4000.007ffffffp-64", 0x26800001},
-    {"-0x4000.007ffffffp-64", 0xa6800001},
-    {"+0x4000.008000000p-64", 0x26800001},
-    {"-0x4000.008000000p-64", 0xa6800001},
-    {"+0x4000.008000001p-64", 0x26800001},
-    {"-0x4000.008000001p-64", 0xa6800001},
-    {"+0x4000.00bffffffp-64", 0x26800001},
-    {"-0x4000.00bffffffp-64", 0xa6800001},
-    {"+0x4000.00c000000p-64", 0x26800002},
-    {"-0x4000.00c000000p-64", 0xa6800002},
-    {"+0x4000.00c000001p-64", 0x26800002},
-    {"-0x4000.00c000001p-64", 0xa6800002},
-    {"+0x4000.00fffffffp-64", 0x26800002},
-    {"-0x4000.00fffffffp-64", 0xa6800002},
-    {"+0x4000.010000001p-64", 0x26800002},
-    {"-0x4000.010000001p-64", 0xa6800002},
-    {"+0x4000.013ffffffp-64", 0x26800002},
-    {"-0x4000.013ffffffp-64", 0xa6800002},
-    {"+0x4000.014000001p-64", 0x26800003},
-    {"-0x4000.014000001p-64", 0xa6800003},
-    {"+0x1.00000100000000000p+50", 0x58800000},
-    {"-0x1.00000100000000000p+50", 0xd8800000},
-    {"+0x1.00000100000000001p+50", 0x58800001},
-    {"-0x1.00000100000000001p+50", 0xd8800001},
-    {"+0x1.000001fffffffffffp+50", 0x58800001},
-    {"-0x1.000001fffffffffffp+50", 0xd8800001},
-    {"+0x1.00000200000000000p+50", 0x58800001},
-    {"-0x1.00000200000000000p+50", 0xd8800001},
-    {"+0x1.00000200000000001p+50", 0x58800001},
-    {"-0x1.00000200000000001p+50", 0xd8800001},
-    {"+0x1.000002fffffffffffp+50", 0x58800001},
-    {"-0x1.000002fffffffffffp+50", 0xd8800001},
-    {"+0x1.00000300000000000p+50", 0x58800002},
-    {"-0x1.00000300000000000p+50", 0xd8800002},
-    {"+0x1.00000300000000001p+50", 0x58800002},
-    {"-0x1.00000300000000001p+50", 0xd8800002},
-    {"+0x1.000003fffffffffffp+50", 0x58800002},
-    {"-0x1.000003fffffffffffp+50", 0xd8800002},
-    {"+0x1.00000400000000000p+50", 0x58800002},
-    {"-0x1.00000400000000000p+50", 0xd8800002},
-    {"+0x1.00000400000000001p+50", 0x58800002},
-    {"-0x1.00000400000000001p+50", 0xd8800002},
-    {"+0x1.000004fffffffffffp+50", 0x58800002},
-    {"-0x1.000004fffffffffffp+50", 0xd8800002},
-    {"+0x1.00000500000000000p+50", 0x58800002},
-    {"-0x1.00000500000000000p+50", 0xd8800002},
-    {"+0x1.00000500000000001p+50", 0x58800003},
-    {"-0x1.00000500000000001p+50", 0xd8800003},
-    {"+0x4000004000000", 0x58800000},
-    {"-0x4000004000000", 0xd8800000},
-    {"+0x4000004000001", 0x58800001},
-    {"-0x4000004000001", 0xd8800001},
-    {"+0x4000007ffffff", 0x58800001},
-    {"-0x4000007ffffff", 0xd8800001},
-    {"+0x4000008000000", 0x58800001},
-    {"-0x4000008000000", 0xd8800001},
-    {"+0x4000008000001", 0x58800001},
-    {"-0x4000008000001", 0xd8800001},
-    {"+0x400000bffffff", 0x58800001},
-    {"-0x400000bffffff", 0xd8800001},
-    {"+0x400000c000000", 0x58800002},
-    {"-0x400000c000000", 0xd8800002},
-    {"+0x0.00000100000000000p-126", 0x0},
-    {"-0x0.00000100000000000p-126", 0x80000000},
-    {"+0x0.00000100000000001p-126", 0x1},
-    {"-0x0.00000100000000001p-126", 0x80000001},
-    {"+0x0.00000101000000000p-126", 0x1},
-    {"+0x0.000001fffffffffffp-126", 0x1},
-    {"-0x0.000001fffffffffffp-126", 0x80000001},
-    {"+0x0.00000200000000000p-126", 0x1},
-    {"-0x0.00000200000000000p-126", 0x80000001},
-    {"+0x0.00000200000000001p-126", 0x1},
-    {"-0x0.00000200000000001p-126", 0x80000001},
-    {"+0x0.000002fffffffffffp-126", 0x1},
-    {"-0x0.000002fffffffffffp-126", 0x80000001},
-    {"+0x0.00000300000000000p-126", 0x2},
-    {"-0x0.00000300000000000p-126", 0x80000002},
-    {"+0x0.00000300000000001p-126", 0x2},
-    {"-0x0.00000300000000001p-126", 0x80000002},
-    {"+0x0.000003fffffffffffp-126", 0x2},
-    {"-0x0.000003fffffffffffp-126", 0x80000002},
-    {"+0x0.00000400000000000p-126", 0x2},
-    {"-0x0.00000400000000000p-126", 0x80000002},
-    {"+0x0.00000400000000001p-126", 0x2},
-    {"-0x0.00000400000000001p-126", 0x80000002},
-    {"+0x0.000004fffffffffffp-126", 0x2},
-    {"-0x0.000004fffffffffffp-126", 0x80000002},
-    {"+0x0.00000500000000000p-126", 0x2},
-    {"-0x0.00000500000000000p-126", 0x80000002},
-    {"+0x0.00000500000000001p-126", 0x3},
-    {"-0x0.00000500000000001p-126", 0x80000003},
-    {"+0x1.fffffe8p127", 0x7f7fffff},
-    {"-0x1.fffffe8p127", 0xff7fffff},
-    {"+0x1.fffffefffffff8p127", 0x7f7fffff},
-    {"-0x1.fffffefffffff8p127", 0xff7fffff},
-    {"+0x1.fffffefffffffffffp127", 0x7f7fffff},
-    {"-0x1.fffffefffffffffffp127", 0xff7fffff},
+      {"+0x1.00000100000000000p-50", 0x26800000},
+      {"-0x1.00000100000000000p-50", 0xa6800000},
+      {"+0x1.00000100000000001p-50", 0x26800001},
+      {"-0x1.00000100000000001p-50", 0xa6800001},
+      {"+0x1.000001fffffffffffp-50", 0x26800001},
+      {"-0x1.000001fffffffffffp-50", 0xa6800001},
+      {"+0x1.00000200000000000p-50", 0x26800001},
+      {"-0x1.00000200000000000p-50", 0xa6800001},
+      {"+0x1.00000200000000001p-50", 0x26800001},
+      {"-0x1.00000200000000001p-50", 0xa6800001},
+      {"+0x1.000002fffffffffffp-50", 0x26800001},
+      {"-0x1.000002fffffffffffp-50", 0xa6800001},
+      {"+0x1.00000300000000000p-50", 0x26800002},
+      {"-0x1.00000300000000000p-50", 0xa6800002},
+      {"+0x1.00000300000000001p-50", 0x26800002},
+      {"-0x1.00000300000000001p-50", 0xa6800002},
+      {"+0x1.000003fffffffffffp-50", 0x26800002},
+      {"-0x1.000003fffffffffffp-50", 0xa6800002},
+      {"+0x1.00000400000000000p-50", 0x26800002},
+      {"-0x1.00000400000000000p-50", 0xa6800002},
+      {"+0x1.00000400000000001p-50", 0x26800002},
+      {"-0x1.00000400000000001p-50", 0xa6800002},
+      {"+0x1.000004fffffffffffp-50", 0x26800002},
+      {"-0x1.000004fffffffffffp-50", 0xa6800002},
+      {"+0x1.00000500000000000p-50", 0x26800002},
+      {"-0x1.00000500000000000p-50", 0xa6800002},
+      {"+0x1.00000500000000001p-50", 0x26800003},
+      {"-0x1.00000500000000001p-50", 0xa6800003},
+      {"+0x4000.004000000p-64", 0x26800000},
+      {"-0x4000.004000000p-64", 0xa6800000},
+      {"+0x4000.004000001p-64", 0x26800001},
+      {"-0x4000.004000001p-64", 0xa6800001},
+      {"+0x4000.007ffffffp-64", 0x26800001},
+      {"-0x4000.007ffffffp-64", 0xa6800001},
+      {"+0x4000.008000000p-64", 0x26800001},
+      {"-0x4000.008000000p-64", 0xa6800001},
+      {"+0x4000.008000001p-64", 0x26800001},
+      {"-0x4000.008000001p-64", 0xa6800001},
+      {"+0x4000.00bffffffp-64", 0x26800001},
+      {"-0x4000.00bffffffp-64", 0xa6800001},
+      {"+0x4000.00c000000p-64", 0x26800002},
+      {"-0x4000.00c000000p-64", 0xa6800002},
+      {"+0x4000.00c000001p-64", 0x26800002},
+      {"-0x4000.00c000001p-64", 0xa6800002},
+      {"+0x4000.00fffffffp-64", 0x26800002},
+      {"-0x4000.00fffffffp-64", 0xa6800002},
+      {"+0x4000.010000001p-64", 0x26800002},
+      {"-0x4000.010000001p-64", 0xa6800002},
+      {"+0x4000.013ffffffp-64", 0x26800002},
+      {"-0x4000.013ffffffp-64", 0xa6800002},
+      {"+0x4000.014000001p-64", 0x26800003},
+      {"-0x4000.014000001p-64", 0xa6800003},
+      {"+0x1.00000100000000000p+50", 0x58800000},
+      {"-0x1.00000100000000000p+50", 0xd8800000},
+      {"+0x1.00000100000000001p+50", 0x58800001},
+      {"-0x1.00000100000000001p+50", 0xd8800001},
+      {"+0x1.000001fffffffffffp+50", 0x58800001},
+      {"-0x1.000001fffffffffffp+50", 0xd8800001},
+      {"+0x1.00000200000000000p+50", 0x58800001},
+      {"-0x1.00000200000000000p+50", 0xd8800001},
+      {"+0x1.00000200000000001p+50", 0x58800001},
+      {"-0x1.00000200000000001p+50", 0xd8800001},
+      {"+0x1.000002fffffffffffp+50", 0x58800001},
+      {"-0x1.000002fffffffffffp+50", 0xd8800001},
+      {"+0x1.00000300000000000p+50", 0x58800002},
+      {"-0x1.00000300000000000p+50", 0xd8800002},
+      {"+0x1.00000300000000001p+50", 0x58800002},
+      {"-0x1.00000300000000001p+50", 0xd8800002},
+      {"+0x1.000003fffffffffffp+50", 0x58800002},
+      {"-0x1.000003fffffffffffp+50", 0xd8800002},
+      {"+0x1.00000400000000000p+50", 0x58800002},
+      {"-0x1.00000400000000000p+50", 0xd8800002},
+      {"+0x1.00000400000000001p+50", 0x58800002},
+      {"-0x1.00000400000000001p+50", 0xd8800002},
+      {"+0x1.000004fffffffffffp+50", 0x58800002},
+      {"-0x1.000004fffffffffffp+50", 0xd8800002},
+      {"+0x1.00000500000000000p+50", 0x58800002},
+      {"-0x1.00000500000000000p+50", 0xd8800002},
+      {"+0x1.00000500000000001p+50", 0x58800003},
+      {"-0x1.00000500000000001p+50", 0xd8800003},
+      {"+0x4000004000000", 0x58800000},
+      {"-0x4000004000000", 0xd8800000},
+      {"+0x4000004000001", 0x58800001},
+      {"-0x4000004000001", 0xd8800001},
+      {"+0x4000007ffffff", 0x58800001},
+      {"-0x4000007ffffff", 0xd8800001},
+      {"+0x4000008000000", 0x58800001},
+      {"-0x4000008000000", 0xd8800001},
+      {"+0x4000008000001", 0x58800001},
+      {"-0x4000008000001", 0xd8800001},
+      {"+0x400000bffffff", 0x58800001},
+      {"-0x400000bffffff", 0xd8800001},
+      {"+0x400000c000000", 0x58800002},
+      {"-0x400000c000000", 0xd8800002},
+      {"+0x0.00000100000000000p-126", 0x0},
+      {"-0x0.00000100000000000p-126", 0x80000000},
+      {"+0x0.00000100000000001p-126", 0x1},
+      {"-0x0.00000100000000001p-126", 0x80000001},
+      {"+0x0.00000101000000000p-126", 0x1},
+      {"+0x0.000001fffffffffffp-126", 0x1},
+      {"-0x0.000001fffffffffffp-126", 0x80000001},
+      {"+0x0.00000200000000000p-126", 0x1},
+      {"-0x0.00000200000000000p-126", 0x80000001},
+      {"+0x0.00000200000000001p-126", 0x1},
+      {"-0x0.00000200000000001p-126", 0x80000001},
+      {"+0x0.000002fffffffffffp-126", 0x1},
+      {"-0x0.000002fffffffffffp-126", 0x80000001},
+      {"+0x0.00000300000000000p-126", 0x2},
+      {"-0x0.00000300000000000p-126", 0x80000002},
+      {"+0x0.00000300000000001p-126", 0x2},
+      {"-0x0.00000300000000001p-126", 0x80000002},
+      {"+0x0.000003fffffffffffp-126", 0x2},
+      {"-0x0.000003fffffffffffp-126", 0x80000002},
+      {"+0x0.00000400000000000p-126", 0x2},
+      {"-0x0.00000400000000000p-126", 0x80000002},
+      {"+0x0.00000400000000001p-126", 0x2},
+      {"-0x0.00000400000000001p-126", 0x80000002},
+      {"+0x0.000004fffffffffffp-126", 0x2},
+      {"-0x0.000004fffffffffffp-126", 0x80000002},
+      {"+0x0.00000500000000000p-126", 0x2},
+      {"-0x0.00000500000000000p-126", 0x80000002},
+      {"+0x0.00000500000000001p-126", 0x3},
+      {"-0x0.00000500000000001p-126", 0x80000003},
+      {"+0x1.fffffe8p127", 0x7f7fffff},
+      {"-0x1.fffffe8p127", 0xff7fffff},
+      {"+0x1.fffffefffffff8p127", 0x7f7fffff},
+      {"-0x1.fffffefffffff8p127", 0xff7fffff},
+      {"+0x1.fffffefffffffffffp127", 0x7f7fffff},
+      {"-0x1.fffffefffffffffffp127", 0xff7fffff},
   };
 
-  for (auto test: kTests) {
+  for (auto test : kTests) {
     AssertHexFloatEquals(test.output, test.input);
   }
 }
@@ -651,149 +650,149 @@ TEST(ParseDouble, RoundingSpec) {
     const char* input;
     uint64_t output;
   } kTests[] = {
-    {"+0x1.000000000000080000000000p-600", 1905022642377719808ull},
-    {"-0x1.000000000000080000000000p-600", 11128394679232495616ull},
-    {"+0x1.000000000000080000000001p-600", 1905022642377719809ull},
-    {"-0x1.000000000000080000000001p-600", 11128394679232495617ull},
-    {"+0x1.0000000000000fffffffffffp-600", 1905022642377719809ull},
-    {"-0x1.0000000000000fffffffffffp-600", 11128394679232495617ull},
-    {"+0x1.000000000000100000000000p-600", 1905022642377719809ull},
-    {"-0x1.000000000000100000000000p-600", 11128394679232495617ull},
-    {"+0x1.000000000000100000000001p-600", 1905022642377719809ull},
-    {"-0x1.000000000000100000000001p-600", 11128394679232495617ull},
-    {"+0x1.00000000000017ffffffffffp-600", 1905022642377719809ull},
-    {"-0x1.00000000000017ffffffffffp-600", 11128394679232495617ull},
-    {"+0x1.000000000000180000000000p-600", 1905022642377719810ull},
-    {"-0x1.000000000000180000000000p-600", 11128394679232495618ull},
-    {"+0x1.000000000000180000000001p-600", 1905022642377719810ull},
-    {"-0x1.000000000000180000000001p-600", 11128394679232495618ull},
-    {"+0x1.0000000000001fffffffffffp-600", 1905022642377719810ull},
-    {"-0x1.0000000000001fffffffffffp-600", 11128394679232495618ull},
-    {"+0x1.000000000000200000000000p-600", 1905022642377719810ull},
-    {"-0x1.000000000000200000000000p-600", 11128394679232495618ull},
-    {"+0x1.000000000000200000000001p-600", 1905022642377719810ull},
-    {"-0x1.000000000000200000000001p-600", 11128394679232495618ull},
-    {"+0x1.00000000000027ffffffffffp-600", 1905022642377719810ull},
-    {"-0x1.00000000000027ffffffffffp-600", 11128394679232495618ull},
-    {"+0x1.000000000000280000000001p-600", 1905022642377719811ull},
-    {"-0x1.000000000000280000000001p-600", 11128394679232495619ull},
-    {"+0x8000000.000000400000000000p-627", 1905022642377719808ull},
-    {"-0x8000000.000000400000000000p-627", 11128394679232495616ull},
-    {"+0x8000000.000000400000000001p-627", 1905022642377719809ull},
-    {"-0x8000000.000000400000000001p-627", 11128394679232495617ull},
-    {"+0x8000000.0000007fffffffffffp-627", 1905022642377719809ull},
-    {"-0x8000000.0000007fffffffffffp-627", 11128394679232495617ull},
-    {"+0x8000000.000000800000000000p-627", 1905022642377719809ull},
-    {"-0x8000000.000000800000000000p-627", 11128394679232495617ull},
-    {"+0x8000000.000000800000000001p-627", 1905022642377719809ull},
-    {"-0x8000000.000000800000000001p-627", 11128394679232495617ull},
-    {"+0x8000000.000000bfffffffffffp-627", 1905022642377719809ull},
-    {"-0x8000000.000000bfffffffffffp-627", 11128394679232495617ull},
-    {"+0x8000000.000000c00000000000p-627", 1905022642377719810ull},
-    {"-0x8000000.000000c00000000000p-627", 11128394679232495618ull},
-    {"+0x8000000.000000c00000000001p-627", 1905022642377719810ull},
-    {"-0x8000000.000000c00000000001p-627", 11128394679232495618ull},
-    {"+0x8000000.000000ffffffffffffp-627", 1905022642377719810ull},
-    {"-0x8000000.000000ffffffffffffp-627", 11128394679232495618ull},
-    {"+0x8000000.000001000000000000p-627", 1905022642377719810ull},
-    {"-0x8000000.000001000000000000p-627", 11128394679232495618ull},
-    {"+0x8000000.000001000000000001p-627", 1905022642377719810ull},
-    {"-0x8000000.000001000000000001p-627", 11128394679232495618ull},
-    {"+0x8000000.0000013fffffffffffp-627", 1905022642377719810ull},
-    {"-0x8000000.0000013fffffffffffp-627", 11128394679232495618ull},
-    {"+0x8000000.000001400000000001p-627", 1905022642377719811ull},
-    {"-0x8000000.000001400000000001p-627", 11128394679232495619ull},
-    {"+0x1.000000000000080000000000p+600", 7309342195222315008ull},
-    {"-0x1.000000000000080000000000p+600", 16532714232077090816ull},
-    {"+0x1.000000000000080000000001p+600", 7309342195222315009ull},
-    {"-0x1.000000000000080000000001p+600", 16532714232077090817ull},
-    {"+0x1.0000000000000fffffffffffp+600", 7309342195222315009ull},
-    {"-0x1.0000000000000fffffffffffp+600", 16532714232077090817ull},
-    {"+0x1.000000000000100000000000p+600", 7309342195222315009ull},
-    {"-0x1.000000000000100000000000p+600", 16532714232077090817ull},
-    {"+0x1.000000000000100000000001p+600", 7309342195222315009ull},
-    {"-0x1.000000000000100000000001p+600", 16532714232077090817ull},
-    {"+0x1.00000000000017ffffffffffp+600", 7309342195222315009ull},
-    {"-0x1.00000000000017ffffffffffp+600", 16532714232077090817ull},
-    {"+0x1.000000000000180000000000p+600", 7309342195222315010ull},
-    {"-0x1.000000000000180000000000p+600", 16532714232077090818ull},
-    {"+0x1.000000000000180000000001p+600", 7309342195222315010ull},
-    {"-0x1.000000000000180000000001p+600", 16532714232077090818ull},
-    {"+0x1.0000000000001fffffffffffp+600", 7309342195222315010ull},
-    {"-0x1.0000000000001fffffffffffp+600", 16532714232077090818ull},
-    {"+0x1.000000000000200000000000p+600", 7309342195222315010ull},
-    {"-0x1.000000000000200000000000p+600", 16532714232077090818ull},
-    {"+0x1.000000000000200000000001p+600", 7309342195222315010ull},
-    {"-0x1.000000000000200000000001p+600", 16532714232077090818ull},
-    {"+0x1.00000000000027ffffffffffp+600", 7309342195222315010ull},
-    {"-0x1.00000000000027ffffffffffp+600", 16532714232077090818ull},
-    {"+0x1.000000000000280000000000p+600", 7309342195222315010ull},
-    {"-0x1.000000000000280000000000p+600", 16532714232077090818ull},
-    {"+0x1.000000000000280000000001p+600", 7309342195222315011ull},
-    {"-0x1.000000000000280000000001p+600", 16532714232077090819ull},
-    {"+0x2000000000000100000000000", 5044031582654955520ull},
-    {"-0x2000000000000100000000000", 14267403619509731328ull},
-    {"+0x2000000000000100000000001", 5044031582654955521ull},
-    {"-0x2000000000000100000000001", 14267403619509731329ull},
-    {"+0x20000000000001fffffffffff", 5044031582654955521ull},
-    {"-0x20000000000001fffffffffff", 14267403619509731329ull},
-    {"+0x2000000000000200000000000", 5044031582654955521ull},
-    {"-0x2000000000000200000000000", 14267403619509731329ull},
-    {"+0x2000000000000200000000001", 5044031582654955521ull},
-    {"-0x2000000000000200000000001", 14267403619509731329ull},
-    {"+0x20000000000002fffffffffff", 5044031582654955521ull},
-    {"-0x20000000000002fffffffffff", 14267403619509731329ull},
-    {"+0x2000000000000300000000000", 5044031582654955522ull},
-    {"-0x2000000000000300000000000", 14267403619509731330ull},
-    {"+0x2000000000000300000000001", 5044031582654955522ull},
-    {"-0x2000000000000300000000001", 14267403619509731330ull},
-    {"+0x20000000000003fffffffffff", 5044031582654955522ull},
-    {"-0x20000000000003fffffffffff", 14267403619509731330ull},
-    {"+0x2000000000000400000000000", 5044031582654955522ull},
-    {"-0x2000000000000400000000000", 14267403619509731330ull},
-    {"+0x2000000000000400000000001", 5044031582654955522ull},
-    {"-0x2000000000000400000000001", 14267403619509731330ull},
-    {"+0x20000000000004fffffffffff", 5044031582654955522ull},
-    {"-0x20000000000004fffffffffff", 14267403619509731330ull},
-    {"+0x2000000000000500000000000", 5044031582654955522ull},
-    {"-0x2000000000000500000000000", 14267403619509731330ull},
-    {"+0x2000000000000500000000001", 5044031582654955523ull},
-    {"-0x2000000000000500000000001", 14267403619509731331ull},
-    {"+0x0.000000000000080000000000p-1022", 0ull},
-    {"-0x0.000000000000080000000000p-1022", 9223372036854775808ull},
-    {"+0x0.000000000000080000000001p-1022", 1ull},
-    {"-0x0.000000000000080000000001p-1022", 9223372036854775809ull},
-    {"+0x0.0000000000000fffffffffffp-1022", 1ull},
-    {"-0x0.0000000000000fffffffffffp-1022", 9223372036854775809ull},
-    {"+0x0.000000000000100000000000p-1022", 1ull},
-    {"-0x0.000000000000100000000000p-1022", 9223372036854775809ull},
-    {"+0x0.000000000000100000000001p-1022", 1ull},
-    {"-0x0.000000000000100000000001p-1022", 9223372036854775809ull},
-    {"+0x0.00000000000017ffffffffffp-1022", 1ull},
-    {"-0x0.00000000000017ffffffffffp-1022", 9223372036854775809ull},
-    {"+0x0.000000000000180000000000p-1022", 2ull},
-    {"-0x0.000000000000180000000000p-1022", 9223372036854775810ull},
-    {"+0x0.000000000000180000000001p-1022", 2ull},
-    {"-0x0.000000000000180000000001p-1022", 9223372036854775810ull},
-    {"+0x0.0000000000001fffffffffffp-1022", 2ull},
-    {"-0x0.0000000000001fffffffffffp-1022", 9223372036854775810ull},
-    {"+0x0.000000000000200000000000p-1022", 2ull},
-    {"-0x0.000000000000200000000000p-1022", 9223372036854775810ull},
-    {"+0x0.000000000000200000000001p-1022", 2ull},
-    {"-0x0.000000000000200000000001p-1022", 9223372036854775810ull},
-    {"+0x0.00000000000027ffffffffffp-1022", 2ull},
-    {"-0x0.00000000000027ffffffffffp-1022", 9223372036854775810ull},
-    {"+0x0.000000000000280000000000p-1022", 2ull},
-    {"-0x0.000000000000280000000000p-1022", 9223372036854775810ull},
-    {"+0x1.000000000000280000000001p-1022", 4503599627370499ull},
-    {"-0x1.000000000000280000000001p-1022", 9227875636482146307ull},
-    {"+0x1.fffffffffffff4p1023", 9218868437227405311ull},
-    {"-0x1.fffffffffffff4p1023", 18442240474082181119ull},
-    {"+0x1.fffffffffffff7ffffffp1023", 9218868437227405311ull},
-    {"-0x1.fffffffffffff7ffffffp1023", 18442240474082181119ull},
+      {"+0x1.000000000000080000000000p-600", 1905022642377719808ull},
+      {"-0x1.000000000000080000000000p-600", 11128394679232495616ull},
+      {"+0x1.000000000000080000000001p-600", 1905022642377719809ull},
+      {"-0x1.000000000000080000000001p-600", 11128394679232495617ull},
+      {"+0x1.0000000000000fffffffffffp-600", 1905022642377719809ull},
+      {"-0x1.0000000000000fffffffffffp-600", 11128394679232495617ull},
+      {"+0x1.000000000000100000000000p-600", 1905022642377719809ull},
+      {"-0x1.000000000000100000000000p-600", 11128394679232495617ull},
+      {"+0x1.000000000000100000000001p-600", 1905022642377719809ull},
+      {"-0x1.000000000000100000000001p-600", 11128394679232495617ull},
+      {"+0x1.00000000000017ffffffffffp-600", 1905022642377719809ull},
+      {"-0x1.00000000000017ffffffffffp-600", 11128394679232495617ull},
+      {"+0x1.000000000000180000000000p-600", 1905022642377719810ull},
+      {"-0x1.000000000000180000000000p-600", 11128394679232495618ull},
+      {"+0x1.000000000000180000000001p-600", 1905022642377719810ull},
+      {"-0x1.000000000000180000000001p-600", 11128394679232495618ull},
+      {"+0x1.0000000000001fffffffffffp-600", 1905022642377719810ull},
+      {"-0x1.0000000000001fffffffffffp-600", 11128394679232495618ull},
+      {"+0x1.000000000000200000000000p-600", 1905022642377719810ull},
+      {"-0x1.000000000000200000000000p-600", 11128394679232495618ull},
+      {"+0x1.000000000000200000000001p-600", 1905022642377719810ull},
+      {"-0x1.000000000000200000000001p-600", 11128394679232495618ull},
+      {"+0x1.00000000000027ffffffffffp-600", 1905022642377719810ull},
+      {"-0x1.00000000000027ffffffffffp-600", 11128394679232495618ull},
+      {"+0x1.000000000000280000000001p-600", 1905022642377719811ull},
+      {"-0x1.000000000000280000000001p-600", 11128394679232495619ull},
+      {"+0x8000000.000000400000000000p-627", 1905022642377719808ull},
+      {"-0x8000000.000000400000000000p-627", 11128394679232495616ull},
+      {"+0x8000000.000000400000000001p-627", 1905022642377719809ull},
+      {"-0x8000000.000000400000000001p-627", 11128394679232495617ull},
+      {"+0x8000000.0000007fffffffffffp-627", 1905022642377719809ull},
+      {"-0x8000000.0000007fffffffffffp-627", 11128394679232495617ull},
+      {"+0x8000000.000000800000000000p-627", 1905022642377719809ull},
+      {"-0x8000000.000000800000000000p-627", 11128394679232495617ull},
+      {"+0x8000000.000000800000000001p-627", 1905022642377719809ull},
+      {"-0x8000000.000000800000000001p-627", 11128394679232495617ull},
+      {"+0x8000000.000000bfffffffffffp-627", 1905022642377719809ull},
+      {"-0x8000000.000000bfffffffffffp-627", 11128394679232495617ull},
+      {"+0x8000000.000000c00000000000p-627", 1905022642377719810ull},
+      {"-0x8000000.000000c00000000000p-627", 11128394679232495618ull},
+      {"+0x8000000.000000c00000000001p-627", 1905022642377719810ull},
+      {"-0x8000000.000000c00000000001p-627", 11128394679232495618ull},
+      {"+0x8000000.000000ffffffffffffp-627", 1905022642377719810ull},
+      {"-0x8000000.000000ffffffffffffp-627", 11128394679232495618ull},
+      {"+0x8000000.000001000000000000p-627", 1905022642377719810ull},
+      {"-0x8000000.000001000000000000p-627", 11128394679232495618ull},
+      {"+0x8000000.000001000000000001p-627", 1905022642377719810ull},
+      {"-0x8000000.000001000000000001p-627", 11128394679232495618ull},
+      {"+0x8000000.0000013fffffffffffp-627", 1905022642377719810ull},
+      {"-0x8000000.0000013fffffffffffp-627", 11128394679232495618ull},
+      {"+0x8000000.000001400000000001p-627", 1905022642377719811ull},
+      {"-0x8000000.000001400000000001p-627", 11128394679232495619ull},
+      {"+0x1.000000000000080000000000p+600", 7309342195222315008ull},
+      {"-0x1.000000000000080000000000p+600", 16532714232077090816ull},
+      {"+0x1.000000000000080000000001p+600", 7309342195222315009ull},
+      {"-0x1.000000000000080000000001p+600", 16532714232077090817ull},
+      {"+0x1.0000000000000fffffffffffp+600", 7309342195222315009ull},
+      {"-0x1.0000000000000fffffffffffp+600", 16532714232077090817ull},
+      {"+0x1.000000000000100000000000p+600", 7309342195222315009ull},
+      {"-0x1.000000000000100000000000p+600", 16532714232077090817ull},
+      {"+0x1.000000000000100000000001p+600", 7309342195222315009ull},
+      {"-0x1.000000000000100000000001p+600", 16532714232077090817ull},
+      {"+0x1.00000000000017ffffffffffp+600", 7309342195222315009ull},
+      {"-0x1.00000000000017ffffffffffp+600", 16532714232077090817ull},
+      {"+0x1.000000000000180000000000p+600", 7309342195222315010ull},
+      {"-0x1.000000000000180000000000p+600", 16532714232077090818ull},
+      {"+0x1.000000000000180000000001p+600", 7309342195222315010ull},
+      {"-0x1.000000000000180000000001p+600", 16532714232077090818ull},
+      {"+0x1.0000000000001fffffffffffp+600", 7309342195222315010ull},
+      {"-0x1.0000000000001fffffffffffp+600", 16532714232077090818ull},
+      {"+0x1.000000000000200000000000p+600", 7309342195222315010ull},
+      {"-0x1.000000000000200000000000p+600", 16532714232077090818ull},
+      {"+0x1.000000000000200000000001p+600", 7309342195222315010ull},
+      {"-0x1.000000000000200000000001p+600", 16532714232077090818ull},
+      {"+0x1.00000000000027ffffffffffp+600", 7309342195222315010ull},
+      {"-0x1.00000000000027ffffffffffp+600", 16532714232077090818ull},
+      {"+0x1.000000000000280000000000p+600", 7309342195222315010ull},
+      {"-0x1.000000000000280000000000p+600", 16532714232077090818ull},
+      {"+0x1.000000000000280000000001p+600", 7309342195222315011ull},
+      {"-0x1.000000000000280000000001p+600", 16532714232077090819ull},
+      {"+0x2000000000000100000000000", 5044031582654955520ull},
+      {"-0x2000000000000100000000000", 14267403619509731328ull},
+      {"+0x2000000000000100000000001", 5044031582654955521ull},
+      {"-0x2000000000000100000000001", 14267403619509731329ull},
+      {"+0x20000000000001fffffffffff", 5044031582654955521ull},
+      {"-0x20000000000001fffffffffff", 14267403619509731329ull},
+      {"+0x2000000000000200000000000", 5044031582654955521ull},
+      {"-0x2000000000000200000000000", 14267403619509731329ull},
+      {"+0x2000000000000200000000001", 5044031582654955521ull},
+      {"-0x2000000000000200000000001", 14267403619509731329ull},
+      {"+0x20000000000002fffffffffff", 5044031582654955521ull},
+      {"-0x20000000000002fffffffffff", 14267403619509731329ull},
+      {"+0x2000000000000300000000000", 5044031582654955522ull},
+      {"-0x2000000000000300000000000", 14267403619509731330ull},
+      {"+0x2000000000000300000000001", 5044031582654955522ull},
+      {"-0x2000000000000300000000001", 14267403619509731330ull},
+      {"+0x20000000000003fffffffffff", 5044031582654955522ull},
+      {"-0x20000000000003fffffffffff", 14267403619509731330ull},
+      {"+0x2000000000000400000000000", 5044031582654955522ull},
+      {"-0x2000000000000400000000000", 14267403619509731330ull},
+      {"+0x2000000000000400000000001", 5044031582654955522ull},
+      {"-0x2000000000000400000000001", 14267403619509731330ull},
+      {"+0x20000000000004fffffffffff", 5044031582654955522ull},
+      {"-0x20000000000004fffffffffff", 14267403619509731330ull},
+      {"+0x2000000000000500000000000", 5044031582654955522ull},
+      {"-0x2000000000000500000000000", 14267403619509731330ull},
+      {"+0x2000000000000500000000001", 5044031582654955523ull},
+      {"-0x2000000000000500000000001", 14267403619509731331ull},
+      {"+0x0.000000000000080000000000p-1022", 0ull},
+      {"-0x0.000000000000080000000000p-1022", 9223372036854775808ull},
+      {"+0x0.000000000000080000000001p-1022", 1ull},
+      {"-0x0.000000000000080000000001p-1022", 9223372036854775809ull},
+      {"+0x0.0000000000000fffffffffffp-1022", 1ull},
+      {"-0x0.0000000000000fffffffffffp-1022", 9223372036854775809ull},
+      {"+0x0.000000000000100000000000p-1022", 1ull},
+      {"-0x0.000000000000100000000000p-1022", 9223372036854775809ull},
+      {"+0x0.000000000000100000000001p-1022", 1ull},
+      {"-0x0.000000000000100000000001p-1022", 9223372036854775809ull},
+      {"+0x0.00000000000017ffffffffffp-1022", 1ull},
+      {"-0x0.00000000000017ffffffffffp-1022", 9223372036854775809ull},
+      {"+0x0.000000000000180000000000p-1022", 2ull},
+      {"-0x0.000000000000180000000000p-1022", 9223372036854775810ull},
+      {"+0x0.000000000000180000000001p-1022", 2ull},
+      {"-0x0.000000000000180000000001p-1022", 9223372036854775810ull},
+      {"+0x0.0000000000001fffffffffffp-1022", 2ull},
+      {"-0x0.0000000000001fffffffffffp-1022", 9223372036854775810ull},
+      {"+0x0.000000000000200000000000p-1022", 2ull},
+      {"-0x0.000000000000200000000000p-1022", 9223372036854775810ull},
+      {"+0x0.000000000000200000000001p-1022", 2ull},
+      {"-0x0.000000000000200000000001p-1022", 9223372036854775810ull},
+      {"+0x0.00000000000027ffffffffffp-1022", 2ull},
+      {"-0x0.00000000000027ffffffffffp-1022", 9223372036854775810ull},
+      {"+0x0.000000000000280000000000p-1022", 2ull},
+      {"-0x0.000000000000280000000000p-1022", 9223372036854775810ull},
+      {"+0x1.000000000000280000000001p-1022", 4503599627370499ull},
+      {"-0x1.000000000000280000000001p-1022", 9227875636482146307ull},
+      {"+0x1.fffffffffffff4p1023", 9218868437227405311ull},
+      {"-0x1.fffffffffffff4p1023", 18442240474082181119ull},
+      {"+0x1.fffffffffffff7ffffffp1023", 9218868437227405311ull},
+      {"-0x1.fffffffffffff7ffffffp1023", 18442240474082181119ull},
   };
 
-  for (auto test: kTests) {
+  for (auto test : kTests) {
     AssertHexDoubleEquals(test.output, test.input);
   }
 }
index 9295c581570c5fef3defb44710d9e72d16c35b85..6d6c4db56b413e6983638941c3bbf1f8bce7274c 100644 (file)
@@ -119,7 +119,6 @@ TEST(OptionParser, FlagCombinedAfterShortParam) {
   EXPECT_EQ(error, "prog: unexpected argument 'stuff'" ERROR_ENDING);
 }
 
-
 TEST(OptionParser, OneArgument) {
   std::string argument;
   OptionParser parser("prog", "desc");
index 3238675d88c9d23d7e078c5f3e8624a2e645f1dd..b8869abdc2f0e650ee8de6f4653af2119a9d9c88 100644 (file)
@@ -21,6 +21,7 @@
 /* Tokens with no additional data (i.e. bare). */
 WABT_TOKEN(Invalid, "Invalid")
 WABT_TOKEN(Array, "array")
+WABT_TOKEN(AssertException, "assert_exception")
 WABT_TOKEN(AssertExhaustion, "assert_exhaustion")
 WABT_TOKEN(AssertInvalid, "assert_invalid")
 WABT_TOKEN(AssertMalformed, "assert_malformed")
@@ -53,6 +54,7 @@ WABT_TOKEN(NanCanonical, "nan:canonical")
 WABT_TOKEN(Offset, "offset")
 WABT_TOKEN(Output, "output")
 WABT_TOKEN(Param, "param")
+WABT_TOKEN(Ref, "ref")
 WABT_TOKEN(Quote, "quote")
 WABT_TOKEN(Register, "register")
 WABT_TOKEN(Result, "result")
index c27e7a9f69460898b861efb40ff16da982db3483..bf42842465feff31630da81ce71a2dc9e4fabbb2 100644 (file)
@@ -43,7 +43,7 @@ using namespace wabt;
 using namespace wabt::interp;
 
 static int s_verbose;
-static const char* s_infile;
+static std::string s_infile;
 static Thread::Options s_thread_options;
 static Stream* s_trace_stream;
 static Features s_features;
@@ -88,7 +88,10 @@ static void ParseOptions(int argc, char** argv) {
                    []() { s_trace_stream = s_stdout_stream.get(); });
 
   parser.AddArgument("filename", OptionParser::ArgumentCount::One,
-                     [](const char* argument) { s_infile = argument; });
+                     [](const char* argument) {
+                       s_infile = argument;
+                       ConvertBackslashToSlash(&s_infile);
+                     });
   parser.Parse(argc, argv);
 }
 
@@ -161,7 +164,7 @@ class RegisterCommand : public CommandMixin<CommandType::Register> {
 
 struct ExpectedValue {
   TypedValue value;
-  Type lane_type;             // Only valid if value.type == Type::V128.
+  Type lane_type;  // Only valid if value.type == Type::V128.
   // Up to 4 NaN values used, depending on |value.type| and |lane_type|:
   //   | type  | lane_type | valid                 |
   //   | f32   |           | nan[0]                |
@@ -309,6 +312,12 @@ typedef AssertModuleCommand<CommandType::AssertUnlinkable>
 typedef AssertModuleCommand<CommandType::AssertUninstantiable>
     AssertUninstantiableCommand;
 
+class AssertExceptionCommand
+    : public CommandMixin<CommandType::AssertException> {
+ public:
+  Action action;
+};
+
 // An extremely simple JSON parser that only knows how to parse the expected
 // format from wat2wasm.
 class JSONParser {
@@ -753,7 +762,7 @@ wabt::Result JSONParser::ParseLaneConstValue(Type lane_type,
     }
 
     default:
-      PrintError("unknown concrete type: \"%s\"", lane_type.GetName());
+      PrintError("unknown concrete type: \"%s\"", lane_type.GetName().c_str());
       return wabt::Result::Error;
   }
 
@@ -825,7 +834,7 @@ wabt::Result JSONParser::ParseConstValue(Type type,
       break;
 
     default:
-      PrintError("unknown concrete type: \"%s\"", type.GetName());
+      PrintError("unknown concrete type: \"%s\"", type.GetName().c_str());
       return wabt::Result::Error;
   }
 
@@ -889,7 +898,8 @@ wabt::Result JSONParser::ParseExpectedValues(
   return wabt::Result::Ok;
 }
 
-wabt::Result JSONParser::ParseConstVector(ValueTypes* out_types, Values* out_values) {
+wabt::Result JSONParser::ParseConstVector(ValueTypes* out_types,
+                                          Values* out_values) {
   out_values->clear();
   EXPECT("[");
   bool first = true;
@@ -1102,6 +1112,19 @@ wabt::Result JSONParser::ParseCommand(CommandPtr* out_command) {
     EXPECT(",");
     CHECK_RESULT(ParseActionResult());
     *out_command = std::move(command);
+  } else if (Match("\"assert_exception\"")) {
+    if (!s_features.exceptions_enabled()) {
+      PrintError("invalid command: exceptions not allowed");
+      return wabt::Result::Error;
+    }
+    auto command = MakeUnique<AssertExceptionCommand>();
+    EXPECT(",");
+    CHECK_RESULT(ParseLine(&command->line));
+    EXPECT(",");
+    CHECK_RESULT(ParseAction(&command->action));
+    EXPECT(",");
+    CHECK_RESULT(ParseActionResult());
+    *out_command = std::move(command);
   } else {
     PrintError("unknown command type");
     return wabt::Result::Error;
@@ -1170,6 +1193,7 @@ class CommandRunner {
   wabt::Result OnAssertReturnCommand(const AssertReturnCommand*);
   wabt::Result OnAssertTrapCommand(const AssertTrapCommand*);
   wabt::Result OnAssertExhaustionCommand(const AssertExhaustionCommand*);
+  wabt::Result OnAssertExceptionCommand(const AssertExceptionCommand*);
 
   wabt::Result CheckAssertReturnResult(const AssertReturnCommand* command,
                                        int index,
@@ -1182,16 +1206,16 @@ class CommandRunner {
   wabt::Result ReadInvalidTextModule(string_view module_filename,
                                      const std::string& header);
   wabt::Result ReadInvalidModule(int line_number,
-                           string_view module_filename,
-                           ModuleType module_type,
-                           const char* desc);
+                                 string_view module_filename,
+                                 ModuleType module_type,
+                                 const char* desc);
   wabt::Result ReadUnlinkableModule(int line_number,
-                              string_view module_filename,
-                              ModuleType module_type,
-                              const char* desc);
+                                    string_view module_filename,
+                                    ModuleType module_type,
+                                    const char* desc);
 
   Store store_;
-  Registry registry_;  // Used when importing.
+  Registry registry_;   // Used when importing.
   Registry instances_;  // Used when referencing module by name in invoke.
   ExportMap last_instance_;
   int passed_ = 0;
@@ -1218,15 +1242,15 @@ CommandRunner::CommandRunner() : store_(s_features) {
 
   for (auto&& print : print_funcs) {
     auto import_name = StringPrintf("spectest.%s", print.name);
-    spectest[print.name] = HostFunc::New(
-        store_, print.type,
-        [=](Thread& inst, const Values& params, Values& results,
-            Trap::Ptr* trap) -> wabt::Result {
-          printf("called host ");
-          WriteCall(s_stdout_stream.get(), import_name, print.type, params,
-                    results, *trap);
-          return wabt::Result::Ok;
-        });
+    spectest[print.name] =
+        HostFunc::New(store_, print.type,
+                      [=](Thread& inst, const Values& params, Values& results,
+                          Trap::Ptr* trap) -> wabt::Result {
+                        printf("called host ");
+                        WriteCall(s_stdout_stream.get(), import_name,
+                                  print.type, params, results, *trap);
+                        return wabt::Result::Ok;
+                      });
   }
 
   spectest["table"] =
@@ -1234,14 +1258,18 @@ CommandRunner::CommandRunner() : store_(s_features) {
 
   spectest["memory"] = interp::Memory::New(store_, MemoryType{Limits{1, 2}});
 
-  spectest["global_i32"] = interp::Global::New(
-      store_, GlobalType{ValueType::I32, Mutability::Const}, Value::Make(u32{666}));
-  spectest["global_i64"] = interp::Global::New(
-      store_, GlobalType{ValueType::I64, Mutability::Const}, Value::Make(u64{666}));
-  spectest["global_f32"] = interp::Global::New(
-      store_, GlobalType{ValueType::F32, Mutability::Const}, Value::Make(f32{666}));
-  spectest["global_f64"] = interp::Global::New(
-      store_, GlobalType{ValueType::F64, Mutability::Const}, Value::Make(f64{666}));
+  spectest["global_i32"] =
+      interp::Global::New(store_, GlobalType{ValueType::I32, Mutability::Const},
+                          Value::Make(u32{666}));
+  spectest["global_i64"] =
+      interp::Global::New(store_, GlobalType{ValueType::I64, Mutability::Const},
+                          Value::Make(u64{666}));
+  spectest["global_f32"] =
+      interp::Global::New(store_, GlobalType{ValueType::F32, Mutability::Const},
+                          Value::Make(f32{666}));
+  spectest["global_f64"] =
+      interp::Global::New(store_, GlobalType{ValueType::F64, Mutability::Const},
+                          Value::Make(f64{666}));
 }
 
 wabt::Result CommandRunner::Run(const Script& script) {
@@ -1295,6 +1323,11 @@ wabt::Result CommandRunner::Run(const Script& script) {
         TallyCommand(OnAssertExhaustionCommand(
             cast<AssertExhaustionCommand>(command.get())));
         break;
+
+      case CommandType::AssertException:
+        TallyCommand(OnAssertExceptionCommand(
+            cast<AssertExceptionCommand>(command.get())));
+        break;
     }
   }
 
@@ -1349,7 +1382,7 @@ ActionResult CommandRunner::RunAction(int line_number,
 }
 
 wabt::Result CommandRunner::ReadInvalidTextModule(string_view module_filename,
-                                            const std::string& header) {
+                                                  const std::string& header) {
   std::vector<uint8_t> file_data;
   wabt::Result result = ReadFile(module_filename, &file_data);
   std::unique_ptr<WastLexer> lexer = WastLexer::CreateBufferLexer(
@@ -1368,7 +1401,7 @@ wabt::Result CommandRunner::ReadInvalidTextModule(string_view module_filename,
 }
 
 interp::Module::Ptr CommandRunner::ReadModule(string_view module_filename,
-                                               Errors* errors) {
+                                              Errors* errors) {
   std::vector<uint8_t> file_data;
 
   if (Failed(ReadFile(module_filename, &file_data))) {
@@ -1381,8 +1414,9 @@ interp::Module::Ptr CommandRunner::ReadModule(string_view module_filename,
   ReadBinaryOptions options(s_features, s_log_stream.get(), kReadDebugNames,
                             kStopOnFirstError, kFailOnCustomSectionError);
   ModuleDesc module_desc;
-  if (Failed(ReadBinaryInterp(file_data.data(), file_data.size(), options,
-                              errors, &module_desc))) {
+  if (Failed(ReadBinaryInterp(module_filename, file_data.data(),
+                              file_data.size(), options, errors,
+                              &module_desc))) {
     return {};
   }
 
@@ -1394,9 +1428,9 @@ interp::Module::Ptr CommandRunner::ReadModule(string_view module_filename,
 }
 
 wabt::Result CommandRunner::ReadInvalidModule(int line_number,
-                                        string_view module_filename,
-                                        ModuleType module_type,
-                                        const char* desc) {
+                                              string_view module_filename,
+                                              ModuleType module_type,
+                                              const char* desc) {
   std::string header = StringPrintf(
       "%s:%d: %s passed", source_filename_.c_str(), line_number, desc);
 
@@ -1498,7 +1532,7 @@ wabt::Result CommandRunner::OnActionCommand(const ActionCommand* command) {
 wabt::Result CommandRunner::OnAssertMalformedCommand(
     const AssertMalformedCommand* command) {
   wabt::Result result = ReadInvalidModule(command->line, command->filename,
-                                    command->type, "assert_malformed");
+                                          command->type, "assert_malformed");
   if (Succeeded(result)) {
     PrintError(command->line, "expected module to be malformed: \"%s\"",
                command->filename.c_str());
@@ -1554,7 +1588,7 @@ wabt::Result CommandRunner::OnAssertUnlinkableCommand(
 wabt::Result CommandRunner::OnAssertInvalidCommand(
     const AssertInvalidCommand* command) {
   wabt::Result result = ReadInvalidModule(command->line, command->filename,
-                                    command->type, "assert_invalid");
+                                          command->type, "assert_invalid");
   if (Succeeded(result)) {
     PrintError(command->line, "expected module to be invalid: \"%s\"",
                command->filename.c_str());
@@ -1628,10 +1662,12 @@ static std::string ExpectedValueToString(const ExpectedValue& ev) {
           return TypedValueToString(ev.value);
 
         case ExpectedNan::Arithmetic:
-          return StringPrintf("%s:nan:arithmetic", ev.value.type.GetName());
+          return StringPrintf("%s:nan:arithmetic",
+                              ev.value.type.GetName().c_str());
 
         case ExpectedNan::Canonical:
-          return StringPrintf("%s:nan:canonical", ev.value.type.GetName());
+          return StringPrintf("%s:nan:canonical",
+                              ev.value.type.GetName().c_str());
       }
       break;
 
@@ -1807,6 +1843,19 @@ wabt::Result CommandRunner::OnAssertExhaustionCommand(
   return wabt::Result::Ok;
 }
 
+wabt::Result CommandRunner::OnAssertExceptionCommand(
+    const AssertExceptionCommand* command) {
+  ActionResult result =
+      RunAction(command->line, &command->action, RunVerbosity::Quiet);
+  if (!result.trap || result.trap->message() != "uncaught exception") {
+    PrintError(command->line, "expected an exception to be thrown");
+    return wabt::Result::Error;
+  }
+  PrintError(command->line, "assert_exception passed");
+
+  return wabt::Result::Ok;
+}
+
 void CommandRunner::TallyCommand(wabt::Result result) {
   if (Succeeded(result)) {
     passed_++;
index 74491e55c34f39b79fac543be73c0819b88881bc..df2bd2b53dceae9143507180abb1785d1e03db77 100644 (file)
@@ -20,8 +20,9 @@
 #include <cstdlib>
 
 #include "src/apply-names.h"
-#include "src/binary-reader.h"
 #include "src/binary-reader-ir.h"
+#include "src/binary-reader.h"
+#include "src/decompiler.h"
 #include "src/error-formatter.h"
 #include "src/feature.h"
 #include "src/generate-names.h"
@@ -30,7 +31,6 @@
 #include "src/stream.h"
 #include "src/validator.h"
 #include "src/wast-lexer.h"
-#include "src/decompiler.h"
 
 using namespace wabt;
 
@@ -45,12 +45,12 @@ int ProgramMain(int argc, char** argv) {
 
   {
     const char s_description[] =
-      "  Read a file in the WebAssembly binary format, and convert it to\n"
-      "  a decompiled text file.\n"
-      "\n"
-      "examples:\n"
-      "  # parse binary file test.wasm and write text file test.dcmp\n"
-      "  $ wasm-decompile test.wasm -o test.dcmp\n";
+        "  Read a file in the WebAssembly binary format, and convert it to\n"
+        "  a decompiled text file.\n"
+        "\n"
+        "examples:\n"
+        "  # parse binary file test.wasm and write text file test.dcmp\n"
+        "  $ wasm-decompile test.wasm -o test.dcmp\n";
     OptionParser parser("wasm-decompile", s_description);
     parser.AddOption(
         'o', "output", "FILENAME",
@@ -77,8 +77,7 @@ int ProgramMain(int argc, char** argv) {
     Errors errors;
     Module module;
     const bool kStopOnFirstError = true;
-    ReadBinaryOptions options(features, nullptr,
-                              true, kStopOnFirstError,
+    ReadBinaryOptions options(features, nullptr, true, kStopOnFirstError,
                               fail_on_custom_section_error);
     result = ReadBinaryIr(infile.c_str(), file_data.data(), file_data.size(),
                           options, &errors, &module);
@@ -86,8 +85,8 @@ int ProgramMain(int argc, char** argv) {
       ValidateOptions options(features);
       result = ValidateModule(&module, &errors, options);
       if (Succeeded(result)) {
-        result = GenerateNames(&module,
-                               static_cast<NameOpts>(NameOpts::AlphaNames));
+        result =
+            GenerateNames(&module, static_cast<NameOpts>(NameOpts::AlphaNames));
       }
       if (Succeeded(result)) {
         // Must be called after ReadBinaryIr & GenerateNames, and before
@@ -103,7 +102,7 @@ int ProgramMain(int argc, char** argv) {
       if (Succeeded(result)) {
         auto s = Decompile(module, decompile_options);
         FileStream stream(!outfile.empty() ? FileStream(outfile)
-                                             : FileStream(stdout));
+                                           : FileStream(stdout));
         stream.WriteData(s.data(), s.size());
       }
     }
index e349a9e32311def3ac7d18626d609389dff2be47..465ad6116295cedc1c800f21c872f881126db552 100644 (file)
@@ -173,15 +173,14 @@ static void BindImports(const Module::Ptr& module, RefVec& imports) {
       auto import_name = StringPrintf("%s.%s", import.type.module.c_str(),
                                       import.type.name.c_str());
 
-      auto host_func =
-          HostFunc::New(s_store, func_type,
-                        [=](Thread& thread, const Values& params,
-                            Values& results, Trap::Ptr* trap) -> Result {
-                          printf("called host ");
-                          WriteCall(stream, import_name, func_type, params,
-                                    results, *trap);
-                          return Result::Ok;
-                        });
+      auto host_func = HostFunc::New(
+          s_store, func_type,
+          [=](Thread& thread, const Values& params, Values& results,
+              Trap::Ptr* trap) -> Result {
+            printf("called host ");
+            WriteCall(stream, import_name, func_type, params, results, *trap);
+            return Result::Ok;
+          });
       imports.push_back(host_func.ref());
       continue;
     }
@@ -205,8 +204,9 @@ static Result ReadModule(const char* module_filename,
   const bool kFailOnCustomSectionError = true;
   ReadBinaryOptions options(s_features, s_log_stream.get(), kReadDebugNames,
                             kStopOnFirstError, kFailOnCustomSectionError);
-  CHECK_RESULT(ReadBinaryInterp(file_data.data(), file_data.size(), options,
-                                errors, &module_desc));
+  CHECK_RESULT(ReadBinaryInterp(module_filename, file_data.data(),
+                                file_data.size(), options, errors,
+                                &module_desc));
 
   if (s_verbose) {
     module_desc.istream.Disassemble(stream);
@@ -301,7 +301,6 @@ static Result ReadAndRunModule(const char* module_filename) {
   } else {
     BindImports(module, imports);
   }
-  BindImports(module, imports);
 
   Instance::Ptr instance;
   CHECK_RESULT(InstantiateModule(imports, module, &instance));
@@ -325,6 +324,7 @@ int ProgramMain(int argc, char** argv) {
   s_stderr_stream = FileStream::CreateStderr();
 
   ParseOptions(argc, argv);
+  s_store.setFeatures(s_features);
 
   wabt::Result result = ReadAndRunModule(s_infile);
   return result != wabt::Result::Ok;
index fbfed12cf1d3dbd123dc7985ae1e7c9e629c54cc..590604321d0b5933b7b0020cb0543780f5a57935 100644 (file)
 #include <cstdlib>
 #include <cstring>
 
+#include "src/binary-reader-objdump.h"
+#include "src/binary-reader.h"
 #include "src/common.h"
 #include "src/option-parser.h"
 #include "src/stream.h"
-#include "src/binary-reader.h"
-#include "src/binary-reader-objdump.h"
 
 using namespace wabt;
 
 static const char s_description[] =
-R"(  Print information about the contents of wasm binaries.
+    R"(  Print information about the contents of wasm binaries.
 
 examples:
   $ wasm-objdump test.wasm
@@ -133,7 +133,7 @@ int ProgramMain(int argc, char** argv) {
     return 1;
   }
 
-  for (const char* filename: s_infiles) {
+  for (const char* filename : s_infiles) {
     if (Failed(dump_file(filename))) {
       return 1;
     }
index 5d6225f098ee1d6320b4b477276a1539eefac64f..4df8598b039da6ec42e283e0588dc2655cdd26e0 100644 (file)
@@ -23,8 +23,8 @@
 #include <map>
 #include <vector>
 
-#include "src/binary-reader.h"
 #include "src/binary-reader-opcnt.h"
+#include "src/binary-reader.h"
 #include "src/option-parser.h"
 #include "src/stream.h"
 
@@ -44,7 +44,7 @@ static std::unique_ptr<FileStream> s_log_stream;
 static Features s_features;
 
 static const char s_description[] =
-R"(  Read a file in the wasm binary format, and count opcode usage for
+    R"(  Read a file in the wasm binary format, and count opcode usage for
   instructions.
 
 examples:
@@ -85,9 +85,7 @@ struct SortByCountDescending {
 
 template <typename T>
 struct WithinCutoff {
-  bool operator()(const T& pair) const {
-    return pair.second >= s_cutoff;
-  }
+  bool operator()(const T& pair) const { return pair.second >= s_cutoff; }
 };
 
 static size_t SumCounts(const OpcodeInfoCounts& info_counts) {
@@ -102,7 +100,7 @@ void WriteCounts(Stream& stream, const OpcodeInfoCounts& info_counts) {
   typedef std::pair<Opcode, size_t> OpcodeCountPair;
 
   std::map<Opcode, size_t> counts;
-  for (auto& info_count_pair: info_counts) {
+  for (auto& info_count_pair : info_counts) {
     Opcode opcode = info_count_pair.first.opcode();
     size_t count = info_count_pair.second;
     counts[opcode] += count;
@@ -124,8 +122,7 @@ void WriteCounts(Stream& stream, const OpcodeInfoCounts& info_counts) {
   }
 }
 
-void WriteCountsWithImmediates(Stream& stream,
-                               const OpcodeInfoCounts& counts) {
+void WriteCountsWithImmediates(Stream& stream, const OpcodeInfoCounts& counts) {
   // Remove const from the key type so we can sort below.
   typedef std::pair<std::remove_const<OpcodeInfoCounts::key_type>::type,
                     OpcodeInfoCounts::mapped_type>
index f83867206459ddf7eec505fa5e8233eb802c3a01..c8f3f83cdd4b72e261be96223c618dfb1a29e84f 100644 (file)
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#include "src/binary.h"
-#include "src/binary-reader.h"
 #include "src/binary-reader-nop.h"
+#include "src/binary-reader.h"
+#include "src/binary.h"
 #include "src/error-formatter.h"
 #include "src/leb128.h"
 #include "src/option-parser.h"
@@ -27,7 +27,7 @@ using namespace wabt;
 static std::string s_filename;
 
 static const char s_description[] =
-R"(  Remove sections of a WebAssembly binary file.
+    R"(  Remove sections of a WebAssembly binary file.
 
 examples:
   # Remove all custom sections from test.wasm
@@ -47,8 +47,7 @@ static void ParseOptions(int argc, char** argv) {
 
 class BinaryReaderStrip : public BinaryReaderNop {
  public:
-  explicit BinaryReaderStrip(Errors* errors)
-      : errors_(errors) {
+  explicit BinaryReaderStrip(Errors* errors) : errors_(errors) {
     stream_.WriteU32(WABT_BINARY_MAGIC, "WASM_BINARY_MAGIC");
     stream_.WriteU32(WABT_BINARY_VERSION, "WASM_BINARY_VERSION");
   }
@@ -90,6 +89,7 @@ int ProgramMain(int argc, char** argv) {
   if (Succeeded(result)) {
     Errors errors;
     Features features;
+    features.EnableAll();
     const bool kReadDebugNames = false;
     const bool kStopOnFirstError = true;
     const bool kFailOnCustomSectionError = false;
index a55c5ed8988d84f15ab93fdb4009ad43a3caf742..dd48e12189544915a83e2a9dbd5f9463c1beb62c 100644 (file)
@@ -19,8 +19,8 @@
 #include <cstdio>
 #include <cstdlib>
 
-#include "src/binary-reader.h"
 #include "src/binary-reader-ir.h"
+#include "src/binary-reader.h"
 #include "src/error-formatter.h"
 #include "src/ir.h"
 #include "src/option-parser.h"
@@ -38,7 +38,7 @@ static bool s_fail_on_custom_section_error = true;
 static std::unique_ptr<FileStream> s_log_stream;
 
 static const char s_description[] =
-R"(  Read a file in the WebAssembly binary format, and validate it.
+    R"(  Read a file in the WebAssembly binary format, and validate it.
 
 examples:
   # validate binary file test.wasm
index 896841a2c6ced4129a7cd6981191f4fef69afa41..a20b7e4b0113f76e6d08a302b84c921bfbc19c9d 100644 (file)
 #include <cstdlib>
 
 #include "src/apply-names.h"
-#include "src/binary-reader.h"
 #include "src/binary-reader-ir.h"
+#include "src/binary-reader.h"
 #include "src/error-formatter.h"
 #include "src/feature.h"
+#include "src/filenames.h"
 #include "src/generate-names.h"
 #include "src/ir.h"
 #include "src/option-parser.h"
@@ -44,7 +45,7 @@ static bool s_read_debug_names = true;
 static std::unique_ptr<FileStream> s_log_stream;
 
 static const char s_description[] =
-R"(  Read a file in the WebAssembly binary format, and convert it to
+    R"(  Read a file in the WebAssembly binary format, and convert it to
   a C source file and header.
 
 examples:
@@ -88,9 +89,11 @@ static void ParseOptions(int argc, char** argv) {
 #undef WABT_FEATURE
 
   if (any_non_default_feature) {
-    fprintf(stderr, "wasm2c currently support only default feature flags.\n");
+    fprintf(stderr,
+            "wasm2c currently only supports a fixed set of features.\n");
     exit(1);
   }
+  s_features.disable_bulk_memory();
 }
 
 // TODO(binji): copied from binary-writer-spec.cc, probably should share.
@@ -137,12 +140,13 @@ int ProgramMain(int argc, char** argv) {
 
       if (Succeeded(result)) {
         if (!s_outfile.empty()) {
-          std::string header_name =
+          std::string header_name_full =
               strip_extension(s_outfile).to_string() + ".h";
           FileStream c_stream(s_outfile.c_str());
-          FileStream h_stream(header_name);
-          result = WriteC(&c_stream, &h_stream, header_name.c_str(), &module,
-                          s_write_c_options);
+          FileStream h_stream(header_name_full);
+          string_view header_name = GetBasename(header_name_full);
+          result = WriteC(&c_stream, &h_stream, header_name.to_string().c_str(),
+                          &module, s_write_c_options);
         } else {
           FileStream stream(stdout);
           result =
@@ -160,4 +164,3 @@ int main(int argc, char** argv) {
   return ProgramMain(argc, argv);
   WABT_CATCH_BAD_ALLOC_AND_EXIT
 }
-
index 58e89849fe3182bb3455baf7f9d5a5e5ba014773..2c50fea79c70b20a3cd1bfc7abea5901f9c18e52 100644 (file)
@@ -20,8 +20,8 @@
 #include <cstdlib>
 
 #include "src/apply-names.h"
-#include "src/binary-reader.h"
 #include "src/binary-reader-ir.h"
+#include "src/binary-reader.h"
 #include "src/error-formatter.h"
 #include "src/feature.h"
 #include "src/generate-names.h"
@@ -46,7 +46,7 @@ static std::unique_ptr<FileStream> s_log_stream;
 static bool s_validate = true;
 
 static const char s_description[] =
-R"(  Read a file in the WebAssembly binary format, and convert it to
+    R"(  Read a file in the WebAssembly binary format, and convert it to
   the WebAssembly text format.
 
 examples:
index a5c9a47d1d11864108d692c101364c4666962110..0418c9a7b5d5de9971bd0733fae57f1581866109 100644 (file)
 #include <cassert>
 #include <cstdarg>
 #include <cstdint>
-#include <cstdlib>
 #include <cstdio>
+#include <cstdlib>
 #include <string>
 
 #include "config.h"
 
-#include "src/binary-writer.h"
 #include "src/binary-writer-spec.h"
+#include "src/binary-writer.h"
 #include "src/common.h"
 #include "src/error-formatter.h"
 #include "src/feature.h"
@@ -49,7 +49,7 @@ static Features s_features;
 static std::unique_ptr<FileStream> s_log_stream;
 
 static const char s_description[] =
-R"(  read a file in the wasm spec test format, check it for errors, and
+    R"(  read a file in the wasm spec test format, check it for errors, and
   convert it to a JSON file and associated wasm binary files.
 
 examples:
index cc6a2cba8e6718080812a45ed57383f5f39a3543..85c2d8a5771b07c6fb8bb7e214ba7cfea785ccfe 100644 (file)
@@ -43,7 +43,7 @@ static bool s_debug_parsing;
 static Features s_features;
 
 static const char s_description[] =
-R"(  read a file in the wasm s-expression format and format it.
+    R"(  read a file in the wasm s-expression format and format it.
 
 examples:
   # write output to stdout
index f77dad277835432f7e09d30cd4056a1d5a110efd..4a71b572fce17c1ed19de23a59b070ca3d1257aa 100644 (file)
@@ -17,8 +17,8 @@
 #include <cassert>
 #include <cstdarg>
 #include <cstdint>
-#include <cstdlib>
 #include <cstdio>
+#include <cstdlib>
 #include <string>
 
 #include "config.h"
@@ -49,7 +49,7 @@ static Features s_features;
 static std::unique_ptr<FileStream> s_log_stream;
 
 static const char s_description[] =
-R"(  read a file in the wasm text format, check it for errors, and
+    R"(  read a file in the wasm text format, check it for errors, and
   convert it to the wasm binary format.
 
 examples:
index 3e875a312f69a24ff55f63e893c5342372f77a42..eb23446f71ac3e2c140718e6779d9da81499216d 100644 (file)
@@ -100,6 +100,24 @@ Result TypeChecker::GetRethrowLabel(Index depth, Label** out_label) {
   return Result::Error;
 }
 
+Result TypeChecker::GetCatchCount(Index depth, Index* out_count) {
+  Label* unused;
+  if (Failed(GetLabel(depth, &unused))) {
+    return Result::Error;
+  }
+
+  Index catch_count = 0;
+  for (Index idx = 0; idx <= depth; idx++) {
+    LabelType type = label_stack_[label_stack_.size() - idx - 1].label_type;
+    if (type == LabelType::Catch) {
+      catch_count++;
+    }
+  }
+  *out_count = catch_count;
+
+  return Result::Ok;
+}
+
 Result TypeChecker::TopLabel(Label** out_label) {
   return GetLabel(0, out_label);
 }
@@ -143,8 +161,9 @@ Result TypeChecker::CheckLabelType(Label* label, LabelType label_type) {
 Result TypeChecker::Check2LabelTypes(Label* label,
                                      LabelType label_type1,
                                      LabelType label_type2) {
-  return label->label_type == label_type1 ||
-         label->label_type == label_type2 ? Result::Ok : Result::Error;
+  return label->label_type == label_type1 || label->label_type == label_type2
+             ? Result::Ok
+             : Result::Error;
 }
 
 Result TypeChecker::GetThisFunctionLabel(Label** label) {
@@ -198,7 +217,7 @@ Result TypeChecker::CheckTypeStackEnd(const char* desc) {
   Result result = (type_stack_.size() == label->type_stack_limit)
                       ? Result::Ok
                       : Result::Error;
-  PrintStackIfFailed(result, desc);
+  PrintStackIfFailedV(result, desc, {}, /*is_end=*/true);
   return result;
 }
 
@@ -206,6 +225,12 @@ Result TypeChecker::CheckType(Type actual, Type expected) {
   if (expected == Type::Any || actual == Type::Any) {
     return Result::Ok;
   }
+
+  if (expected == Type::Reference && actual == Type::Reference) {
+    return expected.GetReferenceIndex() == actual.GetReferenceIndex()
+               ? Result::Ok
+               : Result::Error;
+  }
   if (actual != expected) {
     return Result::Error;
   }
@@ -332,9 +357,10 @@ Result TypeChecker::CheckOpcode3(Opcode opcode,
   return result;
 }
 
-void TypeChecker::PrintStackIfFailed(Result result,
-                                     const char* desc,
-                                     const TypeVector& expected) {
+void TypeChecker::PrintStackIfFailedV(Result result,
+                                      const char* desc,
+                                      const TypeVector& expected,
+                                      bool is_end) {
   if (Succeeded(result)) {
     return;
   }
@@ -371,6 +397,9 @@ void TypeChecker::PrintStackIfFailed(Result result,
   }
 
   std::string message = "type mismatch in ";
+  if (is_end) {
+    message = "type mismatch at end of ";
+  }
   message += desc;
   message += ", expected ";
   message += TypesToString(expected);
@@ -489,10 +518,10 @@ Result TypeChecker::OnCallIndirect(const TypeVector& param_types,
   return result;
 }
 
-Result TypeChecker::OnFuncRef(Index* out_index) {
+Result TypeChecker::OnIndexedFuncRef(Index* out_index) {
   Type type;
   Result result = PeekType(0, &type);
-  if (!type.IsIndex()) {
+  if (!(type == Type::Any || type.IsReferenceWithIndex())) {
     TypeVector actual;
     if (Succeeded(result)) {
       actual.push_back(type);
@@ -504,7 +533,7 @@ Result TypeChecker::OnFuncRef(Index* out_index) {
     result = Result::Error;
   }
   if (Succeeded(result)) {
-    *out_index = type.GetIndex();
+    *out_index = type.GetReferenceIndex();
   }
   result |= DropTypes(1);
   return result;
@@ -569,10 +598,6 @@ Result TypeChecker::OnDelegate(Index depth) {
   // Delegate starts counting after the current try, as the delegate
   // instruction is not actually in the try block.
   CHECK_RESULT(GetLabel(depth + 1, &label));
-  if (Failed(Check2LabelTypes(label, LabelType::Try, LabelType::Func))) {
-    PrintError("try-delegate must target a try block or function label");
-    result = Result::Error;
-  }
 
   Label* try_label;
   CHECK_RESULT(TopLabel(&try_label));
@@ -600,8 +625,8 @@ Result TypeChecker::OnElse() {
   Label* label;
   CHECK_RESULT(TopLabel(&label));
   result |= CheckLabelType(label, LabelType::If);
-  result |= PopAndCheckSignature(label->result_types, "if true branch");
-  result |= CheckTypeStackEnd("if true branch");
+  result |= PopAndCheckSignature(label->result_types, "`if true` branch");
+  result |= CheckTypeStackEnd("`if true` branch");
   ResetTypeStackToLabel(label);
   PushTypes(label->param_types);
   label->label_type = LabelType::Else;
@@ -624,7 +649,8 @@ Result TypeChecker::OnEnd(Label* label,
 Result TypeChecker::OnEnd() {
   Result result = Result::Ok;
   static const char* s_label_type_name[] = {
-      "function", "block", "loop", "if", "if false branch", "try", "try catch"};
+      "function", "initializer expression", "block", "loop",
+      "if",       "`if false` branch",      "try",   "try catch"};
   WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(s_label_type_name) == kLabelTypeCount);
   Label* label;
   CHECK_RESULT(TopLabel(&label));
@@ -749,9 +775,9 @@ Result TypeChecker::OnTableFill(Type elem_type) {
   return PopAndCheck3Types(Type::I32, elem_type, Type::I32, "table.fill");
 }
 
-Result TypeChecker::OnRefFuncExpr(Index func_index) {
+Result TypeChecker::OnRefFuncExpr(Index func_type) {
   if (features_.function_references_enabled()) {
-    PushType(Type(func_index));
+    PushType(Type(Type::Reference, func_type));
   } else {
     PushType(Type::FuncRef);
   }
@@ -766,7 +792,7 @@ Result TypeChecker::OnRefNullExpr(Type type) {
 Result TypeChecker::OnRefIsNullExpr() {
   Type type;
   Result result = PeekType(0, &type);
-  if (!type.IsRef()) {
+  if (!(type == Type::Any || type.IsRef())) {
     TypeVector actual;
     if (Succeeded(result)) {
       actual.push_back(type);
@@ -886,7 +912,9 @@ Result TypeChecker::OnSimdLaneOp(Opcode opcode, uint64_t lane_idx) {
   return result;
 }
 
-Result TypeChecker::OnSimdLoadLane(Opcode opcode, const Limits& limits, uint64_t lane_idx) {
+Result TypeChecker::OnSimdLoadLane(Opcode opcode,
+                                   const Limits& limits,
+                                   uint64_t lane_idx) {
   Result result = Result::Ok;
   uint32_t lane_count = opcode.GetSimdLaneCount();
   if (lane_idx >= lane_count) {
@@ -898,7 +926,9 @@ Result TypeChecker::OnSimdLoadLane(Opcode opcode, const Limits& limits, uint64_t
   return result;
 }
 
-Result TypeChecker::OnSimdStoreLane(Opcode opcode, const Limits& limits, uint64_t lane_idx) {
+Result TypeChecker::OnSimdStoreLane(Opcode opcode,
+                                    const Limits& limits,
+                                    uint64_t lane_idx) {
   Result result = Result::Ok;
   uint32_t lane_count = opcode.GetSimdLaneCount();
   if (lane_idx >= lane_count) {
@@ -938,4 +968,20 @@ Result TypeChecker::EndFunction() {
   return result;
 }
 
+Result TypeChecker::BeginInitExpr(Type type) {
+  type_stack_.clear();
+  label_stack_.clear();
+  PushLabel(LabelType::InitExpr, TypeVector(), {type});
+  return Result::Ok;
+}
+
+Result TypeChecker::EndInitExpr() {
+  Result result = Result::Ok;
+  Label* label;
+  CHECK_RESULT(TopLabel(&label));
+  result |= CheckLabelType(label, LabelType::InitExpr);
+  result |= OnEnd(label, "initializer expression", "initializer expression");
+  return result;
+}
+
 }  // namespace wabt
index b7cdf82dd79b8a58a32bec6bc89c7cdd42ec6912..73ac5fb882e9490bda1a50c5c6b6b09a9aa33af1 100644 (file)
@@ -58,6 +58,7 @@ class TypeChecker {
   bool IsUnreachable();
   Result GetLabel(Index depth, Label** out_label);
   Result GetRethrowLabel(Index depth, Label** out_label);
+  Result GetCatchCount(Index depth, Index* out_depth);
 
   Result BeginFunction(const TypeVector& sig);
   Result OnAtomicFence(uint32_t consistency_model);
@@ -77,9 +78,11 @@ class TypeChecker {
   Result OnCall(const TypeVector& param_types, const TypeVector& result_types);
   Result OnCallIndirect(const TypeVector& param_types,
                         const TypeVector& result_types);
-  Result OnFuncRef(Index* out_index);
-  Result OnReturnCall(const TypeVector& param_types, const TypeVector& result_types);
-  Result OnReturnCallIndirect(const TypeVector& param_types, const TypeVector& result_types);
+  Result OnIndexedFuncRef(Index* out_index);
+  Result OnReturnCall(const TypeVector& param_types,
+                      const TypeVector& result_types);
+  Result OnReturnCallIndirect(const TypeVector& param_types,
+                              const TypeVector& result_types);
   Result OnCatch(const TypeVector& sig);
   Result OnCompare(Opcode);
   Result OnConst(Type);
@@ -110,7 +113,7 @@ class TypeChecker {
   Result OnTableGrow(Type elem_type);
   Result OnTableSize();
   Result OnTableFill(Type elem_type);
-  Result OnRefFuncExpr(Index func_index);
+  Result OnRefFuncExpr(Index func_type);
   Result OnRefNullExpr(Type type);
   Result OnRefIsNullExpr();
   Result OnRethrow(Index depth);
@@ -128,6 +131,9 @@ class TypeChecker {
   Result OnUnreachable();
   Result EndFunction();
 
+  Result BeginInitExpr(Type type);
+  Result EndInitExpr();
+
   static Result CheckType(Type actual, Type expected);
 
  private:
@@ -140,17 +146,21 @@ class TypeChecker {
                  const TypeVector& result_types);
   Result PopLabel();
   Result CheckLabelType(Label* label, LabelType label_type);
-  Result Check2LabelTypes(Label* label, LabelType label_type1, LabelType label_type2);
-  Result GetThisFunctionLabel(Label **label);
+  Result Check2LabelTypes(Label* label,
+                          LabelType label_type1,
+                          LabelType label_type2);
+  Result GetThisFunctionLabel(Label** label);
   Result PeekType(Index depth, Type* out_type);
   Result PeekAndCheckType(Index depth, Type expected);
   Result DropTypes(size_t drop_count);
   void PushType(Type type);
   void PushTypes(const TypeVector& types);
   Result CheckTypeStackEnd(const char* desc);
-  Result CheckTypes(const TypeVector &actual, const TypeVector &expected);
+  Result CheckTypes(const TypeVector& actual, const TypeVector& expected);
   Result CheckSignature(const TypeVector& sig, const char* desc);
-  Result CheckReturnSignature(const TypeVector& sig, const TypeVector &expected,const char *desc);
+  Result CheckReturnSignature(const TypeVector& sig,
+                              const TypeVector& expected,
+                              const char* desc);
   Result PopAndCheckSignature(const TypeVector& sig, const char* desc);
   Result PopAndCheckCall(const TypeVector& param_types,
                          const TypeVector& result_types,
@@ -176,11 +186,14 @@ class TypeChecker {
     // Minor optimization, check result before constructing the vector to pass
     // to the other overload of PrintStackIfFailed.
     if (Failed(result)) {
-      PrintStackIfFailed(result, desc, {args...});
+      PrintStackIfFailedV(result, desc, {args...}, /*is_end=*/false);
     }
   }
 
-  void PrintStackIfFailed(Result, const char* desc, const TypeVector&);
+  void PrintStackIfFailedV(Result,
+                           const char* desc,
+                           const TypeVector&,
+                           bool is_end);
 
   ErrorCallback error_callback_;
   TypeVector type_stack_;
index cd383a16ef6b785da7b41eedd8ff3c9d95d7a8d0..d9b662aafa893ac873a95e1fac5998df16840469 100644 (file)
 #include <vector>
 
 #include "config.h"
+#include "src/base-types.h"
+#include "src/string-format.h"
 
 namespace wabt {
 
 class Type;
 
-using Index = uint32_t;
 using TypeVector = std::vector<Type>;
 
 class Type {
@@ -43,33 +44,41 @@ class Type {
     I16 = -0x07,        // 0x79  : packed-type only, used in gc and as v128 lane
     FuncRef = -0x10,    // 0x70
     ExternRef = -0x11,  // 0x6f
+    Reference = -0x15,  // 0x6b
     Func = -0x20,       // 0x60
     Struct = -0x21,     // 0x5f
     Array = -0x22,      // 0x5e
     Void = -0x40,       // 0x40
     ___ = Void,         // Convenient for the opcode table in opcode.h
 
-    Any = 0,          // Not actually specified, but useful for type-checking
+    Any = 0,   // Not actually specified, but useful for type-checking
     I8U = 4,   // Not actually specified, but used internally with load/store
     I16U = 6,  // Not actually specified, but used internally with load/store
     I32U = 7,  // Not actually specified, but used internally with load/store
   };
 
   Type() = default;  // Provided so Type can be member of a union.
-  Type(int32_t code) : enum_(static_cast<Enum>(code)) {}
-  Type(Enum e) : enum_(e) {}
+  Type(int32_t code)
+      : enum_(static_cast<Enum>(code)), type_index_(kInvalidIndex) {}
+  Type(Enum e) : enum_(e), type_index_(kInvalidIndex) {}
+  Type(Enum e, Index type_index) : enum_(e), type_index_(type_index) {
+    assert(e == Enum::Reference);
+  }
   operator Enum() const { return enum_; }
 
   bool IsRef() const {
-    return enum_ == Type::ExternRef || enum_ == Type::FuncRef;
+    return enum_ == Type::ExternRef || enum_ == Type::FuncRef ||
+           enum_ == Type::Reference;
   }
 
+  bool IsReferenceWithIndex() const { return enum_ == Type::Reference; }
+
   bool IsNullableRef() const {
     // Currently all reftypes are nullable
     return IsRef();
   }
 
-  const char* GetName() const {
+  std::string GetName() const {
     switch (enum_) {
       case Type::I32:       return "i32";
       case Type::I64:       return "i64";
@@ -83,7 +92,10 @@ class Type {
       case Type::Void:      return "void";
       case Type::Any:       return "any";
       case Type::ExternRef: return "externref";
-      default:              return "<type_index>";
+      case Type::Reference:
+        return StringPrintf("(ref %d)", type_index_);
+      default:
+        return StringPrintf("<type_index[%d]>", enum_);
     }
   }
 
@@ -108,7 +120,7 @@ class Type {
   //   (type $T (func (result i32 i64)))
   //   ...
   //   (block (type $T) ...)
-  // 
+  //
   bool IsIndex() const { return static_cast<int32_t>(enum_) >= 0; }
 
   Index GetIndex() const {
@@ -116,6 +128,11 @@ class Type {
     return static_cast<Index>(enum_);
   }
 
+  Index GetReferenceIndex() const {
+    assert(enum_ == Enum::Reference);
+    return type_index_;
+  }
+
   TypeVector GetInlineVector() const {
     assert(!IsIndex());
     switch (enum_) {
@@ -129,6 +146,7 @@ class Type {
       case Type::V128:
       case Type::FuncRef:
       case Type::ExternRef:
+      case Type::Reference:
         return TypeVector(this, this + 1);
 
       default:
@@ -138,6 +156,7 @@ class Type {
 
  private:
   Enum enum_;
+  Index type_index_;  // Only used for for Type::Reference
 };
 
 }  // namespace wabt
index 37a8df00813202b42830abf90b0dd3de7c73c0b1..f3ca98e48598cdd3e3d042c84af33a2b4386f539 100644 (file)
@@ -22,6 +22,7 @@ namespace wabt {
 
 namespace {
 
+// clang-format off
 const int s_utf8_length[256] = {
  // 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 0x00
@@ -41,6 +42,7 @@ const int s_utf8_length[256] = {
     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,  // 0xe0
     4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0xf0
 };
+// clang-format on
 
 // Returns true if this is a valid continuation byte.
 bool IsCont(uint8_t c) {
index d78219ee1cfa2af5ba8b121b6643acaa46955d83..f662b3b05344745e4474216fb06e27c5f8f050ca 100644 (file)
@@ -186,7 +186,8 @@ void ScriptValidator::CheckTypeIndex(const Location* loc,
   if (Failed(TypeChecker::CheckType(actual, expected))) {
     PrintError(loc,
                "type mismatch for %s %" PRIindex " of %s. got %s, expected %s",
-               index_kind, index, desc, actual.GetName(), expected.GetName());
+               index_kind, index, desc, actual.GetName().c_str(),
+               expected.GetName().c_str());
   }
 }
 
@@ -334,7 +335,7 @@ Result Validator::EndIfExpr(IfExpr* expr) {
 }
 
 Result Validator::OnLoadExpr(LoadExpr* expr) {
-  result_ |= validator_.OnLoad(expr->loc, expr->opcode,
+  result_ |= validator_.OnLoad(expr->loc, expr->opcode, expr->memidx,
                                expr->opcode.GetAlignment(expr->align));
   return Result::Ok;
 }
@@ -365,7 +366,8 @@ Result Validator::EndLoopExpr(LoopExpr* expr) {
 }
 
 Result Validator::OnMemoryCopyExpr(MemoryCopyExpr* expr) {
-  result_ |= validator_.OnMemoryCopy(expr->loc);
+  result_ |=
+      validator_.OnMemoryCopy(expr->loc, expr->srcmemidx, expr->destmemidx);
   return Result::Ok;
 }
 
@@ -375,22 +377,22 @@ Result Validator::OnDataDropExpr(DataDropExpr* expr) {
 }
 
 Result Validator::OnMemoryFillExpr(MemoryFillExpr* expr) {
-  result_ |= validator_.OnMemoryFill(expr->loc);
+  result_ |= validator_.OnMemoryFill(expr->loc, expr->memidx);
   return Result::Ok;
 }
 
 Result Validator::OnMemoryGrowExpr(MemoryGrowExpr* expr) {
-  result_ |= validator_.OnMemoryGrow(expr->loc);
+  result_ |= validator_.OnMemoryGrow(expr->loc, expr->memidx);
   return Result::Ok;
 }
 
 Result Validator::OnMemoryInitExpr(MemoryInitExpr* expr) {
-  result_ |= validator_.OnMemoryInit(expr->loc, expr->var);
+  result_ |= validator_.OnMemoryInit(expr->loc, expr->var, expr->memidx);
   return Result::Ok;
 }
 
 Result Validator::OnMemorySizeExpr(MemorySizeExpr* expr) {
-  result_ |= validator_.OnMemorySize(expr->loc);
+  result_ |= validator_.OnMemorySize(expr->loc, expr->memidx);
   return Result::Ok;
 }
 
@@ -484,7 +486,7 @@ Result Validator::OnSelectExpr(SelectExpr* expr) {
 }
 
 Result Validator::OnStoreExpr(StoreExpr* expr) {
-  result_ |= validator_.OnStore(expr->loc, expr->opcode,
+  result_ |= validator_.OnStore(expr->loc, expr->opcode, expr->memidx,
                                 expr->opcode.GetAlignment(expr->align));
   return Result::Ok;
 }
@@ -505,8 +507,7 @@ Result Validator::BeginTryExpr(TryExpr* expr) {
 }
 
 Result Validator::OnCatchExpr(TryExpr*, Catch* catch_) {
-  result_ |= validator_.OnCatch(catch_->loc, catch_->var,
-                                catch_->IsCatchAll());
+  result_ |= validator_.OnCatch(catch_->loc, catch_->var, catch_->IsCatchAll());
   return Result::Ok;
 }
 
@@ -582,9 +583,9 @@ Result Validator::OnSimdLaneOpExpr(SimdLaneOpExpr* expr) {
 }
 
 Result Validator::OnSimdLoadLaneExpr(SimdLoadLaneExpr* expr) {
-  result_ |= validator_.OnSimdLoadLane(
-      expr->loc, expr->opcode, expr->opcode.GetAlignment(expr->align),
-      expr->val);
+  result_ |= validator_.OnSimdLoadLane(expr->loc, expr->opcode,
+                                       expr->opcode.GetAlignment(expr->align),
+                                       expr->val);
   return Result::Ok;
 }
 
@@ -629,11 +630,12 @@ Result Validator::CheckModule() {
       switch (f->type->kind()) {
         case TypeEntryKind::Func: {
           FuncType* func_type = cast<FuncType>(f->type.get());
-          result_ |= validator_.OnFuncType(field.loc,
-                                           func_type->sig.param_types.size(),
-                                           func_type->sig.param_types.data(),
-                                           func_type->sig.result_types.size(),
-                                           func_type->sig.result_types.data());
+          result_ |= validator_.OnFuncType(
+              field.loc, func_type->sig.param_types.size(),
+              func_type->sig.param_types.data(),
+              func_type->sig.result_types.size(),
+              func_type->sig.result_types.data(),
+              module->GetFuncTypeIndex(func_type->sig));
           break;
         }
 
@@ -729,38 +731,12 @@ Result Validator::CheckModule() {
       result_ |=
           validator_.OnGlobal(field.loc, f->global.type, f->global.mutable_);
 
-      if (f->global.init_expr.size() == 1) {
-        const Expr* expr = &f->global.init_expr.front();
-
-        switch (expr->type()) {
-          case ExprType::Const:
-            result_ |= validator_.OnGlobalInitExpr_Const(
-                expr->loc, cast<ConstExpr>(expr)->const_.type());
-            break;
-
-          case ExprType::GlobalGet: {
-            Var var = cast<GlobalGetExpr>(expr)->var;
-            result_ |= validator_.OnGlobalInitExpr_GlobalGet(expr->loc, var);
-            break;
-          }
-
-          case ExprType::RefFunc:
-            result_ |= validator_.OnGlobalInitExpr_RefFunc(
-                expr->loc, cast<RefFuncExpr>(expr)->var);
-            break;
-
-          case ExprType::RefNull:
-            result_ |= validator_.OnGlobalInitExpr_RefNull(
-                expr->loc, cast<RefNullExpr>(expr)->type);
-            break;
-
-          default:
-            result_ |= validator_.OnGlobalInitExpr_Other(field.loc);
-            break;
-        }
-      } else {
-        result_ |= validator_.OnGlobalInitExpr_Other(field.loc);
-      }
+      // Init expr.
+      result_ |= validator_.BeginInitExpr(field.loc, f->global.type);
+      ExprVisitor visitor(this);
+      result_ |=
+          visitor.VisitExprList(const_cast<ExprList&>(f->global.init_expr));
+      result_ |= validator_.EndInitExpr();
     }
   }
 
@@ -796,43 +772,33 @@ Result Validator::CheckModule() {
       validator_.OnElemSegmentElemType(f->elem_segment.elem_type);
 
       // Init expr.
-      if (f->elem_segment.offset.size() == 1) {
-        const Expr* expr = &f->elem_segment.offset.front();
-
-        switch (expr->type()) {
-          case ExprType::Const:
-            result_ |= validator_.OnElemSegmentInitExpr_Const(
-                expr->loc, cast<ConstExpr>(expr)->const_.type());
-            break;
-
-          case ExprType::GlobalGet: {
-            Var var = cast<GlobalGetExpr>(expr)->var;
-            result_ |=
-                validator_.OnElemSegmentInitExpr_GlobalGet(expr->loc, var);
-            break;
-          }
-
-          default:
-            result_ |= validator_.OnElemSegmentInitExpr_Other(field.loc);
-            break;
-        }
-      } else if (f->elem_segment.offset.size() > 1) {
-        result_ |= validator_.OnElemSegmentInitExpr_Other(field.loc);
+      if (f->elem_segment.offset.size()) {
+        result_ |= validator_.BeginInitExpr(field.loc, Type::I32);
+        ExprVisitor visitor(this);
+        result_ |= visitor.VisitExprList(
+            const_cast<ExprList&>(f->elem_segment.offset));
+        result_ |= validator_.EndInitExpr();
       }
 
       // Element expr.
       for (auto&& elem_expr : f->elem_segment.elem_exprs) {
-        switch (elem_expr.kind) {
-          case ElemExprKind::RefNull:
-            // TODO: better location?
-            result_ |= validator_.OnElemSegmentElemExpr_RefNull(field.loc,
-                                                                elem_expr.type);
-            break;
-
-          case ElemExprKind::RefFunc:
-            result_ |= validator_.OnElemSegmentElemExpr_RefFunc(
-                elem_expr.var.loc, elem_expr.var);
-            break;
+        if (elem_expr.size() == 1) {
+          const Expr* expr = &elem_expr.front();
+          switch (expr->type()) {
+            case ExprType::RefNull:
+              result_ |= validator_.OnElemSegmentElemExpr_RefNull(
+                  expr->loc, cast<RefNullExpr>(expr)->type);
+              break;
+            case ExprType::RefFunc:
+              result_ |= validator_.OnElemSegmentElemExpr_RefFunc(
+                  expr->loc, cast<RefFuncExpr>(expr)->var);
+              break;
+            default:
+              result_ |= validator_.OnElemSegmentElemExpr_Other(expr->loc);
+              break;
+          }
+        } else if (elem_expr.size() > 1) {
+          result_ |= validator_.OnElemSegmentElemExpr_Other(field.loc);
         }
       }
     }
@@ -861,32 +827,22 @@ Result Validator::CheckModule() {
   // Data segment section.
   for (const ModuleField& field : module->fields) {
     if (auto* f = dyn_cast<DataSegmentModuleField>(&field)) {
-      result_ |= validator_.OnDataSegment(
-          field.loc, f->data_segment.memory_var, f->data_segment.kind);
+      result_ |= validator_.OnDataSegment(field.loc, f->data_segment.memory_var,
+                                          f->data_segment.kind);
 
       // Init expr.
-      if (f->data_segment.offset.size() == 1) {
-        const Expr* expr = &f->data_segment.offset.front();
-
-        switch (expr->type()) {
-          case ExprType::Const:
-            result_ |= validator_.OnDataSegmentInitExpr_Const(
-                expr->loc, cast<ConstExpr>(expr)->const_.type());
-            break;
-
-          case ExprType::GlobalGet: {
-            Var var = cast<GlobalGetExpr>(expr)->var;
-            result_ |=
-                validator_.OnDataSegmentInitExpr_GlobalGet(expr->loc, var);
-            break;
-          }
-
-          default:
-            result_ |= validator_.OnDataSegmentInitExpr_Other(field.loc);
-            break;
+      if (f->data_segment.offset.size()) {
+        Type offset_type = Type::I32;
+        Index memory_index = module->GetMemoryIndex(f->data_segment.memory_var);
+        if (memory_index < module->memories.size() &&
+            module->memories[memory_index]->page_limits.is_64) {
+          offset_type = Type::I64;
         }
-      } else if (f->data_segment.offset.size() > 1) {
-        result_ |= validator_.OnDataSegmentInitExpr_Other(field.loc);
+        result_ |= validator_.BeginInitExpr(field.loc, offset_type);
+        ExprVisitor visitor(this);
+        result_ |= visitor.VisitExprList(
+            const_cast<ExprList&>(f->data_segment.offset));
+        result_ |= validator_.EndInitExpr();
       }
     }
   }
@@ -1042,6 +998,10 @@ void ScriptValidator::CheckCommand(const Command* command) {
       // ignore result type.
       CheckAction(cast<AssertExhaustionCommand>(command)->action.get());
       break;
+    case CommandType::AssertException:
+      // ignore result type.
+      CheckAction(cast<AssertExceptionCommand>(command)->action.get());
+      break;
   }
 }
 
index b84acbc945645c14375d5714ccac6251ac5c1eda..23ba72c10c1956d9d2c55a729afed6882aed38aa 100644 (file)
@@ -33,4 +33,4 @@ Result ValidateModule(const Module*, Errors*, const ValidateOptions&);
 
 }  // namespace wabt
 
-#endif // WABT_VALIDATOR_H_
+#endif  // WABT_VALIDATOR_H_
index 5954f6510d7f04166a2e8d1491d29b2f419f47e0..96e7d336194c813fa6725570643252711f7053b1 100644 (file)
@@ -227,6 +227,7 @@ bool IsCommand(TokenTypePair pair) {
   }
 
   switch (pair[1]) {
+    case TokenType::AssertException:
     case TokenType::AssertExhaustion:
     case TokenType::AssertInvalid:
     case TokenType::AssertMalformed:
@@ -263,6 +264,39 @@ bool ResolveFuncTypeWithEmptySignature(const Module& module,
   return false;
 }
 
+void ResolveTypeName(
+    const Module& module,
+    Type& type,
+    Index index,
+    const std::unordered_map<uint32_t, std::string>& bindings) {
+  if (type != Type::Reference || type.GetReferenceIndex() != kInvalidIndex) {
+    return;
+  }
+
+  const auto name_iterator = bindings.find(index);
+  assert(name_iterator != bindings.cend());
+  const auto type_index = module.type_bindings.FindIndex(name_iterator->second);
+  assert(type_index != kInvalidIndex);
+  type = Type(Type::Reference, type_index);
+}
+
+void ResolveTypeNames(const Module& module, FuncDeclaration* decl) {
+  assert(decl);
+  auto& signature = decl->sig;
+
+  for (uint32_t param_index = 0; param_index < signature.GetNumParams();
+       ++param_index) {
+    ResolveTypeName(module, signature.param_types[param_index], param_index,
+                    signature.param_type_names);
+  }
+
+  for (uint32_t result_index = 0; result_index < signature.GetNumResults();
+       ++result_index) {
+    ResolveTypeName(module, signature.result_types[result_index], result_index,
+                    signature.result_type_names);
+  }
+}
+
 void ResolveImplicitlyDefinedFunctionType(const Location& loc,
                                           Module* module,
                                           const FuncDeclaration& decl) {
@@ -288,11 +322,12 @@ Result CheckTypeIndex(const Location& loc,
                       Errors* errors) {
   // Types must match exactly; no subtyping should be allowed.
   if (actual != expected) {
-    errors->emplace_back(ErrorLevel::Error, loc,
-                         StringPrintf("type mismatch for %s %" PRIindex
-                                      " of %s. got %s, expected %s",
-                                      index_kind, index, desc, actual.GetName(),
-                                      expected.GetName()));
+    errors->emplace_back(
+        ErrorLevel::Error, loc,
+        StringPrintf("type mismatch for %s %" PRIindex
+                     " of %s. got %s, expected %s",
+                     index_kind, index, desc, actual.GetName().c_str(),
+                     expected.GetName().c_str()));
     return Result::Error;
   }
   return Result::Ok;
@@ -342,9 +377,15 @@ Result CheckFuncTypeVarMatchesExplicit(const Location& loc,
       // ResolveFuncTypeWithEmptySignature), but if they are provided then we
       // have to check. If we get here then the type var is invalid, so we
       // can't check whether they match.
-      errors->emplace_back(ErrorLevel::Error, loc,
-                           StringPrintf("invalid func type index %" PRIindex,
-                                        decl.type_var.index()));
+      if (decl.type_var.is_index()) {
+        errors->emplace_back(ErrorLevel::Error, loc,
+                             StringPrintf("invalid func type index %" PRIindex,
+                                          decl.type_var.index()));
+      } else {
+        errors->emplace_back(ErrorLevel::Error, loc,
+                             StringPrintf("expected func type identifier %s",
+                                          decl.type_var.name().c_str()));
+      }
       result = Result::Error;
     }
   }
@@ -361,6 +402,7 @@ class ResolveFuncTypesExprVisitorDelegate : public ExprVisitor::DelegateNop {
       : module_(module), errors_(errors) {}
 
   void ResolveBlockDeclaration(const Location& loc, BlockDeclaration* decl) {
+    ResolveTypeNames(*module_, decl);
     ResolveFuncTypeWithEmptySignature(*module_, decl);
     if (!IsInlinableFuncSignature(decl->sig)) {
       ResolveImplicitlyDefinedFunctionType(loc, module_, *decl);
@@ -439,6 +481,7 @@ Result ResolveFuncTypes(Module* module, Errors* errors) {
     bool has_func_type_and_empty_signature = false;
 
     if (decl) {
+      ResolveTypeNames(*module, decl);
       has_func_type_and_empty_signature =
           ResolveFuncTypeWithEmptySignature(*module, decl);
       ResolveImplicitlyDefinedFunctionType(field.loc, module, *decl);
@@ -453,7 +496,7 @@ Result ResolveFuncTypes(Module* module, Errors* errors) {
         // local variables share the same index space, we need to increment the
         // local indexes bound to a given name by the number of parameters in
         // the function.
-        for (auto& pair: func->bindings) {
+        for (auto& pair : func->bindings) {
           pair.second.index += func->GetNumParams();
         }
       }
@@ -540,8 +583,8 @@ TokenTypePair WastParser::PeekPair() {
   return TokenTypePair{{Peek(), Peek(1)}};
 }
 
-bool WastParser::PeekMatch(TokenType type) {
-  return Peek() == type;
+bool WastParser::PeekMatch(TokenType type, size_t n) {
+  return Peek(n) == type;
 }
 
 bool WastParser::PeekMatchLpar(TokenType type) {
@@ -552,6 +595,11 @@ bool WastParser::PeekMatchExpr() {
   return IsExpr(PeekPair());
 }
 
+bool WastParser::PeekMatchRefType() {
+  return options_->features.function_references_enabled() &&
+         PeekMatchLpar(TokenType::Ref);
+}
+
 bool WastParser::Match(TokenType type) {
   if (PeekMatch(type)) {
     Consume();
@@ -755,57 +803,64 @@ Result WastParser::ParseVarList(VarVector* out_var_list) {
   }
 }
 
-bool WastParser::ParseElemExprOpt(ElemExpr* out_elem_expr) {
-  Location loc = GetLocation();
+bool WastParser::ParseElemExprOpt(ExprList* out_elem_expr) {
+  WABT_TRACE(ParseElemExprOpt);
   bool item = MatchLpar(TokenType::Item);
-  bool lpar = Match(TokenType::Lpar);
-  if (Match(TokenType::RefNull)) {
-    if (!(options_->features.bulk_memory_enabled() ||
-          options_->features.reference_types_enabled())) {
-      Error(loc, "ref.null not allowed");
-    }
-    Type type;
-    CHECK_RESULT(ParseRefKind(&type));
-    *out_elem_expr = ElemExpr(type);
-  } else if (Match(TokenType::RefFunc)) {
-    Var var;
-    CHECK_RESULT(ParseVar(&var));
-    *out_elem_expr = ElemExpr(var);
-  } else {
-    return false;
-  }
-  if (lpar) {
-    EXPECT(Rpar);
-  }
+  ExprList exprs;
   if (item) {
+    if (ParseTerminatingInstrList(&exprs) != Result::Ok) {
+      return false;
+    }
     EXPECT(Rpar);
+  } else {
+    if (ParseExpr(&exprs) != Result::Ok) {
+      return false;
+    }
+  }
+  if (!exprs.size()) {
+    return false;
   }
+  *out_elem_expr = std::move(exprs);
   return true;
 }
 
-bool WastParser::ParseElemExprListOpt(ElemExprVector* out_list) {
-  ElemExpr elem_expr;
+bool WastParser::ParseElemExprListOpt(ExprListVector* out_list) {
+  ExprList elem_expr;
   while (ParseElemExprOpt(&elem_expr)) {
-    out_list->push_back(elem_expr);
+    out_list->push_back(std::move(elem_expr));
   }
   return !out_list->empty();
 }
 
-bool WastParser::ParseElemExprVarListOpt(ElemExprVector* out_list) {
+bool WastParser::ParseElemExprVarListOpt(ExprListVector* out_list) {
   WABT_TRACE(ParseElemExprVarListOpt);
   Var var;
+  ExprList init_expr;
   while (ParseVarOpt(&var)) {
-    out_list->emplace_back(var);
+    init_expr.push_back(MakeUnique<RefFuncExpr>(var));
+    out_list->push_back(std::move(init_expr));
   }
   return !out_list->empty();
 }
 
-Result WastParser::ParseValueType(Type* out_type) {
+Result WastParser::ParseValueType(Var* out_type) {
   WABT_TRACE(ParseValueType);
-  if (!PeekMatch(TokenType::ValueType)) {
+
+  const bool is_ref_type = PeekMatchRefType();
+  const bool is_value_type = PeekMatch(TokenType::ValueType);
+
+  if (!is_value_type && !is_ref_type) {
     return ErrorExpected({"i32", "i64", "f32", "f64", "v128", "externref"});
   }
 
+  if (is_ref_type) {
+    EXPECT(Lpar);
+    EXPECT(Ref);
+    CHECK_RESULT(ParseVar(out_type));
+    EXPECT(Rpar);
+    return Result::Ok;
+  }
+
   Token token = Consume();
   Type type = token.type();
   bool is_enabled;
@@ -823,18 +878,35 @@ Result WastParser::ParseValueType(Type* out_type) {
   }
 
   if (!is_enabled) {
-    Error(token.loc, "value type not allowed: %s", type.GetName());
+    Error(token.loc, "value type not allowed: %s", type.GetName().c_str());
     return Result::Error;
   }
 
-  *out_type = type;
+  *out_type = Var(type);
   return Result::Ok;
 }
 
-Result WastParser::ParseValueTypeList(TypeVector* out_type_list) {
+Result WastParser::ParseValueTypeList(
+    TypeVector* out_type_list,
+    std::unordered_map<uint32_t, std::string>* type_names) {
   WABT_TRACE(ParseValueTypeList);
-  while (PeekMatch(TokenType::ValueType))
-    out_type_list->push_back(Consume().type());
+  while (true) {
+    if (!PeekMatchRefType() && !PeekMatch(TokenType::ValueType)) {
+      break;
+    }
+
+    Var type;
+    CHECK_RESULT(ParseValueType(&type));
+
+    if (type.is_index()) {
+      out_type_list->push_back(Type(type.index()));
+    } else {
+      assert(type.is_name());
+      assert(options_->features.function_references_enabled());
+      type_names->emplace(out_type_list->size(), type.name());
+      out_type_list->push_back(Type(Type::Reference, kInvalidIndex));
+    }
+  }
 
   return Result::Ok;
 }
@@ -852,7 +924,7 @@ Result WastParser::ParseRefKind(Type* out_type) {
        !options_->features.reference_types_enabled()) ||
       ((type == Type::Struct || type == Type::Array) &&
        !options_->features.gc_enabled())) {
-    Error(token.loc, "value type not allowed: %s", type.GetName());
+    Error(token.loc, "value type not allowed: %s", type.GetName().c_str());
     return Result::Error;
   }
 
@@ -870,7 +942,7 @@ Result WastParser::ParseRefType(Type* out_type) {
   Type type = token.type();
   if (type == Type::ExternRef &&
       !options_->features.reference_types_enabled()) {
-    Error(token.loc, "value type not allowed: %s", type.GetName());
+    Error(token.loc, "value type not allowed: %s", type.GetName().c_str());
     return Result::Error;
   }
 
@@ -954,6 +1026,27 @@ bool WastParser::ParseAlignOpt(Address* out_align) {
   }
 }
 
+Result WastParser::ParseMemidx(Location loc, Var* out_memidx) {
+  WABT_TRACE(ParseMemidx);
+  if (PeekMatchLpar(TokenType::Memory)) {
+    if (!options_->features.multi_memory_enabled()) {
+      Error(loc, "Specifying memory variable is not allowed");
+      return Result::Error;
+    }
+    EXPECT(Lpar);
+    EXPECT(Memory);
+    CHECK_RESULT(ParseVar(out_memidx));
+    EXPECT(Rpar);
+  } else {
+    if (ParseVarOpt(out_memidx, Var(0, loc)) &&
+        !options_->features.multi_memory_enabled()) {
+      Error(loc, "Specifying memory variable is not allowed");
+      return Result::Error;
+    }
+  }
+  return Result::Ok;
+}
+
 Result WastParser::ParseLimitsIndex(Limits* out_limits) {
   WABT_TRACE(ParseLimitsIndex);
 
@@ -1196,13 +1289,31 @@ Result WastParser::ParseElemModuleField(Module* module) {
 Result WastParser::ParseTagModuleField(Module* module) {
   WABT_TRACE(ParseTagModuleField);
   EXPECT(Lpar);
-  auto field = MakeUnique<TagModuleField>(GetLocation());
   EXPECT(Tag);
-  ParseBindVarOpt(&field->tag.name);
-  CHECK_RESULT(ParseTypeUseOpt(&field->tag.decl));
-  CHECK_RESULT(ParseUnboundFuncSignature(&field->tag.decl.sig));
+  std::string name;
+  ParseBindVarOpt(&name);
+
+  ModuleFieldList export_fields;
+  CHECK_RESULT(ParseInlineExports(&export_fields, ExternalKind::Tag));
+
+  if (PeekMatchLpar(TokenType::Import)) {
+    CheckImportOrdering(module);
+    auto import = MakeUnique<TagImport>(name);
+    CHECK_RESULT(ParseInlineImport(import.get()));
+    CHECK_RESULT(ParseTypeUseOpt(&import->tag.decl));
+    CHECK_RESULT(ParseUnboundFuncSignature(&import->tag.decl.sig));
+    auto field =
+        MakeUnique<ImportModuleField>(std::move(import), GetLocation());
+    module->AppendField(std::move(field));
+  } else {
+    auto field = MakeUnique<TagModuleField>(GetLocation(), name);
+    CHECK_RESULT(ParseTypeUseOpt(&field->tag.decl));
+    CHECK_RESULT(ParseUnboundFuncSignature(&field->tag.decl.sig));
+    module->AppendField(std::move(field));
+  }
+
+  AppendInlineExportFields(module, &export_fields, module->tags.size() - 1);
   EXPECT(Rpar);
-  module->AppendField(std::move(field));
   return Result::Ok;
 }
 
@@ -1246,8 +1357,9 @@ Result WastParser::ParseFuncModuleField(Module* module) {
     CHECK_RESULT(ParseTypeUseOpt(&func.decl));
     CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings));
     TypeVector local_types;
-    CHECK_RESULT(ParseBoundValueTypeList(TokenType::Local, &local_types,
-                                         &func.bindings, func.GetNumParams()));
+    CHECK_RESULT(ParseBoundValueTypeList(
+        TokenType::Local, &local_types, &func.bindings,
+        &func.decl.sig.param_type_names, func.GetNumParams()));
     func.local_types.Set(local_types);
     CHECK_RESULT(ParseTerminatingInstrList(&func.exprs));
     module->AppendField(std::move(field));
@@ -1307,11 +1419,15 @@ Result WastParser::ParseField(Field* field) {
     // TODO: Share with ParseGlobalType?
     if (MatchLpar(TokenType::Mut)) {
       field->mutable_ = true;
-      CHECK_RESULT(ParseValueType(&field->type));
+      Var type;
+      CHECK_RESULT(ParseValueType(&type));
+      field->type = Type(type.index());
       EXPECT(Rpar);
     } else {
       field->mutable_ = false;
-      CHECK_RESULT(ParseValueType(&field->type));
+      Var type;
+      CHECK_RESULT(ParseValueType(&type));
+      field->type = Type(type.index());
     }
     return Result::Ok;
   };
@@ -1389,16 +1505,11 @@ Result WastParser::ParseImportModuleField(Module* module) {
       Consume();
       ParseBindVarOpt(&name);
       auto import = MakeUnique<FuncImport>(name);
-      if (PeekMatchLpar(TokenType::Type)) {
-        import->func.decl.has_func_type = true;
-        CHECK_RESULT(ParseTypeUseOpt(&import->func.decl));
-        EXPECT(Rpar);
-      } else {
-        CHECK_RESULT(
-            ParseFuncSignature(&import->func.decl.sig, &import->func.bindings));
-        CHECK_RESULT(ErrorIfLpar({"param", "result"}));
-        EXPECT(Rpar);
-      }
+      CHECK_RESULT(ParseTypeUseOpt(&import->func.decl));
+      CHECK_RESULT(
+          ParseFuncSignature(&import->func.decl.sig, &import->func.bindings));
+      CHECK_RESULT(ErrorIfLpar({"param", "result"}));
+      EXPECT(Rpar);
       field = MakeUnique<ImportModuleField>(std::move(import), loc);
       break;
     }
@@ -1562,9 +1673,9 @@ Result WastParser::ParseTableModuleField(Module* module) {
     elem_segment.elem_type = elem_type;
     // Syntax is either an optional list of var (legacy), or a non-empty list
     // of elem expr.
-    ElemExpr elem_expr;
+    ExprList elem_expr;
     if (ParseElemExprOpt(&elem_expr)) {
-      elem_segment.elem_exprs.push_back(elem_expr);
+      elem_segment.elem_exprs.push_back(std::move(elem_expr));
       // Parse the rest.
       ParseElemExprListOpt(&elem_segment.elem_exprs);
     } else {
@@ -1651,54 +1762,68 @@ Result WastParser::ParseFuncSignature(FuncSignature* sig,
                                       BindingHash* param_bindings) {
   WABT_TRACE(ParseFuncSignature);
   CHECK_RESULT(ParseBoundValueTypeList(TokenType::Param, &sig->param_types,
-                                       param_bindings));
-  CHECK_RESULT(ParseResultList(&sig->result_types));
+                                       param_bindings, &sig->param_type_names));
+  CHECK_RESULT(ParseResultList(&sig->result_types, &sig->result_type_names));
   return Result::Ok;
 }
 
 Result WastParser::ParseUnboundFuncSignature(FuncSignature* sig) {
   WABT_TRACE(ParseUnboundFuncSignature);
-  CHECK_RESULT(ParseUnboundValueTypeList(TokenType::Param, &sig->param_types));
-  CHECK_RESULT(ParseResultList(&sig->result_types));
+  CHECK_RESULT(ParseUnboundValueTypeList(TokenType::Param, &sig->param_types,
+                                         &sig->param_type_names));
+  CHECK_RESULT(ParseResultList(&sig->result_types, &sig->result_type_names));
   return Result::Ok;
 }
 
-Result WastParser::ParseBoundValueTypeList(TokenType token,
-                                           TypeVector* types,
-                                           BindingHash* bindings,
-                                           Index binding_index_offset) {
+Result WastParser::ParseBoundValueTypeList(
+    TokenType token,
+    TypeVector* types,
+    BindingHash* bindings,
+    std::unordered_map<uint32_t, std::string>* type_names,
+    Index binding_index_offset) {
   WABT_TRACE(ParseBoundValueTypeList);
   while (MatchLpar(token)) {
     if (PeekMatch(TokenType::Var)) {
       std::string name;
-      Type type;
+      Var type;
       Location loc = GetLocation();
       ParseBindVarOpt(&name);
       CHECK_RESULT(ParseValueType(&type));
       bindings->emplace(name,
                         Binding(loc, binding_index_offset + types->size()));
-      types->push_back(type);
+      if (type.is_index()) {
+        types->push_back(Type(type.index()));
+      } else {
+        assert(type.is_name());
+        assert(options_->features.function_references_enabled());
+        type_names->emplace(binding_index_offset + types->size(), type.name());
+        types->push_back(Type(Type::Reference, kInvalidIndex));
+      }
     } else {
-      CHECK_RESULT(ParseValueTypeList(types));
+      CHECK_RESULT(ParseValueTypeList(types, type_names));
     }
     EXPECT(Rpar);
   }
   return Result::Ok;
 }
 
-Result WastParser::ParseUnboundValueTypeList(TokenType token,
-                                             TypeVector* types) {
+Result WastParser::ParseUnboundValueTypeList(
+    TokenType token,
+    TypeVector* types,
+    std::unordered_map<uint32_t, std::string>* type_names) {
   WABT_TRACE(ParseUnboundValueTypeList);
   while (MatchLpar(token)) {
-    CHECK_RESULT(ParseValueTypeList(types));
+    CHECK_RESULT(ParseValueTypeList(types, type_names));
     EXPECT(Rpar);
   }
   return Result::Ok;
 }
 
-Result WastParser::ParseResultList(TypeVector* result_types) {
+Result WastParser::ParseResultList(
+    TypeVector* result_types,
+    std::unordered_map<uint32_t, std::string>* type_names) {
   WABT_TRACE(ParseResultList);
-  return ParseUnboundValueTypeList(TokenType::Result, result_types);
+  return ParseUnboundValueTypeList(TokenType::Result, result_types, type_names);
 }
 
 Result WastParser::ParseInstrList(ExprList* exprs) {
@@ -1753,6 +1878,34 @@ Result WastParser::ParsePlainInstrVar(Location loc,
   return Result::Ok;
 }
 
+template <typename T>
+Result WastParser::ParseMemoryInstrVar(Location loc,
+                                       std::unique_ptr<Expr>* out_expr) {
+  Var memidx;
+  Var var;
+  if (PeekMatchLpar(TokenType::Memory)) {
+    if (!options_->features.multi_memory_enabled()) {
+      Error(loc, "Specifying memory variable is not allowed");
+      return Result::Error;
+    }
+    CHECK_RESULT(ParseMemidx(loc, &memidx));
+    CHECK_RESULT(ParseVar(&var));
+    out_expr->reset(new T(var, memidx, loc));
+  } else {
+    CHECK_RESULT(ParseVar(&memidx));
+    if (ParseVarOpt(&var, Var(0, loc))) {
+      if (!options_->features.multi_memory_enabled()) {
+        Error(loc, "Specifiying memory variable is not allowed");
+        return Result::Error;
+      }
+      out_expr->reset(new T(var, memidx, loc));
+    } else {
+      out_expr->reset(new T(memidx, var, loc));
+    }
+  }
+  return Result::Ok;
+}
+
 template <typename T>
 Result WastParser::ParsePlainLoadStoreInstr(Location loc,
                                             Token token,
@@ -1766,6 +1919,83 @@ Result WastParser::ParsePlainLoadStoreInstr(Location loc,
   return Result::Ok;
 }
 
+template <typename T>
+Result WastParser::ParseMemoryLoadStoreInstr(Location loc,
+                                             Token token,
+                                             std::unique_ptr<Expr>* out_expr) {
+  Opcode opcode = token.opcode();
+  Var memidx;
+  Address offset;
+  Address align;
+  CHECK_RESULT(ParseMemidx(loc, &memidx));
+  ParseOffsetOpt(&offset);
+  ParseAlignOpt(&align);
+  out_expr->reset(new T(opcode, memidx, align, offset, loc));
+  return Result::Ok;
+}
+
+template <typename T>
+Result WastParser::ParseSIMDLoadStoreInstr(Location loc,
+                                           Token token,
+                                           std::unique_ptr<Expr>* out_expr) {
+  ErrorUnlessOpcodeEnabled(token);
+
+  Var memidx(0, loc);
+
+  if (options_->features.multi_memory_enabled()) {
+    // We have to be a little careful when reading the memeory index.
+    // If there is just a single integer folloing the instruction that
+    // represents the lane index, so we check for either a pair of intergers
+    // or an integers followed by offset= or align=.
+    bool try_read_mem_index = true;
+    if (PeekMatch(TokenType::Nat)) {
+      // The next token could be a memory index or a lane index
+      if (!PeekMatch(TokenType::OffsetEqNat, 1) &&
+          !PeekMatch(TokenType::AlignEqNat, 1) &&
+          !PeekMatch(TokenType::Nat, 1)) {
+        try_read_mem_index = false;
+      }
+    }
+    if (try_read_mem_index) {
+      CHECK_RESULT(ParseMemidx(loc, &memidx));
+    }
+  }
+  Address offset;
+  Address align;
+  ParseOffsetOpt(&offset);
+  ParseAlignOpt(&align);
+
+  uint64_t lane_idx = 0;
+  Result result = ParseSimdLane(loc, &lane_idx);
+
+  if (Failed(result)) {
+    return Result::Error;
+  }
+
+  out_expr->reset(new T(token.opcode(), memidx, align, offset, lane_idx, loc));
+  return Result::Ok;
+}
+
+template <typename T>
+Result WastParser::ParseMemoryExpr(Location loc,
+                                   std::unique_ptr<Expr>* out_expr) {
+  Var memidx;
+  CHECK_RESULT(ParseMemidx(loc, &memidx));
+  out_expr->reset(new T(memidx, loc));
+  return Result::Ok;
+}
+
+template <typename T>
+Result WastParser::ParseMemoryBinaryExpr(Location loc,
+                                         std::unique_ptr<Expr>* out_expr) {
+  Var srcmemidx;
+  Var destmemidx;
+  CHECK_RESULT(ParseMemidx(loc, &srcmemidx));
+  CHECK_RESULT(ParseMemidx(loc, &destmemidx));
+  out_expr->reset(new T(srcmemidx, destmemidx, loc));
+  return Result::Ok;
+}
+
 Result WastParser::ParseSimdLane(Location loc, uint64_t* lane_idx) {
   if (!PeekMatch(TokenType::Nat) && !PeekMatch(TokenType::Int)) {
     return ErrorExpected({"a natural number in range [0, 32)"});
@@ -1773,8 +2003,8 @@ Result WastParser::ParseSimdLane(Location loc, uint64_t* lane_idx) {
 
   Literal literal = Consume().literal();
 
-  Result result = ParseInt64(literal.text.begin(), literal.text.end(),
-                             lane_idx, ParseIntType::UnsignedOnly);
+  Result result = ParseInt64(literal.text.begin(), literal.text.end(), lane_idx,
+                             ParseIntType::UnsignedOnly);
 
   if (Failed(result)) {
     Error(loc, "invalid literal \"" PRIstringview "\"",
@@ -1817,7 +2047,7 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) {
       TypeVector result;
       if (options_->features.reference_types_enabled() &&
           MatchLpar(TokenType::Result)) {
-        CHECK_RESULT(ParseValueTypeList(&result));
+        CHECK_RESULT(ParseValueTypeList(&result, nullptr));
         EXPECT(Rpar);
       }
       out_expr->reset(new SelectExpr(result, loc));
@@ -1912,12 +2142,12 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) {
 
     case TokenType::Load:
       CHECK_RESULT(
-          ParsePlainLoadStoreInstr<LoadExpr>(loc, Consume(), out_expr));
+          ParseMemoryLoadStoreInstr<LoadExpr>(loc, Consume(), out_expr));
       break;
 
     case TokenType::Store:
       CHECK_RESULT(
-          ParsePlainLoadStoreInstr<StoreExpr>(loc, Consume(), out_expr));
+          ParseMemoryLoadStoreInstr<StoreExpr>(loc, Consume(), out_expr));
       break;
 
     case TokenType::Const: {
@@ -1954,12 +2184,12 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) {
 
     case TokenType::MemoryCopy:
       ErrorUnlessOpcodeEnabled(Consume());
-      out_expr->reset(new MemoryCopyExpr(loc));
+      CHECK_RESULT(ParseMemoryBinaryExpr<MemoryCopyExpr>(loc, out_expr));
       break;
 
     case TokenType::MemoryFill:
       ErrorUnlessOpcodeEnabled(Consume());
-      out_expr->reset(new MemoryFillExpr(loc));
+      CHECK_RESULT(ParseMemoryExpr<MemoryFillExpr>(loc, out_expr));
       break;
 
     case TokenType::DataDrop:
@@ -1969,17 +2199,17 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) {
 
     case TokenType::MemoryInit:
       ErrorUnlessOpcodeEnabled(Consume());
-      CHECK_RESULT(ParsePlainInstrVar<MemoryInitExpr>(loc, out_expr));
+      CHECK_RESULT(ParseMemoryInstrVar<MemoryInitExpr>(loc, out_expr));
       break;
 
     case TokenType::MemorySize:
       Consume();
-      out_expr->reset(new MemorySizeExpr(loc));
+      CHECK_RESULT(ParseMemoryExpr<MemorySizeExpr>(loc, out_expr));
       break;
 
     case TokenType::MemoryGrow:
       Consume();
-      out_expr->reset(new MemoryGrowExpr(loc));
+      CHECK_RESULT(ParseMemoryExpr<MemoryGrowExpr>(loc, out_expr));
       break;
 
     case TokenType::TableCopy: {
@@ -2153,42 +2383,14 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) {
     }
 
     case TokenType::SimdLoadLane: {
-      Token token = Consume();
-      ErrorUnlessOpcodeEnabled(token);
-
-      Address offset;
-      Address align;
-      ParseOffsetOpt(&offset);
-      ParseAlignOpt(&align);
-
-      uint64_t lane_idx = 0;
-      Result result = ParseSimdLane(loc, &lane_idx);
-
-      if (Failed(result)) {
-        return Result::Error;
-      }
-
-      out_expr->reset(new SimdLoadLaneExpr(token.opcode(), align, offset, lane_idx, loc));
+      CHECK_RESULT(
+          ParseSIMDLoadStoreInstr<SimdLoadLaneExpr>(loc, Consume(), out_expr));
       break;
     }
 
     case TokenType::SimdStoreLane: {
-      Token token = Consume();
-      ErrorUnlessOpcodeEnabled(token);
-
-      Address offset;
-      Address align;
-      ParseOffsetOpt(&offset);
-      ParseAlignOpt(&align);
-
-      uint64_t lane_idx = 0;
-      Result result = ParseSimdLane(loc, &lane_idx);
-
-      if (Failed(result)) {
-        return Result::Error;
-      }
-
-      out_expr->reset(new SimdStoreLaneExpr(token.opcode(), align, offset, lane_idx, loc));
+      CHECK_RESULT(
+          ParseSIMDLoadStoreInstr<SimdStoreLaneExpr>(loc, Consume(), out_expr));
       break;
     }
 
@@ -2207,8 +2409,7 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) {
         values.set_u8(lane, static_cast<uint8_t>(lane_idx));
       }
 
-      out_expr->reset(
-          new SimdShuffleOpExpr(token.opcode(), values, loc));
+      out_expr->reset(new SimdShuffleOpExpr(token.opcode(), values, loc));
       break;
     }
 
@@ -2236,13 +2437,11 @@ Result WastParser::ParseSimdV128Const(Const* const_,
     case TokenType::F32X4: { lane_count = 4; integer = false; break; }
     case TokenType::F64X2: { lane_count = 2; integer = false; break; }
     default: {
-      Error(
-        const_->loc,
-        "Unexpected type at start of simd constant. "
-        "Expected one of: i8x16, i16x8, i32x4, i64x2, f32x4, f64x2. "
-        "Found \"%s\".",
-        GetTokenTypeName(token_type)
-      );
+      Error(const_->loc,
+            "Unexpected type at start of simd constant. "
+            "Expected one of: i8x16, i16x8, i32x4, i64x2, f32x4, f64x2. "
+            "Found \"%s\".",
+            GetTokenTypeName(token_type));
       return Result::Error;
     }
   }
@@ -2363,7 +2562,13 @@ Result WastParser::ParseF32(Const* const_, ConstType const_type) {
     const_->set_f32(expected);
     return Result::Ok;
   }
-  auto literal = Consume().literal();
+
+  auto token = Consume();
+  if (!token.HasLiteral()) {
+    return Result::Error;
+  }
+
+  auto literal = token.literal();
   uint32_t f32_bits;
   Result result = ParseFloat(literal.type, literal.text.begin(),
                              literal.text.end(), &f32_bits);
@@ -2378,7 +2583,13 @@ Result WastParser::ParseF64(Const* const_, ConstType const_type) {
     const_->set_f64(expected);
     return Result::Ok;
   }
-  auto literal = Consume().literal();
+
+  auto token = Consume();
+  if (!token.HasLiteral()) {
+    return Result::Error;
+  }
+
+  auto literal = token.literal();
   uint64_t f64_bits;
   Result result = ParseDouble(literal.type, literal.text.begin(),
                               literal.text.end(), &f64_bits);
@@ -2412,7 +2623,11 @@ Result WastParser::ParseConst(Const* const_, ConstType const_type) {
   Result result;
   switch (opcode) {
     case Opcode::I32Const: {
-      auto sv = Consume().literal().text;
+      auto token = Consume();
+      if (!token.HasLiteral()) {
+        return Result::Error;
+      }
+      auto sv = token.literal().text;
       uint32_t u32;
       result = ParseInt32(sv.begin(), sv.end(), &u32,
                           ParseIntType::SignedAndUnsigned);
@@ -2421,7 +2636,11 @@ Result WastParser::ParseConst(Const* const_, ConstType const_type) {
     }
 
     case Opcode::I64Const: {
-      auto sv = Consume().literal().text;
+      auto token = Consume();
+      if (!token.HasLiteral()) {
+        return Result::Error;
+      }
+      auto sv = token.literal().text;
       uint64_t u64;
       result = ParseInt64(sv.begin(), sv.end(), &u64,
                           ParseIntType::SignedAndUnsigned);
@@ -2872,11 +3091,15 @@ Result WastParser::ParseGlobalType(Global* global) {
   WABT_TRACE(ParseGlobalType);
   if (MatchLpar(TokenType::Mut)) {
     global->mutable_ = true;
-    CHECK_RESULT(ParseValueType(&global->type));
+    Var type;
+    CHECK_RESULT(ParseValueType(&type));
+    global->type = Type(type.index());
     CHECK_RESULT(ErrorIfLpar({"i32", "i64", "f32", "f64"}));
     EXPECT(Rpar);
   } else {
-    CHECK_RESULT(ParseValueType(&global->type));
+    Var type;
+    CHECK_RESULT(ParseValueType(&type));
+    global->type = Type(type.index());
   }
 
   return Result::Ok;
@@ -2899,6 +3122,9 @@ Result WastParser::ParseCommandList(Script* script,
 Result WastParser::ParseCommand(Script* script, CommandPtr* out_command) {
   WABT_TRACE(ParseCommand);
   switch (Peek(1)) {
+    case TokenType::AssertException:
+      return ParseAssertExceptionCommand(out_command);
+
     case TokenType::AssertExhaustion:
       return ParseAssertExhaustionCommand(out_command);
 
@@ -2939,6 +3165,12 @@ Result WastParser::ParseCommand(Script* script, CommandPtr* out_command) {
   }
 }
 
+Result WastParser::ParseAssertExceptionCommand(CommandPtr* out_command) {
+  WABT_TRACE(ParseAssertExceptionCommand);
+  return ParseAssertActionCommand<AssertExceptionCommand>(
+      TokenType::AssertException, out_command);
+}
+
 Result WastParser::ParseAssertExhaustionCommand(CommandPtr* out_command) {
   WABT_TRACE(ParseAssertExhaustionCommand);
   return ParseAssertActionTextCommand<AssertExhaustionCommand>(
@@ -3029,7 +3261,7 @@ Result WastParser::ParseModuleCommand(Script* script, CommandPtr* out_command) {
                    &errors, &module);
       module.name = bsm->name;
       module.loc = bsm->loc;
-      for (const auto& error: errors) {
+      for (const auto& error : errors) {
         assert(error.error_level == ErrorLevel::Error);
         if (error.loc.offset == kInvalidOffset) {
           Error(bsm->loc, "error in binary module: %s", error.message.c_str());
index ea762357b72c0f415e699bbab8ff799d976432d8..8c799b7ff2fad830dbec3a6c5512659f792ca1c2 100644 (file)
@@ -18,6 +18,7 @@
 #define WABT_WAST_PARSER_H_
 
 #include <array>
+#include <unordered_map>
 
 #include "src/circular-array.h"
 #include "src/error.h"
@@ -81,7 +82,7 @@ class WastParser {
   TokenTypePair PeekPair();
 
   // Returns true if the next token's type is equal to the parameter.
-  bool PeekMatch(TokenType);
+  bool PeekMatch(TokenType, size_t n = 0);
 
   // Returns true if the next token's type is '(' and the following token is
   // equal to the parameter.
@@ -91,6 +92,9 @@ class WastParser {
   // folded expressions, plain instructions and block instructions.
   bool PeekMatchExpr();
 
+  // Returns true if the next two tokens are form reference type - (ref $t)
+  bool PeekMatchRefType();
+
   // Returns true if the next token's type is equal to the parameter. If so,
   // then the token is consumed.
   bool Match(TokenType);
@@ -126,17 +130,20 @@ class WastParser {
   Result ParseTextList(std::vector<uint8_t>* out_data);
   bool ParseTextListOpt(std::vector<uint8_t>* out_data);
   Result ParseVarList(VarVector* out_var_list);
-  bool ParseElemExprOpt(ElemExpr* out_elem_expr);
-  bool ParseElemExprListOpt(ElemExprVector* out_list);
-  bool ParseElemExprVarListOpt(ElemExprVector* out_list);
-  Result ParseValueType(Type* out_type);
-  Result ParseValueTypeList(TypeVector* out_type_list);
+  bool ParseElemExprOpt(ExprList* out_elem_expr);
+  bool ParseElemExprListOpt(ExprListVector* out_list);
+  bool ParseElemExprVarListOpt(ExprListVector* out_list);
+  Result ParseValueType(Var* out_type);
+  Result ParseValueTypeList(
+      TypeVector* out_type_list,
+      std::unordered_map<uint32_t, std::string>* type_names);
   Result ParseRefKind(Type* out_type);
   Result ParseRefType(Type* out_type);
   bool ParseRefTypeOpt(Type* out_type);
   Result ParseQuotedText(std::string* text);
   bool ParseOffsetOpt(Address* offset);
   bool ParseAlignOpt(Address* align);
+  Result ParseMemidx(Location loc, Var* memidx);
   Result ParseLimitsIndex(Limits*);
   Result ParseLimits(Limits*);
   Result ParseNat(uint64_t*, bool is_64);
@@ -164,9 +171,13 @@ class WastParser {
   Result ParseBoundValueTypeList(TokenType,
                                  TypeVector*,
                                  BindingHash*,
+                                 std::unordered_map<uint32_t, std::string>*,
                                  Index binding_index_offset = 0);
-  Result ParseUnboundValueTypeList(TokenType, TypeVector*);
-  Result ParseResultList(TypeVector*);
+  Result ParseUnboundValueTypeList(TokenType,
+                                   TypeVector*,
+                                   std::unordered_map<uint32_t, std::string>*);
+  Result ParseResultList(TypeVector*,
+                         std::unordered_map<uint32_t, std::string>*);
   Result ParseInstrList(ExprList*);
   Result ParseTerminatingInstrList(ExprList*);
   Result ParseInstr(ExprList*);
@@ -193,11 +204,24 @@ class WastParser {
   template <typename T>
   Result ParsePlainInstrVar(Location, std::unique_ptr<Expr>*);
   template <typename T>
+  Result ParseMemoryInstrVar(Location, std::unique_ptr<Expr>*);
+  template <typename T>
   Result ParsePlainLoadStoreInstr(Location, Token, std::unique_ptr<Expr>*);
+  template <typename T>
+  Result ParseMemoryLoadStoreInstr(Location, Token, std::unique_ptr<Expr>*);
+  template <typename T>
+  Result ParseSIMDLoadStoreInstr(Location loc,
+                                 Token token,
+                                 std::unique_ptr<Expr>* out_expr);
+  template <typename T>
+  Result ParseMemoryExpr(Location, std::unique_ptr<Expr>*);
+  template <typename T>
+  Result ParseMemoryBinaryExpr(Location, std::unique_ptr<Expr>*);
   Result ParseSimdLane(Location, uint64_t*);
 
   Result ParseCommandList(Script*, CommandPtrVector*);
   Result ParseCommand(Script*, CommandPtr*);
+  Result ParseAssertExceptionCommand(CommandPtr*);
   Result ParseAssertExhaustionCommand(CommandPtr*);
   Result ParseAssertInvalidCommand(CommandPtr*);
   Result ParseAssertMalformedCommand(CommandPtr*);
index 6483224b7f447862ba86fa8883a830b09ee9f03c..701134ce3c725d7e952c7448608b426406d30405 100644 (file)
@@ -30,8 +30,8 @@
 #include "src/cast.h"
 #include "src/common.h"
 #include "src/expr-visitor.h"
-#include "src/ir.h"
 #include "src/ir-util.h"
+#include "src/ir.h"
 #include "src/literal.h"
 #include "src/stream.h"
 
@@ -91,8 +91,9 @@ struct ExprTree {
 
 class WatWriter : ModuleContext {
  public:
-  WatWriter(Stream* stream, const WriteWatOptions& options,
-            const Module &module)
+  WatWriter(Stream* stream,
+            const WriteWatOptions& options,
+            const Module& module)
       : ModuleContext(module), options_(options), stream_(stream) {}
 
   Result WriteModule();
@@ -122,6 +123,10 @@ class WatWriter : ModuleContext {
   void WriteQuotedString(string_view str, NextChar next_char);
   void WriteVar(const Var& var, NextChar next_char);
   void WriteVarUnlessZero(const Var& var, NextChar next_char);
+  void WriteMemoryVarUnlessZero(const Var& memidx, NextChar next_char);
+  void WriteTwoMemoryVarsUnlessBothZero(const Var& srcmemidx,
+                                        const Var& destmemidx,
+                                        NextChar next_char);
   void WriteBrVar(const Var& var, NextChar next_char);
   void WriteRefKind(Type type, NextChar next_char);
   void WriteType(Type type, NextChar next_char);
@@ -135,6 +140,8 @@ class WatWriter : ModuleContext {
   void WriteExpr(const Expr* expr);
   template <typename T>
   void WriteLoadStoreExpr(const Expr* expr);
+  template <typename T>
+  void WriteMemoryLoadStoreExpr(const Expr* expr);
   void WriteExprList(const ExprList& exprs);
   void WriteInitExpr(const ExprList& expr);
   template <typename T>
@@ -375,6 +382,27 @@ void WatWriter::WriteVarUnlessZero(const Var& var, NextChar next_char) {
   }
 }
 
+void WatWriter::WriteMemoryVarUnlessZero(const Var& memidx,
+                                         NextChar next_char) {
+  if (module.GetMemoryIndex(memidx) != 0) {
+    WriteVar(memidx, next_char);
+  } else {
+    next_char_ = next_char;
+  }
+}
+
+void WatWriter::WriteTwoMemoryVarsUnlessBothZero(const Var& srcmemidx,
+                                                 const Var& destmemidx,
+                                                 NextChar next_char) {
+  if (module.GetMemoryIndex(srcmemidx) != 0 ||
+      module.GetMemoryIndex(destmemidx) != 0) {
+    WriteVar(srcmemidx, NextChar::Space);
+    WriteVar(destmemidx, next_char);
+  } else {
+    next_char_ = next_char;
+  }
+}
+
 void WatWriter::WriteBrVar(const Var& var, NextChar next_char) {
   if (var.is_index()) {
     if (var.index() < GetLabelStackSize()) {
@@ -394,9 +422,7 @@ void WatWriter::WriteRefKind(Type type, NextChar next_char) {
 }
 
 void WatWriter::WriteType(Type type, NextChar next_char) {
-  const char* type_name = type.GetName();
-  assert(type_name);
-  WritePuts(type_name, next_char);
+  WritePuts(type.GetName().c_str(), next_char);
 }
 
 void WatWriter::WriteTypes(const TypeVector& types, const char* name) {
@@ -504,6 +530,20 @@ void WatWriter::WriteLoadStoreExpr(const Expr* expr) {
   WriteNewline(NO_FORCE_NEWLINE);
 }
 
+template <typename T>
+void WatWriter::WriteMemoryLoadStoreExpr(const Expr* expr) {
+  auto typed_expr = cast<T>(expr);
+  WritePutsSpace(typed_expr->opcode.GetName());
+  WriteMemoryVarUnlessZero(typed_expr->memidx, NextChar::Space);
+  if (typed_expr->offset) {
+    Writef("offset=%" PRIaddress, typed_expr->offset);
+  }
+  if (!typed_expr->opcode.IsNaturallyAligned(typed_expr->align)) {
+    Writef("align=%" PRIaddress, typed_expr->align);
+  }
+  WriteNewline(NO_FORCE_NEWLINE);
+}
+
 class WatWriter::ExprVisitorDelegate : public ExprVisitor::Delegate {
  public:
   explicit ExprVisitorDelegate(WatWriter* writer) : writer_(writer) {}
@@ -635,8 +675,7 @@ Result WatWriter::ExprVisitorDelegate::OnCallIndirectExpr(
   return Result::Ok;
 }
 
-Result WatWriter::ExprVisitorDelegate::OnCallRefExpr(
-    CallRefExpr* expr) {
+Result WatWriter::ExprVisitorDelegate::OnCallRefExpr(CallRefExpr* expr) {
   writer_->WritePutsSpace(Opcode::CallRef_Opcode.GetName());
   return Result::Ok;
 }
@@ -695,7 +734,7 @@ Result WatWriter::ExprVisitorDelegate::EndIfExpr(IfExpr* expr) {
 }
 
 Result WatWriter::ExprVisitorDelegate::OnLoadExpr(LoadExpr* expr) {
-  writer_->WriteLoadStoreExpr<LoadExpr>(expr);
+  writer_->WriteMemoryLoadStoreExpr<LoadExpr>(expr);
   return Result::Ok;
 }
 
@@ -729,7 +768,10 @@ Result WatWriter::ExprVisitorDelegate::EndLoopExpr(LoopExpr* expr) {
 }
 
 Result WatWriter::ExprVisitorDelegate::OnMemoryCopyExpr(MemoryCopyExpr* expr) {
-  writer_->WritePutsNewline(Opcode::MemoryCopy_Opcode.GetName());
+  writer_->WritePutsSpace(Opcode::MemoryCopy_Opcode.GetName());
+  writer_->WriteTwoMemoryVarsUnlessBothZero(expr->srcmemidx, expr->destmemidx,
+                                            NextChar::Space);
+  writer_->WriteNewline(NO_FORCE_NEWLINE);
   return Result::Ok;
 }
 
@@ -740,23 +782,31 @@ Result WatWriter::ExprVisitorDelegate::OnDataDropExpr(DataDropExpr* expr) {
 }
 
 Result WatWriter::ExprVisitorDelegate::OnMemoryFillExpr(MemoryFillExpr* expr) {
-  writer_->WritePutsNewline(Opcode::MemoryFill_Opcode.GetName());
+  writer_->WritePutsSpace(Opcode::MemoryFill_Opcode.GetName());
+  writer_->WriteMemoryVarUnlessZero(expr->memidx, NextChar::Space);
+  writer_->WriteNewline(NO_FORCE_NEWLINE);
   return Result::Ok;
 }
 
 Result WatWriter::ExprVisitorDelegate::OnMemoryGrowExpr(MemoryGrowExpr* expr) {
-  writer_->WritePutsNewline(Opcode::MemoryGrow_Opcode.GetName());
+  writer_->WritePutsSpace(Opcode::MemoryGrow_Opcode.GetName());
+  writer_->WriteMemoryVarUnlessZero(expr->memidx, NextChar::Space);
+  writer_->WriteNewline(NO_FORCE_NEWLINE);
   return Result::Ok;
 }
 
 Result WatWriter::ExprVisitorDelegate::OnMemorySizeExpr(MemorySizeExpr* expr) {
-  writer_->WritePutsNewline(Opcode::MemorySize_Opcode.GetName());
+  writer_->WritePutsSpace(Opcode::MemorySize_Opcode.GetName());
+  writer_->WriteMemoryVarUnlessZero(expr->memidx, NextChar::Space);
+  writer_->WriteNewline(NO_FORCE_NEWLINE);
   return Result::Ok;
 }
 
 Result WatWriter::ExprVisitorDelegate::OnMemoryInitExpr(MemoryInitExpr* expr) {
   writer_->WritePutsSpace(Opcode::MemoryInit_Opcode.GetName());
-  writer_->WriteVar(expr->var, NextChar::Newline);
+  writer_->WriteVar(expr->var, NextChar::Space);
+  writer_->WriteMemoryVarUnlessZero(expr->memidx, NextChar::Space);
+  writer_->WriteNewline(NO_FORCE_NEWLINE);
   return Result::Ok;
 }
 
@@ -865,7 +915,7 @@ Result WatWriter::ExprVisitorDelegate::OnSelectExpr(SelectExpr* expr) {
 }
 
 Result WatWriter::ExprVisitorDelegate::OnStoreExpr(StoreExpr* expr) {
-  writer_->WriteLoadStoreExpr<StoreExpr>(expr);
+  writer_->WriteMemoryLoadStoreExpr<StoreExpr>(expr);
   return Result::Ok;
 }
 
@@ -886,8 +936,8 @@ Result WatWriter::ExprVisitorDelegate::BeginTryExpr(TryExpr* expr) {
   return Result::Ok;
 }
 
-Result WatWriter::ExprVisitorDelegate::OnCatchExpr(
-    TryExpr* expr, Catch* catch_) {
+Result WatWriter::ExprVisitorDelegate::OnCatchExpr(TryExpr* expr,
+                                                   Catch* catch_) {
   writer_->Dedent();
   if (catch_->IsCatchAll()) {
     writer_->WritePutsNewline(Opcode::CatchAll_Opcode.GetName());
@@ -977,7 +1027,8 @@ Result WatWriter::ExprVisitorDelegate::OnSimdLaneOpExpr(SimdLaneOpExpr* expr) {
   return Result::Ok;
 }
 
-Result WatWriter::ExprVisitorDelegate::OnSimdLoadLaneExpr(SimdLoadLaneExpr* expr) {
+Result WatWriter::ExprVisitorDelegate::OnSimdLoadLaneExpr(
+    SimdLoadLaneExpr* expr) {
   writer_->WritePutsSpace(expr->opcode.GetName());
   if (expr->offset) {
     writer_->Writef("offset=%" PRIaddress, expr->offset);
@@ -1396,20 +1447,13 @@ void WatWriter::WriteElemSegment(const ElemSegment& segment) {
     WritePuts("func", NextChar::Space);
   }
 
-  for (const ElemExpr& expr : segment.elem_exprs) {
+  for (const ExprList& expr : segment.elem_exprs) {
     if (flags & SegUseElemExprs) {
-      if (expr.kind == ElemExprKind::RefNull) {
-        WriteOpenSpace("ref.null");
-        WriteRefKind(expr.type, NextChar::Space);
-        WriteCloseSpace();
-      } else {
-        WriteOpenSpace("ref.func");
-        WriteVar(expr.var, NextChar::Space);
-        WriteCloseSpace();
-      }
+      WriteInitExpr(expr);
     } else {
-      assert(expr.kind == ElemExprKind::RefFunc);
-      WriteVar(expr.var, NextChar::Space);
+      assert(expr.size() == 1);
+      assert(expr.front().type() == ExprType::RefFunc);
+      WriteVar(cast<const RefFuncExpr>(&expr.front())->var, NextChar::Space);
     }
   }
   WriteCloseNewline();
@@ -1430,6 +1474,7 @@ void WatWriter::WriteDataSegment(const DataSegment& segment) {
   WriteOpenSpace("data");
   WriteNameOrIndex(segment.name, data_segment_index_, NextChar::Space);
   if (segment.kind != SegmentKind::Passive) {
+    WriteMemoryVarUnlessZero(segment.memory_var, NextChar::Space);
     WriteInitExpr(segment.offset);
   }
   WriteQuotedData(segment.data.data(), segment.data.size());
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/check_tidy.py b/lwnode/code/escargotshim/deps/escargot/tools/check_tidy.py
deleted file mode 100755 (executable)
index 779fbef..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2015-present Samsung Electronics Co., Ltd.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from __future__ import print_function
-
-import os
-import subprocess
-import sys
-
-from argparse import ArgumentParser
-from difflib import unified_diff
-#from check_license import CheckLicenser
-from os.path import abspath, dirname, join, relpath, splitext
-
-DEFAULT_DIR = dirname(dirname(abspath(__file__)))
-
-TERM_RED = '\033[1;31m'
-TERM_GREEN = '\033[1;32m'
-TERM_YELLOW = '\033[1;33m'
-TERM_PURPLE = '\033[35m'
-TERM_EMPTY = '\033[0m'
-
-
-clang_format_exts = ['.cpp', '.h']
-skip_dirs = ['build', 'CMakeFiles', 'docs', 'out', 'tools', 'third_party', 'bin', 'kangax', 'octane', 'test262', 'vendortest', '.git']
-skip_files = []
-
-
-class Stats(object):
-    def __init__(self):
-        self.files = 0
-        self.lines = 0
-        self.empty_lines = 0
-        self.errors = 0
-
-
-def is_checked_by_clang(file):
-    _, ext = splitext(file)
-    return ext in clang_format_exts and file not in skip_files
-
-
-def check_tidy(src_dir, update, clang_format, stats):
-    print('processing directory: %s' % src_dir)
-
-    for dirpath, _, filenames in os.walk(src_dir):
-        if any(d in relpath(dirpath, src_dir) for d in skip_dirs):
-            continue
-
-        for file in [join(dirpath, name) for name in filenames if is_checked_by_clang(name)]:
-            def report_error(msg, line=None):
-                print('%s%s:%s %s%s' % (TERM_YELLOW, file, '%d:' % line if line else '', msg, TERM_EMPTY))
-                stats.errors += 1
-
-            with open(file, 'r') as f:
-                original = f.readlines()
-            formatted = subprocess.check_output([clang_format, '-style=file', file])
-
-            if update:
-                with open(file, 'w') as f:
-                    f.write(formatted)
-
-            stats.files += 1
-            stats.lines += len(original)
-
-            for lineno, line in enumerate(original):
-                lineno += 1
-
-                if '\t' in line:
-                    report_error('TAB character', lineno)
-                if '\r' in line:
-                    report_error('CR character', lineno)
-                if line.endswith(' \n') or line.endswith('\t\n'):
-                    report_error('trailing whitespace', lineno)
-                if not line.endswith('\n'):
-                    report_error('line ends without NEW LINE character', lineno)
-
-                if not line.strip():
-                    stats.empty_lines += 1
-
-            diff = list(unified_diff(original, formatted.splitlines(True)))
-            if diff:
-                report_error('format error')
-                for diffline in diff:
-                    print(diffline, end='')
-
-            # if not CheckLicenser.check(file):
-            #     report_error('incorrect license')
-
-
-def main():
-    parser = ArgumentParser(description='Escargot Source Format Checker and Updater')
-    parser.add_argument('--clang-format', metavar='PATH', default='clang-format-6.0',
-                        help='path to clang-format (default: %(default)s)')
-    parser.add_argument('--update', action='store_true',
-                        help='reformat files')
-    parser.add_argument('--dir', metavar='PATH', default=DEFAULT_DIR,
-                        help='directory to process (default: %(default)s)')
-    args = parser.parse_args()
-
-    stats = Stats()
-
-    check_tidy(args.dir, args.update, args.clang_format, stats)
-
-    print()
-    print('* Total number of files: %d' % stats.files)
-    print('* Total lines of code: %d' % stats.lines)
-    print('* Total non-empty lines of code: %d' % (stats.lines - stats.empty_lines))
-    print('%s* Total number of errors: %d%s' % (TERM_RED if stats.errors else TERM_GREEN,
-                                                stats.errors,
-                                                TERM_EMPTY))
-
-    if args.update:
-        print()
-        print('All files reformatted, check for changes with `git diff`.');
-
-    sys.exit(1 if stats.errors else 0)
-
-
-if __name__ == '__main__':
-    main()
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger.py b/lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger.py
deleted file mode 100755 (executable)
index cfce798..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-#!/usr/bin/env python2.7
-
-# Copyright 2015-present Samsung Electronics Co., Ltd.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from __future__ import print_function
-from cmd import Cmd
-from pprint import pprint
-import math
-import socket
-import sys
-import logging
-import time
-import debugger_core
-import codecs
-import locale
-
-# Wrap sys.stdout into a StreamWriter to allow writing unicode.
-sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)
-
-from debugger_websocket import WebSocket
-from debugger_tcp import TcpSocket
-
-def write(string):
-    print(string, end='')
-
-class DebuggerPrompt(Cmd):
-    # pylint: disable=too-many-instance-attributes,too-many-arguments
-    def __init__(self, debugger):
-        Cmd.__init__(self)
-        self.debugger = debugger
-        self.stop = False
-        self.quit = False
-
-    def precmd(self, line):
-        self.stop = False
-        if self.debugger.non_interactive:
-            print("%s" % line)
-        return line
-
-    def postcmd(self, stop, line):
-        return self.stop
-
-    def do_quit(self, _):
-        """ Exit debugger """
-        self.debugger.quit()
-        self.quit = True
-        self.stop = True
-
-    def do_EOF(self, _):
-        """ Exit Escargot debugger """
-        print("Unexpected end of input. Connection closed.")
-        self.debugger.quit()
-        self.quit = True
-        self.stop = True
-
-    def do_display(self, args):
-        """ Toggle source code display after breakpoints """
-        if args:
-            line_num = src_check_args(args)
-            if line_num >= 0:
-                self.debugger.display = line_num
-        else:
-            print("Non-negative integer number expected, 0 turns off this function")
-
-    def do_break(self, args):
-        """ Insert breakpoints on the given lines or functions """
-        if not args:
-            write("Error: Argument expected\n")
-        else:
-            write(self.debugger.set_break(args))
-    do_b = do_break
-
-    def do_list(self, _):
-        """ Lists the available breakpoints """
-        write(self.debugger.breakpoint_list())
-
-    def do_delete(self, args):
-        """ Delete the given breakpoint, use 'delete all|active|pending' to clear all the given breakpoints """
-        write(self.debugger.delete(args))
-
-    def do_continue(self, _):
-        """ Continue execution """
-        self.debugger.do_continue()
-        self.stop = True
-        if not self.debugger.non_interactive:
-            print("Press enter to stop JavaScript execution.")
-    do_c = do_continue
-
-    def do_step(self, _):
-        """ Next breakpoint, step into functions """
-        self.debugger.step()
-        self.stop = True
-    do_s = do_step
-
-    def do_next(self, args):
-        """ Next breakpoint in the same context """
-        self.stop = True
-        if not args:
-            args = 0
-            self.debugger.next()
-            return
-
-        try:
-            args = int(args)
-            if args <= 0:
-                raise ValueError(args)
-
-            while args > 0:
-                self.debugger.next()
-                time.sleep(0.1)
-
-                while True:
-                    result = self.debugger.process_messages()
-                    res_type = result.get_type()
-
-                    if res_type == result.END:
-                        self.quit = True
-                        return
-                    elif res_type == result.TEXT:
-                        write(result.get_text())
-                    elif res_type == result.PROMPT:
-                        break
-
-                args -= 1
-        except ValueError as val_errno:
-            print("Error: expected a positive integer: %s" % val_errno)
-    do_n = do_next
-
-    def do_finish(self, _):
-        """ Continue running until the current function returns """
-        self.debugger.finish()
-        self.stop = True
-    do_f = do_finish
-
-    def do_src(self, args):
-        """ Get current source code """
-        if args:
-            line_num = src_check_args(args)
-            if line_num >= 0:
-                write(self.debugger.print_source(line_num, 0))
-        else:
-            write(self.debugger.print_source(0, 0))
-    do_source = do_src
-
-    def do_scroll(self, _):
-        """ Scroll the source up or down """
-        while True:
-            key = sys.stdin.readline()
-            if key == 'w\n':
-                _scroll_direction(self.debugger, "up")
-            elif key == 's\n':
-                _scroll_direction(self.debugger, "down")
-            elif key == 'q\n':
-                break
-            else:
-                print("Invalid key")
-
-    def do_eval(self, args):
-        """ Evaluate JavaScript source code """
-        self.debugger.eval(args)
-        self.stop = True
-    do_e = do_eval
-
-    def do_backtrace(self, args):
-        """ Get backtrace data from debugger """
-        write(self.debugger.backtrace(args))
-        self.stop = True
-    do_bt = do_backtrace
-
-    def do_scope(self, args):
-        """ Get lexical environment chain """
-        self.debugger.scope_chain(args)
-        self.stop = True
-
-    def do_variables(self, args):
-        """ Get scope variables """
-        write(self.debugger.scope_variables(args))
-        self.stop = True
-
-    def do_object(self, args):
-        """ Get object by index """
-        if not args:
-            write("Error: Argument expected")
-        else:
-            write(self.debugger.object(args))
-        self.stop = True
-
-    def do_dump(self, args):
-        """ Dump all of the debugger data """
-        if args:
-            print("Error: No argument expected")
-        else:
-            pprint(self.debugger.function_list)
-
-
-def _scroll_direction(debugger, direction):
-    """ Helper function for do_scroll """
-    debugger.src_offset_diff = int(max(math.floor(debugger.display / 3), 1))
-    if direction == "up":
-        debugger.src_offset -= debugger.src_offset_diff
-    else:
-        debugger.src_offset += debugger.src_offset_diff
-    print(debugger.print_source(debugger.display, debugger.src_offset)['value'])
-
-
-def src_check_args(args):
-    try:
-        line_num = int(args)
-        if line_num < 0:
-            print("Error: Non-negative integer number expected")
-            return -1
-
-        return line_num
-    except ValueError as val_errno:
-        print("Error: Non-negative integer number expected: %s" % (val_errno))
-        return -1
-
-
-# pylint: disable=too-many-branches,too-many-locals,too-many-statements,redefined-variable-type
-def main():
-    args = debugger_core.arguments_parse()
-
-    tranport = TcpSocket(args.address)
-    protocol = WebSocket(tranport)
-    debugger = debugger_core.Debugger(protocol)
-
-    debugger.non_interactive = args.non_interactive
-
-    logging.debug("Connected to Escargot")
-
-    prompt = DebuggerPrompt(debugger)
-    prompt.prompt = "(escargot-debugger) "
-
-    if args.color:
-        debugger.set_colors()
-
-    if args.display:
-        debugger.display = args.display
-        prompt.do_display(args.display)
-    else:
-        prompt.stop = False
-
-    if args.exception is not None:
-        prompt.do_exception(str(args.exception))
-
-    if args.client_source:
-        debugger.store_client_sources(args.client_source)
-
-    while True:
-        if prompt.quit:
-            break
-
-        result = debugger.process_messages()
-        res_type = result.get_type()
-
-        if res_type == result.END:
-            break
-        elif res_type == result.PROMPT:
-            prompt.cmdloop()
-        elif res_type == result.TEXT:
-            write(result.get_text())
-        continue
-
-
-if __name__ == "__main__":
-    try:
-        main()
-        sys.exit("Connection closed.")
-    except socket.error as error_msg:
-        ERRNO = error_msg.errno
-        MSG = str(error_msg)
-        if ERRNO == 111:
-            sys.exit("Failed to connect to the Escargot debugger.")
-        elif ERRNO == 32 or ERRNO == 104:
-            sys.exit("Connection closed.")
-        else:
-            sys.exit("Failed to connect to the Escargot debugger.\nError: %s" % (MSG))
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger_core.py b/lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger_core.py
deleted file mode 100644 (file)
index 9b80585..0000000
+++ /dev/null
@@ -1,1148 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2015-present Samsung Electronics Co., Ltd.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from __future__ import print_function
-import argparse
-import logging
-import re
-import select
-import struct
-import sys
-
-# Escargot debugger configuration
-ESCARGOT_DEBUGGER_VERSION = 1
-
-# Messages sent by Escargot to the debugger client.
-ESCARGOT_MESSAGE_VERSION = 0
-ESCARGOT_MESSAGE_CONFIGURATION = 1
-ESCARGOT_MESSAGE_CLOSE_CONNECTION = 2
-ESCARGOT_MESSAGE_RELEASE_FUNCTION = 3
-ESCARGOT_MESSAGE_PARSE_DONE = 4
-ESCARGOT_MESSAGE_PARSE_ERROR = 5
-ESCARGOT_MESSAGE_SOURCE_8BIT = 6
-ESCARGOT_MESSAGE_SOURCE_8BIT_END = 7
-ESCARGOT_MESSAGE_SOURCE_16BIT = 8
-ESCARGOT_MESSAGE_SOURCE_16BIT_END = 9
-ESCARGOT_MESSAGE_FILE_NAME_8BIT = 10
-ESCARGOT_MESSAGE_FILE_NAME_8BIT_END = 11
-ESCARGOT_MESSAGE_FILE_NAME_16BIT = 12
-ESCARGOT_MESSAGE_FILE_NAME_16BIT_END = 13
-ESCARGOT_MESSAGE_FUNCTION_NAME_8BIT = 14
-ESCARGOT_MESSAGE_FUNCTION_NAME_8BIT_END = 15
-ESCARGOT_MESSAGE_FUNCTION_NAME_16BIT = 16
-ESCARGOT_MESSAGE_FUNCTION_NAME_16BIT_END = 17
-ESCARGOT_MESSAGE_BREAKPOINT_LOCATION = 18
-ESCARGOT_MESSAGE_FUNCTION_PTR = 19
-ESCARGOT_MESSAGE_BREAKPOINT_HIT = 20
-ESCARGOT_MESSAGE_EXCEPTION_HIT = 21
-ESCARGOT_MESSAGE_EVAL_RESULT_8BIT = 22
-ESCARGOT_MESSAGE_EVAL_RESULT_8BIT_END = 23
-ESCARGOT_MESSAGE_EVAL_RESULT_16BIT = 24
-ESCARGOT_MESSAGE_EVAL_RESULT_16BIT_END = 25
-ESCARGOT_MESSAGE_EVAL_FAILED_8BIT = 26
-ESCARGOT_MESSAGE_EVAL_FAILED_8BIT_END = 27
-ESCARGOT_MESSAGE_EVAL_FAILED_16BIT = 28
-ESCARGOT_MESSAGE_EVAL_FAILED_16BIT_END = 29
-ESCARGOT_MESSAGE_BACKTRACE_TOTAL = 30
-ESCARGOT_MESSAGE_BACKTRACE = 31
-ESCARGOT_MESSAGE_BACKTRACE_END = 32
-ESCARGOT_MESSAGE_SCOPE_CHAIN = 33
-ESCARGOT_MESSAGE_SCOPE_CHAIN_END = 34
-ESCARGOT_MESSAGE_STRING_8BIT = 35
-ESCARGOT_MESSAGE_STRING_8BIT_END = 36
-ESCARGOT_MESSAGE_STRING_16BIT = 37
-ESCARGOT_MESSAGE_STRING_16BIT_END = 38
-ESCARGOT_MESSAGE_VARIABLE = 39
-ESCARGOT_MESSAGE_PRINT = 40
-ESCARGOT_MESSAGE_EXCEPTION = 41
-ESCARGOT_MESSAGE_EXCEPTION_BACKTRACE = 42
-ESCARGOT_DEBUGGER_WAIT_FOR_SOURCE = 43
-ESCARGOT_DEBUGGER_WAITING_AFTER_PENDING = 44
-
-
-# Messages sent by the debugger client to Escargot.
-ESCARGOT_MESSAGE_FUNCTION_RELEASED = 0
-ESCARGOT_MESSAGE_UPDATE_BREAKPOINT = 1
-ESCARGOT_MESSAGE_CONTINUE = 2
-ESCARGOT_MESSAGE_STEP = 3
-ESCARGOT_MESSAGE_NEXT = 4
-ESCARGOT_MESSAGE_FINISH = 5
-ESCARGOT_MESSAGE_EVAL_8BIT_START = 6
-ESCARGOT_MESSAGE_EVAL_8BIT = 7
-ESCARGOT_MESSAGE_EVAL_16BIT_START = 8
-ESCARGOT_MESSAGE_EVAL_16BIT = 9
-ESCARGOT_MESSAGE_GET_BACKTRACE = 10
-ESCARGOT_MESSAGE_GET_SCOPE_CHAIN = 11
-ESCARGOT_MESSAGE_GET_SCOPE_VARIABLES = 12
-ESCARGOT_MESSAGE_GET_OBJECT = 13
-ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT_START = 14
-ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT = 15
-ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT_START = 16
-ESCARGOT_DEBUGGER_CLIENT_SOURCE_16BIT = 17
-ESCARGOT_DEBUGGER_THERE_WAS_NO_SOURCE = 18
-ESCARGOT_DEBUGGER_PENDING_CONFIG = 19
-ESCARGOT_DEBUGGER_PENDING_RESUME = 20
-
-
-# Environment record types
-ESCARGOT_RECORD_GLOBAL_ENVIRONMENT = 0
-ESCARGOT_RECORD_FUNCTION_ENVIRONMENT = 1
-ESCARGOT_RECORD_DECLARATIVE_ENVIRONMENT = 2
-ESCARGOT_RECORD_OBJECT_ENVIRONMENT = 3
-ESCARGOT_RECORD_MODULE_ENVIRONMENT = 4
-ESCARGOT_RECORD_UNKNOWN_ENVIRONMENT = 5
-
-
-# Variable types
-ESCARGOT_VARIABLE_END = 0
-ESCARGOT_VARIABLE_UNACCESSIBLE = 1
-ESCARGOT_VARIABLE_UNDEFINED = 2
-ESCARGOT_VARIABLE_NULL = 3
-ESCARGOT_VARIABLE_TRUE = 4
-ESCARGOT_VARIABLE_FALSE = 5
-ESCARGOT_VARIABLE_NUMBER = 6
-ESCARGOT_VARIABLE_STRING = 7
-ESCARGOT_VARIABLE_SYMBOL = 8
-ESCARGOT_VARIABLE_BIGINT = 9
-ESCARGOT_VARIABLE_OBJECT = 10
-ESCARGOT_VARIABLE_ARRAY = 11
-ESCARGOT_VARIABLE_FUNCTION = 12
-ESCARGOT_VARIABLE_LONG_NAME = 0x40
-ESCARGOT_VARIABLE_LONG_VALUE = 0x80
-
-
-def arguments_parse():
-    parser = argparse.ArgumentParser(description="Escargot debugger client")
-
-    parser.add_argument("address", action="store", nargs="?", default="localhost:6501",
-                        help="specify a unique network address for tcp connection (default: %(default)s)")
-    parser.add_argument("-v", "--verbose", action="store_true", default=False,
-                        help="increase verbosity (default: %(default)s)")
-    parser.add_argument("--non-interactive", action="store_true", default=False,
-                        help="disable stop when newline is pressed (default: %(default)s)")
-    parser.add_argument("--color", action="store_true", default=False,
-                        help="enable color highlighting on source commands (default: %(default)s)")
-    parser.add_argument("--display", action="store", default=None, type=int,
-                        help="set display range")
-    parser.add_argument("--exception", action="store", default=None, type=int, choices=[0, 1],
-                        help="set exception config, usage 1: [Enable] or 0: [Disable]")
-    parser.add_argument("--client-source", action="store", default=[], type=str, nargs="+",
-                        help="specify a javascript source file to execute")
-    args = parser.parse_args()
-
-    if args.verbose:
-        logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.DEBUG)
-        logging.debug("Debug logging mode: ON")
-
-    return args
-
-
-def _parse_int(value):
-    try:
-        index = int(value)
-        if index < 0:
-             return "Error: A non negative integer number expected"
-        return index
-
-    except ValueError as val_errno:
-        return "Error: Non negative integer number expected, %s\n" % (val_errno)
-
-
-class Breakpoint(object):
-    def __init__(self, line, offset, function):
-        self.line = line
-        self.offset = offset
-        self.function = function
-        self.active_index = -1
-
-    def __str__(self):
-        result = self.function.source_name or "<unknown>"
-        result += ":%d" % (self.line)
-
-        if self.function.is_func:
-            result += " (in "
-            result += self.function.name or "function"
-            result += "() at line:%d, col:%d)" % (self.function.line, self.function.column)
-        return result
-
-    def __repr__(self):
-        return ("Breakpoint(line:%d, offset:%d, active_index:%d)"
-                % (self.line, self.offset, self.active_index))
-
-class PendingBreakpoint(object):
-    def __init__(self, line=None, source_name=None, function=None):
-        self.function = function
-        self.line = line
-        self.source_name = source_name
-
-        self.index = -1
-
-    def __str__(self):
-        result = self.source_name or ""
-        if self.line:
-            result += ":%d" % (self.line)
-        else:
-            result += "%s()" % (self.function)
-        return result
-
-class EscargotFunction(object):
-    # pylint: disable=too-many-instance-attributes,too-many-arguments
-    def __init__(self, is_func, function_info, source, source_name, name, locations):
-        self.is_func = is_func
-        self.byte_code_ptr = function_info[0]
-        self.source = re.split("\r\n|[\r\n]", source)
-        self.source_name = source_name
-        self.name = name
-        self.lines = {}
-        self.offsets = {}
-        self.line = function_info[1]
-        self.column = function_info[2]
-        self.first_breakpoint_line = locations[0][0]
-        self.first_breakpoint_offset = locations[0][1]
-
-        if len(self.source) > 1 and not self.source[-1]:
-            self.source.pop()
-
-        for location in locations:
-            breakpoint = Breakpoint(location[0], location[1], self)
-            self.lines[location[0]] = breakpoint
-            self.offsets[location[1]] = breakpoint
-
-    def __repr__(self):
-        result = ("Function(byte_code_ptr:0x%x, source_name:%r, name:%r { "
-                  % (self.byte_code_ptr, self.source_name, self.name))
-
-        result += ','.join([str(breakpoint) for breakpoint in self.lines.values()])
-
-        return result + " })"
-
-
-class Multimap(object):
-
-    def __init__(self):
-        self.map = {}
-
-    def get(self, key):
-        if key in self.map:
-            return self.map[key]
-        return []
-
-    def insert(self, key, value):
-        if key in self.map:
-            self.map[key].append(value)
-        else:
-            self.map[key] = [value]
-
-    def delete(self, key, value):
-        items = self.map[key]
-
-        if len(items) == 1:
-            del self.map[key]
-        else:
-            del items[items.index(value)]
-
-    def __repr__(self):
-        return "Multimap(%r)" % (self.map)
-
-
-class DebuggerAction(object):
-    END = 0
-    WAIT = 1
-    TEXT = 2
-    PROMPT = 3
-
-    def __init__(self, action_type, action_text):
-        self.action_type = action_type
-        self.action_text = action_text
-
-    def get_type(self):
-        return self.action_type
-
-    def get_text(self):
-        return self.action_text
-
-
-class Debugger(object):
-    # pylint: disable=too-many-instance-attributes,too-many-statements,too-many-public-methods,no-self-use,redefined-variable-type
-    def __init__(self, channel):
-        self.prompt = False
-        self.function_list = {}
-        self.source = ''
-        self.source_name = ''
-        self.exception_string = ''
-        self.frame_index = 0
-        self.scope_vars = ""
-        self.scopes = ""
-        self.no_scope = 4294967295
-        self.client_sources = []
-        self.last_breakpoint_hit = None
-        self.next_breakpoint_index = 0
-        self.active_breakpoint_list = {}
-        self.pending_breakpoint_list = {}
-        self.line_list = Multimap()
-        self.display = 0
-        self.green = ''
-        self.red = ''
-        self.yellow = ''
-        self.green_bg = ''
-        self.yellow_bg = ''
-        self.blue = ''
-        self.nocolor = ''
-        self.src_offset = 0
-        self.src_offset_diff = 0
-        self.non_interactive = False
-        self.current_out = b""
-        self.current_log = b""
-        self.channel = channel
-
-        # The server will send the version message after connection established
-        # type [1]
-        # littleEndian [1]
-        # version [4]
-        result = self.channel.connect()
-
-        if len(result) != 6 or ord(result[0]) != ESCARGOT_MESSAGE_VERSION:
-            raise Exception("Unexpected version info")
-
-        self.little_endian = ord(result[1]) != 0
-
-        if self.little_endian:
-            self.byte_order = "<"
-            logging.debug("Little-endian machine")
-        else:
-            self.byte_order = ">"
-            logging.debug("Big-endian machine")
-
-        self.version = struct.unpack(self.byte_order + 'I', result[2:6])[0]
-        if self.version != ESCARGOT_DEBUGGER_VERSION:
-            raise Exception("Incorrect debugger version from target: %d expected: %d" %
-                            (self.version, ESCARGOT_DEBUGGER_VERSION))
-
-        result = self.channel.get_message(True)
-
-        print("Connection created!!!")
-
-        self.max_message_size = ord(result[1])
-        self.pointer_size = ord(result[2])
-
-        if self.pointer_size == 8:
-            self.pointer_format = "Q"
-        elif self.pointer_size == 4:
-            self.pointer_format = "I"
-        else:
-            raise Exception("Unsupported pointer size: %d" % (self.pointer_size))
-
-        self.idx_format = "I"
-
-        logging.debug("Pointer size: %d", self.pointer_size)
-
-    def __del__(self):
-        if self.channel is not None:
-            self.channel.close()
-
-    def decode8(self, string):
-        return string.decode("latin1")
-
-    def decode16(self, string):
-        return string.decode("UTF-16LE" if self.little_endian else "UTF-16BE", "namereplace")
-
-    # pylint: disable=too-many-branches,too-many-locals,too-many-statements,too-many-return-statements
-    def process_messages(self):
-        result = ""
-        while True:
-            data = self.channel.get_message(False)
-            if not self.non_interactive:
-                if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
-                    sys.stdin.readline()
-                    self.step()
-
-            if data == b'':
-                action_type = DebuggerAction.PROMPT if self.prompt else DebuggerAction.WAIT
-                return DebuggerAction(action_type, "")
-
-            if not data:  # Break the while loop if there is no more data.
-                return DebuggerAction(DebuggerAction.END, "")
-
-            buffer_type = ord(data[0])
-            buffer_size = len(data) - 1
-
-            logging.debug("Main buffer type: %d, message size: %d", buffer_type, buffer_size)
-
-            if buffer_type in [ESCARGOT_MESSAGE_PARSE_ERROR,
-                               ESCARGOT_MESSAGE_SOURCE_8BIT,
-                               ESCARGOT_MESSAGE_SOURCE_8BIT_END,
-                               ESCARGOT_MESSAGE_SOURCE_16BIT,
-                               ESCARGOT_MESSAGE_SOURCE_16BIT_END]:
-                result = self._parse_source(data)
-                if result:
-                    return DebuggerAction(DebuggerAction.TEXT, result)
-
-            elif buffer_type == ESCARGOT_DEBUGGER_WAITING_AFTER_PENDING:
-                self._exec_command(ESCARGOT_DEBUGGER_PENDING_RESUME)
-
-            elif buffer_type == ESCARGOT_MESSAGE_CLOSE_CONNECTION:
-                return DebuggerAction(DebuggerAction.END, "")
-
-            elif buffer_type == ESCARGOT_MESSAGE_RELEASE_FUNCTION:
-                self._release_function(data)
-
-            elif buffer_type == ESCARGOT_MESSAGE_BREAKPOINT_HIT:
-                breakpoint_data = struct.unpack(self.byte_order + self.pointer_format + self.idx_format, data[1:])
-
-                breakpoint = self._get_breakpoint(breakpoint_data)
-                self.last_breakpoint_hit = breakpoint[0]
-
-                if breakpoint[1]:
-                    breakpoint_info = "at"
-                else:
-                    breakpoint_info = "around"
-
-                if breakpoint[0].active_index >= 0:
-                    breakpoint_info += " breakpoint:%s%d%s" % (self.red, breakpoint[0].active_index, self.nocolor)
-
-                result += "Stopped %s %s\n" % (breakpoint_info, breakpoint[0])
-
-                if self.display > 0:
-                    result += self.print_source(self.display, self.src_offset)
-
-                self.prompt = True
-                return DebuggerAction(DebuggerAction.TEXT, result)
-
-            elif buffer_type == ESCARGOT_MESSAGE_BACKTRACE_TOTAL:
-                total = struct.unpack(self.byte_order + self.idx_format, data[1:])[0]
-                result += "Total number of frames: %d\n" % (total)
-                return DebuggerAction(DebuggerAction.TEXT, result)
-
-            elif buffer_type in [ESCARGOT_MESSAGE_EVAL_RESULT_8BIT,
-                                 ESCARGOT_MESSAGE_EVAL_RESULT_8BIT_END,
-                                 ESCARGOT_MESSAGE_EVAL_RESULT_16BIT,
-                                 ESCARGOT_MESSAGE_EVAL_RESULT_16BIT_END]:
-                self.prompt = True
-                return DebuggerAction(DebuggerAction.TEXT, self._receive_string(ESCARGOT_MESSAGE_EVAL_RESULT_8BIT, data));
-
-            elif buffer_type in [ESCARGOT_MESSAGE_EVAL_FAILED_8BIT,
-                                 ESCARGOT_MESSAGE_EVAL_FAILED_8BIT_END,
-                                 ESCARGOT_MESSAGE_EVAL_FAILED_16BIT,
-                                 ESCARGOT_MESSAGE_EVAL_FAILED_16BIT_END]:
-                self.prompt = True
-                result = self._receive_string(ESCARGOT_MESSAGE_EVAL_RESULT_8BIT, data);
-                return DebuggerAction(DebuggerAction.TEXT, "%sException: %s%s" % (self.red, result, self.no_color));
-
-            elif buffer_type in [ESCARGOT_MESSAGE_BACKTRACE,
-                                 ESCARGOT_MESSAGE_EXCEPTION_BACKTRACE]:
-                backtrace_info = struct.unpack(self.byte_order + self.pointer_format + self.idx_format + self.idx_format + self.idx_format, data[1:])
-                function = self.function_list.get(backtrace_info[0])
-
-                depth = ""
-                if backtrace_info[3] != self.no_scope:
-                    depth = " [depth:%d]" % backtrace_info[3]
-
-                if function is not None:
-                    result = "%s:%d:%d%s" % (function.source_name, backtrace_info[1], backtrace_info[2], depth)
-                    if function.name != "":
-                        result += " (in %s)" % (function.name)
-                else:
-                    result = "unknown dynamic function:%d:%d%s" % (backtrace_info[1], backtrace_info[2], depth)
-
-                if buffer_type == ESCARGOT_MESSAGE_BACKTRACE:
-                    return DebuggerAction(DebuggerAction.TEXT, result + "\n")
-                return DebuggerAction(DebuggerAction.TEXT, "%s%s%s\n" % (self.red, result, self.nocolor))
-
-            elif buffer_type == ESCARGOT_MESSAGE_BACKTRACE_END:
-                self.prompt = True
-                return DebuggerAction(DebuggerAction.WAIT, "")
-
-            elif buffer_type in [ESCARGOT_MESSAGE_SCOPE_CHAIN,
-                                 ESCARGOT_MESSAGE_SCOPE_CHAIN_END]:
-                scope_chain = ""
-
-                while buffer_type == ESCARGOT_MESSAGE_SCOPE_CHAIN:
-                    scope_chain += data[1:]
-                    data = self.channel.get_message(True)
-                    buffer_type = ord(data[0])
-
-                if buffer_type != ESCARGOT_MESSAGE_SCOPE_CHAIN_END:
-                    raise Exception("Unexpected message")
-
-                scope_chain += data[1:]
-                result = ""
-
-                for env_type in scope_chain:
-                    env_type = ord(env_type)
-                    if env_type == ESCARGOT_RECORD_GLOBAL_ENVIRONMENT:
-                        result += "Global Environment\n"
-                    elif env_type == ESCARGOT_RECORD_FUNCTION_ENVIRONMENT:
-                        result += "Function Environment\n"
-                    elif env_type == ESCARGOT_RECORD_DECLARATIVE_ENVIRONMENT:
-                        result += "Declarative Environment\n"
-                    elif env_type == ESCARGOT_RECORD_OBJECT_ENVIRONMENT:
-                        result += "Object Environment\n"
-                    elif env_type == ESCARGOT_RECORD_MODULE_ENVIRONMENT:
-                        result += "Module Environment\n"
-                    else:
-                        result += "Unknown Environment\n"
-
-                self.prompt = True
-                return DebuggerAction(DebuggerAction.TEXT, result)
-
-            elif buffer_type == ESCARGOT_MESSAGE_VARIABLE:
-                variable_full_type = ord(data[1])
-                variable_type = variable_full_type & 0x3f
-                variable_has_value = False
-
-                if variable_type == ESCARGOT_VARIABLE_END:
-                    self.prompt = True
-                    return DebuggerAction(DebuggerAction.WAIT, "")
-                elif variable_type == ESCARGOT_VARIABLE_UNACCESSIBLE:
-                    value_str = "unaccessible"
-                elif variable_type == ESCARGOT_VARIABLE_UNDEFINED:
-                    value_str = "undefined"
-                elif variable_type == ESCARGOT_VARIABLE_NULL:
-                    value_str = "null"
-                elif variable_type == ESCARGOT_VARIABLE_TRUE:
-                    value_str = "boolean: true"
-                elif variable_type == ESCARGOT_VARIABLE_FALSE:
-                    value_str = "boolean: false"
-                elif variable_type == ESCARGOT_VARIABLE_NUMBER:
-                    value_str = "number: "
-                    variable_has_value = True
-                elif variable_type == ESCARGOT_VARIABLE_STRING:
-                    value_str = "string: "
-                    variable_has_value = True
-                elif variable_type == ESCARGOT_VARIABLE_SYMBOL:
-                    value_str = "symbol: "
-                    variable_has_value = True
-                elif variable_type == ESCARGOT_VARIABLE_BIGINT:
-                    value_str = "bigint: "
-                    variable_has_value = True
-                elif variable_type == ESCARGOT_VARIABLE_OBJECT:
-                    value_str = "object"
-                elif variable_type == ESCARGOT_VARIABLE_ARRAY:
-                    value_str = "array"
-                elif variable_type == ESCARGOT_VARIABLE_FUNCTION:
-                    value_str = "function"
-
-                name = self._receive_string(ESCARGOT_MESSAGE_STRING_8BIT, self.channel.get_message(True));
-                if variable_full_type & ESCARGOT_VARIABLE_LONG_NAME != 0:
-                    name += "..."
-
-                if variable_has_value:
-                    value_str += self._receive_string(ESCARGOT_MESSAGE_STRING_8BIT, self.channel.get_message(True));
-                    if variable_full_type & ESCARGOT_VARIABLE_LONG_VALUE:
-                        value_str += "..."
-                elif variable_type >= ESCARGOT_VARIABLE_OBJECT:
-                    value_str += " [id: %d]" % (struct.unpack(self.byte_order + self.idx_format, data[2:])[0])
-
-                return DebuggerAction(DebuggerAction.TEXT, "%s: %s\n" % (name, value_str))
-
-            elif buffer_type == ESCARGOT_MESSAGE_PRINT:
-                printMessage ="Print: %s\n" % (self._receive_string(ESCARGOT_MESSAGE_STRING_8BIT, self.channel.get_message(True)))
-                return DebuggerAction(DebuggerAction.TEXT, printMessage);
-
-            elif buffer_type == ESCARGOT_MESSAGE_EXCEPTION:
-                exceptionMessage ="%sException: %s%s\n" % (self.red, self._receive_string(ESCARGOT_MESSAGE_STRING_8BIT, self.channel.get_message(True)), self.nocolor)
-                return DebuggerAction(DebuggerAction.TEXT, exceptionMessage);
-            elif buffer_type == ESCARGOT_DEBUGGER_WAIT_FOR_SOURCE:
-                self.send_client_source()
-            else:
-                raise Exception("Unknown message: %d" % (buffer_type))
-
-    def set_colors(self):
-        self.nocolor = '\033[0m'
-        self.green = '\033[92m'
-        self.red = '\033[31m'
-        self.yellow = '\033[93m'
-        self.green_bg = '\033[42m\033[30m'
-        self.yellow_bg = '\033[43m\033[30m'
-        self.blue = '\033[94m'
-
-    def store_client_sources(self, args):
-        self.client_sources = args
-
-    def send_client_source(self):
-        if not self.client_sources:
-            self._exec_command(ESCARGOT_DEBUGGER_THERE_WAS_NO_SOURCE)
-            return
-        path = self.client_sources.pop(0)
-        if not path.endswith('.js'):
-            sys.exit("Error: Javascript file expected!")
-            return
-        with open(path, 'r') as src_file:
-            content = path + '\0'+ src_file.read()
-        self._send_string(content, ESCARGOT_DEBUGGER_CLIENT_SOURCE_8BIT_START)
-
-    def _exec_command(self, command_id):
-        message = struct.pack(self.byte_order + "BB",
-                              1,
-                              command_id)
-        self.channel.send_message(self.byte_order, message)
-
-    def do_continue(self):
-        self.prompt = False
-        self._exec_command(ESCARGOT_MESSAGE_CONTINUE)
-
-    def step(self):
-        self.prompt = False
-        self._exec_command(ESCARGOT_MESSAGE_STEP)
-
-    def next(self):
-        self.prompt = False
-        self._exec_command(ESCARGOT_MESSAGE_NEXT)
-
-    def finish(self):
-        self.prompt = False
-        self._exec_command(ESCARGOT_MESSAGE_FINISH)
-
-    def quit(self):
-        self.prompt = False
-        self._exec_command(ESCARGOT_MESSAGE_CONTINUE)
-
-    def set_break(self, args):
-        if not args:
-            return "Error: Breakpoint index expected"
-
-        if ':' in args:
-            try:
-                if int(args.split(':', 1)[1]) <= 0:
-                    return "Error: Positive breakpoint index expected"
-
-                return self._set_breakpoint(args, False)
-
-            except ValueError as val_errno:
-                return "Error: Positive breakpoint index expected: %s" % (val_errno)
-
-        return self._set_breakpoint(args, False)
-
-    def delete(self, args):
-        if not args:
-            return "Error: Breakpoint index expected\n" \
-                   "Delete the given breakpoint, use 'delete all|active|pending' " \
-                   "to clear all the given breakpoints\n "
-        elif args == 'all':
-                self.delete_active()
-                self.delete_pending()
-        elif args == "pending":
-                self.delete_pending()
-        elif args == "active":
-                self.delete_active()
-        return ""
-
-        try:
-            breakpoint_index = int(args)
-        except ValueError as val_errno:
-            return "Error: Integer number expected, %s\n" % (val_errno)
-
-        if breakpoint_index in self.active_breakpoint_list:
-            breakpoint = self.active_breakpoint_list[breakpoint_index]
-            del self.active_breakpoint_list[breakpoint_index]
-            breakpoint.active_index = -1
-            self._send_breakpoint(breakpoint)
-            return "Breakpoint %d deleted\n" % (breakpoint_index)
-        elif breakpoint_index in self.pending_breakpoint_list:
-            del self.pending_breakpoint_list[breakpoint_index]
-            if not self.pending_breakpoint_list:
-                self._send_pending_config(0)
-            return "Pending breakpoint %d deleted\n" % (breakpoint_index)
-
-        return "Error: Breakpoint %d not found\n" % (breakpoint_index)
-
-    def breakpoint_list(self):
-        result = ""
-        if self.active_breakpoint_list:
-            result += "=== %sActive breakpoints%s ===\n" % (self.green_bg, self.nocolor)
-            for breakpoint in self.active_breakpoint_list.values():
-                result += " %d: %s\n" % (breakpoint.active_index, breakpoint)
-
-        if self.pending_breakpoint_list:
-            result += "=== %sPending breakpoints%s ===\n" % (self.yellow_bg, self.nocolor)
-            for breakpoint in self.pending_breakpoint_list.values():
-                result += " %d: %s (pending)\n" % (breakpoint.index, breakpoint)
-
-        if not self.active_breakpoint_list and not self.pending_breakpoint_list:
-            result += "No breakpoints\n"
-
-        return result
-
-    def print_source(self, line_num, offset):
-        msg = ""
-        last_bp = self.last_breakpoint_hit
-
-        if not last_bp:
-            return ""
-
-        lines = last_bp.function.source
-        if last_bp.function.source_name:
-            msg += "Source: %s\n" % (last_bp.function.source_name)
-
-        if line_num == 0:
-            start = 0
-            end = len(last_bp.function.source)
-        else:
-            start = max(last_bp.line - line_num, 0)
-            end = min(last_bp.line + line_num - 1, len(last_bp.function.source))
-            if offset:
-                if start + offset < 0:
-                    self.src_offset += self.src_offset_diff
-                    offset += self.src_offset_diff
-                elif end + offset > len(last_bp.function.source):
-                    self.src_offset -= self.src_offset_diff
-                    offset -= self.src_offset_diff
-
-                start = max(start + offset, 0)
-                end = min(end + offset, len(last_bp.function.source))
-
-        for i in range(start, end):
-            if i == last_bp.line - 1:
-                msg += "%s%4d%s %s>%s %s\n" % (self.green, i + 1, self.nocolor, self.red, self.nocolor, lines[i])
-            else:
-                msg += "%s%4d%s   %s\n" % (self.green, i + 1, self.nocolor, lines[i])
-
-        return msg
-
-    def eval(self, code):
-        self._send_string(code, ESCARGOT_MESSAGE_EVAL_8BIT_START)
-        self.prompt = False
-
-    def backtrace(self, args):
-        max_depth = 0
-        min_depth = 0
-        get_total = 0
-
-        if args:
-            args = args.split(" ")
-            try:
-                if "t" in args:
-                    get_total = 1
-                    args.remove("t")
-
-                if len(args) >= 2:
-                    min_depth = int(args[0])
-                    max_depth = int(args[1])
-                    if max_depth <= 0 or min_depth < 0:
-                        return "Error: Positive integer number expected\n"
-                    if min_depth > max_depth:
-                        return "Error: Start depth needs to be lower than or equal to max depth\n"
-                elif len(args) >= 1:
-                    max_depth = int(args[0])
-                    if max_depth <= 0:
-                        return "Error: Positive integer number expected\n"
-
-            except ValueError as val_errno:
-                return "Error: Positive integer number expected, %s\n" % (val_errno)
-
-        self.frame_index = min_depth
-
-        message = struct.pack(self.byte_order + "BB" + self.idx_format + self.idx_format + "B",
-                              1 + 4 + 4 + 1,
-                              ESCARGOT_MESSAGE_GET_BACKTRACE,
-                              min_depth,
-                              max_depth,
-                              get_total)
-
-        self.channel.send_message(self.byte_order, message)
-
-        self.prompt = False
-        return ""
-
-    def scope_chain(self, args):
-        index = 0
-        if args != "":
-            index = _parse_int(args)
-
-        message = struct.pack(self.byte_order + "BB" + self.idx_format,
-                              1 + 4,
-                              ESCARGOT_MESSAGE_GET_SCOPE_CHAIN,
-                              index)
-
-        self.channel.send_message(self.byte_order, message)
-
-        self.prompt = False
-        return ""
-
-    def scope_variables(self, args):
-        args = args.split(" ", 1)
-        stateIndex = 0
-        index = 0
-
-        if len(args) == 1:
-            if args[0] != "":
-                index = _parse_int(args[0])
-        else:
-            stateIndex = _parse_int(args[0])
-            index = _parse_int(args[1])
-
-        message = struct.pack(self.byte_order + "BB" + self.idx_format + self.idx_format,
-                              1 + 4 + 4,
-                              ESCARGOT_MESSAGE_GET_SCOPE_VARIABLES,
-                              stateIndex,
-                              index)
-
-        self.channel.send_message(self.byte_order, message)
-
-        self.prompt = False
-        return ""
-
-    def object(self, args):
-        index = _parse_int(args)
-
-        message = struct.pack(self.byte_order + "BB" + self.idx_format,
-                              1 + 4,
-                              ESCARGOT_MESSAGE_GET_OBJECT,
-                              index)
-
-        self.channel.send_message(self.byte_order, message)
-
-        self.prompt = False
-        return ""
-
-    # pylint: disable=too-many-branches,too-many-locals,too-many-statements
-    def _parse_source(self, data):
-        source = ""
-        source_name = ""
-        is_func = False
-        name = ""
-        locations = []
-
-        result = ""
-        function_list = []
-
-        while True:
-            if data is None:
-                return "Error: connection lost during source code receiving"
-
-            buffer_type = ord(data[0])
-            buffer_size = len(data) - 1
-
-            logging.debug("Parser buffer type: %d, message size: %d", buffer_type, buffer_size)
-
-            if buffer_type == ESCARGOT_MESSAGE_PARSE_DONE:
-                break
-
-            elif buffer_type == ESCARGOT_MESSAGE_PARSE_ERROR:
-                logging.debug("Syntax error encountered")
-                error_str = self._receive_string(ESCARGOT_MESSAGE_STRING_8BIT, self.channel.get_message(True))
-                return "%sSyntaxError: %s%s\n" % (self.red, error_str, self.nocolor)
-
-            elif buffer_type in [ESCARGOT_MESSAGE_SOURCE_8BIT, ESCARGOT_MESSAGE_SOURCE_8BIT_END]:
-                source += data[1:]
-                if buffer_type == ESCARGOT_MESSAGE_SOURCE_8BIT_END:
-                    source = self.decode8(source)
-
-            elif buffer_type in [ESCARGOT_MESSAGE_SOURCE_16BIT, ESCARGOT_MESSAGE_SOURCE_16BIT_END]:
-                source += data[1:]
-                if buffer_type == ESCARGOT_MESSAGE_SOURCE_16BIT_END:
-                    source = self.decode16(source)
-
-            elif buffer_type in [ESCARGOT_MESSAGE_FILE_NAME_8BIT, ESCARGOT_MESSAGE_FILE_NAME_8BIT_END]:
-                source_name += data[1:]
-                if buffer_type == ESCARGOT_MESSAGE_FILE_NAME_8BIT_END:
-                    source_name = self.decode8(source_name)
-
-            elif buffer_type in [ESCARGOT_MESSAGE_FILE_NAME_16BIT, ESCARGOT_MESSAGE_FILE_NAME_16BIT_END]:
-                source_name += data[1:]
-                if buffer_type == ESCARGOT_MESSAGE_FILE_NAME_16BIT_END:
-                    source_name = self.decode16(source_name)
-
-            elif buffer_type in [ESCARGOT_MESSAGE_FUNCTION_NAME_8BIT, ESCARGOT_MESSAGE_FUNCTION_NAME_8BIT_END]:
-                name += data[1:]
-                if buffer_type == ESCARGOT_MESSAGE_FUNCTION_NAME_8BIT_END:
-                    name = self.decode8(name)
-
-            elif buffer_type in [ESCARGOT_MESSAGE_FUNCTION_NAME_16BIT, ESCARGOT_MESSAGE_FUNCTION_NAME_16BIT_END]:
-                name += data[1:]
-                if buffer_type == ESCARGOT_MESSAGE_FUNCTION_NAME_16BIT_END:
-                    name = self.decode16(name)
-
-            elif buffer_type == ESCARGOT_MESSAGE_BREAKPOINT_LOCATION:
-                logging.debug("Breakpoint %s received", source_name)
-
-                buffer_pos = 1
-                while buffer_size > 0:
-                    location = struct.unpack(self.byte_order + self.idx_format + self.idx_format,
-                                             data[buffer_pos: buffer_pos + 8])
-                    locations.append(location)
-                    buffer_pos += 8
-                    buffer_size -= 8
-
-            elif buffer_type == ESCARGOT_MESSAGE_FUNCTION_PTR:
-                function_info = struct.unpack(self.byte_order + self.pointer_format + self.idx_format + self.idx_format, data[1:])
-                logging.debug("Pointer %s received %d", source_name, function_info[0])
-
-                function_list.append(EscargotFunction(is_func, function_info, source, source_name, name, locations))
-
-                is_func = True
-                name = ""
-                locations = []
-
-            elif buffer_type == ESCARGOT_MESSAGE_RELEASE_FUNCTION:
-                self._release_function(data)
-
-            else:
-                logging.error("Parser error!")
-                raise Exception("Unexpected message: %d" % (buffer_type))
-
-            data = self.channel.get_message(True)
-
-        # Only append these functions if parsing is successful
-        for function in function_list:
-            for line, breakpoint in function.lines.items():
-                self.line_list.insert(line, breakpoint)
-            self.function_list[function.byte_code_ptr] = function
-
-        # Try to set the pending breakpoints
-        if self.pending_breakpoint_list:
-            logging.debug("Pending breakpoints available")
-            bp_list = self.pending_breakpoint_list
-
-            for breakpoint_index, breakpoint in bp_list.items():
-                source_lines = 0
-                for src in function_list:
-                    if src.name == breakpoint.source_name:
-                        source_lines = len(src.source)
-                        break
-                if breakpoint.line:
-                    if breakpoint.line <= source_lines:
-                        command = src.source_name + ":" + str(breakpoint.line)
-                        set_result = self._set_breakpoint(command, True)
-                        if set_result:
-                            result += set_result
-                            del bp_list[breakpoint_index]
-                elif breakpoint.function:
-                    command = breakpoint.function
-                    set_result = self._set_breakpoint(command, True)
-                    if set_result:
-                        result += set_result
-                        del bp_list[breakpoint_index]
-            if not bp_list:
-                 self._send_pending_config(0)
-        return result
-
-    def _release_function(self, data):
-        byte_code_ptr = struct.unpack(self.byte_order + self.pointer_format, data[1:])[0]
-
-        function = self.function_list.get(byte_code_ptr)
-        if function is None:
-            return
-
-        for line, breakpoint in function.lines.items():
-            self.line_list.delete(line, breakpoint)
-            if breakpoint.active_index >= 0:
-                del self.active_breakpoint_list[breakpoint.active_index]
-
-        del self.function_list[byte_code_ptr]
-
-        message = struct.pack(self.byte_order + "BB" + self.pointer_format,
-                              1 + self.pointer_size,
-                              ESCARGOT_MESSAGE_FUNCTION_RELEASED,
-                              byte_code_ptr)
-        self.channel.send_message(self.byte_order, message)
-        logging.debug("Function {0x%x} byte-code released", byte_code_ptr)
-
-    def _send_breakpoint(self, breakpoint):
-        message = struct.pack(self.byte_order + "BBB" + self.pointer_format + self.idx_format,
-                              1 + 1 + self.pointer_size + 4,
-                              ESCARGOT_MESSAGE_UPDATE_BREAKPOINT,
-                              int(breakpoint.active_index >= 0),
-                              breakpoint.function.byte_code_ptr,
-                              breakpoint.offset)
-        self.channel.send_message(self.byte_order, message)
-
-    def _send_pending_config(self, enable):
-        message = struct.pack(self.byte_order + "BBB",
-                              1 + 1,
-                              ESCARGOT_DEBUGGER_PENDING_CONFIG,
-                              enable)
-        self.channel.send_message(self.byte_order, message)
-
-    def _get_breakpoint(self, breakpoint_data):
-        function = self.function_list[breakpoint_data[0]]
-        offset = breakpoint_data[1]
-
-        if offset in function.offsets:
-            return (function.offsets[offset], True)
-
-        if offset < function.first_breakpoint_offset:
-            return (function.offsets[function.first_breakpoint_offset], False)
-
-        nearest_offset = -1
-
-        for current_offset in function.offsets:
-            if current_offset <= offset and current_offset > nearest_offset:
-                nearest_offset = current_offset
-
-        return (function.offsets[nearest_offset], False)
-
-    def _enable_breakpoint(self, breakpoint):
-        if isinstance(breakpoint, PendingBreakpoint):
-            if self.breakpoint_pending_exists(breakpoint):
-                return "%sPending breakpoint%s already exists\n" % (self.yellow, self.nocolor)
-
-            self.next_breakpoint_index += 1
-            breakpoint.index = self.next_breakpoint_index
-            self.pending_breakpoint_list[self.next_breakpoint_index] = breakpoint
-            return ("%sPending breakpoint %d%s at %s\n" % (self.yellow,
-                                                           breakpoint.index,
-                                                           self.nocolor,
-                                                           breakpoint))
-        if breakpoint.active_index < 0:
-            self.next_breakpoint_index += 1
-            self.active_breakpoint_list[self.next_breakpoint_index] = breakpoint
-            breakpoint.active_index = self.next_breakpoint_index
-            self._send_breakpoint(breakpoint)
-
-        return "%sBreakpoint %d%s at %s\n" % (self.green,
-                                              breakpoint.active_index,
-                                              self.nocolor,
-                                              breakpoint)
-
-    def _set_breakpoint(self, string, pending):
-        line = re.match("(.*):(\\d+)$", string)
-        result = ""
-
-        if line:
-            source_name = line.group(1)
-            new_line = int(line.group(2))
-
-            for breakpoint in self.line_list.get(new_line):
-                func_source = breakpoint.function.source_name
-                if (source_name == func_source or
-                        func_source.endswith("/" + source_name) or
-                        func_source.endswith("\\" + source_name)):
-
-                    result += self._enable_breakpoint(breakpoint)
-
-        else:
-            functions_to_enable = []
-            for function in self.function_list.values():
-                if function.name == string:
-                    functions_to_enable.append(function)
-
-            functions_to_enable.sort(key=lambda x: x.line)
-
-            for function in functions_to_enable:
-                result += self._enable_breakpoint(function.lines[function.first_breakpoint_line])
-
-        if not result and not pending:
-            print("No breakpoint found, do you want to add a %spending breakpoint%s? (y or [n])" % \
-                  (self.yellow, self.nocolor))
-
-            ans = sys.stdin.readline()
-            if ans in ['yes\n', 'y\n']:
-                if not self.pending_breakpoint_list:
-                    self._send_pending_config(1)
-
-                if line:
-                    breakpoint = PendingBreakpoint(int(line.group(2)), line.group(1))
-                else:
-                    breakpoint = PendingBreakpoint(function=string)
-                result += self._enable_breakpoint(breakpoint)
-
-        return result
-
-    def _send_string(self, args, message_type):
-        # 1: length of type byte
-        # 4: length of an uint32 value
-        message_header = 1 + 4
-
-        if not isinstance(args, unicode):
-            try:
-                args = args.decode("ascii")
-            except UnicodeDecodeError:
-                args = args.decode("utf-8")
-
-        try:
-            args = args.encode("latin1")
-        except UnicodeEncodeError:
-            args = args.encode("UTF-16LE" if self.little_endian else "UTF-16BE", "namereplace")
-            message_type += 2
-
-        size = len(args)
-        max_fragment = min(self.max_message_size - message_header, size)
-
-        message = struct.pack(self.byte_order + "BBI",
-                              max_fragment + message_header,
-                              message_type,
-                              size)
-
-        if size == max_fragment:
-            self.channel.send_message(self.byte_order, message + args)
-            return
-
-        self.channel.send_message(self.byte_order, message + args[0:max_fragment])
-        offset = max_fragment
-
-        # 1: length of type byte
-        message_header = 1
-        message_type += 1
-
-        max_fragment = self.max_message_size - message_header
-        while offset < size:
-            next_fragment = min(max_fragment, size - offset)
-
-            message = struct.pack(self.byte_order + "BB",
-                                  next_fragment + message_header,
-                                  message_type)
-
-            prev_offset = offset
-            offset += next_fragment
-
-            self.channel.send_message(self.byte_order, message + args[prev_offset:offset])
-
-    def _receive_string(self, message_type, data):
-        result = b'';
-        buffer_type = ord(data[0])
-        end_type = message_type + 1;
-
-        if buffer_type > end_type:
-            end_type += 2
-
-        while buffer_type == end_type - 1:
-            result += data[1:]
-            data = self.channel.get_message(True)
-            buffer_type = ord(data[0])
-
-        if buffer_type != end_type:
-            raise Exception("Unexpected message")
-
-        result += data[1:]
-
-        if end_type == message_type + 1:
-            result = self.decode8(result)
-        else:
-            result = self.decode16(result)
-
-        return result;
-
-    def delete_active(self):
-        for i in self.active_breakpoint_list.values():
-            breakpoint = self.active_breakpoint_list[i.active_index]
-            del self.active_breakpoint_list[i.active_index]
-            breakpoint.active_index = -1
-            self._send_breakpoint(breakpoint)
-
-    def delete_pending(self):
-        if self.pending_breakpoint_list:
-            self.pending_breakpoint_list.clear()
-            self._send_pending_config(0)
-
-    def breakpoint_pending_exists(self, breakpoint):
-        for existing_bp in self.pending_breakpoint_list.values():
-            if (breakpoint.line and existing_bp.source_name == breakpoint.source_name and \
-                existing_bp.line == breakpoint.line) \
-                or (not breakpoint.line and existing_bp.function == breakpoint.function):
-                    return True
-
-        return False
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger_tcp.py b/lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger_tcp.py
deleted file mode 100644 (file)
index 279c5ee..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2015-present Samsung Electronics Co., Ltd.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import socket
-import select
-
-# pylint: disable=too-many-arguments,superfluous-parens
-class TcpSocket(object):
-    """ Create a new TCP/IP socket. """
-    def __init__(self, address):
-        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0, None)
-        if ":" not in address:
-            self.address = (address, 6501)
-        else:
-            host, port = address.split(":")
-            self.address = (host, int(port))
-
-    def connect(self):
-        """ Connect to a remote socket at address (host, port). """
-        print("Connecting to: %s:%s" % (self.address[0], self.address[1]))
-        self.socket.connect(self.address)
-
-    def close(self):
-        """ Mark the socket closed. """
-        self.socket.close()
-
-    def receive_data(self, max_size=1024):
-        """ Receive data (maximum amount: max_size). """
-        return self.socket.recv(max_size)
-
-    def send_data(self, data):
-        """ Send data to the remote peer. """
-        return self.socket.send(data)
-
-    def ready(self):
-        """ Checks whether data is available. """
-        result = select.select([self.socket], [], [], 0)[0]
-
-        return self.socket in result
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger_tester.sh b/lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger_tester.sh
deleted file mode 100755 (executable)
index 77d7891..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash
-
-ESCARGOT=$1
-TEST_CASE=$2
-DEBUGGER_CLIENT=$3
-IS_CLIENT_SOURCE=$4
-RESULT_TEMP=`mktemp ${TEST_CASE}.out.XXXXXXXXXX`
-if [[ $IS_CLIENT_SOURCE == 0  ]] && [[ $TEST_CASE != *"tools/debugger/tests/client_source_multiple"* ]]; then
-  ${ESCARGOT} --start-debug-server ${TEST_CASE}.js &
-  sleep 1s
-  (cat "${TEST_CASE}.cmd" | ${DEBUGGER_CLIENT} --non-interactive) >${RESULT_TEMP} 2>&1
-  diff -u ${TEST_CASE}.expected ${RESULT_TEMP}
-elif [[ $IS_CLIENT_SOURCE == 1 ]]; then
-  ${ESCARGOT} --start-debug-server --debugger-wait-source &
-  sleep 1s
-  if [[ $TEST_CASE == *"client_source"* ]]; then
-    (cat "${TEST_CASE}.cmd" | ${DEBUGGER_CLIENT} --client-source ${TEST_CASE}_2.js ${TEST_CASE}_1.js --non-interactive) >${RESULT_TEMP} 2>&1
-  else
-    (cat "${TEST_CASE}.cmd" | ${DEBUGGER_CLIENT} --client-source ${TEST_CASE}.js --non-interactive) >${RESULT_TEMP} 2>&1
-  fi
-  diff -u ${TEST_CASE}.expected ${RESULT_TEMP}
-fi
-
-
-STATUS_CODE=$?
-
-rm -f ${RESULT_TEMP}
-
-exit ${STATUS_CODE}
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger_websocket.py b/lwnode/code/escargotshim/deps/escargot/tools/debugger/debugger_websocket.py
deleted file mode 100644 (file)
index 4271e7c..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2015-present Samsung Electronics Co., Ltd.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import struct
-
-MAX_BUFFER_SIZE = 128
-WEBSOCKET_BINARY_FRAME = 2
-WEBSOCKET_FIN_BIT = 0x80
-
-class WebSocket(object):
-    def __init__(self, transport):
-
-        self.data_buffer = b""
-        self.transport = transport
-
-    def connect(self):
-        """  WebSockets connection. """
-        self.transport.connect()
-        self.receive_buffer = b""
-
-        self.__send_data(b"GET /escargot-debugger HTTP/1.1\r\n" +
-                         b"Upgrade: websocket\r\n" +
-                         b"Connection: Upgrade\r\n" +
-                         b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n")
-
-        # Expected answer from the handshake.
-        expected = (b"HTTP/1.1 101 Switching Protocols\r\n" +
-                    b"Upgrade: websocket\r\n" +
-                    b"Connection: Upgrade\r\n" +
-                    b"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")
-
-        len_expected = len(expected)
-
-        while len(self.receive_buffer) < len_expected:
-            self.receive_buffer += self.transport.receive_data()
-
-        if self.receive_buffer[0:len_expected] != expected:
-            raise Exception("Unexpected handshake")
-
-        if len(self.receive_buffer) > len_expected:
-            self.receive_buffer = self.receive_buffer[len_expected:]
-        else:
-            self.receive_buffer = b""
-
-
-        # First the version info must be returned
-        # header [2] - opcode[1], size[1]
-        # MessageVersion [6 bytes]
-        len_expected = 2 + 6
-
-        while len(self.receive_buffer) < len_expected:
-            self.receive_buffer += self.transport.receive_data()
-
-        expected = struct.pack("BB",
-                               WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
-                               6)
-
-        if self.receive_buffer[0:2] != expected:
-            raise Exception("Unexpected version info")
-
-        result = self.receive_buffer[2:len_expected]
-        self.receive_buffer = self.receive_buffer[len_expected:]
-
-        return result
-
-    def __send_data(self, data):
-        """ Private function to send data using the given transport. """
-        size = len(data)
-
-        while size > 0:
-            bytes_send = self.transport.send_data(data)
-            if bytes_send < size:
-                data = data[bytes_send:]
-            size -= bytes_send
-
-    def send_message(self, byte_order, packed_data):
-        """ Send message. """
-        message = struct.pack(byte_order + "BBI",
-                              WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
-                              WEBSOCKET_FIN_BIT + struct.unpack(byte_order + "B", packed_data[0])[0],
-                              0) + packed_data[1:]
-
-        self.__send_data(message)
-
-    def close(self):
-        """ Close the WebSocket. """
-        self.transport.close()
-
-    def get_message(self, blocking):
-        """ Receive message. """
-
-        # Connection was closed
-        if self.receive_buffer is None:
-            return None
-
-        while True:
-            if len(self.receive_buffer) >= 2:
-                if ord(self.receive_buffer[0]) != WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT:
-                    raise Exception("Unexpected data frame")
-
-                size = ord(self.receive_buffer[1])
-                if size == 0 or size >= 126:
-                    raise Exception("Unexpected data frame")
-
-                if len(self.receive_buffer) >= size + 2:
-                    result = self.receive_buffer[2:size + 2]
-                    self.receive_buffer = self.receive_buffer[size + 2:]
-                    return result
-
-            if not blocking and not self.transport.ready():
-                return b''
-
-            data = self.transport.receive_data(MAX_BUFFER_SIZE)
-
-            if not data:
-                self.receive_buffer = None
-                return None
-            self.receive_buffer += data
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/client_source_multiple.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/client_source_multiple.cmd
deleted file mode 100644 (file)
index 6d14bed..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-n
-n
-s
-s
-s
-s
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/client_source_multiple.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/client_source_multiple.expected
deleted file mode 100644 (file)
index 70e65f9..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/client_source_multiple_2.js:21
-(escargot-debugger) n
-Print: multiple-client-source-test-file-2
-Stopped at tools/debugger/tests/client_source_multiple_1.js:21
-(escargot-debugger) n
-Print: multiple-client-source-test-file-1
-Stopped at tools/debugger/tests/client_source_multiple_1.js:33
-(escargot-debugger) s
-Stopped at tools/debugger/tests/client_source_multiple_1.js:24 (in foo() at line:23, col:1)
-(escargot-debugger) s
-Print: foo
-Stopped at tools/debugger/tests/client_source_multiple_1.js:25 (in foo() at line:23, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/client_source_multiple_2.js:24 (in bar() at line:23, col:1)
-(escargot-debugger) s
-Print: bar
-Stopped at tools/debugger/tests/client_source_multiple_2.js:25 (in bar() at line:23, col:1)
-(escargot-debugger) c
-Print: str-argument: called-from-test-file-1
-Print: crossFoo
-Print: str-argument: called-from-test-file-2
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_backtrace.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_backtrace.cmd
deleted file mode 100644 (file)
index 03c1122..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-s
-backtrace
-s
-s
-s
-bt t
-bt 2
-bt 1 3
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_backtrace.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_backtrace.expected
deleted file mode 100644 (file)
index cf21e73..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_backtrace.js:20
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_backtrace.js:34
-(escargot-debugger) backtrace
-tools/debugger/tests/do_backtrace.js:34:1 [depth:0]
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_backtrace.js:31 (in h() at line:30, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_backtrace.js:27 (in g() at line:26, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_backtrace.js:23 (in f() at line:22, col:1)
-(escargot-debugger) bt t
-Total number of frames: 4
-tools/debugger/tests/do_backtrace.js:23:5 [depth:0] (in f)
-tools/debugger/tests/do_backtrace.js:27:5 [depth:1] (in g)
-tools/debugger/tests/do_backtrace.js:31:5 [depth:2] (in h)
-tools/debugger/tests/do_backtrace.js:34:1 [depth:3]
-(escargot-debugger) bt 2
-tools/debugger/tests/do_backtrace.js:23:5 [depth:0] (in f)
-tools/debugger/tests/do_backtrace.js:27:5 [depth:1] (in g)
-(escargot-debugger) bt 1 3
-tools/debugger/tests/do_backtrace.js:27:5 [depth:1] (in g)
-tools/debugger/tests/do_backtrace.js:31:5 [depth:2] (in h)
-(escargot-debugger) c
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break.cmd
deleted file mode 100644 (file)
index 2d79b57..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-break do_break.js:53
-b do_break.js:39
-b f
-c
-c
-c
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break.expected
deleted file mode 100644 (file)
index 092e014..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_break.js:21
-(escargot-debugger) break do_break.js:53
-Breakpoint 1 at tools/debugger/tests/do_break.js:53
-(escargot-debugger) b do_break.js:39
-Breakpoint 2 at tools/debugger/tests/do_break.js:39 (in test() at line:23, col:1)
-(escargot-debugger) b f
-Breakpoint 3 at tools/debugger/tests/do_break.js:26 (in f() at line:25, col:3)
-Breakpoint 4 at tools/debugger/tests/do_break.js:31 (in f() at line:29, col:3)
-Breakpoint 5 at tools/debugger/tests/do_break.js:36 (in f() at line:34, col:3)
-Breakpoint 6 at tools/debugger/tests/do_break.js:47 (in f() at line:45, col:1)
-(escargot-debugger) c
-Stopped at breakpoint:1 tools/debugger/tests/do_break.js:53
-(escargot-debugger) c
-Stopped at breakpoint:2 tools/debugger/tests/do_break.js:39 (in test() at line:23, col:1)
-(escargot-debugger) c
-Stopped at breakpoint:5 tools/debugger/tests/do_break.js:36 (in f() at line:34, col:3)
-(escargot-debugger) c
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_async.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_async.cmd
deleted file mode 100644 (file)
index f71cc73..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-s
-bt
-b do_break_async.js:40
-b do_break_async.js:31
-b do_break_async.js:22
-c
-bt
-c
-bt
-c
-bt
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_async.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_async.expected
deleted file mode 100644 (file)
index 255b503..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_break_async.js:43
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_break_async.js:39 (in j() at line:38, col:1)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_async.js:39:5 [depth:0] (in j)
-tools/debugger/tests/do_break_async.js:43:1 [depth:1]
-(escargot-debugger) b do_break_async.js:40
-Breakpoint 1 at tools/debugger/tests/do_break_async.js:40 (in j() at line:38, col:1)
-(escargot-debugger) b do_break_async.js:31
-Breakpoint 2 at tools/debugger/tests/do_break_async.js:31 (in h() at line:29, col:1)
-(escargot-debugger) b do_break_async.js:22
-Breakpoint 3 at tools/debugger/tests/do_break_async.js:22 (in f() at line:20, col:1)
-(escargot-debugger) c
-Stopped at breakpoint:1 tools/debugger/tests/do_break_async.js:40 (in j() at line:38, col:1)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_async.js:43:1
-(escargot-debugger) c
-Stopped at breakpoint:2 tools/debugger/tests/do_break_async.js:31 (in h() at line:29, col:1)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_async.js:35:5 (in i)
-tools/debugger/tests/do_break_async.js:43:1
-(escargot-debugger) c
-Stopped at breakpoint:3 tools/debugger/tests/do_break_async.js:22 (in f() at line:20, col:1)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_async.js:26:5 (in g)
-tools/debugger/tests/do_break_async.js:35:5 (in i)
-tools/debugger/tests/do_break_async.js:43:1
-(escargot-debugger) c
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_async_generator.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_async_generator.cmd
deleted file mode 100644 (file)
index c513f43..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-s
-s
-s
-bt
-s
-s
-s
-s
-b do_break_async_generator.js:21
-c
-bt
-c
-bt
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_async_generator.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_async_generator.expected
deleted file mode 100644 (file)
index 241b317..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_break_async_generator.js:38
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_break_async_generator.js:39
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_break_async_generator.js:33 (in g() at line:32, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_break_async_generator.js:21 (in f1() at line:20, col:1)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_async_generator.js:21:5 [depth:0] (in f1)
-tools/debugger/tests/do_break_async_generator.js:38:10
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_break_async_generator.js:44
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_break_async_generator.js:42 (in h() at line:41, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_break_async_generator.js:43 (in h() at line:41, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_break_async_generator.js:46
-(escargot-debugger) b do_break_async_generator.js:21
-Breakpoint 1 at tools/debugger/tests/do_break_async_generator.js:21 (in f1() at line:20, col:1)
-(escargot-debugger) c
-Stopped at breakpoint:1 tools/debugger/tests/do_break_async_generator.js:21 (in f1() at line:20, col:1)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_async_generator.js:21:5 [depth:0] (in f1)
-tools/debugger/tests/do_break_async_generator.js:25:12 [depth:1] (in f2)
-tools/debugger/tests/do_break_async_generator.js:38:10
-(escargot-debugger) c
-Stopped at breakpoint:1 tools/debugger/tests/do_break_async_generator.js:21 (in f1() at line:20, col:1)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_async_generator.js:21:5 [depth:0] (in f1)
-tools/debugger/tests/do_break_async_generator.js:25:12 [depth:1] (in f2)
-tools/debugger/tests/do_break_async_generator.js:29:12 [depth:2] (in f3)
-tools/debugger/tests/do_break_async_generator.js:38:10
-(escargot-debugger) c
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_class.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_class.cmd
deleted file mode 100644 (file)
index c2b95a5..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-b do_break_class.js:37
-n
-b do_break_class.js:36
-c
-bt
-b do_break_class.js:66
-c
-c
-bt
-b do_break_class.js:69
-c
-b do_break_class.js:26
-b do_break_class.js:50
-b do_break_class.js:55
-c
-c
-bt
-c
-bt
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_class.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_class.expected
deleted file mode 100644 (file)
index fedc20d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_break_class.js:20
-(escargot-debugger) b do_break_class.js:37
-No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-(escargot-debugger) b do_break_class.js:36
-Breakpoint 1 at tools/debugger/tests/do_break_class.js:36 (in function() at line:37, col:7)
-(escargot-debugger) c
-Stopped at breakpoint:1 tools/debugger/tests/do_break_class.js:36 (in function() at line:37, col:7)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_class.js:37:6 [depth:0]
-tools/debugger/tests/do_break_class.js:22:14 [depth:1]
-(escargot-debugger) b do_break_class.js:66
-Breakpoint 2 at tools/debugger/tests/do_break_class.js:66 (in function() at line:66, col:24)
-Breakpoint 3 at tools/debugger/tests/do_break_class.js:66 (in function() at line:66, col:48)
-(escargot-debugger) c
-Stopped at breakpoint:2 tools/debugger/tests/do_break_class.js:66 (in function() at line:66, col:24)
-(escargot-debugger) c
-Stopped at breakpoint:3 tools/debugger/tests/do_break_class.js:66 (in function() at line:66, col:48)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_class.js:66:47 [depth:0]
-tools/debugger/tests/do_break_class.js:46:29 [depth:1]
-(escargot-debugger) b do_break_class.js:69
-Breakpoint 4 at tools/debugger/tests/do_break_class.js:69
-(escargot-debugger) c
-Stopped at breakpoint:4 tools/debugger/tests/do_break_class.js:69
-(escargot-debugger) b do_break_class.js:26
-Breakpoint 5 at tools/debugger/tests/do_break_class.js:26 (in function() at line:28, col:7)
-(escargot-debugger) b do_break_class.js:50
-Breakpoint 6 at tools/debugger/tests/do_break_class.js:50 (in function() at line:50, col:16)
-(escargot-debugger) b do_break_class.js:55
-Breakpoint 7 at tools/debugger/tests/do_break_class.js:55 (in constructor() at line:53, col:3)
-(escargot-debugger) c
-Stopped at breakpoint:7 tools/debugger/tests/do_break_class.js:55 (in constructor() at line:53, col:3)
-(escargot-debugger) c
-Stopped at breakpoint:5 tools/debugger/tests/do_break_class.js:26 (in function() at line:28, col:7)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_class.js:28:6 [depth:0]
-tools/debugger/tests/do_break_class.js:55:5 [depth:2] (in constructor)
-tools/debugger/tests/do_break_class.js:69:9 [depth:3]
-(escargot-debugger) c
-Stopped at breakpoint:6 tools/debugger/tests/do_break_class.js:50 (in function() at line:50, col:16)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_class.js:50:15 [depth:0]
-tools/debugger/tests/do_break_class.js:55:5 [depth:1] (in constructor)
-tools/debugger/tests/do_break_class.js:69:9 [depth:2]
-(escargot-debugger) c
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_generator.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_generator.cmd
deleted file mode 100644 (file)
index 7d1cbae..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-b do_break_generator.js:21
-c
-bt
-c
-bt
-c
-bt
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_generator.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_generator.expected
deleted file mode 100644 (file)
index 15cac04..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_break_generator.js:38
-(escargot-debugger) b do_break_generator.js:21
-Breakpoint 1 at tools/debugger/tests/do_break_generator.js:21 (in f1() at line:20, col:1)
-(escargot-debugger) c
-Stopped at breakpoint:1 tools/debugger/tests/do_break_generator.js:21 (in f1() at line:20, col:1)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_generator.js:21:5 [depth:0] (in f1)
-tools/debugger/tests/do_break_generator.js:39:1 [depth:3]
-(escargot-debugger) c
-Stopped at breakpoint:1 tools/debugger/tests/do_break_generator.js:21 (in f1() at line:20, col:1)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_generator.js:21:5 [depth:0] (in f1)
-tools/debugger/tests/do_break_generator.js:25:12 [depth:1] (in f2)
-tools/debugger/tests/do_break_generator.js:42:3 [depth:4] (in h)
-tools/debugger/tests/do_break_generator.js:44:1 [depth:5]
-(escargot-debugger) c
-Stopped at breakpoint:1 tools/debugger/tests/do_break_generator.js:21 (in f1() at line:20, col:1)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_generator.js:21:5 [depth:0] (in f1)
-tools/debugger/tests/do_break_generator.js:25:12 [depth:1] (in f2)
-tools/debugger/tests/do_break_generator.js:29:12 [depth:2] (in f3)
-tools/debugger/tests/do_break_generator.js:46:1 [depth:5]
-(escargot-debugger) c
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_no_arg.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_no_arg.cmd
deleted file mode 100644 (file)
index 3e94a64..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-b
-b
-b
-b
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_no_arg.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_no_arg.expected
deleted file mode 100644 (file)
index 69542dc..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_break_no_arg.js:24
-(escargot-debugger) b
-Error: Argument expected
-(escargot-debugger) b
-Error: Argument expected
-(escargot-debugger) b
-Error: Argument expected
-(escargot-debugger) b
-Error: Argument expected
-(escargot-debugger) c
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_promise_then.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_promise_then.cmd
deleted file mode 100644 (file)
index 69c1aea..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-s
-s
-s
-b do_break_promise_then.js:24
-c
-bt
-c
-bt
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_promise_then.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_break_promise_then.expected
deleted file mode 100644 (file)
index ad1a177..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_break_promise_then.js:20
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_break_promise_then.js:21
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_break_promise_then.js:27
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_break_promise_then.js:41
-(escargot-debugger) b do_break_promise_then.js:24
-Breakpoint 1 at tools/debugger/tests/do_break_promise_then.js:24 (in f() at line:23, col:1)
-(escargot-debugger) c
-Stopped at breakpoint:1 tools/debugger/tests/do_break_promise_then.js:24 (in f() at line:23, col:1)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_promise_then.js:24:5 [depth:0] (in f)
-tools/debugger/tests/do_break_promise_then.js:29:9 [depth:1]
-tools/debugger/tests/do_break_promise_then.js:28:5
-tools/debugger/tests/do_break_promise_then.js:27:1
-(escargot-debugger) c
-Stopped at breakpoint:1 tools/debugger/tests/do_break_promise_then.js:24 (in f() at line:23, col:1)
-(escargot-debugger) bt
-tools/debugger/tests/do_break_promise_then.js:24:5 [depth:0] (in f)
-tools/debugger/tests/do_break_promise_then.js:34:5 [depth:1] (in g)
-tools/debugger/tests/do_break_promise_then.js:38:5 (in h)
-tools/debugger/tests/do_break_promise_then.js:41:1
-(escargot-debugger) c
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_continue.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_continue.cmd
deleted file mode 100644 (file)
index 44c5d7d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-continue
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_continue.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_continue.expected
deleted file mode 100644 (file)
index f5d7d85..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_continue.js:21
-(escargot-debugger) continue
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_delete_pending.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_delete_pending.cmd
deleted file mode 100644 (file)
index 4189602..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-b do_delete_pending.js:21
-b pending1
-y
-b pending2
-y
-list
-delete pending
-list
-b pending3
-y
-delete all
-list
-quit
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_delete_pending.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_delete_pending.expected
deleted file mode 100644 (file)
index 13e6fb2..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_delete_pending.js:20
-(escargot-debugger) b do_delete_pending.js:21
-Breakpoint 1 at tools/debugger/tests/do_delete_pending.js:21
-(escargot-debugger) b pending1
-No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint 2 at pending1()
-(escargot-debugger) b pending2
-No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint 3 at pending2()
-(escargot-debugger) list
-=== Active breakpoints ===
- 1: tools/debugger/tests/do_delete_pending.js:21
-=== Pending breakpoints ===
- 2: pending1() (pending)
- 3: pending2() (pending)
-(escargot-debugger) delete pending
-(escargot-debugger) list
-=== Active breakpoints ===
- 1: tools/debugger/tests/do_delete_pending.js:21
-(escargot-debugger) b pending3
-No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint 4 at pending3()
-(escargot-debugger) delete all
-(escargot-debugger) list
-No breakpoints
-(escargot-debugger) quit
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_exception.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_exception.cmd
deleted file mode 100644 (file)
index f2ad6c7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_exception.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_exception.expected
deleted file mode 100644 (file)
index 2b8ada6..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_exception.js:28
-(escargot-debugger) c
-Exception: RangeError: Test exception
-tools/debugger/tests/do_exception.js:21:10 [depth:0] (in g)
-tools/debugger/tests/do_exception.js:25:4 [depth:1] (in f)
-tools/debugger/tests/do_exception.js:28:1 [depth:2]
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_finish.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_finish.cmd
deleted file mode 100644 (file)
index 0ed8f21..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-b do_finish.js:24
-c
-finish
-f
-b do_finish.js:41
-f
-f
-f
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_finish.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_finish.expected
deleted file mode 100644 (file)
index dfae86a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_finish.js:20
-(escargot-debugger) b do_finish.js:24
-Breakpoint 1 at tools/debugger/tests/do_finish.js:24 (in f() at line:22, col:1)
-(escargot-debugger) c
-Stopped at breakpoint:1 tools/debugger/tests/do_finish.js:24 (in f() at line:22, col:1)
-(escargot-debugger) finish
-Stopped at tools/debugger/tests/do_finish.js:32 (in g() at line:29, col:1)
-(escargot-debugger) f
-Stopped at tools/debugger/tests/do_finish.js:38
-(escargot-debugger) b do_finish.js:41
-Breakpoint 2 at tools/debugger/tests/do_finish.js:41 (in gen() at line:40, col:1)
-(escargot-debugger) f
-Stopped at breakpoint:2 tools/debugger/tests/do_finish.js:41 (in gen() at line:40, col:1)
-(escargot-debugger) f
-Stopped at tools/debugger/tests/do_finish.js:46
-(escargot-debugger) f
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_list.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_list.cmd
deleted file mode 100644 (file)
index 706dfda..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-b do_list.js:20
-b do_list.js:21
-list
-quit
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_list.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_list.expected
deleted file mode 100644 (file)
index 649c6e3..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_list.js:20
-(escargot-debugger) b do_list.js:20
-Breakpoint 1 at tools/debugger/tests/do_list.js:20
-(escargot-debugger) b do_list.js:21
-Breakpoint 2 at tools/debugger/tests/do_list.js:21
-(escargot-debugger) list
-=== Active breakpoints ===
- 1: tools/debugger/tests/do_list.js:20
- 2: tools/debugger/tests/do_list.js:21
-(escargot-debugger) quit
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_object.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_object.cmd
deleted file mode 100644 (file)
index be9887f..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-s
-s
-s
-s
-variables 0
-object 0
-variables 1 0
-object 1
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_object.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_object.expected
deleted file mode 100644 (file)
index 301bea4..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_object.js:30
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_object.js:26 (in f() at line:25, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_object.js:27 (in f() at line:25, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_object.js:21 (in g() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_object.js:22 (in g() at line:20, col:1)
-(escargot-debugger) variables 0
-arr: array [id: 0]
-(escargot-debugger) object 0
-0: number: 1
-1: number: 2
-length: number: 2
-(escargot-debugger) variables 1 0
-obj: object [id: 1]
-(escargot-debugger) object 1
-a: number: 1
-b: number: 2
-(escargot-debugger) c
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_functions.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_functions.cmd
deleted file mode 100644 (file)
index cebb0b3..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-b f
-y
-b b
-y
-b non-existing-breakingpoint
-y
-list
-c
-list
-source
-c
-source
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_functions.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_functions.expected
deleted file mode 100644 (file)
index 908c8fe..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_pending_breakpoints_functions.js:20
-(escargot-debugger) b f
-No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint 1 at f()
-(escargot-debugger) b b
-No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint 2 at b()
-(escargot-debugger) b non-existing-breakingpoint
-No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint 3 at non-existing-breakingpoint()
-(escargot-debugger) list
-=== Pending breakpoints ===
- 1: f() (pending)
- 2: b() (pending)
- 3: non-existing-breakingpoint() (pending)
-(escargot-debugger) c
-Print: pending-breakpoints_functions
-Breakpoint 4 at eval input:2 (in f() at line:1, col:1)
-Breakpoint 5 at eval input:2 (in b() at line:1, col:1)
-Stopped at breakpoint:4 eval input:2 (in f() at line:1, col:1)
-(escargot-debugger) list
-=== Active breakpoints ===
- 4: eval input:2 (in f() at line:1, col:1)
- 5: eval input:2 (in b() at line:1, col:1)
-=== Pending breakpoints ===
- 3: non-existing-breakingpoint() (pending)
-(escargot-debugger) source
-Source: eval input
-   1   function f()
-   2 > { return 5 }
-(escargot-debugger) c
-Print: 5
-Stopped at breakpoint:5 eval input:2 (in b() at line:1, col:1)
-(escargot-debugger) source
-Source: eval input
-   1   function b()
-   2 > { return 8 }
-(escargot-debugger) c
-Print: 8
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_lines.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_lines.cmd
deleted file mode 100644 (file)
index fe36761..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-b :1
-y
-list
-c
-list
-source
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_lines.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_lines.expected
deleted file mode 100644 (file)
index 764e0a7..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_pending_breakpoints_lines.js:20
-(escargot-debugger) b :1
-No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint 1 at :1
-(escargot-debugger) list
-=== Pending breakpoints ===
- 1: :1 (pending)
-(escargot-debugger) c
-Print: pending-breakpoints_lines
-Breakpoint 2 at eval input:1
-Stopped at breakpoint:2 eval input:1
-(escargot-debugger) list
-=== Active breakpoints ===
- 2: eval input:1
-(escargot-debugger) source
-Source: eval input
-   1 > 1;var a = 1
-(escargot-debugger) c
-Print: 1
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_unavailable.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_unavailable.cmd
deleted file mode 100644 (file)
index 59946e0..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-b not_existing_func
-y
-b 22
-y
-n
-n
-b not_existing.js:6
-y
-n
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_unavailable.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_pending_breakpoints_unavailable.expected
deleted file mode 100644 (file)
index 57815b3..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_pending_breakpoints_unavailable.js:20
-(escargot-debugger) b not_existing_func
-No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint 1 at not_existing_func()
-(escargot-debugger) b 22
-No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint 2 at 22()
-(escargot-debugger) n
-Stopped at tools/debugger/tests/do_pending_breakpoints_unavailable.js:21
-(escargot-debugger) n
-Stopped at tools/debugger/tests/do_pending_breakpoints_unavailable.js:22
-(escargot-debugger) b not_existing.js:6
-No breakpoint found, do you want to add a pending breakpoint? (y or [n])
-Pending breakpoint 3 at not_existing.js:6
-(escargot-debugger) n
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_print.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_print.cmd
deleted file mode 100644 (file)
index f2ad6c7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_print.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_print.expected
deleted file mode 100644 (file)
index 389c9ac..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_print.js:20
-(escargot-debugger) c
-Print: start
-Print: middle
-Print: end
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_quit.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_quit.cmd
deleted file mode 100644 (file)
index ff60466..0000000
+++ /dev/null
@@ -1 +0,0 @@
-quit
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_quit.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_quit.expected
deleted file mode 100644 (file)
index b152aa8..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_quit.js:25
-(escargot-debugger) quit
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_statements.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_statements.cmd
deleted file mode 100644 (file)
index 998b9c4..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_statements.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_statements.expected
deleted file mode 100644 (file)
index 217bf0c..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_statements.js:61
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:21 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:22 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:23 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:24 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:28 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:31 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:34 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:35 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:35 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:35 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:35 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:38 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:39 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:39 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:43 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:45 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:48 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:49 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:52 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:53 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:56 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:57 (in f() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_statements.js:59 (in f() at line:20, col:1)
-(escargot-debugger) s
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step.cmd
deleted file mode 100644 (file)
index d855711..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-step
-step
-next
-next
-s
-n
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step.expected
deleted file mode 100644 (file)
index 6cc5ee0..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_step.js:37
-(escargot-debugger) step
-Stopped at tools/debugger/tests/do_step.js:27 (in f1() at line:20, col:1)
-(escargot-debugger) step
-Stopped at tools/debugger/tests/do_step.js:24 (in g() at line:22, col:3)
-(escargot-debugger) next
-Stopped at tools/debugger/tests/do_step.js:28 (in f1() at line:20, col:1)
-(escargot-debugger) next
-Stopped at tools/debugger/tests/do_step.js:29 (in f1() at line:20, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step.js:38
-(escargot-debugger) n
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step2.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step2.cmd
deleted file mode 100644 (file)
index b39119a..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-step
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
-s
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step2.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step2.expected
deleted file mode 100644 (file)
index eaa400e..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_step2.js:20
-(escargot-debugger) step
-Stopped at tools/debugger/tests/do_step2.js:21
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step2.js:20 (in arr() at line:20, col:11)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step2.js:27
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step2.js:28
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step2.js:29
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step2.js:35
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step2.js:36
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step2.js:37
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step2.js:39
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step2.js:40
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step2.js:41
-(escargot-debugger) s
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step_class.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step_class.cmd
deleted file mode 100644 (file)
index ffb6682..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-s
-bt
-s
-s
-s
-s
-bt
-s
-s
-s
-s
-s
-s
-s
-bt
-s
-s
-s
-s
-s
-s
-bt
-s
-s
-s
-s
-s
-s
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step_class.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step_class.expected
deleted file mode 100644 (file)
index dafa14c..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_step_class.js:20
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:36 (in function() at line:37, col:7)
-(escargot-debugger) bt
-tools/debugger/tests/do_step_class.js:37:6 [depth:0]
-tools/debugger/tests/do_step_class.js:22:14 [depth:1]
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:40 (in function() at line:42, col:7)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:43 (in function() at line:43, col:23)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:43 (in function() at line:43, col:46)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:60 (in function() at line:61, col:7)
-(escargot-debugger) bt
-tools/debugger/tests/do_step_class.js:61:6 [depth:0]
-tools/debugger/tests/do_step_class.js:46:29 [depth:1]
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:64 (in function() at line:65, col:7)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:66 (in function() at line:66, col:24)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:66 (in function() at line:66, col:48)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:69
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:54 (in constructor() at line:53, col:3)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:55 (in constructor() at line:53, col:3)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:23 (in function() at line:24, col:7)
-(escargot-debugger) bt
-tools/debugger/tests/do_step_class.js:24:6 [depth:0]
-tools/debugger/tests/do_step_class.js:55:5 [depth:2] (in constructor)
-tools/debugger/tests/do_step_class.js:69:9 [depth:3]
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:26 (in function() at line:28, col:7)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:29 (in function() at line:29, col:15)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:29 (in function() at line:29, col:30)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:32 (in constructor() at line:31, col:3)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:33 (in constructor() at line:31, col:3)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:47 (in function() at line:48, col:7)
-(escargot-debugger) bt
-tools/debugger/tests/do_step_class.js:48:6 [depth:0]
-tools/debugger/tests/do_step_class.js:55:5 [depth:1] (in constructor)
-tools/debugger/tests/do_step_class.js:69:9 [depth:2]
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:50 (in function() at line:50, col:16)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:51 (in function() at line:51, col:16)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:51 (in function() at line:51, col:31)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:56 (in constructor() at line:53, col:3)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class.js:57 (in constructor() at line:53, col:3)
-(escargot-debugger) s
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step_class2.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step_class2.cmd
deleted file mode 100644 (file)
index 0b9516d..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-s
-bt
-s
-s
-s
-s
-bt
-s
-s
-s
-s
-s
-bt
-s
-s
-s
-s
-bt
-s
-s
-s
-s
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step_class2.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_step_class2.expected
deleted file mode 100644 (file)
index 20543ef..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_step_class2.js:20
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:32 (in function() at line:33, col:7)
-(escargot-debugger) bt
-tools/debugger/tests/do_step_class2.js:33:6 [depth:0]
-tools/debugger/tests/do_step_class2.js:22:14 [depth:1]
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:36 (in function() at line:38, col:7)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:39 (in function() at line:39, col:23)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:39 (in function() at line:39, col:46)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:50 (in function() at line:51, col:7)
-(escargot-debugger) bt
-tools/debugger/tests/do_step_class2.js:51:6 [depth:0]
-tools/debugger/tests/do_step_class2.js:42:29 [depth:1]
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:54 (in function() at line:55, col:7)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:56 (in function() at line:56, col:24)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:56 (in function() at line:56, col:48)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:59
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:23 (in function() at line:24, col:7)
-(escargot-debugger) bt
-tools/debugger/tests/do_step_class2.js:24:6 [depth:0]
-unknown dynamic function:3:7 [depth:2]
-tools/debugger/tests/do_step_class2.js:59:9 [depth:3]
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:26 (in function() at line:28, col:7)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:29 (in function() at line:29, col:15)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:29 (in function() at line:29, col:30)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:43 (in function() at line:44, col:7)
-(escargot-debugger) bt
-tools/debugger/tests/do_step_class2.js:44:6 [depth:0]
-unknown dynamic function:3:7 [depth:1]
-tools/debugger/tests/do_step_class2.js:59:9 [depth:2]
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:46 (in function() at line:46, col:16)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:47 (in function() at line:47, col:16)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_step_class2.js:47 (in function() at line:47, col:31)
-(escargot-debugger) s
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_syntax_error.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_syntax_error.cmd
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_syntax_error.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_syntax_error.expected
deleted file mode 100644 (file)
index 838f4b0..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-SyntaxError: Line 21: Identifier 'a' has already been declared
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_variables.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_variables.cmd
deleted file mode 100644 (file)
index 0d452bc..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-s
-s
-scope
-variables
-variables 1
-s
-s
-s
-s
-scope
-variables
-variables 1
-s
-s
-scope
-variables
-s
-s
-s
-scope
-variables
-s
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_variables.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_variables.expected
deleted file mode 100644 (file)
index 882cc90..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_variables.js:21
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_variables.js:23
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_variables.js:24
-(escargot-debugger) scope
-Declarative Environment
-Declarative Environment
-Global Environment
-(escargot-debugger) variables
-c: number: 8
-d: unaccessible
-(escargot-debugger) variables 1
-a: number: 6
-b: unaccessible
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_variables.js:26
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_variables.js:35
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_variables.js:30 (in f() at line:29, col:1)
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_variables.js:32 (in f() at line:29, col:1)
-(escargot-debugger) scope
-Declarative Environment
-Function Environment
-Global Environment
-(escargot-debugger) variables
-c: undefined
-(escargot-debugger) variables 1
-a: number: 1
-b: number: 2
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_variables.js:37
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_variables.js:38
-(escargot-debugger) scope
-Object Environment
-Global Environment
-(escargot-debugger) variables
-p1: number: 1
-p2: number: 2
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_variables.js:43
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_variables.js:44
-(escargot-debugger) s
-Stopped at tools/debugger/tests/do_variables.js:45
-(escargot-debugger) scope
-Declarative Environment
-Global Environment
-(escargot-debugger) variables
-a1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567...: number: 1
-b: string: 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678...
-(escargot-debugger) s
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_variables2.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_variables2.cmd
deleted file mode 100644 (file)
index 24227ff..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-b do_variables2.js:33
-c
-variables
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_variables2.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_variables2.expected
deleted file mode 100644 (file)
index 8fcd042..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_variables2.js:22
-(escargot-debugger) b do_variables2.js:33
-Breakpoint 1 at tools/debugger/tests/do_variables2.js:33
-(escargot-debugger) c
-Stopped at breakpoint:1 tools/debugger/tests/do_variables2.js:33
-(escargot-debugger) variables
-a: undefined
-b: null
-c: boolean: true
-d: boolean: false
-e: number: 3.14
-f: string: str
-g: symbol: sym
-h: object [id: 0]
-i: array [id: 1]
-j: function [id: 2]
-l: bigint: 900719925474099123
-k: unaccessible
-(escargot-debugger) c
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_한글문자.cmd b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_한글문자.cmd
deleted file mode 100644 (file)
index f2ad6c7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-c
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_한글문자.expected b/lwnode/code/escargotshim/deps/escargot/tools/debugger/tests/do_한글문자.expected
deleted file mode 100644 (file)
index 131782f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-Connecting to: localhost:6501
-Connection created!!!
-Stopped at tools/debugger/tests/do_한글문자.js:20
-(escargot-debugger) c
-Print: 모음 쓰기 및 발음
-Print: 이중모음
-Print: 자음
-Print: 자음 발음
-Print: 음절 법칙
-Connection closed.
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/gen_unicode.py b/lwnode/code/escargotshim/deps/escargot/tools/gen_unicode.py
deleted file mode 100755 (executable)
index 73f7706..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2020-present Samsung Electronics Co., Ltd.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import subprocess
-import sys
-import os
-
-from argparse import ArgumentParser
-
-
-PARAGRAPH_SEP = "# ================================================\n"
-ID_START_TITLE = "# Derived Property: ID_Start\n"
-ID_CONTINUE_TITLE = "# Derived Property: ID_Continue\n"
-
-
-BASIC_PLANE_START = dict()
-LONG_RANGE_LENGHT = []
-BASIC_PLANE_CONTINUE = dict()
-
-
-SUPPLEMENTARY_PLANE = dict()
-MERGED_ID_START = dict()
-
-
-TERM_RED = '\033[1;31m'
-TERM_GREEN = '\033[1;32m'
-TERM_YELLOW = '\033[1;33m'
-TERM_EMPTY = '\033[0m'
-
-
-class UnicodeTable:
-    def __init__(self):
-        self.header = []
-        self.data = []
-        self.footer = []
-
-    def add_header(self, header_text):
-        self.header.append(header_text)
-        self.header.append("")
-
-
-    def add_footer(self, footer_text):
-        self.footer.append(footer_text)
-        self.footer.append("")
-
-
-    def add_table(self, table, table_name, table_type, table_descr):
-        self.data.append("/* %s */" % (table_descr))
-        self.data.append("const %s identRange%s[%s] = {" % (table_type,table_name,len(table)))
-        self.data.append('    ' + ', '.join(map(str, table)))
-        self.data.append("};")
-        self.data.append("")
-
-    def generate(self):
-        with open(os.path.dirname(os.path.abspath(__file__)) + "/../src/parser/UnicodeIdentifierTables.cpp", 'w') as unicode_table_file:
-            unicode_table_file.write("\n".join([str(i) for i in self.header]))
-            unicode_table_file.write("\n".join([str(i) for i in self.data]))
-            unicode_table_file.write("\n".join([str(i) for i in self.footer]))
-
-
-def create_basic_plane_table():
-
-    # zero_width_non_joiner and zero_width_joiner needs to be added here
-    # http://www.ecma-international.org/ecma-262/10.0/#prod-IdentifierName
-    # $ and _ are handled directly in the Escargot Lexer
-    other_starters = [0x200C,0x200D]
-    for key in other_starters:
-        BASIC_PLANE_START[key] = 1
-
-    # Create new merged dict
-    for k, v in BASIC_PLANE_START.items():
-        MERGED_ID_START[k] = v
-
-    # Copy unicodes not present in base
-    for continue_key in BASIC_PLANE_CONTINUE.keys():
-        if not MERGED_ID_START.has_key(continue_key):
-            MERGED_ID_START[continue_key] = BASIC_PLANE_CONTINUE[continue_key]
-
-    # Merge ranges if possible
-    # Get collection of keys
-    ordered_keys = sorted(MERGED_ID_START.keys())
-    for key in range(len(MERGED_ID_START)-1, 1, -1):
-        # If key value is equal than
-        if ordered_keys[key] == ordered_keys[key-1]+MERGED_ID_START[ordered_keys[key-1]]+1:
-            # combine the length of the two
-            # refresh key length value with the sum of the sperate values
-            # pop next value out from the dict
-            new_length = MERGED_ID_START[ordered_keys[key]] + MERGED_ID_START[ordered_keys[key-1]] + 1
-            MERGED_ID_START[ordered_keys[key-1]] = new_length
-            error = MERGED_ID_START.pop(ordered_keys[key])
-
-    # Create the long range table
-    long_length_index = 0
-    for key, value in MERGED_ID_START.iteritems():
-        if value >= 200:
-            LONG_RANGE_LENGHT.append(value)
-            new_value = 200+long_length_index
-            long_length_index+=1
-            MERGED_ID_START[key] = new_value
-
-
-def unify_non_basic_plane():
-    # Merge ranges if possible
-    # Get collection of keys
-    ordered_keys = sorted(SUPPLEMENTARY_PLANE.keys())
-    for key in range(len(SUPPLEMENTARY_PLANE)-1, 1, -1):
-        # If key value is equal than
-        if ordered_keys[key] == ordered_keys[key-1]+SUPPLEMENTARY_PLANE[ordered_keys[key-1]]+1:
-            # Combine the length of the two
-            # Refresh key length value with the sum of the sperate values
-            # Pop next value out from the dict
-            new_length = SUPPLEMENTARY_PLANE[ordered_keys[key]] + SUPPLEMENTARY_PLANE[ordered_keys[key-1]]
-            SUPPLEMENTARY_PLANE[ordered_keys[key-1]] = new_length
-            error = SUPPLEMENTARY_PLANE.pop(ordered_keys[key])
-
-
-def generate_ranges(file):
-    bigger = 0
-    long_range_index = 0
-    with open(file, "r") as fp:
-        line = fp.readline()
-        while line:
-            line = fp.readline()
-            if (line == PARAGRAPH_SEP):
-                # Read twice to skip empty line
-                paragraph_title = fp.readline()
-                paragraph_title = fp.readline()
-                if (paragraph_title == ID_START_TITLE) or (paragraph_title == ID_CONTINUE_TITLE):
-                    long_range_index = 0
-                    # Skip 8 lines, containing definition of ID_START
-                    # or skip 9 in case of ID_CONTINUE
-                    skip = 8
-                    if (paragraph_title == ID_CONTINUE_TITLE):
-                        skip = 9
-
-                    for _ in range(skip):
-                        fp.readline()
-                    unicode_range_line = fp.readline()
-                    while (unicode_range_line != "\n"):
-                        sub_lines = ""
-                        ranges = ""
-                        # Cut out ranges
-                        sub_lines = unicode_range_line.split(';')
-                        # Cut ranges to check length
-                        # Convert into int
-                        ranges = sub_lines[0].split('..')
-                        start = (int(ranges[0],16))
-
-                        if (len(ranges) == 2):
-                            length = (int(ranges[1],16) - int(ranges[0],16))
-                        else:
-                            length = 1
-
-                        # Basic plane for Escargot's uint16_t
-                        # Skip the ascii part as it is handled directly
-                        # in the Lexer.cpp
-                        if (128 < start) and (start <= 65535):
-                            if skip == 8:
-                                if not BASIC_PLANE_START.has_key(start):
-                                    BASIC_PLANE_START[start] = length
-                            else:
-                                if not BASIC_PLANE_CONTINUE.has_key(start):
-                                    BASIC_PLANE_CONTINUE[start] = length
-                        # Supplementary Plane data
-                        elif start > 65535:
-                            SUPPLEMENTARY_PLANE[start] = length
-                        unicode_range_line = fp.readline()
-
-
-def main():
-    print("\n%sAutomated Unicode Identifier Table Generator for Escargot %s\n" % (TERM_GREEN,TERM_EMPTY))
-    parser = ArgumentParser(description='Kangax runner for the Escargot engine')
-    parser.add_argument('--derived_core_properties', metavar='FILE', action='store', required=True, help='specify the unicode data file')
-    args = parser.parse_args()
-
-    if not os.path.isfile(args.derived_core_properties):
-        parser.error("\n\n%sArgument file is non-existent!%s\nGiven: %s\n" % (TERM_RED,TERM_EMPTY,args.derived_core_properties))
-
-    # Process Derived File
-    print("%s..Processing Derived Core Properties file %s\n" % (TERM_YELLOW,TERM_EMPTY))
-    generate_ranges(args.derived_core_properties)
-
-    # Porcess data for the basic plane
-    # and unify the supplementary
-    print("%s..Calculating proper ranges %s\n" % (TERM_YELLOW,TERM_EMPTY))
-    create_basic_plane_table()
-    unify_non_basic_plane()
-
-    # Start collecting output data
-    print("%s..Collecting output data %s\n" % (TERM_YELLOW,TERM_EMPTY))
-    generated_data = UnicodeTable()
-    licence = "/* * Copyright (c) 2020-present Samsung Electronics Co., Ltd\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2.1 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\n *  USA\n */\n"
-    header = "/* This file is automatically generated by the %s script\n* from https://www.unicode.org/Public/13.0.0/ucd/DerivedCoreProperties.txt\n* DO NOT EDIT!\n*/" % (os.path.basename(__file__))
-    ifdef_namespace ="#include \"UnicodeIdentifierTables.h\"\n\nnamespace Escargot {\nnamespace EscargotLexer {\n"
-    footer_namespace = "const uint16_t basic_plane_length = sizeof(identRangeStart);\nconst uint16_t supplementary_plane_length = sizeof(identRangeStartSupplementaryPlane);\n}\n}"
-
-    # Append Generated Warning, licence, ifdef
-    generated_data.add_header(licence)
-    generated_data.add_header(header)
-    generated_data.add_header(ifdef_namespace)
-
-    # Fetch data for the basic plane
-    keys = sorted(MERGED_ID_START.keys())
-    values = []
-    for key in keys:
-        values.append(MERGED_ID_START[key])
-
-    # Append basic plane values
-    generated_data.add_table(keys,"Start","uint16_t","Starting codepoints of identifier ranges.")
-    generated_data.add_table(values,"Length","uint16_t","Lengths of identifier ranges.")
-    generated_data.add_table(LONG_RANGE_LENGHT,"LongLength","uint16_t","Lengths of identifier ranges greater than LEXER IDENT_RANGE_LONG.")
-
-    # Fetch data for the supplementary plane
-    keys = sorted(SUPPLEMENTARY_PLANE.keys())
-    values = []
-    for key in keys:
-        values.append(SUPPLEMENTARY_PLANE[key])
-
-    # Append suppelmentary values
-    generated_data.add_table(keys,"StartSupplementaryPlane","uint32_t","Identifier starting codepoints for the supplementary plane")
-    generated_data.add_table(values,"LengthSupplementaryPlane","uint16_t","Lengths of identifier ranges for the supplementary plane")
-    # Append footer
-    generated_data.add_footer(footer_namespace)
-
-    # Writeout data
-    print("%s..Writing out data %s\n" % (TERM_YELLOW,TERM_EMPTY))
-    generated_data.generate()
-    print("\n%sTables generated into src/parser/UnicodeIdentifierTables.cpp %s\n" % (TERM_GREEN,TERM_EMPTY))
-
-if __name__ == '__main__':
-    main()
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/genereate_unicode_pattern_tables.sh b/lwnode/code/escargotshim/deps/escargot/tools/genereate_unicode_pattern_tables.sh
deleted file mode 100644 (file)
index a16bc1b..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright 2021-present Samsung Electronics Co., Ltd.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-UCD_URL="https://www.unicode.org/Public/UCD/latest/ucd/UCD.zip"
-WEBKIT_GENERATOR_URL="https://raw.githubusercontent.com/WebKit/WebKit/main/Source/JavaScriptCore/yarr/generateYarrUnicodePropertyTables.py"
-WEBKIT_HASHER_URL="https://raw.githubusercontent.com/WebKit/WebKit/main/Source/JavaScriptCore/yarr/hasher.py"
-PATTERN_FILE_PATH="./third_party/yarr/UnicodePatternTables.h"
-
-echo -e "\nAutomated Unicode Pattern Table Tool for Escargot \n"
-
-#Fetching data and scripts
-echo -e "\n\nCurl UCD data"
-curl $UCD_URL -O
-
-echo -e "\n\nCurl Webkit pattern generator script"
-curl $WEBKIT_GENERATOR_URL -o "generateYarrUnicodePropertyTables.py"
-
-echo -e "\n\nCurl Hasher for Generator"
-curl $WEBKIT_HASHER_URL -o "hasher.py"
-
-echo -e "\n\nUnzip and move UCD files"
-unzip ./UCD.zip -d UCD
-mv ./UCD/emoji/emoji-data.txt ./UCD
-mv ./UCD/extracted/* ./UCD
-
-echo -e "\n\nGenerate new patter table"
-chmod +x generateYarrUnicodePropertyTables.py
-./generateYarrUnicodePropertyTables.py ./UCD $PATTERN_FILE_PATH
-
-
-#Reformatting for Escargot Usage
-echo -e "\nReformat for Escargot"
-sed -i 's/makeUnique/std::make_unique/g' $PATTERN_FILE_PATH
-grep -v "generated" $PATTERN_FILE_PATH > temp_file; mv temp_file $PATTERN_FILE_PATH
-
-perl -0777 -i -p -e 's/,\n        CharacterClassWidths::HasBothBMPAndNonBMP\);/\);\n    characterClass->m_hasNonBMPCharacters = true;/g' $PATTERN_FILE_PATH
-perl -0777 -i -p -e 's/,\n        CharacterClassWidths::HasBMPChars\);/\);\n    characterClass->m_hasNonBMPCharacters = false;/g' $PATTERN_FILE_PATH
-perl -0777 -i -p -e 's/,\n        CharacterClassWidths::HasNonBMPChars\);/\);\n    characterClass->m_hasNonBMPCharacters = true;/g' $PATTERN_FILE_PATH
-sed -i 's/\s*$//g' $PATTERN_FILE_PATH
-
-#Cleanup
-echo -e "\nCleaning up files"
-rm -rf ./UCD
-rm ./UCD.zip
-rm generateYarrUnicodePropertyTables.py
-rm hasher.py
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/kangax/escargot.patch b/lwnode/code/escargotshim/deps/escargot/tools/kangax/escargot.patch
deleted file mode 100644 (file)
index d85c3fb..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-diff --git a/environments.json b/environments.json
-index f7b14fd7..eca521de 100644
---- a/environments.json
-+++ b/environments.json
-@@ -3204,6 +3204,18 @@
-       "es6"
-     ]
-   },
-+  "escargot": {
-+    "full": "Escargot Master",
-+    "family": "Escargot",
-+    "short": "Esc",
-+    "platformtype": "engine",
-+    "release": "2019-11-15",
-+    "obsolete": false,
-+    "test_suites": [
-+      "es6",
-+      "es2016plus"
-+    ]
-+  },
-   "nashorn1_8": {
-     "full": "Oracle Nashorn 1.8",
-     "family": "Nashorn",
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/kangax/run-kangax.py b/lwnode/code/escargotshim/deps/escargot/tools/kangax/run-kangax.py
deleted file mode 100755 (executable)
index bdbe108..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2020-present Samsung Electronics Co., Ltd.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import subprocess
-import sys
-import os
-
-from argparse import ArgumentParser
-
-PATH = os.path.dirname(os.path.abspath(__file__))
-
-TERM_RED = '\033[1;31m'
-TERM_GREEN = '\033[1;32m'
-TERM_YELLOW = '\033[1;33m'
-TERM_EMPTY = '\033[0m'
-
-
-def separator_line():
-    print("{0}=====================================\n {1}".format(TERM_YELLOW, TERM_EMPTY))
-
-
-def get_results(filename, no_of_lines=1):
-    res = []
-    file = open(filename,'r')
-    lines = file.readlines()
-    last_lines = lines[-no_of_lines:]
-    for line in last_lines:
-        res.append(line)
-    file.close()
-    return res
-
-
-def run_testsuite(suite,engine):
-    separator_line()
-    print("{0}Running kangax suite(s):\n {1}{2}".format(TERM_YELLOW, 'es6\n es2016plus\n' if suite=='""' else suite, TERM_EMPTY))
-    separator_line()
-
-    if engine != 'local':
-        engine = engine
-    else:
-        engine = '../../escargot'
-
-    os.chdir(PATH + '/../../test/kangax/')
-    if suite == '""':
-        es6res = open("./kangaxES6Res.txt", "w")
-        es6plusres = open("./kangaxES6PLUSRes.txt", "w")
-        nodeFails = open("./kangaxRunErrors.txt", "w")
-        subprocess.call(['node', './escargot.js', engine, 'es6'], stdout = es6res, stderr = nodeFails)
-        print("{0}ES6 RESULTS:\n{1}".format(TERM_YELLOW, TERM_EMPTY))
-        grepProc = subprocess.Popen(['grep -hr "actual: false" ./kangaxES6Res.txt'], stdout=subprocess.PIPE, shell=True)
-        (fails, err) = grepProc.communicate()
-        print(''.join(get_results("./kangaxES6Res.txt", 2)))
-        print("{0}ES6 Fails:\n{1}".format(TERM_RED, TERM_EMPTY))
-        print(''.join(fails))
-        print("{0}Errors:\n{1}".format(TERM_RED, TERM_EMPTY))
-        es6res.close()
-        nodeFails.close()
-        with open("./kangaxRunErrors.txt", "r") as lines:
-            print(lines.read())
-        print('\n')
-
-        nodeFails = open("./kangaxRunErrors.txt", "w")
-        subprocess.call(['node', './escargot.js', engine, 'es2016plus'], stdout = es6plusres, stderr = nodeFails)
-        print("{0}ES6PLUS RESULTS:\n{1}".format(TERM_YELLOW, TERM_EMPTY))
-        grepProc = subprocess.Popen(['grep -hr "actual: false" ./kangaxES6PLUSRes.txt'], stdout=subprocess.PIPE, shell=True)
-        (fails, err) = grepProc.communicate()
-        print(''.join(get_results("./kangaxES6PLUSRes.txt", 2)))
-        print("{0}ES6PLUS FAILS:\n{1}".format(TERM_RED, TERM_EMPTY))
-        print(''.join(fails))
-        print("{0}Errors:\n{1}".format(TERM_RED, TERM_EMPTY))
-        es6plusres.close()
-        nodeFails.close()
-        with open("./kangaxRunErrors.txt", "r") as lines:
-            print(lines.read())
-        print('\n')
-    else:
-        res = open("./kangaxRes.txt", "w")
-        nodeFails = open("./kangaxRunErrors.txt", "w")
-        subprocess.call(['node', './escargot.js', engine, suite], stdout = res, stderr = nodeFails)
-        grepProc = subprocess.Popen(['grep -hr "actual: false" ./kangaxRes.txt'], stdout=subprocess.PIPE, shell=True)
-        (fails, err) = grepProc.communicate()
-        print("{0}{1} RESULTS:\n\n{2}".format(TERM_YELLOW, suite, TERM_EMPTY))
-        print( ''.join(get_results("./kangaxRes.txt", 2)))
-        print("{0}FAILS:\n{1}".format(TERM_RED, TERM_EMPTY))
-        print(''.join(fails))
-        print("{0}Errors:\n{1}".format(TERM_RED, TERM_EMPTY))
-        res.close()
-        nodeFails.close()
-        with open("./kangaxRunErrors.txt", "r") as lines:
-            print(lines.read())
-        print('\n')
-
-
-def kangax_setup():
-    os.chdir(PATH + '/../../test/')
-    if os.path.isdir("./kangax/"):
-        print("{0}/test/kangax directory is present\nAssuming correct repository there{1}\n".format(TERM_YELLOW, TERM_EMPTY))
-    else:
-        print("{0}Update kangax repository\n{1}{2}\n".format(TERM_YELLOW, PATH + '/../../test/' + 'kangax', TERM_EMPTY))
-        os.system("git submodule update {0}".format(PATH + '/../../test/kangax'))
-
-
-    separator_line()
-    print("{0}Patching kangax enviroment\n applying patch{1}".format(TERM_YELLOW, TERM_EMPTY))
-    os.chdir(PATH + '/../../test/kangax')
-    os.system('git apply {0}'.format(PATH + '/escargot.patch'))
-    os.chdir(PATH)
-    print("{0} adding Escargot runner{1}\n".format(TERM_YELLOW, TERM_EMPTY))
-    os.system('cp {0} {1}'.format(PATH + '/escargot.js',PATH + '/../../test/kangax/'))
-
-
-
-def main():
-    parser = ArgumentParser(description='Kangax runner for the Escargot engine')
-    parser.add_argument('--suite', nargs='?', default='""',  choices=['es6', 'es2016plus'], help='Run kangax suite (choices: %(choices)s)')
-    parser.add_argument('--engine', nargs='?', default='local', help='Define escargot path. Leave empty for project root ./escargot file')
-    args = parser.parse_args()
-
-    separator_line()
-    print("{0}KANGAX RUNNER FOR \nESCARGOT REPOSITORY\n{1}".format(TERM_YELLOW, TERM_EMPTY))
-    separator_line()
-    kangax_setup()
-    run_testsuite(args.suite,args.engine)
-
-
-if __name__ == '__main__':
-    main()
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/run-tests.py b/lwnode/code/escargotshim/deps/escargot/tools/run-tests.py
deleted file mode 100755 (executable)
index f18e910..0000000
+++ /dev/null
@@ -1,667 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2018-present Samsung Electronics Co., Ltd.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from __future__ import print_function
-
-import os
-import traceback
-import sys
-import time
-import re, fnmatch
-
-from argparse import ArgumentParser
-from difflib import unified_diff
-from glob import glob
-from os.path import abspath, basename, dirname, join, relpath
-from shutil import copy
-from subprocess import PIPE, Popen
-
-
-PROJECT_SOURCE_DIR = dirname(dirname(abspath(__file__)))
-DEFAULT_ESCARGOT = join(PROJECT_SOURCE_DIR, 'escargot')
-
-
-COLOR_RED = '\033[31m'
-COLOR_GREEN = '\033[32m'
-COLOR_YELLOW = '\033[33m'
-COLOR_BLUE = '\033[34m'
-COLOR_PURPLE = '\033[35m'
-COLOR_RESET = '\033[0m'
-
-
-RUNNERS = {}
-DEFAULT_RUNNERS = []
-
-
-class runner(object):
-
-    def __init__(self, suite, default=False):
-        self.suite = suite
-        self.default = default
-
-    def __call__(self, fn):
-        RUNNERS[self.suite] = fn
-        if self.default:
-            DEFAULT_RUNNERS.append(self.suite)
-        return fn
-
-
-def run(args, cwd=None, env=None, stdout=None, checkresult=True, report=False):
-    if cwd:
-        print(COLOR_BLUE + 'cd ' + cwd + ' && \\' + COLOR_RESET)
-    if env:
-        for var, val in sorted(env.items()):
-            print(COLOR_BLUE + var + '=' + val + ' \\' + COLOR_RESET)
-    print(COLOR_BLUE + ' '.join(args) + COLOR_RESET)
-
-    if env is not None:
-        full_env = dict(os.environ)
-        full_env.update(env)
-        env = full_env
-
-    proc = Popen(args, cwd=cwd, env=env, stdout=PIPE if report else stdout)
-
-    counter = 0
-
-    while report:
-        nextline = proc.stdout.readline()
-        if nextline == '' and proc.poll() is not None:
-            break
-        stdout.write(nextline)
-        stdout.flush()
-        if counter % 250 == 0:
-            print('Ran %d tests..' % (counter))
-        counter += 1
-
-    out, _ = proc.communicate()
-
-    if out:
-        print(out)
-
-    if checkresult and proc.returncode:
-        raise Exception('command `%s` exited with %s' % (' '.join(args), proc.returncode))
-    return out
-
-
-def readfile(filename):
-    with open(filename, 'r') as f:
-        return f.readlines()
-
-
-@runner('sunspider')
-def run_sunspider(engine, arch):
-    run([join('.', 'sunspider'),
-        '--shell', engine,
-        '--suite', 'sunspider-1.0.2'],
-        cwd=join(PROJECT_SOURCE_DIR, 'test', 'vendortest', 'SunSpider'))
-
-
-@runner('sunspider-js', default=True)
-def run_sunspider_js(engine, arch):
-    run([engine] + sorted(glob(join(PROJECT_SOURCE_DIR, 'test', 'vendortest', 'SunSpider', 'tests', 'sunspider-1.0.2', '*.js'))))
-
-
-@runner('octane', default=True)
-def run_octane(engine, arch):
-    max_retry_count = 5
-    try_count = 0
-    last_error = None
-    while try_count < max_retry_count:
-        try:
-            OCTANE_DIR = join(PROJECT_SOURCE_DIR, 'test', 'octane')
-
-            stdout = run(['/usr/bin/time', '-f', '%M', '-o', 'mem.txt', engine, 'run.js'],
-                         cwd=OCTANE_DIR,
-                         stdout=PIPE)
-            f = open(join(OCTANE_DIR, 'mem.txt'))
-            for s in f:
-                rss = s.strip("\n")
-            mem = int(rss)
-            print('Octane maximum resident set size: ' + str(mem) + 'KB')
-
-            if arch == str('x86_64') and mem > 250000:
-                raise Exception('Exceed memory consumption')
-            if arch == str('x86') and mem > 150000:
-                raise Exception('Exceed memory consumption')
-
-            if 'Score' not in stdout:
-                raise Exception('no "Score" in stdout')
-            return
-        except Exception as e:
-            last_error = e
-            try_count = try_count + 1
-
-
-    raise last_error
-
-
-@runner('octane-loading', default=True)
-def run_octane_loading(engine, arch):
-    OCTANE_OVERRIDE_DIR = join(PROJECT_SOURCE_DIR, 'tools', 'test', 'octane')
-    OCTANE_DIR = join(PROJECT_SOURCE_DIR, 'test', 'octane')
-    copy(join(OCTANE_OVERRIDE_DIR, 'runLoading.js'), join(OCTANE_DIR, 'runLoading.js'))
-
-    run([engine, 'runLoading.js'],
-         cwd=OCTANE_DIR)
-
-
-@runner('modifiedVendorTest', default=True)
-def run_internal_test(engine, arch):
-    INTERNAL_OVERRIDE_DIR = join(PROJECT_SOURCE_DIR, 'tools', 'test', 'ModifiedVendorTest')
-    INTERNAL_DIR = join(PROJECT_SOURCE_DIR, 'test', 'vendortest', 'ModifiedVendorTest')
-
-    copy(join(INTERNAL_OVERRIDE_DIR, 'internal-test-cases.txt'), join(INTERNAL_DIR, 'internal-test-cases.txt'))
-    copy(join(INTERNAL_OVERRIDE_DIR, 'internal-test-driver.py'), join(INTERNAL_DIR, 'driver.py'))
-
-    run(['python', 'driver.py', engine, 'internal-test-cases.txt'],
-        cwd=INTERNAL_DIR)
-
-
-@runner('test262', default=True)
-def run_test262(engine, arch):
-    TEST262_OVERRIDE_DIR = join(PROJECT_SOURCE_DIR, 'tools', 'test', 'test262')
-    TEST262_DIR = join(PROJECT_SOURCE_DIR, 'test', 'test262')
-
-    copy(join(TEST262_OVERRIDE_DIR, 'excludelist.orig.xml'), join(TEST262_DIR, 'excludelist.xml'))
-    copy(join(TEST262_OVERRIDE_DIR, 'cth.js'), join(TEST262_DIR, 'harness', 'cth.js'))
-    copy(join(TEST262_OVERRIDE_DIR, 'testIntl.js'), join(TEST262_DIR, 'harness', 'testIntl.js'))
-
-    copy(join(TEST262_OVERRIDE_DIR, 'parseTestRecord.py'), join(TEST262_DIR, 'tools', 'packaging', 'parseTestRecord.py'))
-    copy(join(TEST262_OVERRIDE_DIR, 'test262.py'), join(TEST262_DIR, 'tools', 'packaging', 'test262.py')) # for parallel running (we should re-implement this for es6 suite)
-
-    stdout = run(['pypy', join('tools', 'packaging', 'test262.py'),
-         '--command', engine,
-         '--full-summary'],
-        cwd=TEST262_DIR,
-        env={'TZ': 'US/Pacific'},
-        stdout=PIPE)
-
-    summary = stdout.split('=== Test262 Summary ===')[1]
-    if summary.find('- All tests succeeded') < 0:
-        raise Exception('test262 failed')
-    print('test262: All tests passed')
-
-@runner('test262-strict', default=True)
-def run_test262_strict(engine, arch):
-    TEST262_OVERRIDE_DIR = join(PROJECT_SOURCE_DIR, 'tools', 'test', 'test262')
-    TEST262_DIR = join(PROJECT_SOURCE_DIR, 'test', 'test262')
-
-    copy(join(TEST262_OVERRIDE_DIR, 'excludelist.orig.xml'), join(TEST262_DIR, 'excludelist.xml'))
-    copy(join(TEST262_OVERRIDE_DIR, 'test262.py'), join(TEST262_DIR, 'tools', 'packaging', 'test262.py')) # for parallel running (we should re-implement this for es6 suite)
-
-    out = open('test262-strict_out', 'w')
-
-    run(['pypy', join('tools', 'packaging', 'test262.py'),
-         '--command', engine,
-         '--full-summary',
-         '--strict_only'],
-        cwd=TEST262_DIR,
-        env={'TZ': 'US/Pacific'},
-        stdout=out,
-        report=True)
-
-    out.close()
-
-    with open('test262-strict_out', 'r') as out:
-        full = out.read()
-        summary = full.split('=== Summary ===')[1]
-        if summary.find('- All tests succeeded') < 0:
-            print(summary)
-            raise Exception('test262-strict failed')
-
-        print('test262-strict: All tests passed')
-
-
-@runner('test262-nonstrict', default=True)
-def run_test262_nonstrict(engine, arch):
-    TEST262_OVERRIDE_DIR = join(PROJECT_SOURCE_DIR, 'tools', 'test', 'test262')
-    TEST262_DIR = join(PROJECT_SOURCE_DIR, 'test', 'test262')
-
-    copy(join(TEST262_OVERRIDE_DIR, 'excludelist.orig.xml'), join(TEST262_DIR, 'excludelist.xml'))
-    copy(join(TEST262_OVERRIDE_DIR, 'test262.py'), join(TEST262_DIR, 'tools', 'packaging', 'test262.py')) # for parallel running (we should re-implement this for es6 suite)
-
-    out = open('test262-nonstrict_out', 'w')
-
-    run(['pypy', join('tools', 'packaging', 'test262.py'),
-         '--command', engine,
-         '--full-summary',
-         '--non_strict_only'],
-        cwd=TEST262_DIR,
-        env={'TZ': 'US/Pacific'},
-        stdout=out,
-        report=True)
-
-    out.close()
-
-    with open('test262-nonstrict_out', 'r') as out:
-        full = out.read()
-        summary = full.split('=== Summary ===')[1]
-        if summary.find('- All tests succeeded') < 0:
-            print(summary)
-            raise Exception('test262-nonstrict failed')
-
-        print('test262-nonstrict: All tests passed')
-
-
-@runner('spidermonkey', default=True)
-def run_spidermonkey(engine, arch):
-    SPIDERMONKEY_OVERRIDE_DIR = join(PROJECT_SOURCE_DIR, 'tools', 'test', 'spidermonkey')
-    SPIDERMONKEY_DIR = join(PROJECT_SOURCE_DIR, 'test', 'vendortest', 'SpiderMonkey')
-
-    run([join(SPIDERMONKEY_DIR, 'jstests.py'),
-         '--no-progress', '-s',
-         '--timeout', '500',
-         '--xul-info', '%s-gcc3:Linux:false' % arch,
-         '--exclude-file', join(SPIDERMONKEY_OVERRIDE_DIR, 'excludelist.txt'),
-         engine,
-         '--output-file', join(SPIDERMONKEY_OVERRIDE_DIR, '%s.log.txt' % arch),
-         '--failure-file', join(SPIDERMONKEY_OVERRIDE_DIR, '%s.gen.txt' % arch),
-         'non262/Array', 'non262/ArrayBuffer', 'non262/arrow-functions', 'non262/BigInt', 'non262/Boolean', 'non262/class', 'non262/comprehensions', 'non262/DataView', 'non262/Date',
-         'non262/destructuring', 'non262/Error', 'non262/eval', 'non262/Exceptions', 'non262/execution-contexts', 'non262/expressions', 'non262/extensions', 'non262/fields', 'non262/Function',
-         'non262/GC', 'non262/generators', 'non262/get-set', 'non262/global', 'non262/Intl', 'non262/iterable', 'non262/jit', 'non262/JSON', 'non262/lexical', 'non262/lexical-conventions',
-         'non262/lexical-environment', 'non262/literals', 'non262/Map', 'non262/Math', 'non262/misc', 'non262/module', 'non262/Number', 'non262/object', 'non262/operators', 'non262/pipeline',
-         'non262/Promise', 'non262/Proxy', 'non262/Reflect', 'non262/reflect-parse', 'non262/RegExp', 'non262/regress', 'non262/Scope', 'non262/Script', 'non262/Set', 'non262/statements',
-         'non262/strict', 'non262/String', 'non262/Symbol', 'non262/syntax', 'non262/template-strings', 'non262/TypedArray', 'non262/TypedObject', 'non262/types', 'non262/Unicode', 'non262/WeakMap'],
-        env={'LOCALE': 'en_US'})
-
-    orig = sorted(readfile(join(SPIDERMONKEY_OVERRIDE_DIR, '%s.orig.txt' % arch)))
-    gen = sorted(readfile(join(SPIDERMONKEY_OVERRIDE_DIR, '%s.gen.txt' % arch)))
-    diff = list(unified_diff(orig, gen))
-    if diff:
-        for diffline in diff:
-            print(diffline)
-        raise Exception('failure files differ')
-
-
-@runner('jsc-stress', default=True)
-def run_jsc_stress(engine, arch):
-    JSC_DIR = join('test', 'vendortest', 'driver')
-
-    run([join(JSC_DIR, 'driver.py'),
-         '-s', 'stress',
-         '-e', engine,
-         '-a', arch],
-        cwd=PROJECT_SOURCE_DIR,
-        env={'PYTHONPATH': '.'})
-
-
-def _run_regression_tests(engine, assert_js, files, is_fail):
-    fails = 0
-    for file in files:
-        proc = Popen([engine, assert_js, file], stdout=PIPE)
-        out, _ = proc.communicate()
-
-        if is_fail and proc.returncode or not is_fail and not proc.returncode:
-            print('%sOK: %s%s' % (COLOR_GREEN, file, COLOR_RESET))
-        else:
-            print('%sFAIL(%d): %s%s' % (COLOR_RED, proc.returncode, file, COLOR_RESET))
-            print(out)
-
-            fails += 1
-
-    return fails
-
-
-@runner('regression-tests', default=True)
-def run_regression_tests(engine, arch):
-    REGRESSION_DIR = join(PROJECT_SOURCE_DIR, 'test', 'vendortest', 'Escargot', 'regression-tests')
-    REGRESSION_XFAIL_DIR = join(REGRESSION_DIR, 'xfail')
-    REGRESSION_ASSERT_JS = join(REGRESSION_DIR, 'assert.js')
-
-    print('Running regression tests:')
-    xpass = glob(join(REGRESSION_DIR, 'issue-*.js'))
-    xpass_result = _run_regression_tests(engine, REGRESSION_ASSERT_JS, xpass, False)
-
-    print('Running regression tests expected to fail:')
-    xfail = glob(join(REGRESSION_XFAIL_DIR, 'issue-*.js'))
-    xfail_result = _run_regression_tests(engine, REGRESSION_ASSERT_JS, xfail, True)
-
-    tests_total = len(xpass) + len(xfail)
-    fail_total = xfail_result + xpass_result
-    print('TOTAL: %d' % (tests_total))
-    print('%sPASS : %d%s' % (COLOR_GREEN, tests_total - fail_total, COLOR_RESET))
-    print('%sFAIL : %d%s' % (COLOR_RED, fail_total, COLOR_RESET))
-
-    if fail_total > 0:
-        raise Exception("Regression tests failed")
-
-
-def _run_jetstream(engine, target_test):
-    JETSTREAM_OVERRIDE_DIR = join(PROJECT_SOURCE_DIR, 'tools', 'test', 'jetstream')
-    JETSTREAM_DIR = join(PROJECT_SOURCE_DIR, 'test', 'vendortest', 'JetStream-1.1')
-
-    copy(join(JETSTREAM_OVERRIDE_DIR, 'jetstream.CDjsSetup.js'), join(JETSTREAM_DIR, 'CDjsSetup.js'))
-    copy(join(JETSTREAM_OVERRIDE_DIR, 'jetstream.OctaneSetup.js'), join(JETSTREAM_DIR, 'OctaneSetup.js'))
-    copy(join(JETSTREAM_OVERRIDE_DIR, 'jetstream.Octane2Setup.js'), join(JETSTREAM_DIR, 'Octane2Setup.js'))
-    copy(join(JETSTREAM_OVERRIDE_DIR, 'jetstream.SimpleSetup.js'), join(JETSTREAM_DIR, 'SimpleSetup.js'))
-    copy(join(JETSTREAM_OVERRIDE_DIR, 'jetstream.SunSpiderSetup.js'), join(JETSTREAM_DIR, 'SunSpiderSetup.js'))
-    copy(join(JETSTREAM_OVERRIDE_DIR, 'jetstream.cdjs.util.js'), join(JETSTREAM_DIR, 'cdjs', 'util.js'))
-    copy(join(JETSTREAM_OVERRIDE_DIR, 'jetstream.runOnePlan.js'), join(JETSTREAM_DIR, 'runOnePlan.js'))
-    copy(join(JETSTREAM_OVERRIDE_DIR, 'jetstream.run.sh'), join(JETSTREAM_DIR, 'run.sh'))
-
-    run([join('.', 'run.sh'), engine, target_test],
-        cwd=JETSTREAM_DIR)
-    run(['python', join(JETSTREAM_OVERRIDE_DIR, 'parsingResults.py'),
-         join(JETSTREAM_OVERRIDE_DIR, 'jetstream-result-raw.res'),
-         target_test])
-    if 'NaN' in ''.join(readfile(join(JETSTREAM_OVERRIDE_DIR, 'jetstream-result-raw.res'))):
-        raise Exception('result contains "NaN"')
-
-
-@runner('jetstream-only-simple-parallel-1')
-def run_jetstream_only_simple_parallel_1(engine, arch):
-    _run_jetstream(engine, 'simple-1')
-
-
-@runner('jetstream-only-simple-parallel-2')
-def run_jetstream_only_simple_parallel_2(engine, arch):
-    _run_jetstream(engine, 'simple-2')
-
-
-@runner('jetstream-only-simple-parallel-3')
-def run_jetstream_only_simple_parallel_3(engine, arch):
-    _run_jetstream(engine, 'simple-3')
-
-
-@runner('jetstream-only-simple', default=True)
-def run_jetstream_only_simple(engine, arch):
-    _run_jetstream(engine, 'simple')
-
-
-@runner('jetstream-only-cdjs', default=True)
-def run_jetstream_only_cdjs(engine, arch):
-    _run_jetstream(engine, 'cdjs')
-
-
-@runner('jetstream-only-sunspider')
-def run_jetstream_only_sunspider(engine, arch):
-    _run_jetstream(engine, 'sunspider')
-
-
-@runner('jetstream-only-octane')
-def run_jetstream_only_octane(engine, arch):
-    _run_jetstream(engine, 'octane')
-
-
-@runner('chakracore', default=True)
-def run_chakracore(engine, arch):
-    CHAKRACORE_OVERRIDE_DIR = join(PROJECT_SOURCE_DIR, 'tools', 'test', 'chakracore')
-    CHAKRACORE_DIR = join(PROJECT_SOURCE_DIR, 'test', 'vendortest', 'ChakraCore')
-
-    copy(join(CHAKRACORE_OVERRIDE_DIR, 'chakracore.run.sh'), join(CHAKRACORE_DIR, 'run.sh'))
-    copy(join(CHAKRACORE_OVERRIDE_DIR, 'chakracore.include.js'), join(CHAKRACORE_DIR, 'include.js'))
-    copy(join(CHAKRACORE_OVERRIDE_DIR, 'chakracore.rlexedirs.xml'), join(CHAKRACORE_DIR, 'rlexedirs.xml'))
-    for rlexexml in glob(join(CHAKRACORE_OVERRIDE_DIR, '*.rlexe.xml')):
-        dirname, _, filename = basename(rlexexml).partition('.')
-        copy(rlexexml, join(CHAKRACORE_DIR, dirname, filename))
-    for js in [join(CHAKRACORE_DIR, 'DynamicCode', 'eval-nativecodedata.js'),
-               join(CHAKRACORE_DIR, 'utf8', 'unicode_digit_as_identifier_should_work.js')]:
-        with open(js, 'a') as f:
-            f.write("WScript.Echo('PASS');")
-
-    stdout = run(['bash', join(CHAKRACORE_DIR, 'run.sh'), relpath(engine)],
-                 stdout=PIPE)
-    with open(join(PROJECT_SOURCE_DIR, 'test', 'vendortest', 'driver', 'chakracore.%s.gen.txt' % arch), 'w') as gen_txt:
-        gen_txt.write(stdout)
-    run(['diff',
-         join(CHAKRACORE_OVERRIDE_DIR, 'chakracore.%s.orig.txt' % arch),
-         join(PROJECT_SOURCE_DIR, 'test', 'vendortest', 'driver', 'chakracore.%s.gen.txt' % arch)])
-
-
-@runner('v8', default=True)
-def run_v8(engine, arch):
-    V8_OVERRIDE_DIR = join(PROJECT_SOURCE_DIR, 'tools', 'test', 'v8')
-    V8_DIR = join(PROJECT_SOURCE_DIR, 'test', 'vendortest', 'v8')
-
-    copy(join(V8_OVERRIDE_DIR, 'v8.mjsunit.status'), join(V8_DIR, 'test', 'mjsunit', 'mjsunit.status'))
-    copy(join(V8_OVERRIDE_DIR, 'v8.mjsunit.js'), join(V8_DIR, 'test', 'mjsunit', 'mjsunit.js'))
-    copy(join(V8_OVERRIDE_DIR, 'v8.run-tests.py'), join(V8_DIR, 'tools', 'run-tests.py'))
-    copy(join(V8_OVERRIDE_DIR, 'v8.testsuite.py'), join(V8_DIR, 'tools', 'testrunner', 'local', 'testsuite.py'))
-    copy(join(V8_OVERRIDE_DIR, 'v8.execution.py'), join(V8_DIR, 'tools', 'testrunner', 'local', 'execution.py'))
-    copy(join(V8_OVERRIDE_DIR, 'v8.progress.py'), join(V8_DIR, 'tools', 'testrunner', 'local', 'progress.py'))
-
-    arch = {'x86': 'x32', 'x86_64': 'x64'}[arch]
-
-    if (engine == "escargot"):
-        shell_str = "../../../escargot"
-    else:
-        shell_str = engine
-
-    stdout = run([join(V8_DIR, 'tools', 'run-tests.py'),
-                  '--timeout=120',
-                  '--quickcheck',
-                  '--no-presubmit', '--no-variants',
-                  '--arch-and-mode=%s.release' % arch,
-                  '--shell', shell_str,
-                  '--escargot',
-                  '--report',
-                  '-p', 'verbose',
-                  '--no-sorting',
-                  '--no-network',
-                  'mjsunit'],
-                 stdout=PIPE,
-                 checkresult=False)
-    # FIXME: V8 test runner tends to exit with 2 (most probably the result of
-    # a `self.remaining != 0` in `testrunner.local.execution.Runner.Run()`.
-    # Couldn't find out yet why that happens.
-    # NOTE: This has also been suppressed in cmake/make-based executors by
-    # piping the output of run-test.py into a tee. In case of pipes, the
-    # observed exit code is that of the last element of the pipe, which is
-    # tee in that case (which is always 0).
-
-    if '=== All tests succeeded' not in stdout:
-        raise Exception('Not all tests succeeded')
-
-@runner('new-es', default=True)
-def run_new_es(engine, arch):
-    NEW_ES_DIR = join(PROJECT_SOURCE_DIR, 'test', 'vendortest', 'Escargot', 'new-es')
-    NEW_ES_ASSERT_JS = join(NEW_ES_DIR, 'assert.js')
-
-    print('Running new-es test:')
-    files = glob(join(NEW_ES_DIR, '*.js'))
-    files.remove(NEW_ES_ASSERT_JS)
-    fail_total = 0
-    for file in files:
-        proc = Popen([engine, NEW_ES_ASSERT_JS, file], stdout=PIPE)
-        out, _ = proc.communicate()
-
-        if not proc.returncode:
-            print('%sOK: %s%s' % (COLOR_GREEN, file, COLOR_RESET))
-        else:
-            print('%sFAIL(%d): %s%s' % (COLOR_RED, proc.returncode, file, COLOR_RESET))
-            print(out)
-            fail_total += 1
-
-    tests_total = len(files)
-    print('TOTAL: %d' % (tests_total))
-    print('%sPASS : %d%s' % (COLOR_GREEN, tests_total - fail_total, COLOR_RESET))
-    print('%sFAIL : %d%s' % (COLOR_RED, fail_total, COLOR_RESET))
-
-    if fail_total > 0:
-        raise Exception('new-es tests failed')
-
-@runner('intl', default=True)
-def run_intl(engine, arch):
-    INTL_DIR = join(PROJECT_SOURCE_DIR, 'test', 'vendortest', 'Escargot', 'intl')
-    INTL_ASSERT_JS = join(INTL_DIR, 'assert.js')
-
-    print('Running Intl test:')
-    files = glob(join(INTL_DIR, '*.js'))
-    files.remove(INTL_ASSERT_JS)
-    fails = 0
-    for file in files:
-        proc = Popen([engine, INTL_ASSERT_JS, file], stdout=PIPE)
-        out, _ = proc.communicate()
-
-        if not proc.returncode:
-            print('%sOK: %s%s' % (COLOR_GREEN, file, COLOR_RESET))
-        else:
-            print('%sFAIL(%d): %s%s' % (COLOR_RED, proc.returncode, file, COLOR_RESET))
-            print(out)
-            fails += 1
-
-    if fails > 0:
-        raise Exception('Intl tests failed')
-
-@runner('wasm-js', default=False)
-def run_wasm_js(engine, arch):
-    WASM_TEST_ROOT = join(PROJECT_SOURCE_DIR, 'test', 'vendortest', 'wasm-js')
-    WASM_TEST_DIR = join(WASM_TEST_ROOT, 'tests')
-    WASM_TEST_MJS = join(WASM_TEST_ROOT, 'mjsunit.js')
-    WASM_TEST_HARNESS = join(WASM_TEST_ROOT, 'testharness.js')
-
-    copy(join(PROJECT_SOURCE_DIR, 'tools', 'test', 'wasm-js', 'grow-part.any.js'), join(WASM_TEST_DIR, 'memory', 'grow-part.any.js'))
-
-
-    EXCLUDE_LIST_FILE = join(PROJECT_SOURCE_DIR, 'tools', 'test', 'wasm-js', 'exclude_list.txt')
-    exclude_list = []
-    with open(EXCLUDE_LIST_FILE) as f:
-        exclude_list = f.read().replace('\n', ' ').split()
-
-    files = []
-    for root, dirnames, filenames in os.walk(join(WASM_TEST_DIR)):
-        if "proposals" in root:
-            # skip proposals test
-            continue
-        for filename in fnmatch.filter(filenames, '*.any.js'):
-            full_path = join(root, filename)
-            rel_path = full_path[len(WASM_TEST_DIR)+1:]
-            if rel_path in exclude_list:
-                continue
-            files.append(join(root, filename))
-    files = sorted(files)
-
-    WPT_ROOT = "/wasm/jsapi/"
-    META_SCRIPT_REGEXP = re.compile(r"META:\s*script=(.*)")
-    fail_total = 0
-    for file in files:
-        source = ""
-        with open(file) as f:
-            source = f.read()
-
-        script_files = []
-        for script in META_SCRIPT_REGEXP.findall(source):
-            if (script.startswith(WPT_ROOT)):
-                script = join(WASM_TEST_DIR, script[len(WPT_ROOT):])
-            else:
-                script = join(WASM_TEST_DIR, script)
-            script_files.append(script)
-
-        script_files.append(file)
-        proc = Popen([engine, WASM_TEST_MJS, WASM_TEST_HARNESS] + script_files, stdout=PIPE)
-        out, _ = proc.communicate()
-        
-        if not proc.returncode:
-            print('%sOK: %s%s' % (COLOR_GREEN, file, COLOR_RESET))
-        else:
-            print('%sFAIL(%d): %s%s' % (COLOR_RED, proc.returncode, file, COLOR_RESET))
-            print(out)
-            fail_total += 1
-
-    tests_total = len(files)
-    print('TOTAL: %d' % (tests_total))
-    print('%sPASS : %d%s' % (COLOR_GREEN, tests_total - fail_total, COLOR_RESET))
-    print('%sFAIL : %d%s' % (COLOR_RED, fail_total, COLOR_RESET))
-
-    if fail_total > 0:
-        raise Exception('new-es tests failed')
-
-@runner('cctest', default=False)
-def run_cctest(engine, arch):
-    if engine == "escargot":
-        engine = "cctest"
-    proc = Popen([engine], stdout=PIPE)
-    stdout, _ = proc.communicate()
-    print(stdout)
-    if 'FAILED' in stdout:
-        raise Exception('Not all tests succeeded')
-
-@runner('debugger-server-source', default=True)
-def run_escargot_debugger(engine, arch):
-    ESCARGOT_DEBUGGER_TEST_DIR = join(PROJECT_SOURCE_DIR, 'tools', 'debugger', 'tests')
-    ESCARGOT_DEBUGGER_CLIENT = join(PROJECT_SOURCE_DIR, 'tools', 'debugger', 'debugger.py')
-    ESCARGOT_DEBUGGER_TESTER = join(PROJECT_SOURCE_DIR, 'tools', 'debugger', 'debugger_tester.sh')
-    print('Running Escargot-Debugger-Server-Source test:')
-    fails = 0
-    proc = Popen(['chmod', '+x', ESCARGOT_DEBUGGER_TESTER],stdout=PIPE)
-    for files in os.listdir(ESCARGOT_DEBUGGER_TEST_DIR):
-        if files.endswith(".cmd"):
-            test_case, _ = os.path.splitext(files)
-            test_case_path = os.path.join(ESCARGOT_DEBUGGER_TEST_DIR, test_case)
-            proc = Popen([ESCARGOT_DEBUGGER_TESTER, engine, os.path.relpath(test_case_path, PROJECT_SOURCE_DIR), ESCARGOT_DEBUGGER_CLIENT, "0"])
-            proc.communicate()
-            if not proc.returncode:
-                 print('%sOK: %s%s' % (COLOR_GREEN, test_case_path, COLOR_RESET))
-            else:
-                 print('%sFAIL(%d): %s%s' % (COLOR_RED, proc.returncode, test_case_path, COLOR_RESET))
-                 fails += 1
-    if fails > 0:
-        raise Exception('Escargot-Debugger-Server-Source tests failed')
-
-@runner('debugger-client-source', default=True)
-def run_escargot_debugger2(engine, arch):
-    ESCARGOT_DEBUGGER_TEST_DIR = join(PROJECT_SOURCE_DIR, 'tools', 'debugger', 'tests')
-    ESCARGOT_DEBUGGER_CLIENT = join(PROJECT_SOURCE_DIR, 'tools', 'debugger', 'debugger.py')
-    ESCARGOT_DEBUGGER_TESTER = join(PROJECT_SOURCE_DIR, 'tools', 'debugger', 'debugger_tester.sh')
-    print('Running Escargot-Debugger-Client-Source test:')
-    fails = 0
-    proc = Popen(['chmod', '+x', ESCARGOT_DEBUGGER_TESTER],stdout=PIPE)
-    for files in os.listdir(ESCARGOT_DEBUGGER_TEST_DIR):
-        if files.endswith(".cmd"):
-            test_case, _ = os.path.splitext(files)
-            test_case_path = os.path.join(ESCARGOT_DEBUGGER_TEST_DIR, test_case)
-            proc = Popen([ESCARGOT_DEBUGGER_TESTER, engine, os.path.relpath(test_case_path, PROJECT_SOURCE_DIR), ESCARGOT_DEBUGGER_CLIENT, "1"])
-            proc.communicate()
-            if not proc.returncode:
-                 print('%sOK: %s%s' % (COLOR_GREEN, test_case_path, COLOR_RESET))
-            else:
-                 print('%sFAIL(%d): %s%s' % (COLOR_RED, proc.returncode, test_case_path, COLOR_RESET))
-                 fails += 1
-    if fails > 0:
-        raise Exception('Escargot-Debugger-Client-Source tests failed')
-
-def main():
-    parser = ArgumentParser(description='Escargot Test Suite Runner')
-    parser.add_argument('--engine', metavar='PATH', default=DEFAULT_ESCARGOT,
-                        help='path to the engine to be tested (default: %(default)s)')
-    parser.add_argument('--arch', metavar='NAME', choices=['x86', 'x86_64'], default='x86_64',
-                        help='architecture the engine was built for (%(choices)s; default: %(default)s)')
-    parser.add_argument('suite', metavar='SUITE', nargs='*', default=sorted(DEFAULT_RUNNERS),
-                        help='test suite to run (%s; default: %s)' % (', '.join(sorted(RUNNERS.keys())), ' '.join(sorted(DEFAULT_RUNNERS))))
-    args = parser.parse_args()
-
-    for suite in args.suite:
-        if suite not in RUNNERS:
-            parser.error('invalid test suite: %s' % suite)
-
-    success, fail = [], []
-
-    for suite in args.suite:
-        print(COLOR_PURPLE + 'running test suite: ' + suite + COLOR_RESET)
-        try:
-            RUNNERS[suite](args.engine, args.arch)
-            success += [suite]
-        except Exception as e:
-            print('\n'.join(COLOR_YELLOW + line + COLOR_RESET for line in traceback.format_exc().splitlines()))
-            fail += [suite]
-
-    if success:
-        print(COLOR_GREEN + sys.argv[0] + ': success: ' + ', '.join(success) + COLOR_RESET)
-    sys.exit(COLOR_RED + sys.argv[0] + ': fail: ' + ', '.join(fail) + COLOR_RESET if fail else None)
-
-
-if __name__ == '__main__':
-    main()
diff --git a/lwnode/code/escargotshim/deps/escargot/tools/visualize_heap_usage.py b/lwnode/code/escargotshim/deps/escargot/tools/visualize_heap_usage.py
deleted file mode 100755 (executable)
index e9a3715..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2015-present Samsung Electronics Co., Ltd.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import subprocess
-import os
-
-BDWGC_LOGFILE="bdwgcUsage.dat"
-GNUPLOT_DISPLAY_STYLE="lines"
-
-def make_plot_subcmd(col, name):
-    return '\"%s\" using 1:%d title \"%s (KB)\" with %s' % (BDWGC_LOGFILE, col, name, GNUPLOT_DISPLAY_STYLE)
-
-def draw_bdwgc_plot():
-    if not os.path.exists(BDWGC_LOGFILE):
-        print 'Cannot draw plot! No input file %s' % BDWGC_LOGFILE
-        print 'Please re-build escargot with `-DPROFILE_BDWGC` and run again.'
-        exit(1)
-
-    plot_cmd = 'plot '
-    plot_cmd += make_plot_subcmd(2, "Peak RSS")
-    plot_cmd += ', '
-    plot_cmd += make_plot_subcmd(3, "Total Heap")
-    plot_cmd += ', '
-    plot_cmd += make_plot_subcmd(4, "Marked Heap")
-
-    print "gnuplot -p -e '%s'" % plot_cmd
-    print
-    print "See '%s' to see raw data." % BDWGC_LOGFILE
-
-    subprocess.call(['gnuplot', '-p', '-e', plot_cmd])
-
-if __name__ == '__main__':
-    draw_bdwgc_plot()
diff --git a/lwnode/code/escargotshim/deps/node-bindings/include/node_bindings.h b/lwnode/code/escargotshim/deps/node-bindings/include/node_bindings.h
new file mode 100644 (file)
index 0000000..9eb0ec4
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NODE_BINDINGS_H
+#define NODE_BINDINGS_H
+
+typedef struct uv_loop_s uv_loop_t;
+
+namespace LWNode {
+
+void push_aul_message(const char* message);
+void push_aul_termination_message();
+
+class GmainLoopWork {
+ public:
+  virtual bool RunOnce() = 0;
+};
+
+class GmainLoopNodeBindings {
+ public:
+  GmainLoopNodeBindings(GmainLoopWork* bindingWork);
+  virtual ~GmainLoopNodeBindings(){};
+
+  void StartEventLoop();
+  void RunOnce();
+  bool HasMoreTasks();
+  void TerminateGMainLoop() { m_isTerminated = true; }
+
+ private:
+  bool m_isInitialize = {false};
+  bool m_hasMoreNodeTasks = {true};
+  bool m_isTerminated = {false};
+  GmainLoopWork* gmainLoopWork_{nullptr};
+};
+
+}  // namespace LWNode
+
+#endif
diff --git a/lwnode/code/escargotshim/deps/node-bindings/node_bindings.gyp b/lwnode/code/escargotshim/deps/node-bindings/node_bindings.gyp
new file mode 100644 (file)
index 0000000..de32773
--- /dev/null
@@ -0,0 +1,52 @@
+{
+  'variables': {
+  },
+  'includes': [
+    '../../common.gypi'
+  ],
+  'targets': [
+    {
+      'target_name': 'node_bindings',
+      'type': 'static_library',
+      'dependencies': [
+        '../../../../../deps/uv/uv.gyp:libuv',
+       ],
+      'defines': [
+      ],
+      'includes': [
+      ],
+      'include_dirs': [
+        'include',
+      ],
+      'sources': [
+        'src/gmainloop_node_bindings.cc'
+      ],
+      'cflags': [
+        '<!@(pkg-config --cflags glib-2.0)',
+        '-Wno-missing-field-initializers',
+      ],
+      'libraries': [
+        '<!@(pkg-config --libs glib-2.0)',
+      ],
+      'all_dependent_settings': {
+        'defines': [
+        ],
+        'include_dirs': [
+          'include',
+        ],
+        'cflags': [
+          '<!@(pkg-config --cflags glib-2.0)',
+        ],
+        'cflags_cc!': ['-fno-exceptions'],
+        'cflags_cc': [
+          '-fexceptions',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs glib-2.0)',
+        ],
+      }
+    },
+  ],
+  'conditions': [
+  ],
+}
diff --git a/lwnode/code/escargotshim/deps/node-bindings/src/gmainloop_node_bindings.cc b/lwnode/code/escargotshim/deps/node-bindings/src/gmainloop_node_bindings.cc
new file mode 100644 (file)
index 0000000..9ad3a74
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2019-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <cassert>
+#include "uv.h"
+#ifdef HOST_TIZEN
+#include "Extension.h"
+#endif
+
+#include "node_bindings.h"
+
+namespace glib {
+
+using namespace LWNode;
+
+struct SourceData {
+  GSource source;
+  gpointer tag;
+  GmainLoopNodeBindings* node_bindings = nullptr;
+};
+
+// TODO: classify EventLoop if needed
+
+static GMainContext* gcontext;
+static GMainLoop* gmainLoop;
+static GSource* uvsource;
+static GSourceFuncs source_funcs;
+static bool gmainLoopDone = false;
+
+static gboolean GmainLoopPrepareCallback(GSource* source, gint* timeout) {
+  uv_update_time(uv_default_loop());
+  *timeout = uv_backend_timeout(uv_default_loop());
+
+  if (!uv_watcher_queue_empty(uv_default_loop())) {
+    return TRUE;
+  }
+
+  return 0 == *timeout;
+}
+
+static gboolean GmainLoopCheckCallback(GSource* source) {
+  if (!uv_backend_timeout(uv_default_loop())) {
+    return TRUE;
+  }
+
+  return (G_IO_IN ==
+          g_source_query_unix_fd(source, ((SourceData*)source)->tag));
+}
+
+static gboolean GmainLoopDispatchCallback(GSource* source,
+                                          GSourceFunc callback,
+                                          gpointer user_data) {
+  assert(gcontext);
+  g_main_context_iteration(gcontext, FALSE);
+
+  if (gmainLoopDone) {
+    return G_SOURCE_REMOVE;
+  }
+
+  GmainLoopNodeBindings* node_bindings = ((SourceData*)source)->node_bindings;
+
+  node_bindings->RunOnce();
+
+  if (!node_bindings->HasMoreTasks()) {
+    g_main_loop_quit(gmainLoop);
+    return G_SOURCE_REMOVE;
+  }
+  return G_SOURCE_CONTINUE;
+}
+
+void GmainLoopInit(GmainLoopNodeBindings* self) {
+  gcontext = g_main_context_default();
+  gmainLoop = g_main_loop_new(gcontext, FALSE);
+  source_funcs = {
+      .prepare = GmainLoopPrepareCallback,
+      .check = GmainLoopCheckCallback,
+      .dispatch = GmainLoopDispatchCallback,
+  };
+
+  uvsource = g_source_new(&source_funcs, sizeof(SourceData));
+  ((SourceData*)uvsource)->tag = g_source_add_unix_fd(
+      uvsource,
+      uv_backend_fd(uv_default_loop()),
+      (GIOCondition)(G_IO_IN | G_IO_OUT | G_IO_ERR | G_IO_PRI));
+  ((SourceData*)uvsource)->node_bindings = self;
+
+  g_source_attach(uvsource, gcontext);
+  g_source_unref(uvsource);
+
+#ifdef HOST_TIZEN
+  DeviceAPI::ESPostMessageListener::SetMainThreadIdlerRegister(
+      [](DeviceAPI::ESPostMessageListener::Idler_t idler, void* data) {
+        g_idle_add(idler, data);
+      });
+#endif
+}
+
+void GmainLoopStart() {
+  assert(gmainLoop);
+  assert(gcontext);
+
+  g_main_loop_run(gmainLoop);
+  gmainLoopDone = true;
+  g_main_context_iteration(gcontext, TRUE);
+}
+
+void GmainLoopExit() {
+  if (uvsource) {
+    g_source_destroy(uvsource);
+  }
+  if (gmainLoop) {
+    g_main_loop_unref(gmainLoop);
+  }
+  if (gcontext) {
+    g_main_context_unref(gcontext);
+  }
+}
+
+}  // namespace glib
+
+// TODO: pump aul message for Tizen AUL application
+#if 0
+#ifdef HOST_TIZEN
+#include <mutex>
+#include <thread>
+#include "Queue.hpp"
+
+#define NESCARGOT_AUL_TERMINATION_MESSAGE "AUL_TERMINATION"
+
+namespace LWNode {
+
+struct Task {
+  std::string data;
+};
+
+Queue<Task> g_queue;
+
+static void UvNoOp(uv_async_t* handle) {
+  uv_close((uv_handle_t*)handle,
+           [](uv_handle_t* handle) { delete (uv_async_t*)handle; });
+}
+
+void push_aul_message(const char* message) {
+  g_queue.push({.data = message});
+  // wake up the uv queue
+  uv_async_t* async = new uv_async_t;
+  uv_async_init(uv_default_loop(), async, UvNoOp);
+  uv_async_send(async);
+}
+
+void push_aul_termination_message() {
+  push_aul_message(NESCARGOT_AUL_TERMINATION_MESSAGE);
+}
+}  // namespace LWNode
+#endif
+
+namespace LWNode {
+
+// static void pump_aul_message(v8::Isolate* isolate, GmainLoopNodeBindings* bindings) {
+// #ifdef HOST_TIZEN
+//   // TODO: move the following to m_platform.PumpMessageLoop(isolate)
+//   if (!g_queue.empty()) {
+//     auto task = g_queue.pop();
+//     node::EmitMessage(isolate, task.data.c_str());
+//     if (task.data == std::string(NESCARGOT_AUL_TERMINATION_MESSAGE)) {
+//       bindings->TerminateGMainLoop();
+//     }
+//   }
+// #endif
+// }
+}
+#endif
+
+namespace LWNode {
+
+GmainLoopNodeBindings::GmainLoopNodeBindings(GmainLoopWork* gmainLoopWork)
+    : gmainLoopWork_(gmainLoopWork) {
+  m_isInitialize = true;
+}
+
+void GmainLoopNodeBindings::StartEventLoop() {
+  assert(m_isInitialize);
+
+  glib::GmainLoopInit(this);
+
+  RunOnce();
+
+  if (HasMoreTasks()) {
+    glib::GmainLoopStart();
+  }
+
+  glib::GmainLoopExit();
+}
+
+bool GmainLoopNodeBindings::HasMoreTasks() {
+  return (m_hasMoreNodeTasks && !m_isTerminated);
+}
+
+void GmainLoopNodeBindings::RunOnce() {
+  m_hasMoreNodeTasks = gmainLoopWork_->RunOnce();
+}
+
+}  // namespace LWNode
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/Extension.cpp b/lwnode/code/escargotshim/deps/tizen-device-api/src/Extension.cpp
deleted file mode 100644 (file)
index fe16304..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-#if defined(TIZEN_DEVICE_API)
-#include "Extension.h"
-
-#include <dlfcn.h>
-
-#include "escargotbase.h"
-#include "ExtensionAdapter.h"
-#include "EscargotPublic.h"
-#include "TizenDeviceAPILoaderForEscargot.h"
-#include "tizen_node.h"
-
-namespace wrt {
-namespace xwalk {
-
-Extension::Extension(const std::string& path, RuntimeVariableProvider* provider)
-    : initialized_(false),
-      library_path_(path),
-      xw_extension_(0),
-      use_trampoline_(true),
-      created_instance_callback_(NULL),
-      destroyed_instance_callback_(NULL),
-      shutdown_callback_(NULL),
-      handle_msg_callback_(NULL),
-      handle_sync_msg_callback_(NULL),
-      rv_provider_(provider) {}
-
-Extension::Extension(const std::string& path, const std::string& name,
-                     const std::vector<std::string>& entry_points,
-                     RuntimeVariableProvider* provider)
-    : initialized_(false),
-      handle_(NULL),
-      library_path_(path),
-      xw_extension_(0),
-      name_(name),
-      entry_points_(entry_points),
-      use_trampoline_(true),
-      created_instance_callback_(NULL),
-      destroyed_instance_callback_(NULL),
-      shutdown_callback_(NULL),
-      handle_msg_callback_(NULL),
-      handle_sync_msg_callback_(NULL),
-      rv_provider_(provider) {}
-
-Extension::~Extension() {
-  if (!initialized_) return;
-
-  if (handle_) dlclose(handle_);
-
-  if (shutdown_callback_) shutdown_callback_(xw_extension_);
-  ExtensionAdapter::GetInstance()->UnregisterExtension(this);
-}
-
-bool Extension::Initialize() {
-  if (initialized_) return true;
-
-  DEVICEAPI_LOG_INFO("========== << Initialize >> ENTER ==========");
-  DEVICEAPI_SLOG_INFO("Extension Module library : [%s]", library_path_.c_str());
-
-  NESCARGOT_ASSERT(handle_ == NULL);
-  handle_ = dlopen(library_path_.c_str(), RTLD_LAZY);
-  if (!handle_) {
-    const char* error = (const char*)dlerror();
-    DEVICEAPI_LOG_ERROR("Error loading extension '%s'. Reason: %s",
-                        library_path_.c_str(),
-                        (error != NULL ? error : "unknown"));
-    return false;
-  }
-
-  XW_Initialize_Func initialize =
-      reinterpret_cast<XW_Initialize_Func>(dlsym(handle_, "XW_Initialize"));
-  if (!initialize) {
-    DEVICEAPI_LOG_ERROR("Error loading extension");
-    DEVICEAPI_SLOG_ERROR("[%s] couldn't get XW_Initialize function",
-                         library_path_.c_str());
-    dlclose(handle_);
-    handle_ = NULL;
-    return false;
-  }
-
-  ExtensionAdapter* adapter = ExtensionAdapter::GetInstance();
-  xw_extension_ = adapter->GetNextXWExtension();
-  adapter->RegisterExtension(this);
-
-  int ret = initialize(xw_extension_, ExtensionAdapter::GetInterface);
-  if (ret != XW_OK) {
-    DEVICEAPI_LOG_ERROR("Error loading extension");
-    DEVICEAPI_SLOG_ERROR("[%s] XW_Initialize function returned error value.",
-                         library_path_.c_str());
-    dlclose(handle_);
-    handle_ = NULL;
-    return false;
-  }
-
-  initialized_ = true;
-  DEVICEAPI_LOG_INFO("========== << Initialize >> END ==========");
-  return true;
-}
-
-ExtensionInstance* Extension::CreateInstance() {
-  Initialize();
-  ExtensionAdapter* adapter = ExtensionAdapter::GetInstance();
-  XW_Instance xw_instance = adapter->GetNextXWInstance();
-  return new ExtensionInstance(this, xw_instance);
-}
-
-void Extension::GetRuntimeVariable(const char* key, char* value,
-                                   size_t value_len) {
-#if 0
-        if( rv_provider_ ){
-            std::string ret = rv_provider_->GetRuntimeVariable(key);
-            strncpy(value, ret.c_str(), value_len);
-        }
-#else
-  DEVICEAPI_LOG_INFO("GETRUNTIMEVAR: not implemented");
-  NESCARGOT_ASSERT_SHOULD_NOT_BE_HERE();
-#endif
-}
-int Extension::CheckAPIAccessControl(const char* /*api_name*/) {
-  // TODO
-  return XW_OK;
-}
-
-int Extension::RegisterPermissions(const char* /*perm_table*/) {
-  // TODO
-  return XW_OK;
-}
-
-ExtensionInstance::ExtensionInstance(Extension* extension,
-                                     XW_Instance xw_instance)
-    : extension_(extension),
-      xw_instance_(xw_instance),
-      instance_data_(NULL),
-      post_message_listener_(NULL),
-      post_data_listener_(NULL) {
-  DEVICEAPI_LOG_INFO("Enter");
-  ExtensionAdapter::GetInstance()->RegisterInstance(this);
-  XW_CreatedInstanceCallback callback = extension_->created_instance_callback_;
-  if (callback) callback(xw_instance_);
-}
-
-ExtensionInstance::~ExtensionInstance() {
-  DEVICEAPI_LOG_INFO("Enter");
-  XW_DestroyedInstanceCallback callback =
-      extension_->destroyed_instance_callback_;
-  if (callback) callback(xw_instance_);
-  ExtensionAdapter::GetInstance()->UnregisterInstance(this);
-}
-
-void ExtensionInstance::HandleMessage(const std::string& msg) {
-  XW_HandleMessageCallback callback = extension_->handle_msg_callback_;
-  if (callback) callback(xw_instance_, msg.c_str());
-}
-
-void ExtensionInstance::HandleSyncMessage(const std::string& msg) {
-  XW_HandleSyncMessageCallback callback = extension_->handle_sync_msg_callback_;
-  if (callback) {
-    sync_reply_msg_.clear();
-    callback(xw_instance_, msg.c_str());
-  }
-}
-
-void ExtensionInstance::PostMessage(const std::string& msg) {
-  if (post_message_listener_) {
-    post_message_listener_->PostMessageToJS(msg);
-  }
-}
-
-void ExtensionInstance::SyncReply(const std::string& reply) {
-  sync_reply_msg_ = reply;
-}
-
-void ExtensionInstance::HandleData(const std::string& msg, uint8_t* buffer,
-                                   size_t len) {
-  XW_HandleDataCallback callback = extension_->handle_data_callback_;
-  if (callback) callback(xw_instance_, msg.c_str(), buffer, len);
-}
-
-void ExtensionInstance::HandleSyncData(const std::string& msg, uint8_t* buffer,
-                                       size_t len) {
-  XW_HandleDataCallback callback = extension_->handle_sync_data_callback_;
-  if (callback) {
-    sync_reply_msg_.clear();
-    sync_reply_buffer_len_ = 0;
-    sync_reply_buffer_ = NULL;
-    // sync_reply_buffer_ will be freed by XWalkExtensionModule
-    callback(xw_instance_, msg.c_str(), buffer, len);
-  }
-}
-
-void ExtensionInstance::PostData(const std::string& msg, uint8_t* buffer,
-                                 size_t len) {
-  if (post_data_listener_) {
-    post_data_listener_->PostDataToJS(msg, buffer, len);
-  }
-}
-
-void ExtensionInstance::SyncDataReply(const std::string& reply, uint8_t* buffer,
-                                      size_t len) {
-  sync_reply_msg_ = reply;
-  sync_reply_buffer_ = buffer;
-  sync_reply_buffer_len_ = len;
-}
-
-}  // namespace xwalk
-}  // namespace wrt
-
-namespace DeviceAPI {
-
-ESPostListener::ESPostListener(Escargot::ContextRef* context,
-                               Escargot::ObjectRef* listener)
-    : context_(context), listener_(listener) {
-  DEVICEAPI_LOG_INFO("Enter");
-  GC_add_roots(&listener_, &listener_ + sizeof(Escargot::ObjectRef*));
-}
-
-ESPostListener::~ESPostListener() {
-  DEVICEAPI_LOG_INFO("Enter");
-  finalize();
-}
-
-void ESPostListener::finalize() {
-  DEVICEAPI_LOG_INFO("Enter");
-  GC_remove_roots(&listener_, &listener_ + sizeof(Escargot::ObjectRef*));
-  listener_ = nullptr;
-  context_ = nullptr;
-}
-
-void ESPostMessageListener::PostMessageToJS(const std::string& msg) {
-  DEVICEAPI_LOG_INFO(
-      "ESPostMessageListener::PostMessageToJS (msg %s listener %p context "
-      "%p)",
-      msg.c_str(), listener_, context_);
-
-  ExtensionManagerInstance* extensionManagerInstance =
-      ExtensionManagerInstance::get(context_);
-  if (!extensionManagerInstance) {
-    return;
-  }
-
-  struct Params {
-    Escargot::ContextRef* context;
-    Escargot::ObjectRef* listener;
-    std::string msg;
-  };
-
-  Params* params = new Params();
-  params->context = context_;
-  params->listener = listener_;
-  params->msg = msg;
-  DEVICEAPI_LOG_INFO("Post message");
-  node::tizen::AddIdle(
-      [](void* data) {
-        DEVICEAPI_LOG_INFO("Add idle\n");
-        Params* params = (Params*)data;
-        Escargot::ContextRef* context = params->context;
-
-        auto result = Escargot::Evaluator::execute(
-            context,
-            [](Escargot::ExecutionStateRef* state,
-               Params* params) -> Escargot::ValueRef* {
-              Escargot::ObjectRef* listener = params->listener;
-              std::string msg = params->msg;
-              Escargot::ValueRef* arguments[] = {Escargot::ValueRef::create(
-                  Escargot::StringRef::createFromASCII(msg.c_str(),
-                                                       msg.size()))};
-              return listener->call(state, Escargot::ValueRef::createNull(), 1,
-                                    arguments);
-            },
-            params);
-        if (result.error.hasValue()) {
-          DEVICEAPI_LOG_ERROR(
-              "Uncaught %s\n",
-              result.resultOrErrorToString(context)->toStdUTF8String().c_str());
-        }
-
-        delete params;
-        return 0;
-      },
-      params);
-}
-
-void ESPostDataListener::PostDataToJS(const std::string& msg, uint8_t* buffer,
-                                      size_t len) {
-  DEVICEAPI_LOG_INFO("ESPostDataListener::PostDataToJS (%s, %zu)", msg.c_str(),
-                     len);
-
-  ExtensionManagerInstance* extensionManagerInstance =
-      ExtensionManagerInstance::get(context_);
-  if (!extensionManagerInstance) {
-    return;
-  }
-
-  auto result = Escargot::Evaluator::execute(
-      context_, [](Escargot::ExecutionStateRef* state) -> Escargot::ValueRef* {
-#if 0
-            Escargot::ValueRef* arguments[] = {Escargot::ValueRef::create(Escargot::StringRef::createFromASCII(msg.c_str(), msg.size()))};
-            return listener_->call(state, Escargot::ValueRef::createNull(), 1, arguments);
-#else
-            DEVICEAPI_LOG_ERROR("NOT IMPLEMENTED");
-            NESCARGOT_ASSERT_SHOULD_NOT_BE_HERE();
-            return Escargot::ValueRef::createUndefined();
-#endif
-      });
-  if (result.error.hasValue()) {
-    DEVICEAPI_LOG_ERROR(
-        "Uncaught %s\n",
-        result.resultOrErrorToString(context_)->toStdUTF8String().c_str());
-  }
-}
-
-}  // namespace DeviceAPI
-#endif
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/Extension.h b/lwnode/code/escargotshim/deps/tizen-device-api/src/Extension.h
deleted file mode 100644 (file)
index 3c8250e..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WRT_SERVICE_NODE_EXTENSION_H_
-#define WRT_SERVICE_NODE_EXTENSION_H_
-
-#include <string>
-#include <vector>
-
-#include "XW_Extension.h"
-#include "XW_Extension_SyncMessage.h"
-#include "XW_Extension_Data.h"
-
-namespace wrt {
-class RuntimeVariableProvider;
-
-namespace xwalk {
-
-    class ExtensionAdapter;
-    class ExtensionInstance;
-
-    class Extension {
-    public:
-        Extension(const std::string& path, RuntimeVariableProvider* provider);
-        Extension(const std::string& path, const std::string& name,
-                  const std::vector<std::string>& entry_points,
-                  RuntimeVariableProvider* provider);
-
-        virtual ~Extension();
-
-        bool Initialize();
-        ExtensionInstance* CreateInstance();
-
-        XW_Extension xw_extension()
-        {
-            return xw_extension_;
-        }
-
-        std::string name()
-        {
-            return name_;
-        }
-
-        std::string javascript_api()
-        {
-            Initialize();
-            return javascript_api_;
-        }
-
-        std::vector<std::string>& entry_points()
-        {
-            return entry_points_;
-        }
-
-        bool use_trampoline()
-        {
-            return use_trampoline_;
-        }
-
-        void set_name(const std::string& name)
-        {
-            name_ = name;
-        }
-
-        void set_javascript_api(const std::string& javascript_api)
-        {
-            javascript_api_ = javascript_api;
-        }
-
-        void set_use_trampoline(bool use_trampoline)
-        {
-            use_trampoline_ = use_trampoline;
-        }
-
-    private:
-        friend class ExtensionAdapter;
-        friend class ExtensionInstance;
-
-        void GetRuntimeVariable(const char* key, char* value, size_t value_len);
-        int CheckAPIAccessControl(const char* api_name);
-        int RegisterPermissions(const char* perm_table);
-
-        bool initialized_{ false };
-        void* handle_{ nullptr };
-        std::string library_path_;
-
-        XW_Extension xw_extension_{ 0 };
-        std::string name_;
-        std::string javascript_api_;
-        std::vector<std::string> entry_points_;
-        bool use_trampoline_{ true };
-
-        XW_CreatedInstanceCallback created_instance_callback_{ nullptr };
-        XW_DestroyedInstanceCallback destroyed_instance_callback_{ nullptr };
-        XW_ShutdownCallback shutdown_callback_{ nullptr };
-        XW_HandleMessageCallback handle_msg_callback_{ nullptr };
-        XW_HandleSyncMessageCallback handle_sync_msg_callback_{ nullptr };
-        XW_HandleDataCallback handle_data_callback_{ nullptr };
-        XW_HandleDataCallback handle_sync_data_callback_{ nullptr };
-        RuntimeVariableProvider* rv_provider_{ nullptr };
-    };
-
-    class PostMessageListener {
-    public:
-        virtual void PostMessageToJS(const std::string& msg) = 0;
-    };
-
-    class PostDataListener {
-    public:
-        virtual void PostDataToJS(const std::string& msg, uint8_t* buffer,
-                                  size_t len) = 0;
-    };
-
-    class ExtensionInstance {
-    public:
-        ExtensionInstance(Extension* extension, XW_Instance xw_instance);
-        virtual ~ExtensionInstance();
-
-        void HandleMessage(const std::string& msg);
-        void HandleSyncMessage(const std::string& msg);
-
-        void HandleData(const std::string& msg, uint8_t* buffer, size_t len);
-        void HandleSyncData(const std::string& msg, uint8_t* buffer,
-                            size_t len);
-
-        XW_Instance xw_instance()
-        {
-            return xw_instance_;
-        }
-
-        std::string sync_replay_msg()
-        {
-            return sync_reply_msg_;
-        }
-
-        std::string sync_data_reply_msg(uint8_t** buffer, size_t* len)
-        {
-            *buffer = sync_reply_buffer_;
-            *len = sync_reply_buffer_len_;
-            return sync_reply_msg_;
-        }
-
-        void set_post_message_listener(PostMessageListener* listener)
-        {
-            post_message_listener_ = listener;
-        }
-
-        void set_post_data_listener(PostDataListener* listener)
-        {
-            post_data_listener_ = listener;
-        }
-
-    private:
-        friend class ExtensionAdapter;
-
-        void PostMessage(const std::string& msg);
-        void SyncReply(const std::string& reply);
-
-        void PostData(const std::string& msg, uint8_t* buffer, size_t len);
-        void SyncDataReply(const std::string& reply, uint8_t* buffer,
-                           size_t len);
-
-        Extension* extension_;
-        XW_Instance xw_instance_;
-        void* instance_data_;
-        std::string sync_reply_msg_;
-        uint8_t* sync_reply_buffer_;
-        size_t sync_reply_buffer_len_;
-
-        PostMessageListener* post_message_listener_;
-        PostDataListener* post_data_listener_;
-    };
-
-} // namespace xwalk
-} // namespace wrt
-
-namespace Escargot {
-class ContextRef;
-class ObjectRef;
-}
-
-namespace DeviceAPI {
-
-class ESPostListener {
-public:
-    virtual ~ESPostListener();
-    void finalize();
-
-protected:
-    ESPostListener(Escargot::ContextRef* context,
-                   Escargot::ObjectRef* listener);
-
-    Escargot::ContextRef* context_;
-    Escargot::ObjectRef* listener_;
-};
-
-class ESPostMessageListener : public wrt::xwalk::PostMessageListener,
-                              public ESPostListener {
-public:
-    static ESPostMessageListener* create(Escargot::ContextRef* context,
-                                         Escargot::ObjectRef* listener)
-    {
-        return new ESPostMessageListener(context, listener);
-    }
-    void PostMessageToJS(const std::string& msg);
-
-private:
-    ESPostMessageListener(Escargot::ContextRef* context,
-                          Escargot::ObjectRef* listener)
-        : ESPostListener(context, listener)
-    {
-    }
-};
-
-class ESPostDataListener : public wrt::xwalk::PostDataListener,
-                           public ESPostListener {
-public:
-    static ESPostDataListener* create(Escargot::ContextRef* context,
-                                      Escargot::ObjectRef* listener)
-    {
-        return new ESPostDataListener(context, listener);
-    }
-    void PostDataToJS(const std::string& msg, uint8_t* buffer, size_t len);
-
-private:
-    ESPostDataListener(Escargot::ContextRef* context,
-                       Escargot::ObjectRef* listener)
-        : ESPostListener(context, listener)
-    {
-    }
-};
-
-} // namespace DeviceAPI
-
-#endif // WRT_SERVICE_NODE_EXTENSION_H_
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/ExtensionAdapter.cpp b/lwnode/code/escargotshim/deps/tizen-device-api/src/ExtensionAdapter.cpp
deleted file mode 100644 (file)
index 93434ed..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-// Copyright (c) 2013 Intel Corporation. All rights reserved.
-// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-#if defined(TIZEN_DEVICE_API)
-#include "escargotbase.h"
-#include "TizenDeviceAPILoaderForEscargot.h"
-#include "ExtensionAdapter.h"
-
-namespace wrt {
-namespace xwalk {
-
-    ExtensionAdapter::ExtensionAdapter()
-        : next_xw_extension_(1)
-        , next_xw_instance_(1)
-    {
-    }
-
-    ExtensionAdapter::~ExtensionAdapter()
-    {
-    }
-
-    ExtensionAdapter* ExtensionAdapter::GetInstance()
-    {
-        static ExtensionAdapter self;
-        return &self;
-    }
-
-    XW_Extension ExtensionAdapter::GetNextXWExtension()
-    {
-        return next_xw_extension_++;
-    }
-
-    XW_Instance ExtensionAdapter::GetNextXWInstance()
-    {
-        return next_xw_instance_++;
-    }
-
-    void ExtensionAdapter::RegisterExtension(Extension* extension)
-    {
-        XW_Extension xw_extension = extension->xw_extension();
-        if (!(xw_extension > 0 && xw_extension < next_xw_extension_)) {
-            DEVICEAPI_LOG_WARN("xw_extension (%d) is invalid.", xw_extension);
-            return;
-        }
-        if (extension_map_.find(xw_extension) == extension_map_.end())
-            extension_map_[xw_extension] = extension;
-    }
-
-    void ExtensionAdapter::UnregisterExtension(Extension* extension)
-    {
-        XW_Extension xw_extension = extension->xw_extension();
-        if (!(xw_extension > 0 && xw_extension < next_xw_extension_)) {
-            DEVICEAPI_LOG_WARN("xw_extension (%d) is invalid.", xw_extension);
-            return;
-        }
-        if (extension_map_.find(xw_extension) != extension_map_.end())
-            extension_map_.erase(xw_extension);
-    }
-
-    void ExtensionAdapter::RegisterInstance(ExtensionInstance* instance)
-    {
-        XW_Instance xw_instance = instance->xw_instance();
-        if (!(xw_instance > 0 && xw_instance < next_xw_instance_)) {
-            DEVICEAPI_LOG_WARN("xw_instance (%d) is invalid.", xw_instance);
-            return;
-        }
-        if (instance_map_.find(xw_instance) == instance_map_.end())
-            instance_map_[xw_instance] = instance;
-    }
-
-    void ExtensionAdapter::UnregisterInstance(ExtensionInstance* instance)
-    {
-        XW_Instance xw_instance = instance->xw_instance();
-        if (!(xw_instance > 0 && xw_instance < next_xw_instance_)) {
-            DEVICEAPI_LOG_WARN("xw_instance (%d) is invalid.", xw_instance);
-            return;
-        }
-        if (instance_map_.find(xw_instance) != instance_map_.end())
-            instance_map_.erase(xw_instance);
-    }
-
-    const void* ExtensionAdapter::GetInterface(const char* name)
-    {
-        if (!strcmp(name, XW_CORE_INTERFACE_1)) {
-            static const XW_CoreInterface_1 coreInterface1 = {
-                CoreSetExtensionName,          CoreSetJavaScriptAPI,
-                CoreRegisterInstanceCallbacks, CoreRegisterShutdownCallback,
-                CoreSetInstanceData,           CoreGetInstanceData
-            };
-            return &coreInterface1;
-        }
-
-        if (!strcmp(name, XW_MESSAGING_INTERFACE_1)) {
-            static const XW_MessagingInterface_1 messagingInterface1 = {
-                MessagingRegister, MessagingPostMessage
-            };
-            return &messagingInterface1;
-        }
-
-        if (!strcmp(name, XW_INTERNAL_SYNC_MESSAGING_INTERFACE_1)) {
-            static const XW_Internal_SyncMessagingInterface_1
-                syncMessagingInterface1 = { SyncMessagingRegister,
-                                            SyncMessagingSetSyncReply };
-            return &syncMessagingInterface1;
-        }
-
-        if (!strcmp(name, XW_INTERNAL_ENTRY_POINTS_INTERFACE_1)) {
-            static const XW_Internal_EntryPointsInterface_1
-                entryPointsInterface1 = { EntryPointsSetExtraJSEntryPoints };
-            return &entryPointsInterface1;
-        }
-
-        if (!strcmp(name, XW_INTERNAL_RUNTIME_INTERFACE_1)) {
-            static const XW_Internal_RuntimeInterface_1 runtimeInterface1 = {
-                RuntimeGetStringVariable
-            };
-            return &runtimeInterface1;
-        }
-
-        if (!strcmp(name, XW_INTERNAL_PERMISSIONS_INTERFACE_1)) {
-            static const XW_Internal_PermissionsInterface_1
-                permissionsInterface1 = { PermissionsCheckAPIAccessControl,
-                                          PermissionsRegisterPermissions };
-            return &permissionsInterface1;
-        }
-
-        if (!strcmp(name, XW_INTERNAL_DATA_INTERFACE_1)) {
-            static const XW_Internal_DataInterface_1 dataInterface1 = {
-                DataRegisterSync, DataRegisterAsync, DataSetSyncReply,
-                DataPostData
-            };
-            return &dataInterface1;
-        }
-
-        DEVICEAPI_LOG_WARN("Interface '%s' is not supported.", name);
-        return NULL;
-    }
-
-    Extension* ExtensionAdapter::GetExtension(XW_Extension xw_extension)
-    {
-        ExtensionAdapter* adapter = ExtensionAdapter::GetInstance();
-        ExtensionMap::iterator it = adapter->extension_map_.find(xw_extension);
-        if (it == adapter->extension_map_.end())
-            return NULL;
-        return it->second;
-    }
-
-    ExtensionInstance* ExtensionAdapter::GetExtensionInstance(
-        XW_Instance xw_instance)
-    {
-        ExtensionAdapter* adapter = ExtensionAdapter::GetInstance();
-        InstanceMap::iterator it = adapter->instance_map_.find(xw_instance);
-        if (it == adapter->instance_map_.end())
-            return NULL;
-        return it->second;
-    }
-
-#define CHECK(x, xw)                                                   \
-    if (!x) {                                                          \
-        DEVICEAPI_LOG_WARN("Ignoring call. Invalid %s = %d", #xw, xw); \
-        return;                                                        \
-    }
-
-#define RETURN_IF_INITIALIZED(x) \
-    if (x->initialized_)         \
-        return;
-
-    void ExtensionAdapter::CoreSetExtensionName(XW_Extension xw_extension,
-                                                const char* name)
-    {
-        Extension* extension = GetExtension(xw_extension);
-        CHECK(extension, xw_extension);
-        RETURN_IF_INITIALIZED(extension);
-        extension->name_ = name;
-    }
-
-    void ExtensionAdapter::CoreSetJavaScriptAPI(XW_Extension xw_extension,
-                                                const char* javascript_api)
-    {
-        Extension* extension = GetExtension(xw_extension);
-        CHECK(extension, xw_extension);
-        RETURN_IF_INITIALIZED(extension);
-        extension->javascript_api_ = javascript_api;
-    }
-
-    void ExtensionAdapter::CoreRegisterInstanceCallbacks(
-        XW_Extension xw_extension, XW_CreatedInstanceCallback created,
-        XW_DestroyedInstanceCallback destroyed)
-    {
-        Extension* extension = GetExtension(xw_extension);
-        CHECK(extension, xw_extension);
-        RETURN_IF_INITIALIZED(extension);
-        extension->created_instance_callback_ = created;
-        extension->destroyed_instance_callback_ = destroyed;
-    }
-
-    void ExtensionAdapter::CoreRegisterShutdownCallback(
-        XW_Extension xw_extension, XW_ShutdownCallback shutdown)
-    {
-        Extension* extension = GetExtension(xw_extension);
-        CHECK(extension, xw_extension);
-        RETURN_IF_INITIALIZED(extension);
-        extension->shutdown_callback_ = shutdown;
-    }
-
-    void ExtensionAdapter::CoreSetInstanceData(XW_Instance xw_instance,
-                                               void* data)
-    {
-        ExtensionInstance* instance = GetExtensionInstance(xw_instance);
-        CHECK(instance, xw_instance);
-        instance->instance_data_ = data;
-    }
-
-    void* ExtensionAdapter::CoreGetInstanceData(XW_Instance xw_instance)
-    {
-        ExtensionInstance* instance = GetExtensionInstance(xw_instance);
-        if (instance)
-            return instance->instance_data_;
-        else
-            return NULL;
-    }
-
-    void ExtensionAdapter::MessagingRegister(
-        XW_Extension xw_extension, XW_HandleMessageCallback handle_message)
-    {
-        Extension* extension = GetExtension(xw_extension);
-        CHECK(extension, xw_extension);
-        RETURN_IF_INITIALIZED(extension);
-        extension->handle_msg_callback_ = handle_message;
-    }
-
-    void ExtensionAdapter::MessagingPostMessage(XW_Instance xw_instance,
-                                                const char* message)
-    {
-        ExtensionInstance* instance = GetExtensionInstance(xw_instance);
-        CHECK(instance, xw_instance);
-        instance->PostMessage(message);
-    }
-
-    void ExtensionAdapter::SyncMessagingRegister(
-        XW_Extension xw_extension,
-        XW_HandleSyncMessageCallback handle_sync_message)
-    {
-        Extension* extension = GetExtension(xw_extension);
-        CHECK(extension, xw_extension);
-        RETURN_IF_INITIALIZED(extension);
-        extension->handle_sync_msg_callback_ = handle_sync_message;
-    }
-
-    void ExtensionAdapter::SyncMessagingSetSyncReply(XW_Instance xw_instance,
-                                                     const char* reply)
-    {
-        ExtensionInstance* instance = GetExtensionInstance(xw_instance);
-        CHECK(instance, xw_instance);
-        instance->SyncReply(reply);
-    }
-
-    void ExtensionAdapter::EntryPointsSetExtraJSEntryPoints(
-        XW_Extension xw_extension, const char** entry_points)
-    {
-        Extension* extension = GetExtension(xw_extension);
-        CHECK(extension, xw_extension);
-        RETURN_IF_INITIALIZED(extension);
-
-        for (int i = 0; entry_points[i]; ++i) {
-            extension->entry_points_.push_back(std::string(entry_points[i]));
-        }
-    }
-
-    void ExtensionAdapter::RuntimeGetStringVariable(XW_Extension xw_extension,
-                                                    const char* key,
-                                                    char* value,
-                                                    unsigned int value_len)
-    {
-        Extension* extension = GetExtension(xw_extension);
-        CHECK(extension, xw_extension);
-        extension->GetRuntimeVariable(key, value, value_len);
-    }
-
-    int ExtensionAdapter::PermissionsCheckAPIAccessControl(
-        XW_Extension xw_extension, const char* api_name)
-    {
-        Extension* extension = GetExtension(xw_extension);
-        if (extension)
-            return extension->CheckAPIAccessControl(api_name);
-        else
-            return XW_ERROR;
-    }
-
-    int ExtensionAdapter::PermissionsRegisterPermissions(
-        XW_Extension xw_extension, const char* perm_table)
-    {
-        Extension* extension = GetExtension(xw_extension);
-        if (extension)
-            return extension->RegisterPermissions(perm_table);
-        else
-            return XW_ERROR;
-    }
-
-    void ExtensionAdapter::DataRegisterSync(
-        XW_Extension xw_extension, XW_HandleDataCallback handle_sync_data)
-    {
-        Extension* extension = GetExtension(xw_extension);
-        CHECK(extension, xw_extension);
-        RETURN_IF_INITIALIZED(extension);
-        extension->handle_sync_data_callback_ = handle_sync_data;
-    }
-
-    void ExtensionAdapter::DataRegisterAsync(XW_Extension xw_extension,
-                                             XW_HandleDataCallback handle_data)
-    {
-        Extension* extension = GetExtension(xw_extension);
-        CHECK(extension, xw_extension);
-        RETURN_IF_INITIALIZED(extension);
-        extension->handle_data_callback_ = handle_data;
-    }
-
-    void ExtensionAdapter::DataSetSyncReply(XW_Instance xw_instance,
-                                            const char* reply, uint8_t* buffer,
-                                            size_t len)
-    {
-        ExtensionInstance* instance = GetExtensionInstance(xw_instance);
-        CHECK(instance, xw_instance);
-        instance->SyncDataReply(reply, buffer, len);
-    }
-
-    void ExtensionAdapter::DataPostData(XW_Instance xw_instance,
-                                        const char* message, uint8_t* buffer,
-                                        size_t len)
-    {
-        ExtensionInstance* instance = GetExtensionInstance(xw_instance);
-        CHECK(instance, xw_instance);
-        instance->PostData(message, buffer, len);
-    }
-
-} // namespace xwalk
-} // namespace wrt
-#endif
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/ExtensionAdapter.h b/lwnode/code/escargotshim/deps/tizen-device-api/src/ExtensionAdapter.h
deleted file mode 100644 (file)
index be702b2..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WRT_SERVICE_NODE_EXTENSION_ADAPTER_H_
-#define WRT_SERVICE_NODE_EXTENSION_ADAPTER_H_
-
-#include <map>
-
-#include "XW_Extension.h"
-#include "XW_Extension_SyncMessage.h"
-#include "XW_Extension_EntryPoints.h"
-#include "XW_Extension_Runtime.h"
-#include "XW_Extension_Permissions.h"
-#include "XW_Extension_Data.h"
-
-#include "Extension.h"
-
-namespace wrt {
-namespace xwalk {
-
-    class ExtensionAdapter {
-    public:
-        static ExtensionAdapter* GetInstance();
-
-        XW_Extension GetNextXWExtension();
-        XW_Instance GetNextXWInstance();
-
-        void RegisterExtension(Extension* extension);
-        void UnregisterExtension(Extension* extension);
-
-        void RegisterInstance(ExtensionInstance* instance);
-        void UnregisterInstance(ExtensionInstance* instance);
-
-        // Returns the correct struct according to interface asked. This is
-        // passed to external extensions in XW_Initialize() call.
-        static const void* GetInterface(const char* name);
-
-        static Extension* GetExtension(XW_Extension xw_extension);
-        static ExtensionInstance* GetExtensionInstance(XW_Instance xw_instance);
-
-    private:
-        ExtensionAdapter();
-        virtual ~ExtensionAdapter();
-
-        static void CoreSetExtensionName(XW_Extension xw_extension,
-                                         const char* name);
-        static void CoreSetJavaScriptAPI(XW_Extension xw_extension,
-                                         const char* javascript_api);
-        static void CoreRegisterInstanceCallbacks(
-            XW_Extension xw_extension, XW_CreatedInstanceCallback created,
-            XW_DestroyedInstanceCallback destroyed);
-        static void CoreRegisterShutdownCallback(XW_Extension xw_extension,
-                                                 XW_ShutdownCallback shutdown);
-        static void CoreSetInstanceData(XW_Instance xw_instance, void* data);
-        static void* CoreGetInstanceData(XW_Instance xw_instance);
-        static void MessagingRegister(XW_Extension xw_extension,
-                                      XW_HandleMessageCallback handle_message);
-        static void MessagingPostMessage(XW_Instance xw_instance,
-                                         const char* message);
-        static void SyncMessagingRegister(
-            XW_Extension xw_extension,
-            XW_HandleSyncMessageCallback handle_sync_message);
-        static void SyncMessagingSetSyncReply(XW_Instance xw_instance,
-                                              const char* reply);
-        static void EntryPointsSetExtraJSEntryPoints(XW_Extension xw_extension,
-                                                     const char** entry_points);
-        static void RuntimeGetStringVariable(XW_Extension xw_extension,
-                                             const char* key, char* value,
-                                             unsigned int value_len);
-        static int PermissionsCheckAPIAccessControl(XW_Extension xw_extension,
-                                                    const char* api_name);
-        static int PermissionsRegisterPermissions(XW_Extension xw_extension,
-                                                  const char* perm_table);
-        static void DataRegisterSync(XW_Extension xw_extension,
-                                     XW_HandleDataCallback handle_sync_data);
-        static void DataRegisterAsync(XW_Extension xw_extension,
-                                      XW_HandleDataCallback handle_data);
-        static void DataSetSyncReply(XW_Instance instance, const char* reply,
-                                     uint8_t* buffer, size_t len);
-        static void DataPostData(XW_Instance instance, const char* message,
-                                 uint8_t* buffer, size_t len);
-
-        typedef std::map<XW_Extension, Extension*> ExtensionMap;
-        ExtensionMap extension_map_;
-
-        typedef std::map<XW_Instance, ExtensionInstance*> InstanceMap;
-        InstanceMap instance_map_;
-
-        XW_Extension next_xw_extension_;
-        XW_Instance next_xw_instance_;
-    };
-
-} // namespace xwalk
-} // namespace wrt
-
-#endif // WRT_SERVICE_NODE_EXTENSION_ADAPTER_H_
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/ExtensionManager.cpp b/lwnode/code/escargotshim/deps/tizen-device-api/src/ExtensionManager.cpp
deleted file mode 100644 (file)
index e4365ba..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-#if defined(TIZEN_DEVICE_API)
-#include "escargotbase.h"
-#include "ExtensionManager.h"
-
-#include <glob.h>
-// #include <dpl/log/secure_log.h>
-#include <memory>
-#include <iostream>
-#include <fstream>
-
-// #include "runtime_variable_provider.h"
-// #include "picojson.h"
-#include "TizenDeviceAPILoaderForEscargot.h"
-
-namespace wrt {
-namespace xwalk {
-
-    namespace {
-        // TODO: need to cleanup
-        const char kExtensionDir[] = "/usr/lib/wrt-plugins-widget";
-        const char kExtensionPrefix[] = "lib";
-        const char kExtensionSuffix[] = ".so";
-        const char kExtensionMetadataSuffix[] = ".json";
-    }
-
-    ExtensionManager::ExtensionManager()
-    {
-    }
-
-    ExtensionManager::~ExtensionManager()
-    {
-    }
-
-    ExtensionManager* ExtensionManager::GetInstance()
-    {
-        static ExtensionManager self;
-        return &self;
-    }
-
-#if 0
-void ExtensionManager::RegisterExtensionsByMetadata(
-    RuntimeVariableProvider* provider, const std::string& metafile_path) {
-  DEVICEAPI_SLOG_INFO("path : [%s]", metafile_path.c_str());
-  std::ifstream metafile(metafile_path.c_str());
-  if (!metafile.is_open()) {
-    DEVICEAPI_LOG_ERROR("Can't open plugin metadata file");
-    return;
-  }
-
-  picojson::value metadata;
-  metafile >> metadata;
-  if (metadata.is<picojson::array>()) {
-    auto& plugins = metadata.get<picojson::array>();
-    for (auto plugin = plugins.begin(); plugin != plugins.end(); ++plugin) {
-      if (!plugin->is<picojson::object>())
-        continue;
-
-      std::string name = plugin->get("name").to_str();
-      std::string lib = plugin->get("lib").to_str();
-      if (lib.at(0) != '/') {
-        lib = std::string(kExtensionDir) + "/" + lib;
-      }
-      std::vector<std::string> entries;
-      auto& entry_points_value = plugin->get("entry_points");
-      if (entry_points_value.is<picojson::array>()) {
-        auto& entry_points = entry_points_value.get<picojson::array>();
-        for (auto entry = entry_points.begin(); entry != entry_points.end();
-             ++entry) {
-          entries.push_back(entry->to_str());
-        }
-      } else {
-        DEVICEAPI_LOG_ERROR("there is no entry points");
-      }
-      Extension* extension = new Extension(lib, name, entries, provider);
-      RegisterExtension(extension);
-    }
-  } else {
-    DEVICEAPI_LOG_ERROR("Not plugin metadata");
-    DEVICEAPI_SLOG_ERROR("%s is not plugin metadata", metafile_path.c_str());
-  }
-  metafile.close();
-}
-
-void ExtensionManager::RegisterExtensionsByMetadata(
-    RuntimeVariableProvider* provider) {
-  std::string extension_path(kExtensionDir);
-  extension_path.append("/");
-  extension_path.append("*");
-  extension_path.append(kExtensionMetadataSuffix);
-
-  DEVICEAPI_LOG_INFO("Register Extension directory");
-  DEVICEAPI_SLOG_INFO("path : [%s]", extension_path.c_str());
-
-  glob_t glob_result;
-  glob(extension_path.c_str(), GLOB_TILDE, NULL, &glob_result);
-  for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) {
-    RegisterExtensionsByMetadata(provider, glob_result.gl_pathv[i]);
-  }
-  if (glob_result.gl_pathc == 0) {
-    RegisterExtensionsInDirectory(provider);
-  }
-}
-#endif
-
-    void ExtensionManager::RegisterExtensionsInDirectory(
-        RuntimeVariableProvider* provider)
-    {
-        std::string extension_path(kExtensionDir);
-        extension_path.append("/");
-        extension_path.append(kExtensionPrefix);
-        extension_path.append("*");
-        extension_path.append(kExtensionSuffix);
-
-        DEVICEAPI_LOG_INFO("Register Extension directory");
-        DEVICEAPI_SLOG_INFO("path : [%s]", extension_path.c_str());
-
-        glob_t glob_result;
-        glob(extension_path.c_str(), GLOB_TILDE, NULL, &glob_result);
-        for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) {
-            Extension* extension =
-                new Extension(glob_result.gl_pathv[i], provider);
-            if (extension->Initialize()) {
-                RegisterExtension(extension);
-            }
-        }
-    }
-
-    bool ExtensionManager::RegisterExtension(Extension* extension)
-    {
-        DEVICEAPI_LOG_INFO(
-            "========== << RegisterExtension >> ENTER ==========");
-        if (!extension)
-            return false;
-
-        std::string name = extension->name();
-
-        DEVICEAPI_LOG_INFO("Register Extension name : [%s]", name.c_str());
-        if (extension_symbols_.find(name) != extension_symbols_.end()) {
-            DEVICEAPI_LOG_WARN(
-                "Ignoring extension with name already registred. '%s'",
-                name.c_str());
-            return false;
-        }
-
-        std::vector<std::string>& entry_points = extension->entry_points();
-        std::vector<std::string>::iterator iter;
-        for (iter = entry_points.begin(); iter != entry_points.end(); ++iter) {
-            if (extension_symbols_.find(*iter) != extension_symbols_.end()) {
-                DEVICEAPI_LOG_WARN(
-                    "Ignoring extension with entry_point already registred. "
-                    "'%s'",
-                    (*iter).c_str());
-                return false;
-            }
-        }
-
-        for (iter = entry_points.begin(); iter != entry_points.end(); ++iter) {
-            extension_symbols_.insert(*iter);
-        }
-
-        extension_symbols_.insert(name);
-        extensions_[name] = extension;
-
-        DEVICEAPI_LOG_INFO("========== << RegisterExtension >> END ==========");
-        return true;
-    }
-
-} // namespace xwalk
-} // namespace wrt
-#endif
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/ExtensionManager.h b/lwnode/code/escargotshim/deps/tizen-device-api/src/ExtensionManager.h
deleted file mode 100644 (file)
index be3a59f..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WRT_SERVICE_NODE_EXTENSION_MANAGER_H_
-#define WRT_SERVICE_NODE_EXTENSION_MANAGER_H_
-
-#include <string>
-#include <set>
-#include <map>
-
-#include "XW_Extension.h"
-#include "XW_Extension_SyncMessage.h"
-#include "Extension.h"
-
-namespace wrt {
-class RuntimeVariableProvider;
-namespace xwalk {
-
-    typedef std::map<std::string, Extension*> ExtensionMap;
-
-    class ExtensionManager {
-    public:
-        static ExtensionManager* GetInstance();
-
-        void RegisterExtensionsInDirectory(RuntimeVariableProvider* provider);
-#if 0
-  void RegisterExtensionsByMetadata(RuntimeVariableProvider* provider);
-  void RegisterExtensionsByMetadata(RuntimeVariableProvider* provider,
-                                    const std::string& metafile_path);
-#endif
-
-        ExtensionMap& extensions()
-        {
-            return extensions_;
-        }
-
-        bool RegisterExtension(Extension* extension);
-
-    private:
-        ExtensionManager();
-        virtual ~ExtensionManager();
-
-        ExtensionMap extensions_;
-
-        std::set<std::string> extension_symbols_;
-    };
-
-} // namespace xwalk
-} // namespace wrt
-
-#endif // WRT_SERVICE_NODE_EXTENSION_MANAGER_H_
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/TizenDeviceAPILoaderForEscargot.cpp b/lwnode/code/escargotshim/deps/tizen-device-api/src/TizenDeviceAPILoaderForEscargot.cpp
deleted file mode 100644 (file)
index 2d717ea..0000000
+++ /dev/null
@@ -1,813 +0,0 @@
-// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#if defined(TIZEN_DEVICE_API)
-#include "escargotbase.h"
-#include "TizenDeviceAPILoaderForEscargot.h"
-
-#include "EscargotPublic.h"
-
-#include <dlfcn.h>
-#include "ExtensionAdapter.h"
-#include "ExtensionManager.h"
-
-
-using namespace Escargot;
-
-namespace DeviceAPI {
-
-TizenStrings::TizenStrings(ContextRef* context)
-    : m_context(context)
-    , m_initialized(false)
-{
-    initializeEarlyStrings();
-}
-
-#define INIT_TIZEN_STRING(name) \
-    name = AtomicStringRef::create(m_context, "" #name);
-void TizenStrings::initializeEarlyStrings()
-{
-    DEVICEAPI_LOG_INFO("Enter");
-
-    FOR_EACH_EARLY_TIZEN_STRINGS(INIT_TIZEN_STRING)
-    SUPPORTED_TIZEN_PROPERTY(INIT_TIZEN_STRING)
-    SUPPORTED_TIZEN_ENTRYPOINTS(INIT_TIZEN_STRING)
-}
-
-void TizenStrings::initializeLazyStrings()
-{
-    DEVICEAPI_LOG_INFO("Enter");
-
-    if (m_initialized)
-        return;
-
-    FOR_EACH_LAZY_TIZEN_STRINGS(INIT_TIZEN_STRING)
-
-    m_initialized = true;
-}
-#undef INIT_TIZEN_STRING
-
-void printArguments(ContextRef* context, size_t argc, ValueRef** argv)
-{
-    DEVICEAPI_LOG_INFO("printing %zu arguments", argc);
-    Evaluator::execute(
-        context,
-        [](ExecutionStateRef* state, size_t argc,
-           ValueRef** argv) -> ValueRef* {
-            for (size_t i = 0; i < argc; i++) {
-                DEVICEAPI_LOG_INFO(
-                    "argument %zu : %s", i,
-                    argv[i]->toString(state)->toStdUTF8String().c_str());
-            }
-            return ValueRef::createUndefined();
-        },
-        argc, argv);
-}
-
-void* ExtensionManagerInstance::operator new(size_t size)
-{
-    static bool typeInited = false;
-    static GC_descr descr;
-    if (!typeInited) {
-        GC_word obj_bitmap[GC_BITMAP_SIZE(ExtensionManagerInstance)] = { 0 };
-        GC_set_bit(obj_bitmap,
-                   GC_WORD_OFFSET(ExtensionManagerInstance, m_context));
-        GC_set_bit(obj_bitmap,
-                   GC_WORD_OFFSET(ExtensionManagerInstance, m_strings));
-#if defined(STARFISH_TIZEN_WEARABLE_WIDGET)
-        GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ExtensionManagerInstance,
-                                              m_webWidgetAPIInstance));
-#endif
-#define DECLARE_TIZEN_VALUE(name)                                   \
-    GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ExtensionManagerInstance, \
-                                          VALUE_NAME_STRCAT(m_##name)));
-        FOR_EACH_EARLY_TIZEN_STRINGS(DECLARE_TIZEN_VALUE);
-        FOR_EACH_LAZY_TIZEN_STRINGS(DECLARE_TIZEN_VALUE);
-        SUPPORTED_TIZEN_PROPERTY(DECLARE_TIZEN_VALUE);
-        SUPPORTED_TIZEN_ENTRYPOINTS(DECLARE_TIZEN_VALUE);
-#undef DECLARE_TIZEN_VALUE
-        descr = GC_make_descriptor(obj_bitmap,
-                                   GC_WORD_LEN(ExtensionManagerInstance));
-        typeInited = true;
-    }
-    return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
-}
-
-wrt::xwalk::Extension* ExtensionManagerInstance::getExtension(
-    const char* apiName)
-{
-    DEVICEAPI_LOG_INFO("Enter");
-    wrt::xwalk::ExtensionMap& extensions =
-        wrt::xwalk::ExtensionManager::GetInstance()->extensions();
-
-    auto it = extensions.find(apiName);
-    if (it == extensions.end()) {
-        DEVICEAPI_LOG_INFO("Enter");
-        char library_path[512];
-        if (!strcmp(apiName, "tizen"))
-            snprintf(library_path, 512,
-                     "/usr/lib/tizen-extensions-crosswalk/libtizen.so");
-        else if (!strcmp(apiName, "sensorservice"))
-            snprintf(library_path, 512,
-                     "/usr/lib/tizen-extensions-crosswalk/libtizen_sensor.so");
-        else if (!strcmp(apiName, "sa")) {
-            snprintf(library_path, 512,
-                     "/usr/lib/tizen-extensions-crosswalk/libwebapis_sa.so");
-        } else
-            snprintf(library_path, 512,
-                     "/usr/lib/tizen-extensions-crosswalk/libtizen_%s.so",
-                     apiName);
-        wrt::xwalk::Extension* extension =
-            new wrt::xwalk::Extension(library_path, nullptr);
-        if (extension->Initialize()) {
-            wrt::xwalk::ExtensionManager::GetInstance()->RegisterExtension(
-                extension);
-            extensions[apiName] = extension;
-            return extension;
-        } else {
-            DEVICEAPI_LOG_INFO("Cannot initialize extension %s", apiName);
-            return nullptr;
-        }
-    } else {
-        return it->second;
-    }
-}
-
-// Caution: this function is called only inside existing js execution context,
-// so we don't handle JS exception around ESFunctionObject::call()
-ObjectRef* ExtensionManagerInstance::initializeExtensionInstance(
-    const char* apiName)
-{
-    DEVICEAPI_LOG_INFO("Enter");
-
-    return Evaluator::execute(
-               m_context,
-               [](ExecutionStateRef* state, ExtensionManagerInstance* self,
-                  const char* apiName) -> ValueRef* {
-                   wrt::xwalk::Extension* extension = getExtension(apiName);
-                   if (!extension) {
-                       DEVICEAPI_LOG_INFO("Cannot load extension %s", apiName);
-                       return ObjectRef::create(state);
-                   }
-                   std::string str;
-                   str.append("(function(extension){");
-                   str.append("extension.internal = {};");
-                   str.append(
-                       "extension.internal.sendSyncMessage_ = "
-                       "extension.sendSyncMessage;");
-                   str.append(
-                       "extension.internal.sendSyncMessage = function(){ "
-                       "return "
-                       "extension.internal.sendSyncMessage_.apply(extension, "
-                       "arguments); };");
-                   str.append("delete extension.sendSyncMessage;");
-                   str.append("var exports = {};");
-                   str.append("console.log('Start loading ");
-                   str.append(apiName);
-                   str.append("');");
-                   str.append("(function() {'use strict';");
-                   str.append(extension->javascript_api().c_str());
-                   str.append("})();");
-                   str.append("console.log('Loading ");
-                   str.append(apiName);
-                   str.append(" done ');");
-                   str.append("return exports;})");
-
-                   std::string jsFileName = apiName;
-                   jsFileName += ".js";
-                   jsFileName = "tizen_api_internal_" + jsFileName;
-                   StringRef* apiSource =
-                       StringRef::createFromUTF8(str.c_str(), str.length());
-                   FunctionObjectRef* initializer =
-                       self->m_context->scriptParser()
-                           ->initializeScript(
-                               apiSource,
-                               StringRef::createFromUTF8(jsFileName.c_str(),
-                                                         jsFileName.length()))
-                           .script.value()
-                           ->execute(state)
-                           ->asFunctionObject();
-                   ObjectRef* extensionObject =
-                       self->createExtensionObject(state);
-                   wrt::xwalk::ExtensionInstance* extensionInstance =
-                       extension->CreateInstance();
-                   self->m_extensionInstances[extensionObject] =
-                       extensionInstance;
-                   ValueRef* arguments[] = { ValueRef::create(
-                       extensionObject) };
-                   return initializer
-                       ->call(state, ValueRef::createNull(), 1, arguments)
-                       ->toObject(state);
-               },
-               this, apiName)
-        .result->asObject();
-}
-
-ObjectRef* ExtensionManagerInstance::createExtensionObject(
-    ExecutionStateRef* state)
-{
-    DEVICEAPI_LOG_INFO("Enter");
-
-    ObjectRef* extensionObject = ObjectRef::create(state);
-
-    FunctionObjectRef* postMessageFn = FunctionObjectRef::create(
-        state,
-        FunctionObjectRef::NativeFunctionInfo(
-            m_strings->postMessage,
-            [](ExecutionStateRef* state, ValueRef* thisValue, size_t argc,
-               ValueRef** argv, bool isNewExpression) -> ValueRef* {
-                DEVICEAPI_LOG_ERROR("extension.postMessage UNIMPLEMENTED");
-                printArguments(state->context(), argc, argv);
-                NESCARGOT_ASSERT_SHOULD_NOT_BE_HERE();
-                return ValueRef::createUndefined();
-            },
-            0, true, true));
-
-    extensionObject->defineDataProperty(
-        state, ValueRef::create(m_strings->postMessage->string()),
-        ValueRef::create(postMessageFn), true, true, true);
-
-    FunctionObjectRef* sendSyncMessageFn = FunctionObjectRef::create(
-        state,
-        FunctionObjectRef::NativeFunctionInfo(
-            m_strings->sendSyncMessage,
-            [](ExecutionStateRef* state, ValueRef* thisValue, size_t argc,
-               ValueRef** argv, bool isNewExpression) -> ValueRef* {
-                DEVICEAPI_LOG_INFO("extension.sendSyncMessage");
-                printArguments(state->context(), argc, argv);
-
-                ExtensionManagerInstance* extensionManagerInstance =
-                    get(state->context());
-                wrt::xwalk::ExtensionInstance* extensionInstance =
-                    extensionManagerInstance
-                        ->getExtensionInstanceFromCallingContext(
-                            state->context(), thisValue);
-                if (!extensionInstance || argc != 1) {
-                    return ValueRef::create(false);
-                }
-
-                StringRef* message = argv[0]->toString(state);
-                extensionInstance->HandleSyncMessage(
-                    message->toStdUTF8String());
-
-                std::string reply = extensionInstance->sync_replay_msg();
-                DEVICEAPI_LOG_INFO(
-                    "extension.sendSyncMessage Done with reply %s",
-                    reply.c_str());
-
-                if (reply.empty()) {
-                    return ValueRef::createNull();
-                }
-                return ValueRef::create(
-                    StringRef::createFromASCII(reply.c_str(), reply.size()));
-            },
-            0, true, true));
-
-    extensionObject->defineDataProperty(
-        state, ValueRef::create(m_strings->sendSyncMessage->string()),
-        ValueRef::create(sendSyncMessageFn), true, true, true);
-
-    FunctionObjectRef* sendSyncDataFn = FunctionObjectRef::create(
-        state,
-        FunctionObjectRef::NativeFunctionInfo(
-            m_strings->sendSyncData,
-            [](ExecutionStateRef* state, ValueRef* thisValue, size_t argc,
-               ValueRef** argv, bool isNewExpression) -> ValueRef* {
-                DEVICEAPI_LOG_INFO("extension.sendSyncData");
-                printArguments(state->context(), argc, argv);
-
-                ExtensionManagerInstance* extensionManagerInstance =
-                    get(state->context());
-                wrt::xwalk::ExtensionInstance* extensionInstance =
-                    extensionManagerInstance
-                        ->getExtensionInstanceFromCallingContext(
-                            state->context(), thisValue);
-                if (!extensionInstance || argc < 1) {
-                    return ValueRef::create(false);
-                }
-
-                ChunkData chunkData(nullptr, 0);
-                if (argc > 1) {
-                    ValueRef* dataValue = argv[1];
-                    if (dataValue->isObject()) {
-                        ObjectRef* arrayData = dataValue->toObject(state);
-                        size_t length =
-                            arrayData
-                                ->get(state,
-                                      ValueRef::create(
-                                          StringRef::createFromASCII("length")))
-                                ->toLength(state);
-                        uint8_t* buffer =
-                            (uint8_t*)malloc(sizeof(uint8_t) * length);
-                        for (size_t i = 0; i < length; i++) {
-                            buffer[i] = static_cast<uint8_t>(
-                                arrayData->get(state, ValueRef::create(i))
-                                    ->toNumber(state));
-                        }
-                        chunkData = ChunkData(buffer, length);
-                    } else if (dataValue->isString()) {
-                        StringRef* stringData = dataValue->toString(state);
-                        chunkData = ChunkData(
-                            (uint8_t*)stringData->toStdUTF8String().c_str(),
-                            stringData->length());
-                    }
-                }
-
-                StringRef* message = argv[0]->toString(state);
-                extensionInstance->HandleSyncData(message->toStdUTF8String(),
-                                                  chunkData.m_buffer,
-                                                  chunkData.m_length);
-
-                uint8_t* replyBuffer = nullptr;
-                size_t replyLength = 0;
-                std::string reply = extensionInstance->sync_data_reply_msg(
-                    &replyBuffer, &replyLength);
-
-                DEVICEAPI_LOG_INFO(
-                    "extension.sendSyncData Done with reply %s (buffer %s)",
-                    reply.c_str(), replyBuffer);
-
-                if (reply.empty()) {
-                    return ValueRef::createNull();
-                }
-
-                ObjectRef* returnObject = ObjectRef::create(state);
-                returnObject->defineDataProperty(
-                    state,
-                    ValueRef::create(
-                        extensionManagerInstance->strings()->reply->string()),
-                    ValueRef::create(StringRef::createFromASCII(reply.c_str(),
-                                                                reply.size())),
-                    true, true, true);
-
-                if (replyBuffer || replyLength > 0) {
-                    size_t chunkID = extensionManagerInstance->addChunk(
-                        replyBuffer, replyLength);
-                    returnObject->defineDataProperty(
-                        state,
-                        ValueRef::create(extensionManagerInstance->strings()
-                                             ->chunk_id->string()),
-                        ValueRef::create(chunkID), true, true, true);
-                }
-
-                return ValueRef::create(returnObject);
-            },
-            0, true, true));
-
-    extensionObject->defineDataProperty(
-        state, ValueRef::create(m_strings->sendSyncData->string()),
-        ValueRef::create(sendSyncDataFn), true, true, true);
-
-    FunctionObjectRef* sendRuntimeMessageFn = FunctionObjectRef::create(
-        state,
-        FunctionObjectRef::NativeFunctionInfo(
-            m_strings->sendRuntimeMessage,
-            [](ExecutionStateRef* state, ValueRef* thisValue, size_t argc,
-               ValueRef** argv, bool isNewExpression) -> ValueRef* {
-                DEVICEAPI_LOG_ERROR(
-                    "extension.sendRuntimeMessage UNIMPLEMENTED");
-                printArguments(state->context(), argc, argv);
-                NESCARGOT_ASSERT_SHOULD_NOT_BE_HERE();
-                return ValueRef::createUndefined();
-            },
-            0, true, true));
-
-    extensionObject->defineDataProperty(
-        state, ValueRef::create(m_strings->sendRuntimeMessage->string()),
-        ValueRef::create(sendRuntimeMessageFn), true, true, true);
-
-    FunctionObjectRef* sendRuntimeAsyncMessageFn = FunctionObjectRef::create(
-        state,
-        FunctionObjectRef::NativeFunctionInfo(
-            m_strings->sendRuntimeAsyncMessage,
-            [](ExecutionStateRef* state, ValueRef* thisValue, size_t argc,
-               ValueRef** argv, bool isNewExpression) -> ValueRef* {
-                DEVICEAPI_LOG_ERROR(
-                    "extension.sendRuntimeAsyncMessage UNIMPLEMENTED");
-                printArguments(state->context(), argc, argv);
-                NESCARGOT_ASSERT_SHOULD_NOT_BE_HERE();
-                return ValueRef::createUndefined();
-            },
-            0, true, true));
-
-    extensionObject->defineDataProperty(
-        state, ValueRef::create(m_strings->sendRuntimeAsyncMessage->string()),
-        ValueRef::create(sendRuntimeAsyncMessageFn), true, true, true);
-
-    FunctionObjectRef* sendRuntimeSyncMessageFn = FunctionObjectRef::create(
-        state,
-        FunctionObjectRef::NativeFunctionInfo(
-            m_strings->sendRuntimeSyncMessage,
-            [](ExecutionStateRef* state, ValueRef* thisValue, size_t argc,
-               ValueRef** argv, bool isNewExpression) -> ValueRef* {
-                DEVICEAPI_LOG_ERROR(
-                    "extension.sendRuntimeSyncMessage UNIMPLEMENTED");
-                printArguments(state->context(), argc, argv);
-                NESCARGOT_ASSERT_SHOULD_NOT_BE_HERE();
-                return ValueRef::createUndefined();
-            },
-            0, true, true));
-
-    extensionObject->defineDataProperty(
-        state, ValueRef::create(m_strings->sendRuntimeSyncMessage->string()),
-        ValueRef::create(sendRuntimeSyncMessageFn), true, true, true);
-
-    FunctionObjectRef* setMessageListenerFn = FunctionObjectRef::create(
-        state,
-        FunctionObjectRef::NativeFunctionInfo(
-            m_strings->setMessageListener,
-            [](ExecutionStateRef* state, ValueRef* thisValue, size_t argc,
-               ValueRef** argv, bool isNewExpression) -> ValueRef* {
-                DEVICEAPI_LOG_INFO("extension.setMessageListener");
-                printArguments(state->context(), argc, argv);
-
-                ExtensionManagerInstance* extensionManagerInstance =
-                    get(state->context());
-                wrt::xwalk::ExtensionInstance* extensionInstance =
-                    extensionManagerInstance
-                        ->getExtensionInstanceFromCallingContext(
-                            state->context(), thisValue);
-
-                if (!extensionInstance || argc != 1) {
-                    return ValueRef::create(false);
-                }
-
-                ValueRef* listenerValue = argv[0];
-                if (listenerValue->isUndefined()) {
-                    extensionInstance->set_post_message_listener(nullptr);
-                    return ValueRef::create(true);
-                }
-
-                if (!listenerValue->isCallable()) {
-                    DEVICEAPI_LOG_ERROR("Invalid message listener.");
-                    return ValueRef::create(false);
-                }
-
-                ObjectRef* listener = listenerValue->asObject();
-                ESPostMessageListener* postMessageListener =
-                    ESPostMessageListener::create(state->context(), listener);
-                extensionInstance->set_post_message_listener(
-                    postMessageListener);
-
-                extensionManagerInstance->m_postListeners.push_back(
-                    postMessageListener);
-
-                return ValueRef::create(true);
-            },
-            0, true, true));
-
-    extensionObject->defineDataProperty(
-        state, ValueRef::create(m_strings->setMessageListener->string()),
-        ValueRef::create(setMessageListenerFn), true, true, true);
-
-    FunctionObjectRef* receiveChunkDataFn = FunctionObjectRef::create(
-        state,
-        FunctionObjectRef::NativeFunctionInfo(
-            m_strings->receiveChunkData,
-            [](ExecutionStateRef* state, ValueRef* thisValue, size_t argc,
-               ValueRef** argv, bool isNewExpression) -> ValueRef* {
-                DEVICEAPI_LOG_ERROR("extension.receiveChunkData");
-                printArguments(state->context(), argc, argv);
-
-                ExtensionManagerInstance* extensionManagerInstance =
-                    get(state->context());
-                wrt::xwalk::ExtensionInstance* extensionInstance =
-                    extensionManagerInstance
-                        ->getExtensionInstanceFromCallingContext(
-                            state->context(), thisValue);
-
-                if (!extensionInstance || argc < 1) {
-                    return ValueRef::create(false);
-                }
-
-                TizenStrings* strings = extensionManagerInstance->strings();
-
-                size_t chunkID = argv[0]->toNumber(state);
-                ExtensionManagerInstance::ChunkData chunkData =
-                    extensionManagerInstance->getChunk(chunkID);
-                if (!chunkData.m_buffer) {
-                    return ValueRef::createNull();
-                }
-
-                StringRef* type = argv[1]->toString(state);
-                bool isStringType = (!type->equals(strings->octet->string()));
-
-                ValueRef* ret;
-                if (isStringType) {
-                    ret = ValueRef::create(StringRef::createFromUTF8(
-                        (const char*)chunkData.m_buffer,
-                        strlen((const char*)chunkData.m_buffer)));
-                } else {
-                    ArrayObjectRef* octetArray = ArrayObjectRef::create(state);
-                    for (size_t i = 0; i < chunkData.m_length; i++) {
-                        octetArray->set(
-                            state, ValueRef::create(i),
-                            ValueRef::create(chunkData.m_buffer[i]));
-                    }
-                    ret = ValueRef::create(octetArray);
-                }
-                free(chunkData.m_buffer);
-                return ret;
-            },
-            0, true, true));
-
-    extensionObject->defineDataProperty(
-        state, ValueRef::create(m_strings->receiveChunkData->string()),
-        ValueRef::create(receiveChunkDataFn), true, true, true);
-
-    return extensionObject;
-}
-
-wrt::xwalk::ExtensionInstance*
-ExtensionManagerInstance::getExtensionInstanceFromCallingContext(
-    ContextRef* context, ValueRef* thisValue)
-{
-    DEVICEAPI_LOG_INFO("Enter");
-    if (thisValue->isUndefinedOrNull()) {
-        return nullptr;
-    }
-
-    ObjectRef* obj = Evaluator::execute(m_context,
-                                        [](ExecutionStateRef* state,
-                                           ValueRef* thisValue) -> ValueRef* {
-                                            return thisValue->toObject(state);
-                                        },
-                                        thisValue)
-                         .result->asObject();
-
-    auto it = m_extensionInstances.find(obj);
-    if (it == m_extensionInstances.end()) {
-        return nullptr;
-    }
-
-    return it->second;
-}
-
-size_t ExtensionManagerInstance::addChunk(uint8_t* buffer, size_t length)
-{
-    DEVICEAPI_LOG_INFO("Enter");
-    size_t chunkID = m_chunkID++;
-    m_chunkDataMap[chunkID] = ChunkData(buffer, length);
-    return chunkID;
-}
-
-ExtensionManagerInstance::ChunkData ExtensionManagerInstance::getChunk(
-    size_t chunkID)
-{
-    DEVICEAPI_LOG_INFO("Enter");
-    auto it = m_chunkDataMap.find(chunkID);
-    if (it == m_chunkDataMap.end()) {
-        return ChunkData(nullptr, 0);
-    } else {
-        ChunkData chunkData = it->second;
-        m_chunkDataMap.erase(it);
-        return chunkData;
-    }
-}
-
-ExtensionManagerInstance::ExtensionManagerInstanceMap
-    ExtensionManagerInstance::s_extensionManagerInstances;
-
-std::mutex ExtensionManagerInstance::s_mutex;
-
-ExtensionManagerInstance::ExtensionManagerInstance(ContextRef* context)
-    : m_context(context)
-    , m_chunkID(0)
-{
-    DEVICEAPI_LOG_INFO("new ExtensionManagerInstance %p", this);
-
-#define DECLARE_TIZEN_OBJECT(name) VALUE_NAME_STRCAT(m_##name) = nullptr;
-    FOR_EACH_EARLY_TIZEN_STRINGS(DECLARE_TIZEN_OBJECT);
-    FOR_EACH_LAZY_TIZEN_STRINGS(DECLARE_TIZEN_OBJECT);
-    SUPPORTED_TIZEN_PROPERTY(DECLARE_TIZEN_OBJECT);
-    SUPPORTED_TIZEN_ENTRYPOINTS(DECLARE_TIZEN_OBJECT);
-#undef DECLARE_TIZEN_OBJECT
-
-    m_strings = new TizenStrings(m_context);
-    Evaluator::execute(
-        m_context,
-        [](ExecutionStateRef* state,
-           ExtensionManagerInstance* self) -> ValueRef* {
-            ValueRef* tizenGetter = ValueRef::create(FunctionObjectRef::create(
-                state,
-                FunctionObjectRef::NativeFunctionInfo(
-                    self->m_strings->tizen,
-                    [](ExecutionStateRef* state, ValueRef* thisValue,
-                       size_t argc, ValueRef** argv,
-                       bool isNewExpression) -> ValueRef* {
-                        DEVICEAPI_LOG_INFO("Enter");
-
-                        ExtensionManagerInstance* extensionManagerInstance =
-                            get(state->context());
-
-                        if (extensionManagerInstance->m_tizenValue) {
-                            return extensionManagerInstance->m_tizenValue;
-                        }
-
-                        TizenStrings* strings =
-                            extensionManagerInstance->strings();
-                        strings->initializeLazyStrings();
-
-                        // initialize tizen object
-                        ObjectRef* tizenObject =
-                            extensionManagerInstance
-                                ->initializeExtensionInstance("tizen");
-                        extensionManagerInstance->m_tizenValue =
-                            ValueRef::create(tizenObject);
-
-#define DEFINE_SUPPORTED_TIZEN_API(name)                                       \
-    tizenObject->defineAccessorProperty(                                       \
-        state, ValueRef::create(StringRef::createFromASCII("" #name)),         \
-        ObjectRef::AccessorPropertyDescriptor(                                 \
-            ValueRef::create(FunctionObjectRef::create(                        \
-                state,                                                         \
-                FunctionObjectRef::NativeFunctionInfo(                         \
-                    AtomicStringRef::create(state->context(), "" #name),       \
-                    [](ExecutionStateRef* state, ValueRef* thisValue,          \
-                       size_t argc, ValueRef** argv,                           \
-                       bool isNewExpression) -> ValueRef* {                    \
-                        ExtensionManagerInstance* extensionManagerInstance =   \
-                            get(state->context());                             \
-                        if (extensionManagerInstance->VALUE_NAME_STRCAT(       \
-                                m_##name)) {                                   \
-                            return extensionManagerInstance                    \
-                                ->VALUE_NAME_STRCAT(m_##name);                 \
-                        }                                                      \
-                        DEVICEAPI_LOG_INFO("Loading plugin for %s", "" #name); \
-                        ObjectRef* apiObject =                                 \
-                            extensionManagerInstance                           \
-                                ->initializeExtensionInstance("" #name);       \
-                        extensionManagerInstance->VALUE_NAME_STRCAT(           \
-                            m_##name) = ValueRef::create(apiObject);           \
-                        thisValue->toObject(state)->defineDataProperty(        \
-                            state, ValueRef::create(                           \
-                                       StringRef::createFromASCII("" #name)),  \
-                            ValueRef::create(apiObject), false, true, false);  \
-                        return ValueRef::create(apiObject);                    \
-                    },                                                         \
-                    0, true, true))),                                          \
-            nullptr, ObjectRef::PresentAttribute::EnumerablePresent));
-
-                        SUPPORTED_TIZEN_PROPERTY(DEFINE_SUPPORTED_TIZEN_API)
-#undef DEFINE_SUPPORTED_TIZEN_API
-
-#define DEFINE_SUPPORTED_TIZEN_ENTRYPOINTS(name)                               \
-    ObjectRef::NativeDataAccessorPropertyData* nativeData##name =              \
-        new NativeDataAccessorPropertyDataForEntryPoint(                       \
-            true, true, true,                                                  \
-            [](ExecutionStateRef* state, ObjectRef* self,                      \
-               ObjectRef::NativeDataAccessorPropertyData* data) -> ValueRef* { \
-                ExtensionManagerInstance* extensionManagerInstance =           \
-                    get(state->context());                                     \
-                if (extensionManagerInstance->VALUE_NAME_STRCAT(m_##name)) {   \
-                    return extensionManagerInstance->VALUE_NAME_STRCAT(        \
-                        m_##name);                                             \
-                }                                                              \
-                DEVICEAPI_LOG_INFO("Loading plugin for %s", "" #name);         \
-                NativeDataAccessorPropertyDataForEntryPoint* myData =          \
-                    (NativeDataAccessorPropertyDataForEntryPoint*)data;        \
-                extensionManagerInstance->VALUE_NAME_STRCAT(m_##name) =        \
-                    myData->m_data;                                            \
-                return myData->m_data;                                         \
-            },                                                                 \
-            [](ExecutionStateRef* state, ObjectRef* self,                      \
-               ObjectRef::NativeDataAccessorPropertyData* data,                \
-               ValueRef* setterInputData) -> bool {                            \
-                NativeDataAccessorPropertyDataForEntryPoint* myData =          \
-                    (NativeDataAccessorPropertyDataForEntryPoint*)data;        \
-                myData->m_data = setterInputData;                              \
-                return true;                                                   \
-            });                                                                \
-    tizenObject->defineNativeDataAccessorProperty(                             \
-        state, ValueRef::create(StringRef::createFromASCII(#name)),            \
-        nativeData##name);
-
-                        SUPPORTED_TIZEN_ENTRYPOINTS(
-                            DEFINE_SUPPORTED_TIZEN_ENTRYPOINTS)
-#undef DEFINE_SUPPORTED_TIZEN_ENTRYPOINTS
-
-#if defined(STARFISH_TIZEN_WEARABLE_WIDGET)
-                        WebWidgetAPIInstance* ww =
-                            new (GC) WebWidgetAPIInstance();
-                        extensionManagerInstance->m_webWidgetAPIInstance = ww;
-                        ObjectRef* widgetAPIObj =
-                            ww->createWebWidgetAPIObject(state->context());
-                        tizenObject->defineDataProperty(
-                            state, ValueRef::create(
-                                       StringRef::createFromASCII("webWidget")),
-                            ValueRef::create(widgetAPIObj), false, true, false);
-#endif
-
-                        return ValueRef::create(tizenObject);
-                    },
-                    0, true, true)));
-
-            self->m_context->globalObject()->defineAccessorProperty(
-                state, ValueRef::create(self->m_strings->tizen->string()),
-                ObjectRef::AccessorPropertyDescriptor(
-                    tizenGetter, nullptr,
-                    ObjectRef::PresentAttribute::EnumerablePresent));
-
-            ValueRef* xwalkGetter = ValueRef::create(FunctionObjectRef::create(
-                state,
-                FunctionObjectRef::NativeFunctionInfo(
-                    self->m_strings->xwalk,
-                    [](ExecutionStateRef* state, ValueRef* thisValue,
-                       size_t argc, ValueRef** argv,
-                       bool isNewExpression) -> ValueRef* {
-                        DEVICEAPI_LOG_INFO("xwalkGetter Enter");
-
-                        ExtensionManagerInstance* extensionManagerInstance =
-                            get(state->context());
-                        if (extensionManagerInstance->m_xwalkValue) {
-                            return extensionManagerInstance->m_xwalkValue;
-                        }
-                        DEVICEAPI_LOG_INFO("Loading plugin for xwalk.utils");
-
-                        TizenStrings* strings =
-                            extensionManagerInstance->strings();
-                        strings->initializeLazyStrings();
-
-                        // initialize xwalk object
-                        ObjectRef* xwalkObject =
-                            extensionManagerInstance
-                                ->initializeExtensionInstance("utils");
-                        extensionManagerInstance->m_xwalkValue =
-                            ValueRef::create(xwalkObject);
-
-                        // re-define xwalk object
-                        thisValue->toObject(state)->defineDataProperty(
-                            state, ValueRef::create(strings->xwalk->string()),
-                            ValueRef::create(xwalkObject), false, true, false);
-
-                        return ValueRef::create(xwalkObject);
-                    },
-                    0, true, true)));
-
-            self->m_context->globalObject()->defineAccessorProperty(
-                state, ValueRef::create(self->m_strings->xwalk->string()),
-                ObjectRef::AccessorPropertyDescriptor(
-                    xwalkGetter, nullptr,
-                    ObjectRef::PresentAttribute::EnumerablePresent));
-
-            return ValueRef::createUndefined();
-
-        },
-        this);
-
-#if defined(STARFISH_TIZEN_WEARABLE_WIDGET)
-    m_webWidgetAPIInstance = nullptr;
-#endif
-    std::lock_guard<std::mutex> guard(s_mutex);
-    s_extensionManagerInstances[m_context] = this;
-    DEVICEAPI_LOG_INFO("ExtensionManagerInstance %zu => %zu",
-                       s_extensionManagerInstances.size() - 1,
-                       s_extensionManagerInstances.size());
-}
-
-ExtensionManagerInstance::~ExtensionManagerInstance()
-{
-    std::lock_guard<std::mutex> guard(s_mutex);
-    DEVICEAPI_LOG_INFO(
-        "ExtensionManagerInstance delete ExtensionManagerInstance %p", this);
-    for (auto it : m_extensionInstances)
-        delete it.second;
-    for (auto it : m_postListeners)
-        it->finalize();
-    auto it = s_extensionManagerInstances.find(m_context);
-    s_extensionManagerInstances.erase(it);
-    DEVICEAPI_LOG_INFO("ExtensionManagerInstance %zu => %zu",
-                       s_extensionManagerInstances.size() + 1,
-                       s_extensionManagerInstances.size());
-}
-
-ExtensionManagerInstance* ExtensionManagerInstance::get(ContextRef* context)
-{
-    std::lock_guard<std::mutex> guard(s_mutex);
-    ExtensionManagerInstance* instance = nullptr;
-
-    auto it = s_extensionManagerInstances.find(context);
-    if (it != s_extensionManagerInstances.end()) {
-        instance = it->second;
-    }
-
-    return instance;
-}
-
-ExtensionManagerInstance* initialize(ContextRef* context)
-{
-    DEVICEAPI_LOG_INFO("ExtensionManagerInstance Enter with context %p",
-                       context);
-    return new ExtensionManagerInstance(context);
-}
-
-void close(ContextRef* context)
-{
-    DEVICEAPI_LOG_INFO("ExtensionManagerInstance Enter with context %p",
-                       context);
-    delete ExtensionManagerInstance::get(context);
-}
-}
-
-#endif
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/TizenDeviceAPILoaderForEscargot.h b/lwnode/code/escargotshim/deps/tizen-device-api/src/TizenDeviceAPILoaderForEscargot.h
deleted file mode 100644 (file)
index 0ed63dd..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef __TizenDeviceAPILoaderForEscargot__
-#define __TizenDeviceAPILoaderForEscargot__
-
-#ifdef TIZEN_DEVICE_API
-
-#include <mutex>
-
-#include "escargotbase.h"
-#include "EscargotPublic.h"
-
-#undef LOGGER_TAG
-#define LOGGER_TAG "EscargotNodeDeviceAPI"
-
-#ifndef __MODULE__
-#define __MODULE__ \
-  (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
-#endif
-
-// #define _LOGGER_LOG(prio, fmt, args...)                                   \
-//   dlog_print(prio, LOGGER_TAG, "%s: %s(%d) > " fmt, __MODULE__, __func__, \
-//              __LINE__, ##args);
-
-// #define _LOGGER_SLOG(prio, fmt, args...)                                  \
-//   dlog_print(prio, LOGGER_TAG, "%s: %s(%d) > " fmt, __MODULE__, __func__, \
-//              __LINE__, ##args);
-
-#define _LOGGER_LOG(prio, fmt, args...)                                   \
-  printf("%s: %s(%d) > " fmt "\n", __MODULE__, __func__, \
-             __LINE__, ##args);
-
-#define _LOGGER_SLOG(prio, fmt, args...)                                  \
-  printf("%s: %s(%d) > " fmt "\n", __MODULE__, __func__, \
-             __LINE__, ##args);
-
-#define DEVICEAPI_LOG_INFO(fmt, args...) _LOGGER_LOG(DLOG_INFO, fmt, ##args)
-#define DEVICEAPI_LOG_ERROR(fmt, args...) \
-  _LOGGER_LOG(DLOG_ERROR, "Error: " fmt, ##args)
-#define DEVICEAPI_LOG_WARN(fmt, args...) _LOGGER_LOG(DLOG_WARN, fmt, ##args)
-
-#define DEVICEAPI_SLOG_INFO(fmt, args...) _LOGGER_SLOG(DLOG_INFO, fmt, ##args)
-#define DEVICEAPI_SLOG_ERROR(fmt, args...) _LOGGER_SLOG(DLOG_ERROR, fmt, ##args)
-#define DEVICEAPI_SLOG_WARN(fmt, args...) _LOGGER_SLOG(DLOG_WARN, fmt, ##args)
-#define VALUE_NAME_STRCAT(name) name##Value
-
-namespace wrt {
-namespace xwalk {
-class Extension;
-class ExtensionInstance;
-}
-}
-
-namespace DeviceAPI {
-
-class ESPostListener;
-
-#define FOR_EACH_EARLY_TIZEN_STRINGS(F) \
-  F(tizen)                              \
-  F(xwalk)                              \
-  F(webapis)
-
-#define FOR_EACH_LAZY_TIZEN_STRINGS(F) \
-  F(utils)                             \
-  F(common)                            \
-  F(extension)                         \
-  F(postMessage)                       \
-  F(sendSyncMessage)                   \
-  F(sendSyncData)                      \
-  F(sendRuntimeMessage)                \
-  F(sendRuntimeSyncMessage)            \
-  F(sendRuntimeAsyncMessage)           \
-  F(setMessageListener)                \
-  F(receiveChunkData)                  \
-  F(reply)                             \
-  F(chunk_id)                          \
-  F(string)                            \
-  F(octet)
-
-#define SUPPORTED_TIZEN_PROPERTY(F) \
-  F(application)                    \
-  F(filesystem)                     \
-  F(messageport)                    \
-  F(systeminfo)                     \
-  F(sensorservice)                  \
-  F(preference)                     \
-  F(power)                          \
-  F(time)
-
-#define SUPPORTED_TIZEN_ENTRYPOINTS(F) \
-  F(ApplicationControl)                \
-  F(ApplicationControlData)
-
-class TizenStrings {
- public:
-  TizenStrings(Escargot::ContextRef* context);
-  void initializeEarlyStrings();
-  void initializeLazyStrings();
-
-#define DECLARE_TIZEN_STRING(name) Escargot::AtomicStringRef* name;
-  FOR_EACH_EARLY_TIZEN_STRINGS(DECLARE_TIZEN_STRING);
-  FOR_EACH_LAZY_TIZEN_STRINGS(DECLARE_TIZEN_STRING);
-  SUPPORTED_TIZEN_PROPERTY(DECLARE_TIZEN_STRING);
-  SUPPORTED_TIZEN_ENTRYPOINTS(DECLARE_TIZEN_STRING);
-#undef DECLARE_TIZEN_STRING
-
- private:
-  Escargot::ContextRef* m_context;
-  bool m_initialized;
-};
-
-/*
- * Extension: (tizen, utils, common, messageport, sensorservice...) * 1
- * ExtensionManager: (manager) * 1
- * ExtensionInstance: (tizen, utils, common, messageport, sensorservice...) *
- * number of ESVMInstances
- * ExtensionManagerInstance: (manager) * number of ESVMInstances
- */
-
-class ExtensionManagerInstance : public gc {
- public:
-  ExtensionManagerInstance(Escargot::ContextRef* context);
-  ~ExtensionManagerInstance();
-
-  void* operator new(size_t size);
-  void* operator new[](size_t size) = delete;
-
-  static ExtensionManagerInstance* get(Escargot::ContextRef* context);
-  TizenStrings* strings() { return m_strings; }
-  wrt::xwalk::ExtensionInstance* getExtensionInstanceFromCallingContext(
-      Escargot::ContextRef*, Escargot::ValueRef* thisValue);
-  Escargot::ObjectRef* initializeExtensionInstance(const char*);
-#if defined(STARFISH_TIZEN_WEARABLE_WIDGET)
-  WebWidgetAPIInstance* webWidgetAPIInstance() {
-    return m_webWidgetAPIInstance;
-  }
-#endif
-
- private:
-  struct ChunkData {
-    ChunkData() {}
-    ChunkData(uint8_t* buffer, size_t length)
-        : m_buffer(buffer), m_length(length) {}
-    uint8_t* m_buffer;
-    size_t m_length;
-  };
-
-  typedef std::map<size_t, ChunkData> ChunkDataMap;
-  typedef std::map<Escargot::ObjectRef*, wrt::xwalk::ExtensionInstance*>
-      ExtensionInstanceMap;
-  typedef std::vector<ESPostListener*> ESPostListenerVector;
-
-  Escargot::ObjectRef* createExtensionObject(
-      Escargot::ExecutionStateRef* state);
-  size_t addChunk(uint8_t* buffer, size_t length);
-  ChunkData getChunk(size_t chunkID);
-
-  Escargot::ContextRef* m_context;
-  ExtensionInstanceMap m_extensionInstances;
-  ESPostListenerVector m_postListeners;
-  ChunkDataMap m_chunkDataMap;
-  size_t m_chunkID;
-  TizenStrings* m_strings;
-#if defined(STARFISH_TIZEN_WEARABLE_WIDGET)
-  WebWidgetAPIInstance* m_webWidgetAPIInstance;
-#endif
-#define DECLARE_TIZEN_OBJECT(name) \
-  Escargot::ValueRef* VALUE_NAME_STRCAT(m_##name);
-  FOR_EACH_EARLY_TIZEN_STRINGS(DECLARE_TIZEN_OBJECT);
-  FOR_EACH_LAZY_TIZEN_STRINGS(DECLARE_TIZEN_OBJECT);
-  SUPPORTED_TIZEN_PROPERTY(DECLARE_TIZEN_OBJECT);
-  SUPPORTED_TIZEN_ENTRYPOINTS(DECLARE_TIZEN_OBJECT);
-#undef DECLARE_TIZEN_OBJECT
-
-  // static members
-  typedef std::map<Escargot::ContextRef*, ExtensionManagerInstance*>
-      ExtensionManagerInstanceMap;
-  static wrt::xwalk::Extension* getExtension(const char* apiName);
-  static ExtensionManagerInstanceMap s_extensionManagerInstances;
-  static std::mutex s_mutex;
-};
-
-inline ExtensionManagerInstance* ExtensionManagerInstanceGet(
-    Escargot::ContextRef* context) {
-  return ExtensionManagerInstance::get(context);
-}
-
-ExtensionManagerInstance* initialize(Escargot::ContextRef* context);
-void close(Escargot::ContextRef* context);
-}
-
-class NativeDataAccessorPropertyDataForEntryPoint
-    : public Escargot::ObjectRef::NativeDataAccessorPropertyData {
- public:
-  NativeDataAccessorPropertyDataForEntryPoint(
-      bool isWritable, bool isEnumerable, bool isConfigurable,
-      Escargot::ObjectRef::NativeDataAccessorPropertyGetter getter,
-      Escargot::ObjectRef::NativeDataAccessorPropertySetter setter)
-      : NativeDataAccessorPropertyData(isWritable, isEnumerable, isConfigurable,
-                                       getter, setter) {
-    m_data = Escargot::ValueRef::createUndefined();
-  }
-
-  void* operator new(size_t size) { return GC_MALLOC(size); }
-
-  Escargot::ValueRef* m_data;
-};
-
-#endif  // TIZEN_DEVICE_API
-
-#endif  // __TizenDeviceAPILoaderForEscargot__
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension.h b/lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension.h
deleted file mode 100644 (file)
index 7ca7511..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright (c) 2013 Intel Corporation. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_
-#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_
-
-// Crosswalk Extensions are modules of code loaded by Crosswalk runtime that
-// allow extending its capabilities. The extension is expected to define a
-// XW_Initialize() function as declared below, get the interfaces it need to
-// use and register to whatever callbacks it needs, then return XW_OK.
-//
-// The Extension is represented by the type XW_Extension. Each extension
-// loaded may be used multiple times for different pages, so to each execution
-// there will be an associated XW_Instance. A reasonable analogy is that the
-// XW_Extension represent a "class", and have concrete instances running.
-//
-// An interface is a struct with a set of functions, provided by Crosswalk,
-// that allow the extension code to interact with the web content. Certain
-// functions in an interface are used to register callbacks, so that Crosswalk
-// can call the extension at specific situations.
-//
-// Crosswalk won't call an extension's XW_Initialize() multiple times in the
-// same process.
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if __GNUC__ >= 4
-#define XW_EXPORT __attribute__((visibility("default")))
-#elif defined(_MSC_VER)
-#define XW_EXPORT __declspec(dllexport)
-#endif
-
-#include <stddef.h>
-#include <stdint.h>
-
-// XW_Extension is used to identify your extension when calling functions from
-// the API. You should always use the XW_Extension received at XW_Initialize().
-//
-// XW_Instance is used to identify different web contents using your
-// extension. Each time a new web content is created you can be notified
-// registering the XW_CreatedInstanceCallback, that receives the new
-// XW_Instance. When interacting with an Instance (for example to post a
-// message), you should pass the corresponding XW_Instance.
-//
-// In both types the zero value is never used by Crosswalk, so can be used to
-// initialize variables.
-typedef int32_t XW_Extension;
-typedef int32_t XW_Instance;
-
-enum { XW_OK = 0, XW_ERROR = -1 };
-
-// Returns a struct containing functions to be used by the extension. Those
-// structs can be stored statically and used until the extension is unloaded.
-// Extensions should use definitions like XW_CORE_INTERFACE, instead of using
-// the versioned definition or the literal string. Returns NULL if the
-// interface is not supported.
-typedef const void* (*XW_GetInterface)(const char* interface_name);
-
-typedef int32_t (*XW_Initialize_Func)(XW_Extension extension,
-                                      XW_GetInterface get_interface);
-
-// XW_Initialize is called after the extension code is loaded. The 'extension'
-// value should be used in further calls that expect XW_Extension argument.
-//
-// The 'get_interface' function should be used to get access to functions that
-// interact with the web content. It is only valid during the execution of the
-// XW_Initialize() function.
-//
-// This function should return XW_OK when the extension was succesfully
-// loaded, otherwise XW_ERROR.
-XW_EXPORT int32_t XW_Initialize(XW_Extension extension,
-                                XW_GetInterface get_interface);
-
-//
-// XW_CORE_INTERFACE: Basic functionality for Crosswalk Extensions. All
-// extensions should use this interface to set at least their name.
-//
-
-#define XW_CORE_INTERFACE_1 "XW_CoreInterface_1"
-#define XW_CORE_INTERFACE XW_CORE_INTERFACE_1
-
-typedef void (*XW_CreatedInstanceCallback)(XW_Instance instance);
-typedef void (*XW_DestroyedInstanceCallback)(XW_Instance instance);
-typedef void (*XW_ShutdownCallback)(XW_Extension extension);
-
-struct XW_CoreInterface_1 {
-    // Set the name of the extension. It is used as the namespace for the
-    // JavaScript code exposed by the extension. So extension named
-    // 'my_extension', will expose its JavaScript functionality inside
-    // the 'my_extension' namespace.
-    //
-    // This function should be called only during XW_Initialize().
-    void (*SetExtensionName)(XW_Extension extension, const char* name);
-
-    // Set the JavaScript code loaded in the web content when the extension is
-    // used. This can be used together with the messaging mechanism to implement
-    // a higher-level API that posts messages to extensions, see
-    // XW_MESSAGING_INTERFACE below.
-    //
-    // The code will be executed inside a JS function context with the following
-    // objects available:
-    //
-    // - exports: this object should be filled with properties and functions
-    //            that will be exposed in the namespace associated with this
-    //            extension.
-    //
-    // - extension.postMessage(): post a string message to the extension native
-    //                            code. See below for details.
-    // - extension.setMessageListener(): allow setting a callback that is called
-    //                                   when the native code sends a message
-    //                                   to JavaScript. Callback takes a string.
-    //
-    // This function should be called only during XW_Initialize().
-    void (*SetJavaScriptAPI)(XW_Extension extension, const char* api);
-
-    // Register callbacks that are called when an instance of this extension
-    // is created or destroyed. Everytime a new web content is loaded, it will
-    // get a new associated instance.
-    //
-    // This function should be called only during XW_Initialize().
-    void (*RegisterInstanceCallbacks)(XW_Extension extension,
-                                      XW_CreatedInstanceCallback created,
-                                      XW_DestroyedInstanceCallback destroyed);
-
-    // Register a callback to be executed when the extension will be unloaded.
-    //
-    // This function should be called only during XW_Initialize().
-    void (*RegisterShutdownCallback)(XW_Extension extension,
-                                     XW_ShutdownCallback shutdown_callback);
-
-    // These two functions are conveniences used to associated arbitrary data
-    // with a given XW_Instance. They can be used only with instances that were
-    // created but not yet completely destroyed. GetInstanceData() can be used
-    // during the destroyed instance callback. If not instance data was set,
-    // getting it returns NULL.
-    void (*SetInstanceData)(XW_Instance instance, void* data);
-    void* (*GetInstanceData)(XW_Instance instance);
-};
-
-typedef struct XW_CoreInterface_1 XW_CoreInterface;
-
-//
-// XW_MESSAGING_INTERFACE: Exchange asynchronous messages with JavaScript
-// code provided by extension.
-//
-
-#define XW_MESSAGING_INTERFACE_1 "XW_MessagingInterface_1"
-#define XW_MESSAGING_INTERFACE XW_MESSAGING_INTERFACE_1
-
-typedef void (*XW_HandleMessageCallback)(XW_Instance instance,
-                                         const char* message);
-
-struct XW_MessagingInterface_1 {
-    // Register a callback to be called when the JavaScript code associated
-    // with the extension posts a message. Note that the callback will be called
-    // with the XW_Instance that posted the message as well as the message
-    // contents.
-    void (*Register)(XW_Extension extension,
-                     XW_HandleMessageCallback handle_message);
-
-    // Post a message to the web content associated with the instance. To
-    // receive this message the extension's JavaScript code should set a
-    // listener using extension.setMessageListener() function.
-    //
-    // This function is thread-safe and can be called until the instance is
-    // destroyed.
-    void (*PostMessage)(XW_Instance instance, const char* message);
-};
-
-typedef struct XW_MessagingInterface_1 XW_MessagingInterface;
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_Data.h b/lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_Data.h
deleted file mode 100644 (file)
index 896d9f0..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2017-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 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
- */
-
-#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_DATA_H_
-#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_DATA_H_
-
-#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_
-#error "You should include XW_Extension.h before this file"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//
-// XW_INTERNAL_DATA_INTERFACE: allow extensions to exchange binary chunk data
-// between extension and loader.
-//
-
-#define XW_INTERNAL_DATA_INTERFACE_1 "XW_InternalDataInterface_1"
-#define XW_INTERNAL_DATA_INTERFACE XW_INTERNAL_DATA_INTERFACE_1
-
-// Synchronous / Asynchronous data exchanging interface
-typedef void (*XW_HandleDataCallback)(XW_Instance instance, const char* message,
-                                      uint8_t* buffer, size_t len);
-
-struct XW_Internal_DataInterface_1 {
-    void (*RegisterSync)(XW_Extension extension,
-                         XW_HandleDataCallback handle_data);
-
-    void (*RegisterAsync)(XW_Extension extension,
-                          XW_HandleDataCallback handle_data);
-
-    void (*SetSyncReply)(XW_Instance instance, const char* reply,
-                         uint8_t* buffer, size_t len);
-
-    void (*PostData)(XW_Instance instance, const char* message, uint8_t* buffer,
-                     size_t len);
-};
-
-typedef struct XW_Internal_DataInterface_1 XW_Internal_DataInterface;
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_DATA_H_
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_EntryPoints.h b/lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_EntryPoints.h
deleted file mode 100644 (file)
index 65da47d..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2013 Intel Corporation. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_ENTRYPOINTS_H_
-#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_ENTRYPOINTS_H_
-
-// NOTE: This file and interfaces marked as internal are not considered stable
-// and can be modified in incompatible ways between Crosswalk versions.
-
-#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_
-#error "You should include XW_Extension.h before this file"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define XW_INTERNAL_ENTRY_POINTS_INTERFACE_1 \
-    "XW_Internal_EntryPointsInterface_1"
-#define XW_INTERNAL_ENTRY_POINTS_INTERFACE XW_INTERNAL_ENTRY_POINTS_INTERFACE_1
-
-//
-// XW_INTERNAL_ENTRY_POINTS_INTERFACE: provides a way for extensions to add
-// more information about its implementation. For now, allow extensions to
-// specify more objects that the access should cause the extension to be
-// loaded.
-//
-
-struct XW_Internal_EntryPointsInterface_1 {
-    // Register extra entry points for this extension. An "extra" entry points
-    // are objects outside the implicit namespace for which the extension should
-    // be loaded when they are touched.
-    //
-    // This function should be called only during XW_Initialize().
-    void (*SetExtraJSEntryPoints)(XW_Extension extension,
-                                  const char** entry_points);
-};
-
-typedef struct XW_Internal_EntryPointsInterface_1
-    XW_Internal_EntryPointsInterface;
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_ENTRYPOINTS_H_
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_Permissions.h b/lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_Permissions.h
deleted file mode 100644 (file)
index 15c94a7..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2014 Intel Corporation. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_PERMISSIONS_H_
-#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_PERMISSIONS_H_
-
-// NOTE: This file and interfaces marked as internal are not considered stable
-// and can be modified in incompatible ways between Crosswalk versions.
-
-#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_
-#error "You should include XW_Extension.h before this file"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define XW_INTERNAL_PERMISSIONS_INTERFACE_1 "XW_Internal_PermissionsInterface_1"
-#define XW_INTERNAL_PERMISSIONS_INTERFACE XW_INTERNAL_PERMISSIONS_INTERFACE_1
-
-//
-// XW_INTERNAL_PERMISSIONS_INTERFACE: provides a way for extensions
-// check if they have the proper permissions for certain APIs.
-//
-
-struct XW_Internal_PermissionsInterface_1 {
-    int (*CheckAPIAccessControl)(XW_Extension extension, const char* api_name);
-    int (*RegisterPermissions)(XW_Extension extension, const char* perm_table);
-};
-
-typedef struct XW_Internal_PermissionsInterface_1
-    XW_Internal_PermissionsInterface;
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_PERMISSIONS_H_
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_Runtime.h b/lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_Runtime.h
deleted file mode 100644 (file)
index ba55bf7..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2013 Intel Corporation. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_RUNTIME_H_
-#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_RUNTIME_H_
-
-// NOTE: This file and interfaces marked as internal are not considered stable
-// and can be modified in incompatible ways between Crosswalk versions.
-
-#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_
-#error "You should include XW_Extension.h before this file"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define XW_INTERNAL_RUNTIME_INTERFACE_1 "XW_Internal_RuntimeInterface_1"
-#define XW_INTERNAL_RUNTIME_INTERFACE XW_INTERNAL_RUNTIME_INTERFACE_1
-
-//
-// XW_INTERNAL_RUNTIME_INTERFACE: allow extensions to gather information
-// from the runtime.
-//
-
-struct XW_Internal_RuntimeInterface_1 {
-    void (*GetRuntimeVariableString)(XW_Extension extension, const char* key,
-                                     char* value, unsigned int value_len);
-};
-
-typedef struct XW_Internal_RuntimeInterface_1 XW_Internal_RuntimeInterface;
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_RUNTIME_H_
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_SyncMessage.h b/lwnode/code/escargotshim/deps/tizen-device-api/src/XW_Extension_SyncMessage.h
deleted file mode 100644 (file)
index b2eafec..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2013 Intel Corporation. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_SYNCMESSAGE_H_
-#define XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_SYNCMESSAGE_H_
-
-// NOTE: This file and interfaces marked as internal are not considered stable
-// and can be modified in incompatible ways between Crosswalk versions.
-
-#ifndef XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_H_
-#error "You should include XW_Extension.h before this file"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//
-// XW_INTERNAL_SYNC_MESSAGING_INTERFACE: allow JavaScript code to send a
-// synchronous message to extension code and block until response is
-// available. The response is made available by calling the SetSyncReply
-// function, that can be done from outside the context of the SyncMessage
-// handler.
-//
-
-#define XW_INTERNAL_SYNC_MESSAGING_INTERFACE_1 \
-    "XW_InternalSyncMessagingInterface_1"
-#define XW_INTERNAL_SYNC_MESSAGING_INTERFACE \
-    XW_INTERNAL_SYNC_MESSAGING_INTERFACE_1
-
-typedef void (*XW_HandleSyncMessageCallback)(XW_Instance instance,
-                                             const char* message);
-
-struct XW_Internal_SyncMessagingInterface_1 {
-    void (*Register)(XW_Extension extension,
-                     XW_HandleSyncMessageCallback handle_sync_message);
-    void (*SetSyncReply)(XW_Instance instance, const char* reply);
-};
-
-typedef struct XW_Internal_SyncMessagingInterface_1
-    XW_Internal_SyncMessagingInterface;
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // XWALK_EXTENSIONS_PUBLIC_XW_EXTENSION_SYNCMESSAGE_H_
diff --git a/lwnode/code/escargotshim/deps/tizen-device-api/src/wrt-common-native-plugin.h b/lwnode/code/escargotshim/deps/tizen-device-api/src/wrt-common-native-plugin.h
deleted file mode 100644 (file)
index 08823c2..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2017-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 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
- */
-
-#ifndef WRT_COMMON_NATIVE_PLUGIN_H_
-#define WRT_COMMON_NATIVE_PLUGIN_H_
-
-#include <string>
-
-namespace wrt {
-namespace common {
-
-    class NativePlugin {
-    public:
-        virtual void OnLoad() = 0;
-        virtual std::string OnCallSync(std::string& data) = 0;
-        virtual std::string OnCall(std::string& data, int callback_handle) = 0;
-    };
-
-    typedef NativePlugin* create_native_plugin_t();
-
-} // namespace common
-} // namespace wrt
-
-#define EXPORT_NATIVE_PLUGIN(pluginClass)                        \
-    extern "C" wrt::common::NativePlugin* create_native_plugin() \
-    {                                                            \
-        return (wrt::common::NativePlugin*)(new pluginClass());  \
-    }
-
-#endif // WRT_COMMON_NATIVE_PLUGIN_H_
index 191989f728dce6f796d1053e24934c20f58c6b2a..bfe0180bdc6970c1b001c4f4636aec298b4e3852 100755 (executable)
@@ -4,10 +4,11 @@
     'target_arch%': '<(target_arch)',
     'target_os%': '<(target_os)',
     'build_host%': '<(build_host)',
-    'build_asan%': '<(build_asan)',
+    'asan%': '<(asan)',
     'escargot_dir%': 'deps/escargot',
     "escargot_lib_type%": 'shared_lib', # static_lib | shared_lib
     'escargot_threading%': '<(escargot_threading)',
+    'escargot_debugger%': '<(escargot_debugger)',
     'conditions': [
       ['escargot_lib_type=="shared_lib"', {
         'lib_ext': '.so'
@@ -66,6 +67,7 @@
       'defines': [
         'ESCARGOT_ENABLE_TYPEDARRAY=1',
         'ESCARGOT_ENABLE_PROMISE=1',
+        'ESCARGOT_USE_CUSTOM_LOGGING=1',
       ],
       'include_dirs': [
         '<(escargot_dir)/src/api',
           'cmake', '<(escargot_dir)', '-B<(output_dir)',
           '-GNinja',
           '-DESCARGOT_SMALL_CONFIG=1',
+          '-DESCARGOT_USE_CUSTOM_LOGGING=ON',
           '-DESCARGOT_ARCH=<(target_arch)',
           '-DESCARGOT_MODE=<(build_mode)',
           '-DESCARGOT_HOST=<(build_host)',
           '-DESCARGOT_OUTPUT=<(escargot_lib_type)',
           '-DESCARGOT_THREADING=<(escargot_threading)',
-          '-DESCARGOT_ASAN=<(build_asan)',
+          '-DESCARGOT_ASAN=<(asan)',
+          '-DESCARGOT_DEBUGGER=<(escargot_debugger)'
         ],
       },
       {
index 4b02a0f5394bf0e3760e46c40dd2c162c763b9e7..2187721541a835907a8f7b5df7d5cbe2c5fd739c 100755 (executable)
@@ -3,9 +3,12 @@
   'variables': {
     'library%': 'static_library',
     'tizen_device_api_dir': 'deps/tizen-device-api',
+    'node_bindings_dir': 'deps/node-bindings',
     'enable_escargotshim_asan%': 0,
     'enable_reload_script%': 'false',
+    'escargot_debugger%': 'false',
     'enable_experimental%': 'false',
+    'include_node_bindings%': 'true',
   },
   'targets': [
     {
@@ -32,6 +35,8 @@
         'src/api-serialization.cc',
         'src/api-template.cc',
         'src/api-additionals.cc',
+        'src/api-experimental-serialization.cc',
+        'src/base.cc',
         'src/internal.cc',
         'src/init/v8.cc',
         'src/execution/v8threads.cc',
@@ -46,7 +51,8 @@
         'src/api/utils/smaps.cc',
         'src/api/utils/string-util.cc',
         'src/api/utils/logger/flags.cc',
-        'src/api/utils/logger/logger.cc',
+        'src/api/utils/logger/logger-impl.cc',
+        'src/api/utils/logger/logger-util.cc',
         'src/api/arraybuffer-allocator.cc',
         'src/api/arraybuffer-deleter.cc',
         'src/api/es-helper.cc',
         'src/api/isolate.cc',
         'src/api/context.cc',
         'src/api/global-handles.cc',
+        'src/api/global.cc',
         'src/api/function.cc',
         'src/api/object.cc',
         'src/api/stack-trace.cc',
+        'src/api/serializer.cc',
+        'src/api/error-message.cc',
         'src/lwnode/lwnode.cc',
         'src/lwnode/lwnode-loader.cc',
         'src/lwnode/lwnode-gc-strategy.cc',
       ],
-      'defines': ['V8_PROMISE_INTERNAL_FIELD_COUNT=1'],
+      'defines': ['V8_PROMISE_INTERNAL_FIELD_COUNT=1',
+        'LWNODE_ENABLE_EXPERIMENTAL_SERIALIZATION=1',
+      ],
       'cflags_cc!': ['-fno-exceptions'],
       'cflags_cc': [
         '-std=gnu++14',
         ['enable_reload_script == "true"', {
           'defines': ['LWNODE_USE_RELOAD_SCRIPT'],
         }],
+        ['escargot_debugger == 1', {
+          'defines': ['LWNODE_ENABLE_DEBUGGER']
+        }],
         ['enable_experimental == "true"', {
           'defines': [
             'LWNODE_ENABLE_EXPERIMENTAL=1',
+            'LWNODE_ENABLE_EXPERIMENTAL_SERIALIZATION=1',
+            'LWNODE_ENABLE_EXPERIMENTAL_PROMISE=1',
+            'LWNODE_ENABLE_EXPERIMENTAL_STACKTRACE=1',
+          ],
+        }],
+        ['include_node_bindings == "true"', {
+          'dependencies': [
+            '<(node_bindings_dir)/node_bindings.gyp:node_bindings',
           ],
         }],
       ],
index e9ac85fc0e13c92bec825ed4a6ef049905991732..786bb7b217e87d3cc010ac3f3d1254bd604a41d2 100644 (file)
 #include <functional>
 #include <memory>
 
+namespace Escargot {
+class ContextRef;
+class ValueRef;
+}  // namespace Escargot
+
 namespace LWNode {
 
 void InitializeProcessMethods(v8::Local<v8::Object> target,
                               v8::Local<v8::Context> context);
 
-void IdleGC(v8::Isolate* isolate);
+void IdleGC(v8::Isolate* isolate = nullptr);
+void initDebugger();
 bool dumpSelfMemorySnapshot();
 
 class MessageLoop {
@@ -53,4 +59,12 @@ class MessageLoop {
   std::unique_ptr<Internal> internal_;
 };
 
+class Utils {
+ public:
+  static Escargot::ContextRef* ToEsContext(v8::Context* context);
+
+  static v8::Local<v8::Value> NewLocal(v8::Isolate* isolate,
+                                       Escargot::ValueRef* ptr);
+};
+
 }  // namespace LWNode
index 880679ab65a18b280dc19db2e41ef66da039a4ac..91620eaac6b7dbd2e779ada96b6a80428b6634c0 100644 (file)
@@ -15,6 +15,8 @@
  */
 
 #include "api.h"
+
+#include "api/global.h"
 #include "api/utils.h"
 #include "base.h"
 
@@ -62,8 +64,8 @@ bool Value::IsFunction() const {
 }
 
 bool Value::IsName() const {
-  auto esValue = CVAL(this)->value();
-  return esValue->isString() || esValue->isSymbol();
+  auto esSelf = CVAL(this)->value();
+  return esSelf->isString() || esSelf->isSymbol();
 }
 
 bool Value::FullIsString() const {
@@ -161,11 +163,11 @@ bool Value::IsBoolean() const {
 }
 
 bool Value::IsExternal() const {
-  auto esValue = CVAL(this)->value();
-  if (!esValue->isObject()) {
+  auto esSelf = CVAL(this)->value();
+  if (!esSelf->isObject()) {
     return false;
   }
-  auto data = ObjectRefHelper::getExtraData(esValue->asObject());
+  auto data = ObjectRefHelper::getExtraData(esSelf->asObject());
   return data && data->isExternalObjectData();
 }
 
@@ -175,13 +177,13 @@ bool Value::IsInt32() const {
   if (esSelf->isInt32()) {
     return true;
   } else if (esSelf->isNumber()) {
-    double val = esSelf->asNumber();
-    bool rangeOk = false;
-    if (std::numeric_limits<int32_t>::min() <= val &&
-        val <= std::numeric_limits<int32_t>::max()) {
-      rangeOk = true;
+    double value = esSelf->asNumber();
+    bool isInRange = false;
+    if (std::numeric_limits<int32_t>::min() <= value &&
+        value <= std::numeric_limits<int32_t>::max()) {
+      isInRange = true;
     }
-    return isInteger(esSelf) && rangeOk;
+    return isInteger(esSelf) && isInRange;
   }
 
   return false;
@@ -193,12 +195,12 @@ bool Value::IsUint32() const {
   if (esSelf->isUInt32()) {
     return true;
   } else if (esSelf->isNumber()) {
-    double val = esSelf->asNumber();
-    bool rangeOk = false;
-    if (0 <= val && val <= std::numeric_limits<uint32_t>::max()) {
-      rangeOk = true;
+    double value = esSelf->asNumber();
+    bool isInRange = false;
+    if (0 <= value && value <= std::numeric_limits<uint32_t>::max()) {
+      isInRange = true;
     }
-    return isInteger(esSelf) && rangeOk;
+    return isInteger(esSelf) && isInRange;
   }
 
   return false;
@@ -213,16 +215,16 @@ bool Value::IsRegExp() const {
 }
 
 bool Value::IsAsyncFunction() const {
-  auto esValue = CVAL(this)->value();
+  auto esSelf = CVAL(this)->value();
 
-  if (esValue->isFunctionObject() == false) {
+  if (esSelf->isFunctionObject() == false) {
     return false;
   }
 
   auto esPureContext =
       ContextRef::create(IsolateWrap::GetCurrent()->vmInstance());
   auto esString =
-      ObjectRefHelper::getConstructorName(esPureContext, esValue->asObject());
+      ObjectRefHelper::getConstructorName(esPureContext, esSelf->asObject());
 
   return StringRefHelper::equalsWithASCIIString(esString, "AsyncFunction");
 }
@@ -256,17 +258,17 @@ MaybeLocal<String> Value::ToString(Local<Context> context) const {
 
   auto esContext = VAL(*context)->context()->get();
 
-  auto esValue = CVAL(this)->value();
-  if (esValue->isString()) {
-    return Utils::NewLocal<String>(lwIsolate->toV8(), esValue);
+  auto esSelf = CVAL(this)->value();
+  if (esSelf->isString()) {
+    return Utils::NewLocal<String>(lwIsolate->toV8(), esSelf);
   }
 
   EvalResult r = Evaluator::execute(
       esContext,
-      [](ExecutionStateRef* state, ValueRef* esValue) -> ValueRef* {
-        return esValue->toString(state);
+      [](ExecutionStateRef* state, ValueRef* esSelf) -> ValueRef* {
+        return esSelf->toString(state);
       },
-      esValue);
+      esSelf);
 
   API_HANDLE_EXCEPTION(r, lwIsolate, MaybeLocal<String>());
 
@@ -274,20 +276,22 @@ MaybeLocal<String> Value::ToString(Local<Context> context) const {
 }
 
 MaybeLocal<String> Value::ToDetailString(Local<Context> context) const {
-  LWNODE_RETURN_LOCAL(String);
+  EsScope scope(context, this);
+
+  auto esString = scope.self()->toStringWithoutException(scope.context());
+  return Utils::NewLocal<String>(scope.v8Isolate(), esString);
 }
 
 MaybeLocal<Object> Value::ToObject(Local<Context> context) const {
   API_ENTER_WITH_CONTEXT(context, MaybeLocal<Object>());
   auto esContext = VAL(*context)->context()->get();
-  auto esValue = CVAL(this)->value();
 
   EvalResult r = Evaluator::execute(
       esContext,
-      [](ExecutionStateRef* state, ValueRef* esValue) -> ValueRef* {
-        return esValue->toObject(state);
+      [](ExecutionStateRef* state, ValueRef* esSelf) -> ValueRef* {
+        return esSelf->toObject(state);
       },
-      esValue);
+      CVAL(this)->value());
   API_HANDLE_EXCEPTION(r, lwIsolate, MaybeLocal<Object>());
 
   return Utils::NewLocal<Object>(lwIsolate->toV8(), r.result);
@@ -298,21 +302,19 @@ MaybeLocal<BigInt> Value::ToBigInt(Local<Context> context) const {
 }
 
 bool Value::BooleanValue(Isolate* v8_isolate) const {
-  Local<Boolean> val = ToBoolean(v8_isolate);
-  return val->Value();
+  return ToBoolean(v8_isolate)->Value();
 }
 
 Local<Boolean> Value::ToBoolean(Isolate* v8_isolate) const {
   API_ENTER(v8_isolate, Local<Boolean>());
   auto esContext = lwIsolate->GetCurrentContext()->get();
 
-  auto esValue = CVAL(this)->value();
   EvalResult r = Evaluator::execute(
       esContext,
-      [](ExecutionStateRef* esState, ValueRef* esValue) -> ValueRef* {
-        return ValueRef::create(esValue->toBoolean(esState));
+      [](ExecutionStateRef* esState, ValueRef* esSelf) -> ValueRef* {
+        return ValueRef::create(esSelf->toBoolean(esState));
       },
-      esValue);
+      CVAL(this)->value());
 
   API_HANDLE_EXCEPTION(r, lwIsolate, Local<Boolean>());
 
@@ -323,13 +325,12 @@ MaybeLocal<Number> Value::ToNumber(Local<Context> context) const {
   API_ENTER_WITH_CONTEXT(context, MaybeLocal<Number>());
   auto esContext = lwIsolate->GetCurrentContext()->get();
 
-  auto esValue = CVAL(this)->value();
   EvalResult r = Evaluator::execute(
       esContext,
-      [](ExecutionStateRef* esState, ValueRef* esValue) -> ValueRef* {
-        return ValueRef::create(esValue->toNumber(esState));
+      [](ExecutionStateRef* esState, ValueRef* esSelf) -> ValueRef* {
+        return ValueRef::create(esSelf->toNumber(esState));
       },
-      esValue);
+      CVAL(this)->value());
 
   API_HANDLE_EXCEPTION(r, lwIsolate, Local<Number>());
 
@@ -340,13 +341,12 @@ MaybeLocal<Integer> Value::ToInteger(Local<Context> context) const {
   API_ENTER_WITH_CONTEXT(context, MaybeLocal<Integer>());
   auto esContext = lwIsolate->GetCurrentContext()->get();
 
-  auto esValue = CVAL(this)->value();
   EvalResult r = Evaluator::execute(
       esContext,
-      [](ExecutionStateRef* esState, ValueRef* esValue) -> ValueRef* {
-        return ValueRef::create(esValue->toInteger(esState));
+      [](ExecutionStateRef* esState, ValueRef* esSelf) -> ValueRef* {
+        return ValueRef::create(esSelf->toInteger(esState));
       },
-      esValue);
+      CVAL(this)->value());
 
   API_HANDLE_EXCEPTION(r, lwIsolate, Local<Integer>());
 
@@ -357,13 +357,12 @@ MaybeLocal<Int32> Value::ToInt32(Local<Context> context) const {
   API_ENTER_WITH_CONTEXT(context, MaybeLocal<Int32>());
   auto esContext = lwIsolate->GetCurrentContext()->get();
 
-  auto esValue = CVAL(this)->value();
   EvalResult r = Evaluator::execute(
       esContext,
-      [](ExecutionStateRef* esState, ValueRef* esValue) -> ValueRef* {
-        return ValueRef::create(esValue->toInt32(esState));
+      [](ExecutionStateRef* esState, ValueRef* esSelf) -> ValueRef* {
+        return ValueRef::create(esSelf->toInt32(esState));
       },
-      esValue);
+      CVAL(this)->value());
 
   API_HANDLE_EXCEPTION(r, lwIsolate, Local<Int32>());
 
@@ -374,13 +373,12 @@ MaybeLocal<Uint32> Value::ToUint32(Local<Context> context) const {
   API_ENTER_WITH_CONTEXT(context, MaybeLocal<Uint32>());
   auto esContext = lwIsolate->GetCurrentContext()->get();
 
-  auto esValue = CVAL(this)->value();
   EvalResult r = Evaluator::execute(
       esContext,
-      [](ExecutionStateRef* esState, ValueRef* esValue) -> ValueRef* {
-        return ValueRef::create(esValue->toUint32(esState));
+      [](ExecutionStateRef* esState, ValueRef* esSelf) -> ValueRef* {
+        return ValueRef::create(esSelf->toUint32(esState));
       },
-      esValue);
+      CVAL(this)->value());
 
   API_HANDLE_EXCEPTION(r, lwIsolate, Local<Uint32>());
 
@@ -389,7 +387,6 @@ MaybeLocal<Uint32> Value::ToUint32(Local<Context> context) const {
 
 i::Isolate* i::IsolateFromNeverReadOnlySpaceObject(i::Address obj) {
   LWNODE_RETURN_NULLPTR;
-  ;
 }
 
 bool i::ShouldThrowOnError(i::Isolate* isolate) {
@@ -576,7 +573,9 @@ void v8::TypedArray::CheckCast(Value* that) {
 }
 
 #define CHECK_TYPED_ARRAY_CAST(Type, typeName, TYPE, ctype)                    \
-  void v8::Type##Array::CheckCast(Value* that) { LWNODE_UNIMPLEMENT; }
+  void v8::Type##Array::CheckCast(Value* that) {                               \
+    LWNODE_CHECK(that->Is##Type##Array());                                     \
+  }
 
 TYPED_ARRAYS(CHECK_TYPED_ARRAY_CAST)
 
@@ -619,9 +618,9 @@ void v8::RegExp::CheckCast(v8::Value* that) {
 }
 
 Maybe<double> Value::NumberValue(Local<Context> context) const {
-  auto lwValue = CVAL(this)->value();
-  if (lwValue->isNumber()) {
-    return Just(lwValue->asNumber());
+  auto esSelf = CVAL(this)->value();
+  if (esSelf->isNumber()) {
+    return Just(esSelf->asNumber());
   }
 
   API_ENTER_WITH_CONTEXT(context, Nothing<double>());
@@ -631,7 +630,7 @@ Maybe<double> Value::NumberValue(Local<Context> context) const {
       [](ExecutionStateRef* esState, ValueRef* self) {
         return ValueRef::create(self->toNumber(esState));
       },
-      lwValue);
+      esSelf);
   API_HANDLE_EXCEPTION(r, lwIsolate, Nothing<double>());
 
   return Just(r.result->asNumber());
@@ -685,18 +684,18 @@ Maybe<uint32_t> Value::Uint32Value(Local<Context> context) const {
   API_ENTER_WITH_CONTEXT(context, Nothing<uint32_t>());
   auto lwContext = lwIsolate->GetCurrentContext();
 
-  uint32_t val = 0;
+  uint32_t value = 0;
   auto r = Evaluator::execute(
       lwContext->get(),
-      [](ExecutionStateRef* esState, ValueRef* self, uint32_t* val) {
-        *val = self->toUint32(esState);
-        return ValueRef::create(*val);
+      [](ExecutionStateRef* esState, ValueRef* self, uint32_t* value) {
+        *value = self->toUint32(esState);
+        return ValueRef::create(*value);
       },
       CVAL(this)->value(),
-      &val);
+      &value);
   API_HANDLE_EXCEPTION(r, lwIsolate, Nothing<uint32_t>());
 
-  return Just(val);
+  return Just(value);
 }
 
 MaybeLocal<Uint32> Value::ToArrayIndex(Local<Context> context) const {
@@ -741,7 +740,6 @@ Maybe<bool> Value::Equals(Local<Context> context, Local<Value> that) const {
 }
 
 bool Value::StrictEquals(Local<Value> that) const {
-  auto esValue = CVAL(this)->value();
   auto lwIsolate = IsolateWrap::GetCurrent();
   auto lwContext = lwIsolate->GetCurrentContext();
 
@@ -750,8 +748,7 @@ bool Value::StrictEquals(Local<Value> that) const {
       [](ExecutionStateRef* esState,
          ValueRef* self,
          ValueRef* that) -> ValueRef* {
-        bool r = self->equalsTo(esState, that);
-        return ValueRef::create(r);
+        return ValueRef::create(self->equalsTo(esState, that));
       },
       CVAL(this)->value(),
       CVAL(*that)->value());
@@ -786,7 +783,6 @@ bool Value::SameValue(Local<Value> that) const {
 
 Local<String> Value::TypeOf(v8::Isolate* external_isolate) {
   API_ENTER_NO_EXCEPTION(external_isolate);
-  auto esSelf = CVAL(this)->value();
   auto lwContext = lwIsolate->GetCurrentContext();
 
   auto r = Evaluator::execute(
@@ -813,7 +809,8 @@ Local<String> Value::TypeOf(v8::Isolate* external_isolate) {
         return ValueRef::create(
             StringRef::createFromASCII(type.data(), type.length()));
       },
-      esSelf);
+      CVAL(this)->value());
+
   LWNODE_CHECK(r.isSuccessful());
 
   return Utils::NewLocal<String>(lwIsolate->toV8(), r.result);
@@ -822,9 +819,7 @@ Local<String> Value::TypeOf(v8::Isolate* external_isolate) {
 Maybe<bool> Value::InstanceOf(v8::Local<v8::Context> context,
                               v8::Local<v8::Object> object) {
   API_ENTER_WITH_CONTEXT(context, Nothing<bool>());
-  auto esSelf = CVAL(this)->value();
   auto lwContext = lwIsolate->GetCurrentContext();
-  auto esObject = CVAL(*object)->value()->asObject();
 
   auto r = Evaluator::execute(
       lwContext->get(),
@@ -833,8 +828,9 @@ Maybe<bool> Value::InstanceOf(v8::Local<v8::Context> context,
          ObjectRef* object) -> ValueRef* {
         return ValueRef::create(self->instanceOf(esState, object));
       },
-      esSelf,
-      esObject);
+      CVAL(this)->value(),
+      CVAL(*object)->value()->asObject());
+
   API_HANDLE_EXCEPTION(r, lwIsolate, Nothing<bool>());
 
   return Just(r.result->asBoolean());
@@ -891,7 +887,7 @@ PropertyDescriptor::PrivateData::PrivateData(Escargot::ValueRef* get,
 }
 
 PropertyDescriptor::PrivateData::~PrivateData() {
-  if (!isExternalDescriptor) {
+  if (!isExternalDescriptor_) {
     delete descriptor_;
     descriptor_ = nullptr;
   }
@@ -901,7 +897,7 @@ void PropertyDescriptor::PrivateData::setDescriptor(
     Escargot::ObjectPropertyDescriptorRef* descriptor) {
   LWNODE_CHECK_NULL(descriptor_);
   descriptor_ = descriptor;
-  isExternalDescriptor = true;
+  isExternalDescriptor_ = true;
 }
 
 v8::PropertyDescriptor::PropertyDescriptor() : private_(new PrivateData()) {}
@@ -1073,43 +1069,44 @@ Maybe<bool> v8::Object::DefineProperty(v8::Local<v8::Context> context,
   auto esObject = CVAL(this)->value()->asObject();
   auto esKey = CVAL(*key)->value();
 
-  ObjectRef::PresentAttribute attr = ObjectRef::PresentAttribute::NotPresent;
+  ObjectRef::PresentAttribute attribute =
+      ObjectRef::PresentAttribute::NotPresent;
 
   if (descriptor.has_writable()) {
     if (descriptor.writable()) {
-      attr = static_cast<ObjectRef::PresentAttribute>(
-          attr | ObjectRef::PresentAttribute::WritablePresent);
+      attribute = static_cast<ObjectRef::PresentAttribute>(
+          attribute | ObjectRef::PresentAttribute::WritablePresent);
     } else {
-      attr = static_cast<ObjectRef::PresentAttribute>(
-          attr | ObjectRef::PresentAttribute::NonWritablePresent);
+      attribute = static_cast<ObjectRef::PresentAttribute>(
+          attribute | ObjectRef::PresentAttribute::NonWritablePresent);
     }
   }
 
   if (descriptor.has_enumerable()) {
     if (descriptor.enumerable()) {
-      attr = static_cast<ObjectRef::PresentAttribute>(
-          attr | ObjectRef::PresentAttribute::EnumerablePresent);
+      attribute = static_cast<ObjectRef::PresentAttribute>(
+          attribute | ObjectRef::PresentAttribute::EnumerablePresent);
     } else {
-      attr = static_cast<ObjectRef::PresentAttribute>(
-          attr | ObjectRef::PresentAttribute::NonEnumerablePresent);
+      attribute = static_cast<ObjectRef::PresentAttribute>(
+          attribute | ObjectRef::PresentAttribute::NonEnumerablePresent);
     }
   }
 
   if (descriptor.has_configurable()) {
     if (descriptor.enumerable()) {
-      attr = static_cast<ObjectRef::PresentAttribute>(
-          attr | ObjectRef::PresentAttribute::ConfigurablePresent);
+      attribute = static_cast<ObjectRef::PresentAttribute>(
+          attribute | ObjectRef::PresentAttribute::ConfigurablePresent);
     } else {
-      attr = static_cast<ObjectRef::PresentAttribute>(
-          attr | ObjectRef::PresentAttribute::NonConfigurablePresent);
+      attribute = static_cast<ObjectRef::PresentAttribute>(
+          attribute | ObjectRef::PresentAttribute::NonConfigurablePresent);
     }
   }
 
   if (descriptor.has_value()) {
-    ObjectRef::DataPropertyDescriptor desc(CVAL(*descriptor.value())->value(),
-                                           attr);
-    auto r =
-        ObjectRefHelper::defineDataProperty(esContext, esObject, esKey, desc);
+    ObjectRef::DataPropertyDescriptor dataDescriptor(
+        CVAL(*descriptor.value())->value(), attribute);
+    auto r = ObjectRefHelper::defineDataProperty(
+        esContext, esObject, esKey, dataDescriptor);
     API_HANDLE_EXCEPTION(r, lwIsolate, Nothing<bool>());
     return Just(r.result->asBoolean());
   } else if (descriptor.has_get()) {
@@ -1117,21 +1114,20 @@ Maybe<bool> v8::Object::DefineProperty(v8::Local<v8::Context> context,
     if (descriptor.has_set()) {
       setter = CVAL(*descriptor.set())->value();
     }
-    ObjectRef::AccessorPropertyDescriptor desc(
-        CVAL(*descriptor.get())->value(), setter, attr);
+    ObjectRef::AccessorPropertyDescriptor accessorDescriptor(
+        CVAL(*descriptor.get())->value(), setter, attribute);
     auto r = ObjectRefHelper::defineAccessorProperty(
-        esContext, esObject, esKey, desc);
+        esContext, esObject, esKey, accessorDescriptor);
     API_HANDLE_EXCEPTION(r, lwIsolate, Nothing<bool>());
     return Just(r.result->asBoolean());
   } else {
-    ObjectRef::DataPropertyDescriptor desc(ValueRef::createUndefined(), attr);
-    auto r =
-        ObjectRefHelper::defineDataProperty(esContext, esObject, esKey, desc);
+    ObjectRef::DataPropertyDescriptor dataDescriptor(
+        ValueRef::createUndefined(), attribute);
+    auto r = ObjectRefHelper::defineDataProperty(
+        esContext, esObject, esKey, dataDescriptor);
     API_HANDLE_EXCEPTION(r, lwIsolate, Nothing<bool>());
     return Just(r.result->asBoolean());
   }
-
-  return Just(false);
 }
 
 Maybe<bool> v8::Object::SetPrivate(Local<Context> context,
@@ -1198,8 +1194,9 @@ Maybe<PropertyAttribute> v8::Object::GetPropertyAttributes(
     return Just(PropertyAttribute::None);
   }
 
-  PropertyAttribute attr = static_cast<PropertyAttribute>(r.result->asUInt32());
-  return Just(attr);
+  PropertyAttribute attribute =
+      static_cast<PropertyAttribute>(r.result->asUInt32());
+  return Just(attribute);
 }
 
 MaybeLocal<Value> v8::Object::GetOwnPropertyDescriptor(Local<Context> context,
@@ -1636,8 +1633,9 @@ Maybe<PropertyAttribute> v8::Object::GetRealNamedPropertyAttributes(
     return Just(PropertyAttribute::None);
   }
 
-  auto attr = static_cast<ObjectRef::PresentAttribute>(r.result->asUInt32());
-  return Just(V8Helper::toPropertyAttribute(attr));
+  auto attribute =
+      static_cast<ObjectRef::PresentAttribute>(r.result->asUInt32());
+  return Just(V8Helper::toPropertyAttribute(attribute));
 }
 
 Local<v8::Object> v8::Object::Clone() {
@@ -1859,22 +1857,28 @@ MaybeLocal<v8::Value> Function::Call(Local<Context> context,
     arguments.push_back(VAL(*argv[i])->value());
   }
 
+  lwIsolate->increaseCallDepth();
   auto r = Evaluator::execute(
       esContext,
       [](ExecutionStateRef* state,
+         IsolateWrap* lwIsolate,
          ValueRef* self,
          ValueRef* receiver,
          const size_t argc,
          ValueRef** argv) -> ValueRef* {
-        return self->call(state, receiver, argc, argv);
+        auto r = self->call(state, receiver, argc, argv);
+        lwIsolate->ThrowErrorIfHasException(state);
+        return r;
       },
+      lwIsolate,
       CVAL(this)->value(),
       CVAL(*recv)->value(),
       arguments.size(),
       arguments.data());
+  lwIsolate->decreaseCallDepth();
 
   if (!r.isSuccessful()) {
-    LWNODE_DLOG_ERROR("Evaluate");
+    LWNODE_DLOG_ERROR("Function::Call()");
     LWNODE_DLOG_RAW("Internal:\n  this: %p (es: %p)\n  recv: %p (es: %p)",
                     this,
                     CVAL(this)->value(),
@@ -1891,14 +1895,32 @@ MaybeLocal<v8::Value> Function::Call(Local<Context> context,
                       toStdStringWithoutException(esContext, esValue).c_str());
     }
 
-    LWNODE_DLOG_RAW("Execute:\n  %s (%s:%d)\nResource:\n  %s\n%s",
-                    TRACE_ARGS2,
+    LWNODE_DLOG_RAW("Execute:\n  %s\nResource:\n  %s\n%s",
+                    __CODE_LOCATION__,
                     "N/A",
                     EvalResultHelper::getErrorString(
                         lwIsolate->GetCurrentContext()->get(), r)
                         .c_str());
 
-    lwIsolate->SetPendingExceptionAndMessage(r.error.get(), r.stackTraceData);
+    if (EscargotShim::Global::flags()->isOn(
+            Flag::Type::AbortOnUncaughtException)) {
+      if (!lwIsolate->abortOnUncaughtExceptionCallback() ||
+          lwIsolate->abortOnUncaughtExceptionCallback()(lwIsolate->toV8())) {
+        LWNODE_DLOG_INFO("Abort because of uncaught exception callback!");
+        abort();
+      }
+    }
+
+    if (lwIsolate->hasCallDepth()) {
+      lwIsolate->ScheduleThrow(r.error.get());
+    } else {
+      lwIsolate->SetPendingExceptionAndMessage(r.error.get(), r.stackTrace);
+      lwIsolate->ReportPendingMessages();
+    }
+    return MaybeLocal<Value>();
+  }
+
+  if (lwIsolate->sholdReportPendingMessage(false)) {
     lwIsolate->ReportPendingMessages();
     return MaybeLocal<Value>();
   }
@@ -1907,11 +1929,34 @@ MaybeLocal<v8::Value> Function::Call(Local<Context> context,
 }
 
 void Function::SetName(v8::Local<v8::String> name) {
-  LWNODE_ONCE(LWNODE_UNIMPLEMENT);
+  auto r = Evaluator::execute(
+      IsolateWrap::GetCurrent()->GetCurrentContext()->get(),
+      [](ExecutionStateRef* esState,
+         FunctionObjectRef* esFunction,
+         StringRef* esName) -> ValueRef* {
+        esFunction->setName(
+            AtomicStringRef::create(esState->context(), esName));
+        return ValueRef::createNull();
+      },
+      CVAL(this)->value()->asFunctionObject(),
+      CVAL(*name)->value()->asString());
+  LWNODE_CHECK(r.isSuccessful());
 }
 
 Local<Value> Function::GetName() const {
-  LWNODE_RETURN_LOCAL(Value);
+  auto lwIsolate = IsolateWrap::GetCurrent();
+
+  auto r = Evaluator::execute(
+      lwIsolate->GetCurrentContext()->get(),
+      [](ExecutionStateRef* esState,
+         FunctionObjectRef* esFunction) -> ValueRef* {
+        return esFunction->getOwnProperty(esState,
+                                          StringRef::createFromASCII("name"));
+      },
+      CVAL(this)->value()->asFunctionObject());
+  LWNODE_CHECK(r.isSuccessful());
+
+  return Utils::NewLocal<String>(lwIsolate->toV8(), r.result);
 }
 
 Local<Value> Function::GetInferredName() const {
@@ -2249,23 +2294,23 @@ template <typename T, typename F>
 static T getValue(ValueRef* esValue, F toValue) {
   auto lwContext = IsolateWrap::GetCurrent()->GetCurrentContext();
   LWNODE_CHECK(lwContext != nullptr);
-  T v = 0;
+  T outValue = 0;
   auto r = Evaluator::execute(
       lwContext->get(),
-      [](ExecutionStateRef* esState, ValueRef* esValue, T* v, F toValue)
+      [](ExecutionStateRef* esState, ValueRef* esValue, T* outValue, F toValue)
           -> ValueRef* {
-        *v = toValue(esValue, esState);
+        *outValue = toValue(esValue, esState);
         return esValue;
       },
       esValue,
-      &v,
+      &outValue,
       toValue);
 
   if (!r.isSuccessful()) {
     LWNODE_RETURN_0;  // TODO: handle error
   }
 
-  return v;
+  return outValue;
 }
 
 double Number::Value() const {
@@ -2367,13 +2412,4 @@ void v8::Object::SetAlignedPointerInInternalFields(int argc,
   LWNODE_RETURN_VOID;
 }
 
-// static void* ExternalValue(i::Object obj) {
-//   // Obscure semantics for undefined, but somehow checked in our unit
-//   tests... if (obj.IsUndefined()) {
-//     return nullptr;
-//   }
-//   i::Object foreign = i::JSObject::cast(obj).GetEmbedderField(0);
-//   return
-//   reinterpret_cast<void*>(i::Foreign::cast(foreign).foreign_address());
-// }
 }  // namespace v8
index 7b463676ccccdcc3fefc8370eba5002694ab25d7..e3931c00029daa1318380e6208008802b6767e55 100644 (file)
@@ -39,6 +39,9 @@ void v8::V8::ShutdownPlatform() {
 
 bool v8::V8::Initialize(const int build_config) {
   Engine::Initialize();
+
+  RegisterExtension(std::make_unique<ExternalizeStringExtension>());
+  RegisterExtension(std::make_unique<ExternalizeGcExtension>());
   return true;
 }
 
@@ -175,7 +178,8 @@ Local<Context> v8::Context::New(
     esNewGlobalObjectTemplate = esGlobalTemplate;
   }
 
-  auto lwContext = ContextWrap::New(IsolateWrap::fromV8(external_isolate));
+  auto lwContext =
+      ContextWrap::New(IsolateWrap::fromV8(external_isolate), extensions);
 
   if (esNewGlobalObjectTemplate) {
     auto esContext = lwContext->get();
@@ -253,7 +257,9 @@ Local<v8::Object> Context::GetExtrasBindingObject() {
                                  lwContext->GetExtrasBindingObject());
 }
 
-void Context::AllowCodeGenerationFromStrings(bool allow) {}
+void Context::AllowCodeGenerationFromStrings(bool allow) {
+  LWNODE_RETURN_VOID;
+}
 
 bool Context::IsCodeGenerationFromStringsAllowed() {
   LWNODE_RETURN_FALSE;
@@ -444,30 +450,30 @@ Local<String> v8::String::Concat(Isolate* v8_isolate,
   auto rightStrBufferData = esRightStr->stringBufferAccessData();
 
   size_t nchars = leftStrBufferData.length + rightStrBufferData.length;
-  size_t charSize = sizeof(char16_t);
-  Local<String> r;
+
+  Local<String> result;
 
   if (leftStrBufferData.has8BitContent && rightStrBufferData.has8BitContent) {
-    unsigned char* buf = new unsigned char[nchars];
-    memcpy(buf, leftStrBufferData.buffer, leftStrBufferData.length);
-    memcpy(buf + leftStrBufferData.length,
+    unsigned char* buffer = new unsigned char[nchars];
+    memcpy(buffer, leftStrBufferData.buffer, leftStrBufferData.length);
+    memcpy(buffer + leftStrBufferData.length,
            rightStrBufferData.buffer,
            rightStrBufferData.length);
 
-    r = Utils::NewLocal<String>(v8_isolate,
-                                StringRef::createFromLatin1(buf, nchars));
-    delete[] buf;
+    result = Utils::NewLocal<String>(
+        v8_isolate, StringRef::createFromLatin1(buffer, nchars));
+    delete[] buffer;
   } else {
-    char16_t* buf = new char16_t[nchars];
-    copyStringToTwoByteArray(buf, esLeftStr);
-    copyStringToTwoByteArray(buf + leftStrBufferData.length, esRightStr);
+    char16_t* buffer = new char16_t[nchars];
+    copyStringToTwoByteArray(buffer, esLeftStr);
+    copyStringToTwoByteArray(buffer + leftStrBufferData.length, esRightStr);
 
-    r = Utils::NewLocal<String>(v8_isolate,
-                                StringRef::createFromUTF16(buf, nchars));
-    delete[] buf;
+    result = Utils::NewLocal<String>(
+        v8_isolate, StringRef::createFromUTF16(buffer, nchars));
+    delete[] buffer;
   }
 
-  return r;
+  return result;
 }
 
 MaybeLocal<String> v8::String::NewExternalTwoByte(
@@ -563,9 +569,9 @@ Local<v8::Value> v8::NumberObject::New(Isolate* isolate, double value) {
   EvalResult r = Evaluator::execute(
       esContext,
       [](ExecutionStateRef* esState, double value) -> ValueRef* {
-        auto obj = NumberObjectRef::create(esState);
-        obj->setPrimitiveValue(esState, ValueRef::create(value));
-        return obj;
+        auto object = NumberObjectRef::create(esState);
+        object->setPrimitiveValue(esState, ValueRef::create(value));
+        return object;
       },
       value);
   LWNODE_CHECK(r.isSuccessful());
@@ -594,9 +600,9 @@ Local<v8::Value> v8::BooleanObject::New(Isolate* isolate, bool value) {
   EvalResult r = Evaluator::execute(
       esContext,
       [](ExecutionStateRef* esState, bool value) -> ValueRef* {
-        auto b = BooleanObjectRef::create(esState);
-        b->setPrimitiveValue(esState, ValueRef::create(value));
-        return b;
+        auto object = BooleanObjectRef::create(esState);
+        object->setPrimitiveValue(esState, ValueRef::create(value));
+        return object;
       },
       value);
   LWNODE_CHECK(r.isSuccessful());
@@ -619,9 +625,9 @@ Local<v8::Value> v8::StringObject::New(Isolate* v8_isolate,
   EvalResult r = Evaluator::execute(
       esContext,
       [](ExecutionStateRef* esState, StringRef* esValue) -> ValueRef* {
-        auto obj = StringObjectRef::create(esState);
-        obj->setPrimitiveValue(esState, esValue);
-        return obj;
+        auto object = StringObjectRef::create(esState);
+        object->setPrimitiveValue(esState, esValue);
+        return object;
       },
       esValue);
   LWNODE_CHECK(r.isSuccessful());
@@ -645,9 +651,9 @@ Local<v8::Value> v8::SymbolObject::New(Isolate* isolate, Local<Symbol> value) {
   EvalResult r = Evaluator::execute(
       esContext,
       [](ExecutionStateRef* esState, SymbolRef* esValue) -> ValueRef* {
-        auto obj = SymbolObjectRef::create(esState);
-        obj->setPrimitiveValue(esState, esValue);
-        return obj;
+        auto object = SymbolObjectRef::create(esState);
+        object->setPrimitiveValue(esState, esValue);
+        return object;
       },
       esValue);
   LWNODE_CHECK(r.isSuccessful());
@@ -750,15 +756,15 @@ MaybeLocal<v8::Object> v8::RegExp::Exec(Local<Context> context,
       [](ExecutionStateRef* state,
          RegExpObjectRef* self,
          StringRef* subject) -> ValueRef* {
-        RegExpObjectRef::RegexMatchResult r;
-        self->match(state, subject, r, false, 0);
+        RegExpObjectRef::RegexMatchResult result;
+        self->match(state, subject, result, false, 0);
 
-        if (r.m_matchResults.empty()) {
+        if (result.m_matchResults.empty()) {
           return ValueRef::createNull();
         }
 
         auto vector = ValueVectorRef::create();
-        for (auto tokens : r.m_matchResults) {
+        for (auto tokens : result.m_matchResults) {
           for (auto token : tokens) {
             auto match = subject->substring(token.m_start, token.m_end);
             vector->pushBack(match);
@@ -776,67 +782,39 @@ MaybeLocal<v8::Object> v8::RegExp::Exec(Local<Context> context,
 
 Local<v8::Array> v8::Array::New(Isolate* isolate, int length) {
   API_ENTER_NO_EXCEPTION(isolate);
-  auto lwContext = lwIsolate->GetCurrentContext();
-  uint64_t len = 0;
-  if (length > 0) {
-    len = length;
-  }
-
-  auto r = Evaluator::execute(
-      lwContext->get(),
-      [](ExecutionStateRef* esState, uint64_t len) -> ValueRef* {
-        return ArrayObjectRef::create(esState, len);
-      },
-      len);
-  LWNODE_CHECK(r.isSuccessful());
-
-  return Utils::NewLocal<Array>(isolate, r.result);
+  return Utils::NewLocal<Array>(
+      isolate,
+      ArrayObjectRefHelper::create(lwIsolate->GetCurrentContext()->get(),
+                                   (length >= 0) ? length : 0));
 }
 
 Local<v8::Array> v8::Array::New(Isolate* isolate,
                                 Local<Value>* elements,
                                 size_t length) {
   API_ENTER_NO_EXCEPTION(isolate);
-  auto lwContext = lwIsolate->GetCurrentContext();
 
   auto vector = ValueVectorRef::create();
   for (size_t i = 0; i < length; i++) {
     vector->pushBack(VAL(**(elements + i))->value());
   }
 
-  auto r = Evaluator::execute(
-      lwContext->get(),
-      [](ExecutionStateRef* esState, ValueVectorRef* vector) -> ValueRef* {
-        return ArrayObjectRef::create(esState, vector);
-      },
-      vector);
-  LWNODE_CHECK(r.isSuccessful());
-
-  return Utils::NewLocal<Array>(isolate, r.result);
+  return Utils::NewLocal<Array>(
+      isolate,
+      ArrayObjectRefHelper::create(lwIsolate->GetCurrentContext()->get(),
+                                   vector));
 }
 
 uint32_t v8::Array::Length() const {
-  auto esArrayObject = CVAL(this)->value()->asArrayObject();
-  auto lwIsolate = IsolateWrap::GetCurrent();
-  auto lwContext = lwIsolate->GetCurrentContext();
-
-  auto r = Evaluator::execute(
-      lwContext->get(),
-      [](ExecutionStateRef* esState, ArrayObjectRef* object) -> ValueRef* {
-        return ValueRef::create(object->length(esState));
-      },
-      esArrayObject);
-  API_HANDLE_EXCEPTION(r, lwIsolate, 0);
-
-  return r.result->asUInt32();
+  return static_cast<uint32_t>(ArrayObjectRefHelper::length(
+      IsolateWrap::GetCurrent()->GetCurrentContext()->get(),
+      CVAL(this)->value()->asArrayObject()));
 }
 
 Local<v8::Map> v8::Map::New(Isolate* isolate) {
-  API_ENTER_NO_EXCEPTION(isolate);
-  auto esContext = lwIsolate->GetCurrentContext()->get();
+  EsScope scope(isolate);
 
   EvalResult r = Evaluator::execute(
-      esContext, [](ExecutionStateRef* esState) -> ValueRef* {
+      scope.context(), [](ExecutionStateRef* esState) -> ValueRef* {
         return MapObjectRef::create(esState);
       });
   LWNODE_CHECK(r.isSuccessful());
@@ -845,127 +823,108 @@ Local<v8::Map> v8::Map::New(Isolate* isolate) {
 }
 
 size_t v8::Map::Size() const {
-  auto lwIsolate = IsolateWrap::GetCurrent();
-  auto esContext = lwIsolate->GetCurrentContext()->get();
-  auto esSelf = CVAL(this)->value()->asMapObject();
+  API_ENTER_NO_TERMINATION_CHECK(EsScope, nullptr);
 
   EvalResult r = Evaluator::execute(
-      esContext,
+      scope.context(),
       [](ExecutionStateRef* esState, MapObjectRef* esSelf) -> ValueRef* {
         return ValueRef::create(esSelf->size(esState));
       },
-      esSelf);
+      scope.self()->asMapObject());
   LWNODE_CHECK(r.isSuccessful());
 
   return r.result->asNumber();
 }
 
 void Map::Clear() {
-  auto lwIsolate = IsolateWrap::GetCurrent();
-  auto esContext = lwIsolate->GetCurrentContext()->get();
-  auto esSelf = CVAL(this)->value()->asMapObject();
+  API_ENTER_NO_TERMINATION_CHECK(EsScope, nullptr);
 
   EvalResult r = Evaluator::execute(
-      esContext,
+      scope.context(),
       [](ExecutionStateRef* esState, MapObjectRef* esSelf) -> ValueRef* {
         esSelf->clear(esState);
         return ValueRef::createNull();
       },
-      esSelf);
+      scope.self()->asMapObject());
   LWNODE_CHECK(r.isSuccessful());
 }
 
 MaybeLocal<Value> Map::Get(Local<Context> context, Local<Value> key) {
-  API_ENTER_WITH_CONTEXT(context, MaybeLocal<Value>());
-  auto esContext = lwIsolate->GetCurrentContext()->get();
-  auto esSelf = CVAL(this)->value()->asMapObject();
-  auto esKey = CVAL(*key)->value();
+  API_ENTER_AND_EXIT_IF_TERMINATING(EsScope, context, MaybeLocal<Value>());
 
   EvalResult r = Evaluator::execute(
-      esContext,
+      scope.context(),
       [](ExecutionStateRef* esState,
          MapObjectRef* esSelf,
          ValueRef* esKey) -> ValueRef* { return esSelf->get(esState, esKey); },
-      esSelf,
-      esKey);
-  API_HANDLE_EXCEPTION(r, lwIsolate, MaybeLocal<Value>());
+      scope.self()->asMapObject(),
+      scope.asValue(key));
+  API_EXIT_IF_EXCEPTION_OCCURRED(r, MaybeLocal<Value>());
 
-  return Utils::NewLocal<Value>(lwIsolate->toV8(), r.result);
+  return Utils::NewLocal<Value>(scope.v8Isolate(), r.result);
 }
 
 MaybeLocal<Map> Map::Set(Local<Context> context,
                          Local<Value> key,
                          Local<Value> value) {
-  API_ENTER_WITH_CONTEXT(context, MaybeLocal<Map>());
-  auto esContext = lwIsolate->GetCurrentContext()->get();
-  auto esSelf = CVAL(this)->value()->asMapObject();
-  auto esKey = CVAL(*key)->value();
-  auto esValue = CVAL(*value)->value();
+  API_ENTER_AND_EXIT_IF_TERMINATING(EsScope, context, MaybeLocal<Map>());
 
   EvalResult r = Evaluator::execute(
-      esContext,
+      scope.context(),
       [](ExecutionStateRef* esState,
          MapObjectRef* esSelf,
          ValueRef* esKey,
          ValueRef* esValue) -> ValueRef* {
         esSelf->set(esState, esKey, esValue);
-        return ValueRef::createNull();
+        return esSelf;
       },
-      esSelf,
-      esKey,
-      esValue);
-  API_HANDLE_EXCEPTION(r, lwIsolate, MaybeLocal<Map>());
+      scope.self()->asMapObject(),
+      scope.asValue(key),
+      scope.asValue(value));
+  API_EXIT_IF_EXCEPTION_OCCURRED(r, MaybeLocal<Map>());
 
-  return Utils::NewLocal<Map>(lwIsolate->toV8(), esSelf);
+  return Utils::NewLocal<Map>(scope.v8Isolate(), r.result);
 }
 
 Maybe<bool> Map::Has(Local<Context> context, Local<Value> key) {
-  API_ENTER_WITH_CONTEXT(context, Nothing<bool>());
-  auto esContext = lwIsolate->GetCurrentContext()->get();
-  auto esSelf = CVAL(this)->value()->asMapObject();
-  auto esKey = CVAL(*key)->value();
+  API_ENTER_AND_EXIT_IF_TERMINATING(EsScope, context, Nothing<bool>());
 
   EvalResult r = Evaluator::execute(
-      esContext,
+      scope.context(),
       [](ExecutionStateRef* esState,
          MapObjectRef* esSelf,
          ValueRef* esKey) -> ValueRef* {
         return ValueRef::create(esSelf->has(esState, esKey));
       },
-      esSelf,
-      esKey);
-  API_HANDLE_EXCEPTION(r, lwIsolate, Nothing<bool>());
+      scope.self()->asMapObject(),
+      scope.asValue(key));
+  API_EXIT_IF_EXCEPTION_OCCURRED(r, Nothing<bool>());
 
   return Just(r.result->asBoolean());
 }
 
 Maybe<bool> Map::Delete(Local<Context> context, Local<Value> key) {
-  API_ENTER_WITH_CONTEXT(context, Nothing<bool>());
-  auto esContext = lwIsolate->GetCurrentContext()->get();
-  auto esSelf = CVAL(this)->value()->asMapObject();
-  auto esKey = CVAL(*key)->value();
+  API_ENTER_AND_EXIT_IF_TERMINATING(EsScope, context, Nothing<bool>());
 
   EvalResult r = Evaluator::execute(
-      esContext,
+      scope.context(),
       [](ExecutionStateRef* esState,
          MapObjectRef* esSelf,
          ValueRef* esKey) -> ValueRef* {
         return ValueRef::create(esSelf->deleteOperation(esState, esKey));
       },
-      esSelf,
-      esKey);
-  API_HANDLE_EXCEPTION(r, lwIsolate, Nothing<bool>());
+      scope.self()->asMapObject(),
+      scope.asValue(key));
+  API_EXIT_IF_EXCEPTION_OCCURRED(r, Nothing<bool>());
 
   return Just(r.result->asBoolean());
 }
 
 Local<Array> Map::AsArray() const {
-  auto lwIsolate = IsolateWrap::GetCurrent();
-  auto esContext = lwIsolate->GetCurrentContext()->get();
-  auto esSelf = CVAL(this)->value()->asMapObject();
+  API_ENTER_NO_TERMINATION_CHECK(EsScope, nullptr);
 
   EvalResult r = Evaluator::execute(
-      esContext,
+      scope.context(),
       [](ExecutionStateRef* esState, MapObjectRef* esSelf) -> ValueRef* {
         auto done = StringRef::createFromASCII("done");
         auto value = StringRef::createFromASCII("value");
@@ -988,10 +947,10 @@ Local<Array> Map::AsArray() const {
 
         return ArrayObjectRef::create(esState, vector);
       },
-      esSelf);
+      scope.self()->asMapObject());
   LWNODE_CHECK(r.isSuccessful());
 
-  return Utils::NewLocal<Array>(lwIsolate->toV8(), r.result);
+  return Utils::NewLocal<Array>(scope.v8Isolate(), r.result);
 }
 
 Local<v8::Set> v8::Set::New(Isolate* isolate) {
@@ -1115,8 +1074,7 @@ Local<Array> Set::AsArray() const {
         for (auto entry = itr->next(esState);
              entry->asObject()->get(esState, done)->isFalse();
              entry = itr->next(esState)) {
-          auto val = entry->asObject()->get(esState, value);
-          vector->pushBack(val);
+          vector->pushBack(entry->asObject()->get(esState, value));
         }
 
         return ArrayObjectRef::create(esState, vector);
@@ -1151,43 +1109,49 @@ Local<Promise> Promise::Resolver::GetPromise() {
 
 Maybe<bool> Promise::Resolver::Resolve(Local<Context> context,
                                        Local<Value> value) {
-  API_ENTER_WITH_CONTEXT(context, Nothing<bool>());
-  auto esContext = lwIsolate->GetCurrentContext()->get();
-  auto self = CVAL(this)->value()->asPromiseObject();
-
+  API_ENTER_AND_EXIT_IF_TERMINATING(EsScope, context, Nothing<bool>());
+  auto self = scope.self()->asPromiseObject();
   if (self->state() != Escargot::PromiseObjectRef::PromiseState::Pending) {
     return Just(true);
   }
 
+  auto esValueTofulfill = scope.asValue(value);
+  if (esValueTofulfill->isPromiseObject()) {
+    esValueTofulfill = esValueTofulfill->asPromiseObject()->promiseResult();
+  }
+
   EvalResult r = Evaluator::execute(
-      esContext,
+      scope.context(),
       [](ExecutionStateRef* state,
          PromiseObjectRef* promise,
-         ValueRef* esValue,
+         ValueRef* value,
          EscargotShim::IsolateWrap* lwIsolate) -> ValueRef* {
-        promise->fulfill(state, esValue);
+        promise->fulfill(state, value);
         return ValueRef::createUndefined();
       },
       self,
-      CVAL(*value)->value(),
-      lwIsolate);
-  API_HANDLE_EXCEPTION(r, lwIsolate, Nothing<bool>());
+      esValueTofulfill,
+      scope.lwIsolate());
+  API_EXIT_IF_EXCEPTION_OCCURRED(r, Nothing<bool>());
 
   return Just(true);
 }
 
 Maybe<bool> Promise::Resolver::Reject(Local<Context> context,
                                       Local<Value> value) {
-  API_ENTER_WITH_CONTEXT(context, Nothing<bool>());
-  auto esContext = lwIsolate->GetCurrentContext()->get();
-  auto self = CVAL(this)->value()->asPromiseObject();
-
+  API_ENTER_AND_EXIT_IF_TERMINATING(EsScope, context, Nothing<bool>());
+  auto self = scope.self()->asPromiseObject();
   if (self->state() != Escargot::PromiseObjectRef::PromiseState::Pending) {
     return Just(true);
   }
 
+  auto esValueToReject = scope.asValue(value);
+  if (esValueToReject->isPromiseObject()) {
+    esValueToReject = esValueToReject->asPromiseObject()->promiseResult();
+  }
+
   EvalResult r = Evaluator::execute(
-      esContext,
+      scope.context(),
       [](ExecutionStateRef* state,
          PromiseObjectRef* promise,
          ValueRef* esValue,
@@ -1196,9 +1160,9 @@ Maybe<bool> Promise::Resolver::Reject(Local<Context> context,
         return ValueRef::createUndefined();
       },
       self,
-      CVAL(*value)->value(),
-      lwIsolate);
-  API_HANDLE_EXCEPTION(r, lwIsolate, Nothing<bool>());
+      esValueToReject,
+      scope.lwIsolate());
+  API_EXIT_IF_EXCEPTION_OCCURRED(r, Nothing<bool>());
 
   return Just(true);
 }
@@ -1264,7 +1228,8 @@ MaybeLocal<Promise> Promise::Then(Local<Context> context,
 }
 
 bool Promise::HasHandler() {
-  LWNODE_RETURN_FALSE;
+  auto self = CVAL(this)->value()->asPromiseObject();
+  return self->hasRejectHandlers() || self->hasResolveHandlers();
 }
 
 Local<Value> Promise::Result() {
@@ -1406,7 +1371,8 @@ bool v8::ArrayBuffer::IsExternal() const {
 }
 
 bool v8::ArrayBuffer::IsDetachable() const {
-  LWNODE_RETURN_FALSE;
+  auto esSelf = CVAL(this)->value()->asArrayBufferObject();
+  return !esSelf->isDetachedBuffer();
 }
 
 v8::ArrayBuffer::Contents::Contents(void* data,
@@ -1947,7 +1913,7 @@ bool Isolate::InContext() {
 }
 
 void Isolate::ClearKeptObjects() {
-  LWNODE_RETURN_VOID;
+  LWNODE_ONCE(LWNODE_UNIMPLEMENT);
 }
 
 v8::Local<v8::Context> Isolate::GetCurrentContext() {
@@ -2045,7 +2011,7 @@ void Isolate::RequestInterrupt(InterruptCallback callback, void* data) {
 }
 
 void Isolate::RequestGarbageCollectionForTesting(GarbageCollectionType type) {
-  IsolateWrap::GetCurrent()->CollectGarbage();
+  IsolateWrap::GetCurrent()->CollectGarbage(GarbageCollectionReason::kTesting);
 }
 
 Isolate* Isolate::GetCurrent() {
@@ -2054,6 +2020,7 @@ Isolate* Isolate::GetCurrent() {
 
 // static
 Isolate* Isolate::Allocate() {
+  Engine::current()->initializeThread();
   return IsolateWrap::toV8(IsolateWrap::New());
 }
 
@@ -2073,6 +2040,7 @@ Isolate* Isolate::New(const Isolate::CreateParams& params) {
 
 void Isolate::Dispose() {
   IsolateWrap::fromV8(this)->Dispose();
+  Engine::current()->finalizeThread();
 }
 
 void Isolate::DumpAndResetStats() {
@@ -2110,12 +2078,12 @@ Maybe<bool> FinalizationGroup::Cleanup(
 
 void Isolate::SetHostImportModuleDynamicallyCallback(
     HostImportModuleDynamicallyCallback callback) {
-  LWNODE_RETURN_VOID;
+  LWNODE_ONCE(LWNODE_UNIMPLEMENT);
 }
 
 void Isolate::SetHostInitializeImportMetaObjectCallback(
     HostInitializeImportMetaObjectCallback callback) {
-  LWNODE_RETURN_VOID;
+  LWNODE_ONCE(LWNODE_UNIMPLEMENT);
 }
 
 void Isolate::SetPrepareStackTraceCallback(PrepareStackTraceCallback callback) {
@@ -2126,11 +2094,11 @@ Isolate::DisallowJavascriptExecutionScope::DisallowJavascriptExecutionScope(
     Isolate* isolate,
     Isolate::DisallowJavascriptExecutionScope::OnFailure on_failure)
     : on_failure_(on_failure) {
-  LWNODE_RETURN_VOID;
+  LWNODE_ONCE(LWNODE_UNIMPLEMENT);
 }
 
 Isolate::DisallowJavascriptExecutionScope::~DisallowJavascriptExecutionScope() {
-  LWNODE_RETURN_VOID;
+  LWNODE_ONCE(LWNODE_UNIMPLEMENT);
 }
 
 Isolate::AllowJavascriptExecutionScope::AllowJavascriptExecutionScope(
@@ -2258,7 +2226,7 @@ void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) {
 }
 
 void Isolate::PerformMicrotaskCheckpoint() {
-  LWNODE_RETURN_VOID;
+  IsolateWrap::fromV8(this)->PerformMicrotaskCheckpoint();
 }
 
 void Isolate::EnqueueMicrotask(Local<Function> v8_function) {
@@ -2606,9 +2574,8 @@ String::Utf8Value::~Utf8Value() {
 
 String::Value::Value(v8::Isolate* isolate, v8::Local<v8::Value> obj)
     : str_(nullptr), length_(0) {
-  MaybeLocal<String> s = obj->ToString(isolate->GetCurrentContext());
   Local<String> str;
-  if (!s.ToLocal(&str)) {
+  if (!obj->ToString(isolate->GetCurrentContext()).ToLocal(&str)) {
     return;
   }
 
@@ -2651,8 +2618,37 @@ DEFINE_UNIMPLEMENTED_ERROR(WasmRuntimeError, wasm_runtime_error)
 Local<Message> Exception::CreateMessage(Isolate* isolate,
                                         Local<Value> exception) {
   API_ENTER_NO_EXCEPTION(isolate);
+  auto esContext = lwIsolate->GetCurrentContext()->get();
   auto esException = CVAL(*exception)->value();
-  return Utils::NewLocal<Message>(isolate, esException);
+
+  StringRef* messageString = StringRef::emptyString();
+  if (esException->isString()) {
+    messageString = esException->asString();
+  }
+
+  EvalResult r = Evaluator::execute(
+      esContext,
+      [](ExecutionStateRef* esState, StringRef* messageString) -> ValueRef* {
+        auto object = StringObjectRef::create(esState);
+        object->setPrimitiveValue(esState, messageString);
+        return object;
+      },
+      messageString);
+  LWNODE_CHECK(r.isSuccessful());
+
+  if (esException->isObject()) {
+    auto esExtraData = ObjectRefHelper::getExtraData(esException->asObject());
+    if (esExtraData) {
+      auto esExceptionData = esExtraData->asExceptionObjectData();
+      ExtraDataHelper::setExtraData(r.result->asObject(), esExceptionData);
+    } else {
+      // FIXME: Check if missing extradata is ok. We print a warning
+      // here until this issue is investigated
+      LWNODE_LOG_WARN("esException does not have an extraData\n");
+    }
+  }
+
+  return Utils::NewLocal<Message>(isolate, r.result);
 }
 
 Local<StackTrace> Exception::GetStackTrace(Local<Value> exception) {
index f9b7a941f8609a6ab684475b593e4803181a937e..449aef35eca5dc9ebdf39ece6fbba8f0456f6a62 100644 (file)
@@ -62,6 +62,7 @@ v8::TryCatch::~TryCatch() {
       // message, script, and location need to be restored to Isolate TLS
       // for reuse.  capture_message_ needs to be disabled so that Throw()
       // does not create a new message.
+      isolate_->RestorePendingMessageFromTryCatch(this);
     }
     isolate_->UnregisterTryCatchHandler(this);
     reinterpret_cast<Isolate*>(isolate_)->ThrowException(v8Exception);
@@ -74,6 +75,10 @@ v8::TryCatch::~TryCatch() {
     }
     isolate_->UnregisterTryCatchHandler(this);
   }
+
+  if (isolate_->sholdReportPendingMessage(is_verbose_)) {
+    isolate_->ReportPendingMessages(true);
+  }
 }
 
 void* v8::TryCatch::operator new(size_t) {
@@ -94,17 +99,18 @@ void v8::TryCatch::operator delete[](void*, size_t) {
 bool v8::TryCatch::HasCaught() const {
   bool hasCaught = (exception_ != nullptr);
 
-  LWNODE_CALL_TRACE_ID(TRYCATCH, "hasCaught: %s", strBool(hasCaught));
+  LWNODE_CALL_TRACE_ID(TRYCATCH, "hasCaught: %b", hasCaught);
 
   return hasCaught;
 }
 
 bool v8::TryCatch::CanContinue() const {
-  LWNODE_RETURN_FALSE;
+  LWNODE_UNIMPLEMENT;
+  return false;
 }
 
 bool v8::TryCatch::HasTerminated() const {
-  LWNODE_RETURN_FALSE;
+  return has_terminated_;
 }
 
 v8::Local<v8::Value> v8::TryCatch::ReThrow() {
@@ -154,7 +160,7 @@ void v8::TryCatch::ResetInternal() {
 }
 
 void v8::TryCatch::SetVerbose(bool value) {
-  LWNODE_CALL_TRACE_ID(TRYCATCH, "%s", strBool(value));
+  LWNODE_CALL_TRACE_ID(TRYCATCH, "%b", value);
   is_verbose_ = value;
 }
 
@@ -164,7 +170,7 @@ bool v8::TryCatch::IsVerbose() const {
 }
 
 void v8::TryCatch::SetCaptureMessage(bool value) {
-  LWNODE_CALL_TRACE_ID(TRYCATCH, "%s", strBool(value));
+  LWNODE_CALL_TRACE_ID(TRYCATCH, "%b", value);
   capture_message_ = value;
 }
 
@@ -221,13 +227,13 @@ ScriptOrigin Message::GetScriptOrigin() const {
 
 v8::Local<Value> Message::GetScriptResourceName() const {
   auto lwIsolate = IsolateWrap::GetCurrent();
+  auto self = CVAL(this)->value();
 
-  if (!hasStackTraceData(lwIsolate->pending_exception())) {
+  if (!hasStackTraceData(self)) {
     return Utils::NewLocal<String>(lwIsolate->toV8(), StringRef::emptyString());
   }
 
-  auto stackTrace = ExceptionObjectData::stackTrace(
-      lwIsolate->pending_exception()->asObject());
+  auto stackTrace = ExceptionObjectData::stackTrace(self->asObject());
 
   auto top = stackTrace->front();
   return Utils::NewLocal<String>(lwIsolate->toV8(), top->src());
@@ -238,42 +244,39 @@ v8::Local<v8::StackTrace> Message::GetStackTrace() const {
 }
 
 Maybe<int> Message::GetLineNumber(Local<Context> context) const {
-  auto lwIsolate = CVAL(*context)->context()->GetIsolate();
+  auto self = CVAL(this)->value();
 
-  if (!hasStackTraceData(lwIsolate->pending_exception())) {
+  if (!hasStackTraceData(self)) {
     return Just<int>(0);
   }
 
-  auto stackTrace = ExceptionObjectData::stackTrace(
-      lwIsolate->pending_exception()->asObject());
+  auto stackTrace = ExceptionObjectData::stackTrace(self->asObject());
 
   auto top = stackTrace->front();
   return Just<int>(top->loc().line);
 }
 
 int Message::GetStartPosition() const {
-  auto lwIsolate = IsolateWrap::GetCurrent();
+  auto self = CVAL(this)->value();
 
-  if (!hasStackTraceData(lwIsolate->pending_exception())) {
+  if (!hasStackTraceData(self)) {
     return 0;
   }
 
-  auto stackTrace = ExceptionObjectData::stackTrace(
-      lwIsolate->pending_exception()->asObject());
+  auto stackTrace = ExceptionObjectData::stackTrace(self->asObject());
 
   auto top = stackTrace->front();
   return top->loc().index;
 }
 
 int Message::GetEndPosition() const {
-  auto lwIsolate = IsolateWrap::GetCurrent();
+  auto self = CVAL(this)->value();
 
-  if (!hasStackTraceData(lwIsolate->pending_exception())) {
+  if (!hasStackTraceData(self)) {
     return 0;
   }
 
-  auto stackTrace = ExceptionObjectData::stackTrace(
-      lwIsolate->pending_exception()->asObject());
+  auto stackTrace = ExceptionObjectData::stackTrace(self->asObject());
 
   auto top = stackTrace->front();
   return top->loc().index + 1;
@@ -299,14 +302,13 @@ int Message::GetWasmFunctionIndex() const {
 }
 
 Maybe<int> Message::GetStartColumn(Local<Context> context) const {
-  auto lwIsolate = CVAL(*context)->context()->GetIsolate();
+  auto self = CVAL(this)->value();
 
-  if (!hasStackTraceData(lwIsolate->pending_exception())) {
+  if (!hasStackTraceData(self)) {
     return Nothing<int>();
   }
 
-  auto stackTrace = ExceptionObjectData::stackTrace(
-      lwIsolate->pending_exception()->asObject());
+  auto stackTrace = ExceptionObjectData::stackTrace(self->asObject());
 
   auto top = stackTrace->front();
   return Just<int>(top->loc().column - 1);
@@ -317,14 +319,13 @@ int Message::GetEndColumn() const {
 }
 
 Maybe<int> Message::GetEndColumn(Local<Context> context) const {
-  auto lwIsolate = CVAL(*context)->context()->GetIsolate();
+  auto self = CVAL(this)->value();
 
-  if (!hasStackTraceData(lwIsolate->pending_exception())) {
+  if (!hasStackTraceData(self)) {
     return Nothing<int>();
   }
 
-  auto stackTrace = ExceptionObjectData::stackTrace(
-      lwIsolate->pending_exception()->asObject());
+  auto stackTrace = ExceptionObjectData::stackTrace(self->asObject());
 
   auto top = stackTrace->front();
   int endCol = top->loc().column;
@@ -342,13 +343,12 @@ bool Message::IsOpaque() const {
 
 MaybeLocal<String> Message::GetSourceLine(Local<Context> context) const {
   auto lwIsolate = CVAL(*context)->context()->GetIsolate();
-
-  if (!hasStackTraceData(lwIsolate->pending_exception())) {
+  auto self = CVAL(this)->value();
+  if (!hasStackTraceData(self)) {
     return Utils::NewLocal<String>(lwIsolate->toV8(), StringRef::emptyString());
   }
 
-  auto stackTrace = ExceptionObjectData::stackTrace(
-      lwIsolate->pending_exception()->asObject());
+  auto stackTrace = ExceptionObjectData::stackTrace(self->asObject());
 
   auto top = stackTrace->front();
   std::string code = top->sourceCode()->toStdUTF8String();
diff --git a/lwnode/code/escargotshim/src/api-experimental-serialization.cc b/lwnode/code/escargotshim/src/api-experimental-serialization.cc
new file mode 100644 (file)
index 0000000..bc6bf06
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2021-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(LWNODE_ENABLE_EXPERIMENTAL_SERIALIZATION)
+
+#include "api.h"
+#include "base.h"
+
+using namespace Escargot;
+using namespace EscargotShim;
+
+namespace v8 {
+// --- V a l u e   S e r i a l i z a t i o n ---
+
+Maybe<bool> ValueSerializer::Delegate::WriteHostObject(Isolate* v8_isolate,
+                                                       Local<Object> object) {
+  LWNODE_RETURN_MAYBE(bool);
+}
+
+Maybe<uint32_t> ValueSerializer::Delegate::GetSharedArrayBufferId(
+    Isolate* v8_isolate, Local<SharedArrayBuffer> shared_array_buffer) {
+  LWNODE_RETURN_MAYBE(uint32_t);
+}
+
+Maybe<uint32_t> ValueSerializer::Delegate::GetWasmModuleTransferId(
+    Isolate* v8_isolate, Local<WasmModuleObject> module) {
+  LWNODE_RETURN_MAYBE(uint32_t);
+}
+
+void* ValueSerializer::Delegate::ReallocateBufferMemory(void* old_buffer,
+                                                        size_t size,
+                                                        size_t* actual_size) {
+  *actual_size = size;
+  return realloc(old_buffer, size);
+}
+
+void ValueSerializer::Delegate::FreeBufferMemory(void* buffer) {
+  return free(buffer);
+}
+
+struct ValueSerializer::PrivateData {
+  explicit PrivateData(Isolate* isolate, ValueSerializer::Delegate* delegate)
+      : serializer(IsolateWrap::fromV8(isolate), delegate) {}
+  EscargotShim::ValueSerializer serializer;
+};
+
+ValueSerializer::ValueSerializer(Isolate* isolate)
+    : ValueSerializer(isolate, nullptr) {
+  LWNODE_UNIMPLEMENT;
+}
+
+ValueSerializer::ValueSerializer(Isolate* isolate, Delegate* delegate)
+    : private_(new PrivateData(isolate, delegate)) {}
+
+ValueSerializer::~ValueSerializer() {
+  delete private_;
+}
+
+void ValueSerializer::WriteHeader() {
+  private_->serializer.WriteHeader();
+}
+
+void ValueSerializer::SetTreatArrayBufferViewsAsHostObjects(bool mode) {}
+
+Maybe<bool> ValueSerializer::WriteValue(Local<Context> context,
+                                        Local<Value> value) {
+  bool result = private_->serializer.WriteValue(CVAL(*value)->value());
+  return Just(result);
+}
+
+std::pair<uint8_t*, size_t> ValueSerializer::Release() {
+  auto result = private_->serializer.Release();
+  return result;
+}
+
+void ValueSerializer::TransferArrayBuffer(uint32_t transfer_id,
+                                          Local<ArrayBuffer> array_buffer) {
+  LWNODE_RETURN_VOID;
+}
+
+void ValueSerializer::WriteUint32(uint32_t value) {
+  private_->serializer.WriteUint32(value);
+}
+
+void ValueSerializer::WriteUint64(uint64_t value) {
+  LWNODE_RETURN_VOID;
+}
+
+void ValueSerializer::WriteDouble(double value) {
+  LWNODE_RETURN_VOID;
+}
+
+void ValueSerializer::WriteRawBytes(const void* source, size_t length) {
+  LWNODE_RETURN_VOID;
+}
+
+MaybeLocal<Object> ValueDeserializer::Delegate::ReadHostObject(
+    Isolate* v8_isolate) {
+  LWNODE_RETURN_LOCAL(Object);
+}
+
+MaybeLocal<WasmModuleObject> ValueDeserializer::Delegate::GetWasmModuleFromId(
+    Isolate* v8_isolate, uint32_t id) {
+  LWNODE_RETURN_LOCAL(WasmModuleObject);
+}
+
+MaybeLocal<SharedArrayBuffer>
+ValueDeserializer::Delegate::GetSharedArrayBufferFromId(Isolate* v8_isolate,
+                                                        uint32_t id) {
+  LWNODE_RETURN_LOCAL(SharedArrayBuffer);
+}
+
+struct ValueDeserializer::PrivateData {
+  explicit PrivateData(Isolate* isolate,
+                       Delegate* delegate,
+                       const uint8_t* data,
+                       size_t size)
+      : deserializer(IsolateWrap::fromV8(isolate), delegate, data, size) {}
+  EscargotShim::ValueDeserializer deserializer;
+};
+
+ValueDeserializer::ValueDeserializer(Isolate* isolate,
+                                     const uint8_t* data,
+                                     size_t size)
+    : ValueDeserializer(isolate, data, size, nullptr) {}
+
+ValueDeserializer::ValueDeserializer(Isolate* isolate,
+                                     const uint8_t* data,
+                                     size_t size,
+                                     Delegate* delegate)
+    : private_(new PrivateData(isolate, delegate, data, size)) {}
+
+ValueDeserializer::~ValueDeserializer() {
+  delete private_;
+}
+
+Maybe<bool> ValueDeserializer::ReadHeader(Local<Context> context) {
+  return Just(true);
+}
+
+void ValueDeserializer::SetSupportsLegacyWireFormat(
+    bool supports_legacy_wire_format) {
+  LWNODE_RETURN_VOID;
+}
+
+uint32_t ValueDeserializer::GetWireFormatVersion() const {
+  LWNODE_RETURN_0;
+}
+
+MaybeLocal<Value> ValueDeserializer::ReadValue(Local<Context> context) {
+  API_ENTER_WITH_CONTEXT(context, MaybeLocal<Value>());
+  auto esContext = lwIsolate->GetCurrentContext()->get();
+  auto output = private_->deserializer.ReadValue();
+  if (!output.hasValue()) {
+    LWNODE_CALL_TRACE_ID(SERIALIZER, "Cannot read value");
+    return Utils::NewLocal<Uint32>(
+        lwIsolate->toV8(),
+        ExceptionHelper::createErrorObject(esContext,
+                                           ErrorMessageType::kNotReadValue));
+  }
+  return Utils::NewLocal<Uint32>(lwIsolate->toV8(), output.get());
+}
+
+void ValueDeserializer::TransferArrayBuffer(uint32_t transfer_id,
+                                            Local<ArrayBuffer> array_buffer) {
+  LWNODE_RETURN_VOID;
+}
+
+void ValueDeserializer::TransferSharedArrayBuffer(
+    uint32_t transfer_id, Local<SharedArrayBuffer> shared_array_buffer) {
+  LWNODE_RETURN_VOID;
+}
+
+bool ValueDeserializer::ReadUint32(uint32_t* value) {
+  return private_->deserializer.ReadUint32(value);
+}
+
+bool ValueDeserializer::ReadUint64(uint64_t* value) {
+  LWNODE_RETURN_FALSE;
+}
+
+bool ValueDeserializer::ReadDouble(double* value) {
+  LWNODE_RETURN_FALSE;
+}
+
+bool ValueDeserializer::ReadRawBytes(size_t length, const void** data) {
+  LWNODE_RETURN_FALSE;
+}
+}  // namespace v8
+
+#endif
index 1d42960143d2f004a32f68c7f1fa1ab1f3ef907f..71d99ef75ba6c758ddf1dbf93ad2aa949f157258 100644 (file)
@@ -67,7 +67,7 @@ i::Address* HandleScope::CreateHandle(i::Isolate* isolate, i::Address value) {
 
   if (lwIsolate->isCurrentScopeSealed()) {
     lwIsolate->onFatalError(
-        createCodeLocation(TRACE_ARGS).c_str(),
+        __CODE_LOCATION__,
         "the current scope isn't allowed to allocate a handle");
   }
 
index 126af551b2e7965a53a56a8c1f81c69e7601ff4e..f5eb2774b620b04f8129641b0ad2861a750d14ea 100644 (file)
@@ -140,31 +140,37 @@ Local<UnboundScript> Script::GetUnboundScript() {
 
 // static
 Local<PrimitiveArray> PrimitiveArray::New(Isolate* v8_isolate, int length) {
-  auto array = Array::New(v8_isolate, length);
-  return Utils::NewLocal<PrimitiveArray>(v8_isolate, CVAL(*array)->value());
+  API_ENTER_NO_EXCEPTION(v8_isolate);
+  return Utils::NewLocal<PrimitiveArray>(
+      v8_isolate,
+      ArrayObjectRefHelper::create(lwIsolate->GetCurrentContext()->get(),
+                                   (length >= 0) ? length : 0));
 }
 
 int PrimitiveArray::Length() const {
-  auto v8Isolate = Isolate::GetCurrent();
-  auto array = Utils::NewLocal<Array>(v8Isolate, CVAL(this)->value());
-  return array->Length();
+  API_ENTER_NO_EXCEPTION(Isolate::GetCurrent());
+  return static_cast<int>(
+      ArrayObjectRefHelper::length(lwIsolate->GetCurrentContext()->get(),
+                                   CVAL(this)->value()->asArrayObject()));
 }
 
 void PrimitiveArray::Set(Isolate* v8_isolate,
                          int index,
                          Local<Primitive> item) {
-  auto v8Context = v8_isolate->GetCurrentContext();
-  auto array = Utils::NewLocal<Array>(v8_isolate, CVAL(this)->value());
-  auto ok = array->Set(v8Context, index, item);
+  API_ENTER_NO_EXCEPTION(v8_isolate);
+  ArrayObjectRefHelper::set(lwIsolate->GetCurrentContext()->get(),
+                            CVAL(this)->value()->asArrayObject(),
+                            index,
+                            VAL(*item)->value());
 }
 
 Local<Primitive> PrimitiveArray::Get(Isolate* v8_isolate, int index) {
-  auto v8Context = v8_isolate->GetCurrentContext();
-  auto array = Utils::NewLocal<Array>(v8_isolate, CVAL(this)->value());
-  auto val = array->Get(v8Context, index);
-  auto r = val.FromMaybe(
-      Utils::NewLocal<Value>(v8_isolate, ValueRef::createUndefined()));
-  return Utils::NewLocal<Primitive>(v8_isolate, CVAL(*r)->value());
+  API_ENTER_NO_EXCEPTION(v8_isolate);
+  return Utils::NewLocal<Primitive>(
+      v8_isolate,
+      ArrayObjectRefHelper::get(lwIsolate->GetCurrentContext()->get(),
+                                CVAL(this)->value()->asArrayObject(),
+                                index));
 }
 
 Module::Status Module::GetStatus() const {
@@ -286,16 +292,11 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal(
     r.error = ExceptionHelper::createErrorObject(
         esPureContext, result.parseErrorCode, result.parseErrorMessage);
 
-    lwIsolate->SetPendingExceptionAndMessage(r.error.get(), r.stackTraceData);
+    lwIsolate->SetPendingExceptionAndMessage(r.error.get(), r.stackTrace);
     lwIsolate->ReportPendingMessages();
     return MaybeLocal<UnboundScript>();
   }
 
-  // wrap the parsed script with the current isolate
-  // auto lwValue = ValueWrap::createScript(result.script.get());
-
-  // ExtraData extra(1, lwIsolate);
-  // lwValue->setExtra(std::move(extra));
   return Utils::NewLocal<UnboundScript>(v8_isolate, result.script.get());
 }
 
@@ -315,7 +316,9 @@ MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context,
   auto maybe =
       CompileUnboundInternal(isolate, source, options, no_cache_reason);
   Local<UnboundScript> result;
-  if (!maybe.ToLocal(&result)) return MaybeLocal<Script>();
+  if (!maybe.ToLocal(&result)) {
+    return MaybeLocal<Script>();
+  }
   v8::Context::Scope scope(context);
   return result->BindToCurrentContext();
 }
@@ -380,6 +383,12 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext(
 
   auto esContext = VAL(*v8_context)->context()->get();
   auto esSource = VAL(*source->source_string)->value()->asString();
+  StringRef* esSourceName = nullptr;
+  if (*source->resource_name) {
+    esSourceName = VAL(*source->resource_name)->value()->asString();
+  } else {
+    esSourceName = StringRef::emptyString();
+  }
 
   handleShebang(esSource);
 
@@ -388,36 +397,38 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext(
   for (size_t i = 0; i < arguments_count; i++) {
     arguments_list.push_back(VAL(*arguments[i])->value());
   }
-  arguments_list.push_back(esSource);
 
   EvalResult r = Evaluator::execute(
       esContext,
       [](ExecutionStateRef* state,
-         FunctionObjectRef* function,
-         const size_t argc,
+         StringRef* sourceName,
+         StringRef* source,
+         size_t argc,
          ValueRef** argv) -> ValueRef* {
-        LWNODE_CHECK(function->isConstructible());
-        return function->construct(state, argc, argv);
+        return FunctionObjectRef::create(
+            state,
+            sourceName,
+            AtomicStringRef::create(state->context(), "anonymous"),
+            argc,
+            argv,
+            source);
       },
-      esContext->globalObject()->function(),
+      esSourceName,
+      esSource,
       arguments_list.size(),
       arguments_list.data());
 
   // note: expand API_HANDLE_EXCEPTION and add the resource name
   if (!r.isSuccessful()) {
     LWNODE_DLOG_ERROR("Evaluate");
-    LWNODE_DLOG_RAW("Execute:\n  %s (%s:%d)\nResource:\n  %s\n%s",
-                    TRACE_ARGS2,
-                    VAL(*source->resource_name)
-                        ->value()
-                        ->asString()
-                        ->toStdUTF8String()
-                        .c_str(),
+    LWNODE_DLOG_RAW("Execute:\n  %s\nResource:\n  %s\n%s",
+                    __CODE_LOCATION__,
+                    esSourceName->toStdUTF8String().c_str(),
                     EvalResultHelper::getErrorString(
                         lwIsolate->GetCurrentContext()->get(), r)
                         .c_str());
 
-    lwIsolate->SetPendingExceptionAndMessage(r.error.get(), r.stackTraceData);
+    lwIsolate->SetPendingExceptionAndMessage(r.error.get(), r.stackTrace);
     lwIsolate->ReportPendingMessages();
     return MaybeLocal<Function>();
   }
index da937eda03238f79f07a67e50b2ea4650ab2f665..4f2d0873952ca09b66934ec6183575b9f7d563a5 100644 (file)
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#if !defined(LWNODE_ENABLE_EXPERIMENTAL_SERIALIZATION)
+
 #include "api.h"
 #include "base.h"
 
@@ -224,3 +226,5 @@ bool ValueDeserializer::ReadRawBytes(size_t length, const void** data) {
   LWNODE_RETURN_FALSE;
 }
 }  // namespace v8
+
+#endif
index d66b91092ef988e10d7b955a6c5ddf9333e13ffa..552b5313b406c0cd3707772d9975f9a29ee3395b 100644 (file)
@@ -30,19 +30,22 @@ void Template::Set(v8::Local<Name> name,
   bool isEnumerable = !(attribute & DontEnum);
   bool isConfigurable = !(attribute & DontDelete);
 
-  TemplateRef* esTemplate = CVAL(this)->tpl();
-
+  EsScopeTemplate scope(this);
   // Name can be either a string or symbol
-  auto esName = CVAL(*name)->value();
   auto lwValue = CVAL(*value);
-
   if (lwValue->type() == HandleWrap::Type::ObjectTemplate ||
       lwValue->type() == HandleWrap::Type::FunctionTemplate) {
-    esTemplate->set(
-        esName, lwValue->tpl(), isWritable, isEnumerable, isConfigurable);
+    scope.self()->set(scope.asValue(name),
+                      lwValue->tpl(),
+                      isWritable,
+                      isEnumerable,
+                      isConfigurable);
   } else {
-    esTemplate->set(
-        esName, lwValue->value(), isWritable, isEnumerable, isConfigurable);
+    scope.self()->set(scope.asValue(name),
+                      lwValue->value(),
+                      isWritable,
+                      isEnumerable,
+                      isConfigurable);
   }
 }
 
@@ -57,8 +60,8 @@ void Template::SetAccessorProperty(v8::Local<v8::Name> name,
                                    v8::Local<FunctionTemplate> setter,
                                    v8::PropertyAttribute attribute,
                                    v8::AccessControl access_control) {
-  auto esTemplate = CVAL(this)->tpl();
-  auto esName = CVAL(*name)->value()->asString();
+  EsScopeTemplate scope(this);
+
   FunctionTemplateRef* esGetter = nullptr;
   if (!getter.IsEmpty()) {
     esGetter = CVAL(*getter)->ftpl();
@@ -68,20 +71,19 @@ void Template::SetAccessorProperty(v8::Local<v8::Name> name,
     esSetter = CVAL(*setter)->ftpl();
   }
 
-  esTemplate->setAccessorProperty(esName,
-                                  OptionalRef<FunctionTemplateRef>(esGetter),
-                                  OptionalRef<FunctionTemplateRef>(esSetter),
-                                  !(attribute & DontEnum),
-                                  !(attribute & DontDelete));
+  scope.self()->setAccessorProperty(scope.asValue(name)->asString(),
+                                    OptionalRef<FunctionTemplateRef>(esGetter),
+                                    OptionalRef<FunctionTemplateRef>(esSetter),
+                                    !(attribute & DontEnum),
+                                    !(attribute & DontDelete));
 }
 
 // --- F u n c t i o n   T e m p l a t e ---
 
 Local<ObjectTemplate> FunctionTemplate::PrototypeTemplate() {
-  FunctionTemplateRef* esFunctionTemplate = CVAL(this)->ftpl();
+  EsScopeFunctionTemplate scope(this);
 
-  return Utils::NewLocal(IsolateWrap::GetCurrent()->toV8(),
-                         esFunctionTemplate->prototypeTemplate());
+  return Utils::NewLocal(scope.v8Isolate(), scope.self()->prototypeTemplate());
 }
 
 void FunctionTemplate::SetPrototypeProviderTemplate(
@@ -90,139 +92,118 @@ void FunctionTemplate::SetPrototypeProviderTemplate(
 }
 
 void FunctionTemplate::Inherit(v8::Local<FunctionTemplate> value) {
-  auto esThisFunctionTemplate = CVAL(this)->ftpl();
-  auto esThatFunctionTemplate = CVAL(*value)->ftpl();
+  EsScopeFunctionTemplate scope(this);
 
+  auto esThatFunctionTemplate = scope.asFunctionTemplate(value);
   LWNODE_CALL_TRACE_ID_LOG(EXTRADATA,
                            "FunctionTemplate(%p)::Inherit(): %p",
-                           esThisFunctionTemplate,
+                           scope.self(),
                            esThatFunctionTemplate);
 
-  esThisFunctionTemplate->inherit(esThatFunctionTemplate);
+  scope.self()->inherit(esThatFunctionTemplate);
   LWNODE_CALL_TRACE_ID_LOG(
       EXTRADATA,
       "FunctionTemplate(%p)::Inherit(): ExtraData1: %p, ExtraData2: %p",
-      esThisFunctionTemplate,
-      ExtraDataHelper::getExtraData(esThisFunctionTemplate),
-      ExtraDataHelper::getExtraData(esThatFunctionTemplate));
+      scope.self(),
+      ExtraDataHelper::getFunctionTemplateExtraData(scope.self()),
+      ExtraDataHelper::getFunctionTemplateExtraData(esThatFunctionTemplate));
 }
 
-// e.g.,
-// sig_obj()
-// var s = new sig_obj();
-//  target: sig_obj == constructor obj, thisValue: s
-// s.x();
-//  target: null, thisValue: s
-static ValueRef* FunctionTemplateNativeFunction(
-    ExecutionStateRef* state,
-    ValueRef* thisValue,
-    size_t argc,
-    ValueRef** argv,
-    OptionalRef<ObjectRef> newTarget) {
-  Escargot::OptionalRef<Escargot::FunctionObjectRef> callee =
-      state->resolveCallee();
-
-  auto calleeExtraData = ExtraDataHelper::getExtraData(callee.value());
+static FunctionData* getFunctionDataFromCallee(FunctionObjectRef* callee) {
+  auto calleeExtraData = ExtraDataHelper::getExtraData(callee);
   LWNODE_DCHECK_NOT_NULL(calleeExtraData);
 
-  FunctionData* fnData = nullptr;
+  FunctionData* functionData = nullptr;
   // callee->extraData() is one of two types below
   if (calleeExtraData->isFunctionData()) {
-    fnData = calleeExtraData->asFunctionData();
+    functionData = calleeExtraData->asFunctionData();
   } else if (calleeExtraData->isFunctionTemplateData()) {
-    fnData = new FunctionData(
+    functionData = new FunctionData(
         calleeExtraData->asFunctionTemplateData()->functionTemplate());
   } else {
     LWNODE_CHECK(false);
   }
 
-  LWNODE_CALL_TRACE_ID(TEMPLATE,
-                       "es: %p newTarget: %s",
-                       thisValue,
-                       strBool(newTarget.hasValue()));
+  return functionData;
+}
 
-  if (newTarget.hasValue()) {
-    auto extraData = ExtraDataHelper::getExtraData(newTarget.value());
-    if (extraData) {
-      // targetData was created in FunctionTemplate::GetFunction()
-      auto targetData = extraData->asFunctionData();
-      auto functionTemplate = targetData->functionTemplate();
-      auto objectTemplate = functionTemplate->instanceTemplate();
-
-      LWNODE_CALL_TRACE_ID_LOG(EXTRADATA,
-                               "FunctionTemplateNativeFunction::targetData: %p",
-                               targetData);
-
-      auto newInstance = thisValue->asObject();
-      auto newInstanceData = ExtraDataHelper::getExtraData(newInstance);
-      if (newInstanceData) {
-        // newInstanceData was created in FunctionTemplate::InstanceTemplate()
-        LWNODE_CHECK(newInstanceData->isObjectTemplateData());
-        auto objectTemplateData = newInstanceData->asObjectTemplateData();
-        LWNODE_CALL_TRACE_ID_LOG(EXTRADATA,
-                                 "FunctionTemplateNative: Existing Data 1: %p",
-                                 newInstanceData);
-        auto newObjectData =
-            objectTemplateData->createObjectData(objectTemplate);
-        // Replace ObjectTemplateData with its objectData, i.e., creating an
-        // instance
-        ObjectRefHelper::setExtraData(newInstance, newObjectData, true);
-      } else {
-        auto objectTemplateData = ExtraDataHelper::getExtraData(objectTemplate);
-        if (objectTemplateData) {
-          // newInstance was created from ObjectTemplate
-          auto newObjectData =
-              objectTemplateData->asObjectTemplateData()->createObjectData(
-                  objectTemplate);
-          LWNODE_CALL_TRACE_ID_LOG(EXTRADATA,
-                                   "FunctionTemplateNative: New ExtaData: %p",
-                                   newObjectData);
-          ObjectRefHelper::setExtraData(newInstance, newObjectData);
-        } else {
-          // newInstance was created from FunctionTemplate::GetFunction(), and
-          // with "var s = new S();" in Javascript
-          LWNODE_CHECK(targetData);
-          auto newObjectData = new ObjectData(targetData->functionTemplate());
-          LWNODE_CALL_TRACE_ID_LOG(EXTRADATA,
-                                   "FunctionTemplateNative: New ExtraData: %p",
-                                   newObjectData);
-          ObjectRefHelper::setExtraData(newInstance, newObjectData);
-        }
-      }
+static void setExtraDataToNewObjectInstance(ValueRef* thisValue,
+                                            ObjectRef* newTarget) {
+  auto targetData = ExtraDataHelper::getFunctionExtraData(newTarget);
+  LWNODE_CALL_TRACE_ID_LOG(EXTRADATA, "targetData: %p", targetData);
+
+  if (!targetData) {
+    return;
+  }
+
+  // newTarget was created from JavaScript using Template.
+  // targetData was created from FunctionTemplate::GetFunction()
+  auto objectTemplate = targetData->functionTemplate()->instanceTemplate();
+
+  auto newInstance = thisValue->asObject();
+  auto newInstanceObjectTemplateData =
+      ExtraDataHelper::getObjectTemplateExtraData(newInstance);
+  ObjectData* newObjectData = nullptr;
+  if (newInstanceObjectTemplateData) {
+    // 1. newInstanceObjectTemplateData was created from
+    // FunctionTemplate::InstanceTemplate()
+    LWNODE_CALL_TRACE_ID_LOG(
+        EXTRADATA, "Existing Data: %p", newInstanceObjectTemplateData);
+    newObjectData =
+        newInstanceObjectTemplateData->createObjectData(objectTemplate);
+    // Replace ObjectTemplateData with correct ObjectData
+    ObjectRefHelper::setExtraData(newInstance, newObjectData, true);
+  } else {
+    auto objectTemplateData =
+        ExtraDataHelper::getObjectTemplateExtraData(objectTemplate);
+    if (objectTemplateData) {
+      // 2. newInstance was created from ObjectTemplate
+      newObjectData = objectTemplateData->createObjectData(objectTemplate);
+      ObjectRefHelper::setExtraData(newInstance, newObjectData);
     } else {
-      // newTarget was created from JavaScript without using Template
+      // 3. newInstance was created from FunctionTemplate::GetFunction(),
+      // with "var s = new S();" in Javascript
+      newObjectData = new ObjectData(targetData->functionTemplate());
+      ObjectRefHelper::setExtraData(newInstance, newObjectData);
     }
   }
 
+  LWNODE_CALL_TRACE_ID_LOG(EXTRADATA, "New ExtraData: %p", newObjectData);
+}
+
+static ValueRef* runNativeFunctionCallback(ExecutionStateRef* state,
+                                           FunctionData* functionData,
+                                           ValueRef* thisValue,
+                                           ObjectRef* newTarget,
+                                           size_t argc,
+                                           ValueRef** argv) {
   auto lwIsolate = IsolateWrap::GetCurrent();
-  if (!newTarget.hasValue() &&
-      !fnData->checkSignature(state, thisValue->asObject())) {
-    lwIsolate->ScheduleThrow(TypeErrorObjectRef::create(
-        state, StringRef::createFromASCII("Illegal invocation")));
+  if (!functionData->checkSignature(state, thisValue->asObject())) {
+    lwIsolate->ScheduleThrow(ExceptionHelper::createErrorObject(
+        state->context(), ErrorMessageType::kIllegalInvocation));
     lwIsolate->ThrowErrorIfHasException(state);
     LWNODE_DLOG_ERROR("Signature mismatch!");
-    return ValueRef::createUndefined();
+    return nullptr;
   }
 
   Local<Value> result;
-  if (fnData->callback()) {
+  if (functionData->callback()) {
     LWNODE_CALL_TRACE_ID(TEMPLATE, "> Call JS callback");
-    FunctionCallbackInfoWrap info(fnData->isolate(),
+    lwIsolate->increaseCallDepth();
+    FunctionCallbackInfoWrap info(functionData->isolate(),
                                   thisValue,
                                   thisValue,
                                   newTarget,
-                                  VAL(fnData->callbackData()),
+                                  VAL(functionData->callbackData()),
                                   argc,
                                   argv);
-    fnData->callback()(info);
+    functionData->callback()(info);
+    lwIsolate->decreaseCallDepth();
+
     lwIsolate->ThrowErrorIfHasException(state);
     result = info.GetReturnValue().Get();
   }
 
-  if (newTarget.hasValue()) {
-    return thisValue;
-  }
-
   if (!result.IsEmpty()) {
     return VAL(*result)->value();
   }
@@ -230,6 +211,41 @@ static ValueRef* FunctionTemplateNativeFunction(
   return ValueRef::createUndefined();
 }
 
+// e.g.,
+// sig_obj()
+// var s = new sig_obj();
+//  target: sig_obj == constructor obj, thisValue: s
+// s.x();
+//  target: null, thisValue: s
+static ValueRef* FunctionTemplateNativeFunction(
+    ExecutionStateRef* state,
+    ValueRef* thisValue,
+    size_t argc,
+    ValueRef** argv,
+    OptionalRef<ObjectRef> newTarget) {
+  LWNODE_CALL_TRACE_ID(
+      TEMPLATE, "es: %p newTarget: %b", thisValue, newTarget.hasValue());
+
+  FunctionData* functionData =
+      getFunctionDataFromCallee(state->resolveCallee().value());
+
+  if (newTarget.hasValue()) {
+    setExtraDataToNewObjectInstance(thisValue, newTarget.value());
+  }
+
+  ValueRef* result = runNativeFunctionCallback(
+      state, functionData, thisValue, newTarget.value(), argc, argv);
+  if (result == nullptr) {
+    return ValueRef::createUndefined();
+  }
+
+  if (newTarget.hasValue()) {
+    return thisValue;
+  }
+
+  return result;
+}
+
 Local<FunctionTemplate> FunctionTemplate::New(Isolate* isolate,
                                               FunctionCallback callback,
                                               v8::Local<Value> data,
@@ -306,38 +322,37 @@ void FunctionTemplate::SetCallHandler(FunctionCallback callback,
     LWNODE_RETURN_VOID;
   }
 
-  Escargot::FunctionTemplateRef* esFunctionTemplate = CVAL(this)->ftpl();
-  auto functionTemplateData = ExtraDataHelper::getExtraData(esFunctionTemplate)
-                                  ->asFunctionTemplateData();
+  EsScopeFunctionTemplate scope(this);
+  auto functionTemplateData =
+      ExtraDataHelper::getFunctionTemplateExtraData(scope.self());
   functionTemplateData->setCallback(callback);
   functionTemplateData->setCallbackData(*data);
 }
 
 Local<ObjectTemplate> FunctionTemplate::InstanceTemplate() {
-  FunctionTemplateRef* esFunctionTemplate = CVAL(this)->ftpl();
-  LWNODE_CALL_TRACE_ID_LOG(
-      EXTRADATA, "InstanceTemplate(%p)", esFunctionTemplate);
+  EsScopeFunctionTemplate scope(this);
+  LWNODE_CALL_TRACE_ID_LOG(EXTRADATA, "InstanceTemplate(%p)", scope.self());
 
-  auto functionTemplateData = ExtraDataHelper::getExtraData(esFunctionTemplate)
-                                  ->asFunctionTemplateData();
+  auto functionTemplateData =
+      ExtraDataHelper::getFunctionTemplateExtraData(scope.self());
   LWNODE_CHECK(functionTemplateData);
 
   // Only one instanceTemplate should exist.
-  auto esObjectTemplate = esFunctionTemplate->instanceTemplate();
-  auto objectTemplateData = ExtraDataHelper::getExtraData(esObjectTemplate);
+  auto esObjectTemplate = scope.self()->instanceTemplate();
+  auto objectTemplateData =
+      ExtraDataHelper::getObjectTemplateExtraData(esObjectTemplate);
   if (objectTemplateData) {
     // objectTemplateData was set by itself in the below 'else'
-    LWNODE_CHECK(objectTemplateData->isObjectTemplateData());
     LWNODE_CALL_TRACE_ID_LOG(EXTRADATA,
                              "InstanceTemplate(%p): Existing ExtraData: %p",
                              esObjectTemplate,
                              objectTemplateData);
   } else {
-    auto objectTemplateData = new ObjectTemplateData(esFunctionTemplate);
+    auto objectTemplateData = new ObjectTemplateData(scope.self());
     LWNODE_CALL_TRACE_ID_LOG(
         EXTRADATA,
         "FunctionTemplate(%p)::InstanceTemplate(%p): New ExtarData: %p",
-        esFunctionTemplate,
+        scope.self(),
         esObjectTemplate,
         objectTemplateData);
     ExtraDataHelper::setExtraData(esObjectTemplate, objectTemplateData);
@@ -347,18 +362,16 @@ Local<ObjectTemplate> FunctionTemplate::InstanceTemplate() {
 }
 
 void FunctionTemplate::SetLength(int length) {
-  FunctionTemplateRef* self = CVAL(this)->ftpl();
-  self->setLength(length);
+  EsScopeFunctionTemplate scope(this);
+  scope.self()->setLength(length);
 }
 
 void FunctionTemplate::SetClassName(Local<String> name) {
-  auto lwIsolate = IsolateWrap::GetCurrent();
-  auto lwContext = lwIsolate->GetCurrentContext();
-  FunctionTemplateRef* self = CVAL(this)->ftpl();
+  EsScopeFunctionTemplate scope(this);
   auto esName = CVAL(*name)->value()->asString();
 
   auto r = Evaluator::execute(
-      lwContext->get(),
+      scope.context(),
       [](ExecutionStateRef* esState,
          FunctionTemplateRef* esFunctionTemplate,
          StringRef* esName) -> ValueRef* {
@@ -366,7 +379,7 @@ void FunctionTemplate::SetClassName(Local<String> name) {
             AtomicStringRef::create(esState->context(), esName));
         return ValueRef::createNull();
       },
-      self,
+      scope.self(),
       esName);
   LWNODE_CHECK(r.isSuccessful());
 }
@@ -385,17 +398,15 @@ void FunctionTemplate::RemovePrototype() {
 
 // Returns a unique function instance in the "current execution context"
 MaybeLocal<v8::Function> FunctionTemplate::GetFunction(Local<Context> context) {
-  API_ENTER_WITH_CONTEXT(context, MaybeLocal<Function>(), TEMPLATE);
-  auto esContext = lwIsolate->GetCurrentContext()->get();
-  auto esFunctionTemplate = CVAL(this)->ftpl();
-
-  auto esFunction = esFunctionTemplate->instantiate(esContext);
-  auto functionTemplateData = ExtraDataHelper::getExtraData(esFunctionTemplate)
-                                  ->asFunctionTemplateData();
+  API_ENTER_AND_EXIT_IF_TERMINATING(
+      EsScopeFunctionTemplate, context, MaybeLocal<Function>());
+  auto esFunction = scope.self()->instantiate(scope.context());
+  auto functionTemplateData =
+      ExtraDataHelper::getFunctionTemplateExtraData(scope.self());
 
   LWNODE_CALL_TRACE_ID_LOG(EXTRADATA,
                            "FunctionTemplate(%p)::GetFunction(%p)",
-                           esFunctionTemplate,
+                           scope.self(),
                            esFunction);
 
   auto functionData = ExtraDataHelper::getExtraData(esFunction);
@@ -403,18 +414,18 @@ MaybeLocal<v8::Function> FunctionTemplate::GetFunction(Local<Context> context) {
     LWNODE_CALL_TRACE_ID_LOG(
         EXTRADATA,
         "FunctionTemplate(%p)::GetFunction(%p): Existing functionData: %p",
-        esFunctionTemplate,
+        scope.self(),
         esFunction,
         functionData);
     if (functionData->isFunctionTemplateData()) {
       // This functionData was created by FunctionTemplate::New(), and
       // FunctionTemplateData was set in esFunction. We need to replace it with
       // a new FunctionData
-      auto newFunctionData = new FunctionData(esFunctionTemplate);
+      auto newFunctionData = new FunctionData(scope.self());
       LWNODE_CALL_TRACE_ID_LOG(
           EXTRADATA,
           "FunctionTemplate(%p)::GetFunction(%p): New functionData: %p",
-          esFunctionTemplate,
+          scope.self(),
           esFunction,
           newFunctionData);
       ExtraDataHelper::setExtraData(
@@ -429,7 +440,7 @@ MaybeLocal<v8::Function> FunctionTemplate::GetFunction(Local<Context> context) {
     LWNODE_CHECK(false);
   }
 
-  return Utils::NewLocal<Function>(lwIsolate->toV8(), esFunction);
+  return Utils::NewLocal<Function>(scope.v8Isolate(), esFunction);
 }
 
 MaybeLocal<v8::Object> FunctionTemplate::NewRemoteInstance() {
@@ -437,21 +448,20 @@ MaybeLocal<v8::Object> FunctionTemplate::NewRemoteInstance() {
 }
 
 bool FunctionTemplate::HasInstance(v8::Local<v8::Value> value) {
+  EsScopeFunctionTemplate scope(this);
   LWNODE_CALL_TRACE();
-  auto esSelf = CVAL(this)->ftpl();
   LWNODE_CALL_TRACE_ID_LOG(EXTRADATA,
                            "FunctionTemplate(%p)::HasInstance(): %p",
-                           CVAL(this)->ftpl(),
-                           CVAL(*value)->value()->asObject());
+                           scope.self(),
+                           scope.asValue(value)->asObject());
   LWNODE_CALL_TRACE_ID_LOG(
       EXTRADATA,
-      "FunctionTemplate(%p)::HasInstance: ExtraData: %p, %p?",
-      esSelf,
-      ExtraDataHelper::getExtraData(CVAL(this)->ftpl()),
-      ExtraDataHelper::getExtraData(CVAL(*value)->value()->asObject()));
+      "FunctionTemplate(%p)::HasInstance: ExtraData: %p, %p",
+      scope.self(),
+      ExtraDataHelper::getFunctionTemplateExtraData(scope.self()),
+      ExtraDataHelper::getExtraData(scope.asValue(value)->asObject()));
 
-  auto esContext = IsolateWrap::GetCurrent()->GetCurrentContext()->get();
-  auto esValue = CVAL(*value)->value();
+  auto esValue = scope.asValue(value);
   if (!esValue->isObject()) {
     return false;
   }
@@ -467,13 +477,12 @@ bool FunctionTemplate::HasInstance(v8::Local<v8::Value> value) {
     LWNODE_CALL_TRACE_ID_LOG(
         EXTRADATA,
         "FunctionTemplate(%p)::HasInstance: Existing ExtraData: %p",
-        esSelf,
+        scope.self(),
         extraData->asObjectData());
 
     if (extraData->asObjectData()->objectTemplate()) {
-      auto objectTemplateData = ExtraDataHelper::getExtraData(
-                                    extraData->asObjectData()->objectTemplate())
-                                    ->asObjectTemplateData();
+      auto objectTemplateData = ExtraDataHelper::getObjectTemplateExtraData(
+          extraData->asObjectData()->objectTemplate());
       esOtherFunctionTemplate = objectTemplateData->functionTemplate();
     }
   } else if (extraData->isObjectTemplateData()) {
@@ -483,8 +492,10 @@ bool FunctionTemplate::HasInstance(v8::Local<v8::Value> value) {
     LWNODE_CHECK(false);
   }
 
-  for (auto p = esOtherFunctionTemplate; p; p = p->parent().value()) {
-    if (esSelf == p) {
+  for (auto functionTemplate = esOtherFunctionTemplate;
+       functionTemplate != nullptr;
+       functionTemplate = functionTemplate->parent().value()) {
+    if (scope.self() == functionTemplate) {
       return true;
     }
   }
@@ -591,275 +602,247 @@ void ObjectTemplate::SetAccessor(v8::Local<Name> name,
                                    attribute);
 }
 
-struct HandlerConfiguration : public gc {
-  HandlerConfiguration(
-      v8::Isolate* isolate,
-      const v8::NamedPropertyHandlerConfiguration& namedPropertyHandler)
-      : m_isolate(isolate), m_namedPropertyHandler(namedPropertyHandler) {}
-  v8::Isolate* m_isolate;
-  v8::NamedPropertyHandlerConfiguration m_namedPropertyHandler;
+class NamePropertyPolicy {
+ public:
+  static Local<Name> getPropertyName(ExecutionStateRef* state,
+                                     ValueRef* value) {
+    return Utils::ToLocal<Name>(value);
+  }
 };
 
-void ObjectTemplate::SetHandler(
-    const NamedPropertyHandlerConfiguration& config) {
-  ObjectTemplateRef* esObjectTemplate = CVAL(this)->otpl();
-  HandlerConfiguration* handlerConfiguration =
-      new HandlerConfiguration(IsolateWrap::GetCurrent()->toV8(), config);
-
-  ObjectTemplateNamedPropertyHandlerData esHandlerData;
-  if (config.getter) {
-    esHandlerData.getter = [](ExecutionStateRef* state,
-                              ObjectRef* esSelf,
-                              ValueRef* esReceiver,
-                              void* data,
-                              ValueRef* propertyName) -> OptionalRef<ValueRef> {
-      auto handlerConfiguration = reinterpret_cast<HandlerConfiguration*>(data);
-
-      if (!handlerConfiguration->m_namedPropertyHandler.getter) {
-        return Escargot::OptionalRef<Escargot::ValueRef>();
-      }
-
-      Local<Name> v8PropertyName = Utils::ToLocal<Name>(propertyName);
-
-      PropertyCallbackInfoWrap<v8::Value> info(
-          handlerConfiguration->m_isolate,
-          esSelf,
-          esReceiver,
-          VAL(*handlerConfiguration->m_namedPropertyHandler.data));
+class IndexPropertyPolicy {
+ public:
+  static uint32_t getPropertyName(ExecutionStateRef* state, ValueRef* value) {
+    auto index = value->tryToUseAsIndexProperty(state);
+    LWNODE_DCHECK(index != ValueRef::InvalidIndexPropertyValue);
+    return index;
+  }
+};
 
-      handlerConfiguration->m_namedPropertyHandler.getter(v8PropertyName, info);
+template <typename T>
+struct ObjectTemplateLocalData : public gc {
+ public:
+  ObjectTemplateLocalData(v8::Isolate* isolate,
+                          const T& propertyHandlerConfiguration)
+      : isolate(isolate), config(propertyHandlerConfiguration) {}
 
-      if (info.hasReturnValue()) {
-        Local<Value> ret = info.GetReturnValue().Get();
-        return CVAL(*ret)->value();
-      }
+  v8::Isolate* isolate{nullptr};
+  T config;
+};
 
-      return Escargot::OptionalRef<Escargot::ValueRef>();
-    };
+template <typename T, typename GetPropertyNamePolicy>
+class ObjectTemplateSetHandlerCallbackHelper {
+ public:
+  static void applyHelper(
+      const T& v8Config, ObjectTemplatePropertyHandlerConfiguration& esConfig) {
+    esConfig.getter = v8Config.getter ? getterCallback : nullptr;
+    esConfig.setter = v8Config.setter ? setterCallback : nullptr;
+    esConfig.query = v8Config.query ? queryCallback : nullptr;
+    esConfig.deleter = v8Config.deleter ? deleterCallback : nullptr;
+    esConfig.enumerator = v8Config.enumerator ? enumeratorCallback : nullptr;
+    esConfig.definer = v8Config.definer ? definerCallback : nullptr;
+    esConfig.descriptor = v8Config.descriptor ? descriptorCallback : nullptr;
   }
 
-  if (config.setter) {
-    esHandlerData.setter = [](ExecutionStateRef* state,
-                              ObjectRef* esSelf,
-                              ValueRef* esReceiver,
-                              void* data,
-                              ValueRef* propertyName,
-                              ValueRef* esValue) -> OptionalRef<ValueRef> {
-      auto handlerConfiguration = reinterpret_cast<HandlerConfiguration*>(data);
+  static ObjectTemplateLocalData<T>* getHelperData(void* data) {
+    LWNODE_DCHECK_NOT_NULL(data);
+    return reinterpret_cast<ObjectTemplateLocalData<T>*>(data);
+  }
 
-      if (!handlerConfiguration->m_namedPropertyHandler.setter) {
-        return Escargot::OptionalRef<Escargot::ValueRef>();
-      }
+  static OptionalRef<ValueRef> getterCallback(ExecutionStateRef* state,
+                                              ObjectRef* esSelf,
+                                              ValueRef* esReceiver,
+                                              void* data,
+                                              ValueRef* propertyName) {
+    auto helperData = getHelperData(data);
 
-      Local<Name> v8PropertyName = v8::Utils::ToLocal<Name>(propertyName);
-
-      PropertyCallbackInfoWrap<v8::Value> info(
-          handlerConfiguration->m_isolate,
-          esSelf,
-          esReceiver,
-          VAL(*handlerConfiguration->m_namedPropertyHandler.data));
-
-      handlerConfiguration->m_namedPropertyHandler.setter(
-          v8PropertyName, v8::Utils::ToLocal<Value>(esValue), info);
-
-      if (info.hasReturnValue()) {
-        Local<Value> ret = info.GetReturnValue().Get();
-        if (ret->IsFalse()) {
-          return Escargot::OptionalRef<Escargot::ValueRef>(
-              ValueRef::create(false));
-        }
-        return Escargot::OptionalRef<Escargot::ValueRef>(
-            ValueRef::create(true));
-      }
+    PropertyCallbackInfoWrap<v8::Value> info(
+        helperData->isolate, esSelf, esReceiver, VAL(*helperData->config.data));
 
-      return Escargot::OptionalRef<Escargot::ValueRef>();
-    };
-  }
+    LWNODE_DCHECK_NOT_NULL(helperData->config.getter);
+    helperData->config.getter(
+        GetPropertyNamePolicy::getPropertyName(state, propertyName), info);
 
-  if (config.query) {
-    esHandlerData.query =
-        [](ExecutionStateRef* state,
-           ObjectRef* esSelf,
-           ValueRef* esReceiver,
-           void* data,
-           ValueRef* propertyName) -> TemplatePropertyAttribute {
-      auto handlerConfiguration = reinterpret_cast<HandlerConfiguration*>(data);
+    if (info.hasReturnValue()) {
+      return CVAL(*info.GetReturnValue().Get())->value();
+    }
 
-      if (!handlerConfiguration->m_namedPropertyHandler.query) {
-        return TemplatePropertyAttribute::TemplatePropertyAttributeNotExist;
-      }
+    return OptionalRef<ValueRef>();
+  }
 
-      Local<Name> v8PropertyName = v8::Utils::ToLocal<Name>(propertyName);
-
-      PropertyCallbackInfoWrap<Integer> info(
-          handlerConfiguration->m_isolate,
-          esSelf,
-          esReceiver,
-          VAL(*handlerConfiguration->m_namedPropertyHandler.data));
-
-      handlerConfiguration->m_namedPropertyHandler.query(v8PropertyName, info);
-      Local<Value> ret = info.GetReturnValue().Get();
-      if (info.hasReturnValue()) {
-        bool hasNone = (handlerConfiguration->m_namedPropertyHandler.flags ==
-                        PropertyHandlerFlags::kNone);
-        bool hasNoSideEffect =
-            (static_cast<int>(
-                 handlerConfiguration->m_namedPropertyHandler.flags) &
-             static_cast<int>(PropertyHandlerFlags::kHasNoSideEffect));
-
-        if (hasNone) {
-          return TemplatePropertyAttribute::TemplatePropertyAttributeExist;
-        } else if (hasNoSideEffect) {
-          return TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable;
-        } else {
-          LWNODE_UNIMPLEMENT;
-        }
-        return TemplatePropertyAttribute::TemplatePropertyAttributeExist;
+  static OptionalRef<ValueRef> setterCallback(ExecutionStateRef* state,
+                                              ObjectRef* esSelf,
+                                              ValueRef* esReceiver,
+                                              void* data,
+                                              ValueRef* propertyName,
+                                              ValueRef* esValue) {
+    auto helperData = getHelperData(data);
+
+    PropertyCallbackInfoWrap<v8::Value> info(
+        helperData->isolate, esSelf, esReceiver, VAL(*helperData->config.data));
+
+    LWNODE_DCHECK_NOT_NULL(helperData->config.setter);
+    helperData->config.setter(
+        GetPropertyNamePolicy::getPropertyName(state, propertyName),
+        v8::Utils::ToLocal<Value>(esValue),
+        info);
+
+    if (info.hasReturnValue()) {
+      if (info.GetReturnValue().Get()->IsFalse()) {
+        return OptionalRef<ValueRef>(ValueRef::create(false));
       }
+      return OptionalRef<ValueRef>(ValueRef::create(true));
+    }
 
-      return TemplatePropertyAttribute::TemplatePropertyAttributeNotExist;
-    };
+    return OptionalRef<ValueRef>();
   }
 
-  if (config.deleter) {
-    esHandlerData.deleter =
-        [](ExecutionStateRef* state,
-           ObjectRef* esSelf,
-           ValueRef* esReceiver,
-           void* data,
-           ValueRef* propertyName) -> OptionalRef<ValueRef> {
-      auto handlerConfiguration = reinterpret_cast<HandlerConfiguration*>(data);
-
-      if (!handlerConfiguration->m_namedPropertyHandler.deleter) {
-        return Escargot::OptionalRef<Escargot::ValueRef>();
+  static ObjectTemplatePropertyAttribute queryCallback(ExecutionStateRef* state,
+                                                       ObjectRef* esSelf,
+                                                       ValueRef* esReceiver,
+                                                       void* data,
+                                                       ValueRef* propertyName) {
+    auto helperData = getHelperData(data);
+
+    PropertyCallbackInfoWrap<v8::Integer> info(
+        helperData->isolate, esSelf, esReceiver, VAL(*helperData->config.data));
+
+    LWNODE_DCHECK_NOT_NULL(helperData->config.query);
+    helperData->config.query(
+        GetPropertyNamePolicy::getPropertyName(state, propertyName), info);
+
+    if (info.hasReturnValue()) {
+      bool hasNone = (helperData->config.flags == PropertyHandlerFlags::kNone);
+      bool hasNoSideEffect =
+          (static_cast<int>(helperData->config.flags) &
+           static_cast<int>(PropertyHandlerFlags::kHasNoSideEffect));
+
+      if (hasNone) {
+        return ObjectTemplatePropertyAttribute::PropertyAttributeExist;
+      } else if (hasNoSideEffect) {
+        return ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable;
+      } else {
+        LWNODE_UNIMPLEMENT;
       }
+      return ObjectTemplatePropertyAttribute::PropertyAttributeExist;
+    }
+
+    return ObjectTemplatePropertyAttribute::PropertyAttributeNotExist;
+  }
 
-      Local<Name> v8PropertyName = v8::Utils::ToLocal<Name>(propertyName);
+  static OptionalRef<ValueRef> deleterCallback(ExecutionStateRef* state,
+                                               ObjectRef* esSelf,
+                                               ValueRef* esReceiver,
+                                               void* data,
+                                               ValueRef* propertyName) {
+    auto helperData = getHelperData(data);
 
-      PropertyCallbackInfoWrap<v8::Boolean> info(
-          handlerConfiguration->m_isolate,
-          esSelf,
-          esReceiver,
-          VAL(*handlerConfiguration->m_namedPropertyHandler.data));
+    PropertyCallbackInfoWrap<v8::Boolean> info(
+        helperData->isolate, esSelf, esReceiver, VAL(*helperData->config.data));
 
-      handlerConfiguration->m_namedPropertyHandler.deleter(v8PropertyName,
-                                                           info);
+    LWNODE_DCHECK_NOT_NULL(helperData->config.deleter);
+    helperData->config.deleter(
+        GetPropertyNamePolicy::getPropertyName(state, propertyName), info);
 
-      if (info.hasReturnValue()) {
-        Local<Value> ret = info.GetReturnValue().Get();
-        return CVAL(*ret)->value();
-      }
+    if (info.hasReturnValue()) {
+      return CVAL(*info.GetReturnValue().Get())->value();
+    }
 
-      return Escargot::OptionalRef<Escargot::ValueRef>();
-    };
+    return OptionalRef<ValueRef>();
   }
 
-  if (config.enumerator) {
-    esHandlerData.enumerator = [](ExecutionStateRef* state,
-                                  ObjectRef* esSelf,
-                                  ValueRef* esReceiver,
-                                  void* data) -> ValueVectorRef* {
-      auto handlerConfiguration = reinterpret_cast<HandlerConfiguration*>(data);
-
-      if (!handlerConfiguration->m_namedPropertyHandler.enumerator) {
-        return ValueVectorRef::create(0);
-      }
+  static ValueVectorRef* enumeratorCallback(ExecutionStateRef* state,
+                                            ObjectRef* esSelf,
+                                            ValueRef* esReceiver,
+                                            void* data) {
+    auto helperData = getHelperData(data);
 
-      PropertyCallbackInfoWrap<v8::Array> info(
-          handlerConfiguration->m_isolate,
-          esSelf,
-          esReceiver,
-          VAL(*handlerConfiguration->m_namedPropertyHandler.data));
+    PropertyCallbackInfoWrap<v8::Array> info(
+        helperData->isolate, esSelf, esReceiver, VAL(*helperData->config.data));
 
-      handlerConfiguration->m_namedPropertyHandler.enumerator(info);
+    LWNODE_DCHECK_NOT_NULL(helperData->config.enumerator);
+    helperData->config.enumerator(info);
 
-      if (info.hasReturnValue()) {
-        Local<Value> ret = info.GetReturnValue().Get();
-        auto esArray = CVAL(*ret)->value()->asArrayObject();
-        auto length = esArray->length(state);
-        auto v = ValueVectorRef::create(length);
+    if (info.hasReturnValue()) {
+      auto esArray =
+          CVAL(*info.GetReturnValue().Get())->value()->asArrayObject();
+      auto length = esArray->length(state);
+      auto vector = ValueVectorRef::create(length);
 
-        for (size_t i = 0; i < length; i++) {
-          v->set(i, esArray->get(state, ValueRef::create(i))->toString(state));
-        }
-        return v;
+      for (size_t i = 0; i < length; i++) {
+        vector->set(i,
+                    esArray->get(state, ValueRef::create(i))->toString(state));
       }
+      return vector;
+    }
 
-      return ValueVectorRef::create(0);
-    };
+    return ValueVectorRef::create(0);
   }
 
-  if (config.definer) {
-    esHandlerData.definer =
-        [](ExecutionStateRef* state,
-           ObjectRef* esSelf,
-           ValueRef* esReceiver,
-           void* data,
-           ValueRef* propertyName,
-           const ObjectPropertyDescriptorRef& esDesc) -> OptionalRef<ValueRef> {
-      auto handlerConfiguration = reinterpret_cast<HandlerConfiguration*>(data);
+  static OptionalRef<ValueRef> definerCallback(
+      ExecutionStateRef* state,
+      ObjectRef* esSelf,
+      ValueRef* esReceiver,
+      void* data,
+      ValueRef* propertyName,
+      const ObjectPropertyDescriptorRef& esDescriptor) {
+    auto helperData = getHelperData(data);
+
+    PropertyCallbackInfoWrap<v8::Value> info(
+        helperData->isolate, esSelf, esReceiver, VAL(*helperData->config.data));
+
+    PropertyDescriptor descriptor;
+    descriptor.get_private()->setDescriptor(
+        const_cast<ObjectPropertyDescriptorRef*>(&esDescriptor));
+
+    LWNODE_DCHECK_NOT_NULL(helperData->config.definer);
+    helperData->config.definer(
+        GetPropertyNamePolicy::getPropertyName(state, propertyName),
+        descriptor,
+        info);
+
+    if (info.hasReturnValue()) {
+      return OptionalRef<ValueRef>(CVAL(*info.GetReturnValue().Get())->value());
+    }
+    return OptionalRef<ValueRef>();
+  }
 
-      if (!handlerConfiguration->m_namedPropertyHandler.definer) {
-        return Escargot::OptionalRef<Escargot::ValueRef>();
-      }
+  static OptionalRef<ValueRef> descriptorCallback(ExecutionStateRef* state,
+                                                  ObjectRef* esSelf,
+                                                  ValueRef* esReceiver,
+                                                  void* data,
+                                                  ValueRef* propertyName) {
+    auto helperData = getHelperData(data);
 
-      Local<Name> v8PropertyName = v8::Utils::ToLocal<Name>(propertyName);
+    PropertyCallbackInfoWrap<v8::Value> info(
+        helperData->isolate, esSelf, esReceiver, VAL(*helperData->config.data));
 
-      PropertyCallbackInfoWrap<v8::Value> info(
-          handlerConfiguration->m_isolate,
-          esSelf,
-          esReceiver,
-          VAL(*handlerConfiguration->m_namedPropertyHandler.data));
+    LWNODE_DCHECK_NOT_NULL(helperData->config.descriptor);
+    helperData->config.descriptor(
+        GetPropertyNamePolicy::getPropertyName(state, propertyName), info);
 
-      PropertyDescriptor desc;
-      desc.get_private()->setDescriptor(
-          const_cast<ObjectPropertyDescriptorRef*>(&esDesc));
-      handlerConfiguration->m_namedPropertyHandler.definer(
-          v8PropertyName, desc, info);
+    if (info.hasReturnValue()) {
+      return OptionalRef<ValueRef>(CVAL(*info.GetReturnValue().Get())->value());
+    }
 
-      if (info.hasReturnValue()) {
-        Local<Value> ret = info.GetReturnValue().Get();
-        return Escargot::OptionalRef<Escargot::ValueRef>(CVAL(*ret)->value());
-      }
-      return Escargot::OptionalRef<Escargot::ValueRef>();
-    };
+    return OptionalRef<ValueRef>();
   }
+};
 
-  if (config.descriptor) {
-    esHandlerData.descriptor =
-        [](ExecutionStateRef* state,
-           ObjectRef* esSelf,
-           ValueRef* esReceiver,
-           void* data,
-           ValueRef* propertyName) -> OptionalRef<ValueRef> {
-      auto handlerConfiguration = reinterpret_cast<HandlerConfiguration*>(data);
-
-      if (!handlerConfiguration->m_namedPropertyHandler.descriptor) {
-        return Escargot::OptionalRef<Escargot::ValueRef>();
-      }
-
-      Local<Name> v8PropertyName = v8::Utils::ToLocal<Name>(propertyName);
-
-      PropertyCallbackInfoWrap<v8::Value> info(
-          handlerConfiguration->m_isolate,
-          esSelf,
-          esReceiver,
-          VAL(*handlerConfiguration->m_namedPropertyHandler.data));
+void ObjectTemplate::SetHandler(
+    const NamedPropertyHandlerConfiguration& config) {
+  EsScopeObjectTemplate scope(this);
 
-      handlerConfiguration->m_namedPropertyHandler.descriptor(v8PropertyName,
-                                                              info);
+  ObjectTemplatePropertyHandlerConfiguration esConfig;
+  esConfig.data =
+      new ObjectTemplateLocalData<NamedPropertyHandlerConfiguration>(
+          IsolateWrap::GetCurrent()->toV8(), config);
 
-      if (info.hasReturnValue()) {
-        Local<Value> ret = info.GetReturnValue().Get();
-        return Escargot::OptionalRef<Escargot::ValueRef>(CVAL(*ret)->value());
-      }
+  ObjectTemplateSetHandlerCallbackHelper<
+      NamedPropertyHandlerConfiguration,
+      NamePropertyPolicy>::applyHelper(config, esConfig);
 
-      return Escargot::OptionalRef<Escargot::ValueRef>();
-    };
-  }
-
-  esHandlerData.data = handlerConfiguration;
-  esObjectTemplate->setNamedPropertyHandler(esHandlerData);
+  scope.self()->setNamedPropertyHandler(esConfig);
 }
 
 void ObjectTemplate::MarkAsUndetectable() {
@@ -881,7 +864,18 @@ void ObjectTemplate::SetAccessCheckCallbackAndHandler(
 
 void ObjectTemplate::SetHandler(
     const IndexedPropertyHandlerConfiguration& config) {
-  LWNODE_RETURN_VOID;
+  EsScopeObjectTemplate scope(this);
+
+  ObjectTemplatePropertyHandlerConfiguration esConfig;
+  esConfig.data =
+      new ObjectTemplateLocalData<IndexedPropertyHandlerConfiguration>(
+          IsolateWrap::GetCurrent()->toV8(), config);
+
+  ObjectTemplateSetHandlerCallbackHelper<
+      IndexedPropertyHandlerConfiguration,
+      IndexPropertyPolicy>::applyHelper(config, esConfig);
+
+  scope.self()->setIndexedPropertyHandler(esConfig);
 }
 
 void ObjectTemplate::SetCallAsFunctionHandler(FunctionCallback callback,
@@ -890,18 +884,19 @@ void ObjectTemplate::SetCallAsFunctionHandler(FunctionCallback callback,
 }
 
 int ObjectTemplate::InternalFieldCount() {
-  auto esObjectTemplate = CVAL(this)->otpl();
-  return ObjectTemplateRefHelper::getInternalFieldCount(esObjectTemplate);
+  EsScopeObjectTemplate scope(this);
+  return ObjectTemplateRefHelper::getInternalFieldCount(scope.self());
 }
 
 void ObjectTemplate::SetInternalFieldCount(int value) {
-  auto esObjectTemplate = CVAL(this)->otpl();
-  if (esObjectTemplate->didInstantiate()) {
+  EsScopeObjectTemplate scope(this);
+
+  if (scope.self()->didInstantiate()) {
     LWNODE_DLOG_WARN(
         "Don't modify internal field count after instantiating object");
     return;
   }
-  ObjectTemplateRefHelper::setInternalFieldCount(esObjectTemplate, value);
+  ObjectTemplateRefHelper::setInternalFieldCount(scope.self(), value);
 }
 
 bool ObjectTemplate::IsImmutableProto() {
@@ -913,18 +908,17 @@ void ObjectTemplate::SetImmutableProto() {
 }
 
 MaybeLocal<v8::Object> ObjectTemplate::NewInstance(Local<Context> context) {
-  API_ENTER_WITH_CONTEXT(context, MaybeLocal<v8::Object>(), TEMPLATE);
-  auto esContext = VAL(*context)->context()->get();
-  auto esObjectTemplate = CVAL(this)->otpl();
+  API_ENTER_AND_EXIT_IF_TERMINATING(
+      EsScopeObjectTemplate, context, MaybeLocal<v8::Object>());
 
-  auto esNewObject = esObjectTemplate->instantiate(esContext);
+  auto esNewObject = scope.self()->instantiate(scope.context());
   LWNODE_CALL_TRACE_ID_LOG(EXTRADATA,
                            "ObjectTemplate(%p)::NewInstance(): %p",
-                           esObjectTemplate,
+                           scope.self(),
                            esNewObject);
 
   auto objectTemplateData =
-      ExtraDataHelper::getExtraData(esObjectTemplate)->asObjectTemplateData();
+      ExtraDataHelper::getObjectTemplateExtraData(scope.self());
 
   auto objectData = ObjectRefHelper::getExtraData(esNewObject);
   if (objectData) {
@@ -934,19 +928,19 @@ MaybeLocal<v8::Object> ObjectTemplate::NewInstance(Local<Context> context) {
     LWNODE_CALL_TRACE_ID_LOG(
         EXTRADATA,
         "ObjectTemplate(%p)::NewInstance(): Existing Data: %p",
-        esObjectTemplate,
+        scope.self(),
         objectData);
-    auto objectData = objectTemplateData->createObjectData(esObjectTemplate);
+    auto objectData = objectTemplateData->createObjectData(scope.self());
     LWNODE_CALL_TRACE_ID_LOG(
         EXTRADATA,
         "ObjectTemplate(%p)::NewInstance() New objectData: %p",
-        esObjectTemplate,
+        scope.self(),
         objectData);
     ObjectRefHelper::setExtraData(esNewObject, objectData, true);
   } else {
     LWNODE_CHECK(false);
   }
 
-  return Utils::NewLocal<Object>(lwIsolate->toV8(), esNewObject);
+  return Utils::NewLocal<Object>(scope.v8Isolate(), esNewObject);
 }
 }  // namespace v8
index a7733608ec2135bf15e249a61835a1c97b8c9521..8493f5ac70fb4529f155a18ade07b37ddc38376f 100644 (file)
 // found in the LICENSE file.
 
 #include "api.h"
+
+#include <malloc.h>  // for malloc_trim
+#include <cstdlib>
 #include <sstream>
+
+#include "api/global.h"
 #include "base.h"
 
 using namespace Escargot;
@@ -154,92 +159,120 @@ void V8::SetFlagsFromString(const char* str, size_t length) {
 }
 
 void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
-  flag_t flags = FlagType::Empty;
+  flag_t userOptions = Flag::Type::Empty;
 
   for (int i = 1; i < *argc; i++) {
-    char* arg = argv[i];
-    bool checked = false;
-
-    if (strEquals("--expose-gc", arg) || strEquals("--expose_gc", arg)) {
-      flags |= FlagType::ExposeGC;
-      checked = true;
-    } else if (strEquals("--use-strict", arg) ||
-               strEquals("--use_strict", arg)) {
-      flags |= FlagType::UseStrict;
-      checked = true;
-    } else if (strEquals("--off-idlegc", arg) ||
-               strEquals("--off_idlegc", arg)) {
-      flags |= FlagType::DisableIdleGC;
-      checked = true;
-    } else if (strEquals("--harmony-top-level-await", arg)) {
-      // @check https://github.sec.samsung.net/lws/node-escargot/issues/394
-      flags |= FlagType::TopLevelWait;
-      checked = true;
-    } else if (strEquals("--trace-gc", arg)) {
-      flags |= FlagType::TraceGC;
-      checked = true;
-    } else if (strStartsWith(arg, "--trace-call")) {
-      flags |= FlagType::TraceCall;
-      checked = true;
-
-      std::string str(arg);
-      std::string::size_type pos = str.find_first_of('=');
-      if (std::string::npos != pos) {
-        std::stringstream ss(str.substr(pos + 1));  // +1 for skipping =
-        std::string token;
-        while (std::getline(ss, token, ',')) {
-          if (token.find('-') == 0) {
-            Flags::setNagativeTraceCallId(token.substr(1));
-          } else {
-            Flags::setTraceCallId(token);
-          }
-        }
-      }
-    } else if (strEquals("--internal-log", arg)) {
-      flags |= FlagType::InternalLog;
-      checked = true;
-    } else if (remove_flags && (strStartsWith(arg, "--debug") ||
-                                strStartsWith(arg, "--stack-size=") ||
-                                strStartsWith(arg, "--nolazy") ||
-                                strStartsWith(arg, "--trace_debug"))) {
-      checked = true;
-    } else {
-      LWNODE_DLOG_WARN("'%s' flag is ignored", arg);
-    }
+    std::string userOption = argv[i];
+    bool isValidToRemove = false;
+
+    EscargotShim::Global::flags()->add(userOption);
 
-    if (checked && remove_flags) {
+    if (remove_flags) {
       argv[i] = nullptr;
     }
   }
 
-  Flags::set(flags);
-
   if (remove_flags) {
-    int count = 0;
-    for (int idx = 0; idx < *argc; idx++) {
-      if (argv[idx]) {
-        argv[count++] = argv[idx];
+    EscargotShim::Global::flags()->shrinkArgumentList(argc, argv);
+  }
+}
+
+// v8::Extension
+
+class ExtensionSourceString : public v8::String::ExternalOneByteStringResource {
+ public:
+  explicit ExtensionSourceString(const char* data)
+      : v8::String::ExternalOneByteStringResource(), data_(data) {}
+  virtual ~ExtensionSourceString() override {}
+
+  static void* operator new(size_t size) { return malloc(size); }
+  static void operator delete(void* ptr) { free(ptr); }
+
+  const char* data() const override { return data_; }
+  size_t length() const override { return strlen(data_); }
+
+ private:
+  const char* data_;
+};
+
+std::vector<std::unique_ptr<Extension>> RegisteredExtension::extensions;
+
+void RegisterExtension(std::unique_ptr<Extension> extension) {
+  RegisteredExtension::registerExtension(std::move(extension));
+}
+
+void RegisteredExtension::registerExtension(
+    std::unique_ptr<Extension> extension) {
+  extensions.push_back(std::move(extension));
+}
+
+void RegisteredExtension::unregisterAll() {
+  extensions.clear();
+}
+
+void RegisteredExtension::applyAll(ContextRef* context) {
+  for (auto& extension : extensions) {
+    if (isLwExtension(extension.get())) {
+      auto lwExtension = reinterpret_cast<LwExtension*>(extension.get());
+      if (lwExtension->isRegisteredExtension()) {
+        lwExtension->apply(context);
       }
+    } else {
+      applyV8Extension(context, extension.get());
     }
-    *argc = count;
   }
 }
 
-// RegisteredExtension* RegisteredExtension::first_extension_ = nullptr;
+bool RegisteredExtension::isLwExtension(Extension* extension) {
+  std::string name = extension->name();
+  return (name == "v8/externalize") || (name == "v8/gc");
+}
+
+void RegisteredExtension::applyV8Extension(ContextRef* context,
+                                           Extension* extension) {
+  if (extension->source() == nullptr ||
+      extension->source()->data() == nullptr) {
+    LWNODE_LOG_WARN("Extension empty string");
+    return;
+  }
+
+  std::string src = extension->source()->data();
+  std::string prefix = "native function ";
+  size_t prefixPosition = src.find(prefix.c_str());
+  if (prefixPosition == std::string::npos) {
+    EvalResultHelper::compileRun(context, extension->source()->data());
+    return;
+  }
 
-// RegisteredExtension::RegisteredExtension(std::unique_ptr<Extension>
-// extension)
-//     : extension_(std::move(extension)) {}
+  // Register v8 native function extension
+  auto lwIsolate = IsolateWrap::GetCurrent();
+  v8::Local<v8::String> str;
+  v8::Local<v8::FunctionTemplate> v8FunctionTemplate =
+      extension->GetNativeFunctionTemplate(lwIsolate->toV8(), str);
 
-// // static
-// void RegisteredExtension::Register(std::unique_ptr<Extension> extension) {
-//   LWNODE_RETURN_VOID;
-// }
+  auto esFunctionTemplate = CVAL(*v8FunctionTemplate)->ftpl();
+  src = src.substr(prefixPosition + prefix.length());
+  src = src.substr(0, src.find("("));
+  std::string name = src;
 
-// // static
-// void RegisteredExtension::UnregisterAll() {
-//   LWNODE_RETURN_VOID;
-// }
+  EvalResult r = Evaluator::execute(
+      context,
+      [](ExecutionStateRef* state,
+         std::string* name,
+         FunctionTemplateRef* functionTemplate) -> ValueRef* {
+        state->context()->globalObject()->defineDataProperty(
+            state,
+            StringRef::createFromASCII(name->c_str(), name->length()),
+            functionTemplate->instantiate(state->context()),
+            false,
+            false,
+            false);
+        return ValueRef::createUndefined();
+      },
+      &name,
+      esFunctionTemplate);
+  LWNODE_CHECK(r.isSuccessful());
+}
 
 Extension::Extension(const char* name,
                      const char* source,
@@ -253,9 +286,214 @@ Extension::Extension(const char* name,
       dep_count_(dep_count),
       deps_(deps),
       auto_enable_(false) {
-  LWNODE_UNIMPLEMENT;
+  if (source) {
+    source_ = new ExtensionSourceString(source);
+  }
 }
 
+// --expose-externalize-string
+
+ValueRef* ExternalizeStringExtension::externalizeStringCallback(
+    ExecutionStateRef* state,
+    ValueRef* thisValue,
+    size_t argc,
+    ValueRef** argv,
+    bool isConstructCall) {
+  if (argc > 0 && argv[0]->isString()) {
+    return argv[0]->asString();
+  }
+
+  return ValueRef::createUndefined();
+}
+
+ValueRef* ExternalizeStringExtension::isOneByteStringCallback(
+    ExecutionStateRef* state,
+    ValueRef* thisValue,
+    size_t argc,
+    ValueRef** argv,
+    bool isConstructCall) {
+  if (argc > 0 && argv[0]->isString()) {
+    return ValueRef::create(
+        StringRefHelper::isOneByteString(argv[0]->asString()));
+  }
+  return ValueRef::create(false);
+}
+
+// NOTE: --expose-externalize-string requires to define this dummy function
+// i.e., function x() { return 1; }
+ValueRef* ExternalizeStringExtension::xFunctionCallback(
+    ExecutionStateRef* state,
+    ValueRef* thisValue,
+    size_t argc,
+    ValueRef** argv,
+    bool isConstructCall) {
+  return ValueRef::create(1);
+}
+
+v8::Local<v8::FunctionTemplate>
+ExternalizeStringExtension::GetNativeFunctionTemplate(
+    v8::Isolate* isolate, v8::Local<v8::String> name) {
+  EsScope scope(isolate);
+  std::string functionName = scope.asValue(name)->toStdUTF8String();
+
+  FunctionTemplateRef* functionTemplate = nullptr;
+  if (functionName == "externalizeString") {
+    functionTemplate = createExternalizeString(scope.lwIsolate());
+  } else if (functionName == "isOneByteString") {
+    functionTemplate = createIsOneByteString(scope.lwIsolate());
+  } else {
+    functionTemplate = createXFunction(scope.lwIsolate());
+  }
+
+  return Utils::NewLocal(isolate, functionTemplate);
+}
+
+bool ExternalizeStringExtension::isRegisteredExtension() {
+  return EscargotShim::Global::flags()->isOn(
+      Flag::Type::ExposeExternalizeString);
+}
+
+void ExternalizeStringExtension::apply(ContextRef* context) {
+  ObjectRefHelper::addNativeFunction(
+      context,
+      context->globalObject(),
+      StringRef::createFromASCII("externalizeString"),
+      ExternalizeStringExtension::externalizeStringCallback);
+  ObjectRefHelper::addNativeFunction(
+      context,
+      context->globalObject(),
+      StringRef::createFromASCII("isOneByteString"),
+      ExternalizeStringExtension::isOneByteStringCallback);
+  ObjectRefHelper::addNativeFunction(
+      context,
+      context->globalObject(),
+      StringRef::createFromASCII("x"),
+      ExternalizeStringExtension::xFunctionCallback);
+}
+
+FunctionTemplateRef* ExternalizeStringExtension::createExternalizeString(
+    IsolateWrap* isolate) {
+  auto functionTemplate = FunctionTemplateRef::create(
+      AtomicStringRef::emptyAtomicString(),
+      1,
+      false,
+      false,
+      ExternalizeStringExtension::externalizeString);
+  auto extraData = new FunctionTemplateData(functionTemplate,
+                                            isolate->toV8(),
+                                            v8::FunctionCallback(),
+                                            nullptr,
+                                            nullptr);
+  ExtraDataHelper::setExtraData(functionTemplate, extraData);
+
+  return functionTemplate;
+}
+
+FunctionTemplateRef* ExternalizeStringExtension::createIsOneByteString(
+    IsolateWrap* isolate) {
+  auto functionTemplate =
+      FunctionTemplateRef::create(AtomicStringRef::emptyAtomicString(),
+                                  1,
+                                  false,
+                                  false,
+                                  ExternalizeStringExtension::isOneByteString);
+  auto extraData = new FunctionTemplateData(functionTemplate,
+                                            isolate->toV8(),
+                                            v8::FunctionCallback(),
+                                            nullptr,
+                                            nullptr);
+  ExtraDataHelper::setExtraData(functionTemplate, extraData);
+
+  return functionTemplate;
+}
+
+FunctionTemplateRef* ExternalizeStringExtension::createXFunction(
+    IsolateWrap* isolate) {
+  auto functionTemplate =
+      FunctionTemplateRef::create(AtomicStringRef::emptyAtomicString(),
+                                  1,
+                                  false,
+                                  false,
+                                  ExternalizeStringExtension::xFunction);
+  auto extraData = new FunctionTemplateData(functionTemplate,
+                                            isolate->toV8(),
+                                            v8::FunctionCallback(),
+                                            nullptr,
+                                            nullptr);
+  ExtraDataHelper::setExtraData(functionTemplate, extraData);
+
+  return functionTemplate;
+}
+
+// --expose-gc
+
+v8::Local<v8::FunctionTemplate>
+ExternalizeGcExtension::GetNativeFunctionTemplate(v8::Isolate* isolate,
+                                                  v8::Local<v8::String> name) {
+  EsScope scope(isolate);
+  std::string functionName = scope.asValue(name)->toStdUTF8String();
+
+  FunctionTemplateRef* gcFunctionTemplate = nullptr;
+  if (functionName == "gc") {
+    gcFunctionTemplate = createGcFunctionTemplate(scope.lwIsolate());
+  }
+
+  return Utils::NewLocal(isolate, gcFunctionTemplate);
+}
+
+FunctionTemplateRef* ExternalizeGcExtension::createGcFunctionTemplate(
+    EscargotShim::IsolateWrap* isolate) {
+  auto gcFunctionTemplate =
+      FunctionTemplateRef::create(AtomicStringRef::emptyAtomicString(),
+                                  1,
+                                  false,
+                                  false,
+                                  ExternalizeGcExtension::gc);
+  auto extraData = new FunctionTemplateData(gcFunctionTemplate,
+                                            isolate->toV8(),
+                                            v8::FunctionCallback(),
+                                            nullptr,
+                                            nullptr);
+
+  return gcFunctionTemplate;
+}
+
+ValueRef* ExternalizeGcExtension::gcCallback(ExecutionStateRef* state,
+                                             ValueRef* thisValue,
+                                             size_t argc,
+                                             ValueRef** argv,
+                                             bool isConstructCall) {
+  if (argc > 0) {
+    return ValueRef::createUndefined();
+  }
+
+  auto isolate = IsolateWrap::GetCurrent();
+  if (isolate) {
+    // cleanup gc objects and then delete native c++ objects
+    // that were linked to a gc object, but became dangling by
+    // the above gc
+    isolate->CollectGarbage();  // should release weak values
+  }
+
+  Escargot::Memory::gc();
+  malloc_trim(0);
+
+  return ValueRef::createUndefined();
+}
+
+bool ExternalizeGcExtension::isRegisteredExtension() {
+  return EscargotShim::Global::flags()->isOn(Flag::Type::ExposeGC);
+}
+
+void ExternalizeGcExtension::apply(ContextRef* context) {
+  ObjectRefHelper::addNativeFunction(context,
+                                     context->globalObject(),
+                                     StringRef::createFromASCII("gc"),
+                                     ExternalizeGcExtension::gcCallback);
+}
+
+// -------------------------
+
 void ResourceConstraints::ConfigureDefaultsFromHeapSize(
     size_t initial_heap_size_in_bytes, size_t maximum_heap_size_in_bytes) {
   LWNODE_RETURN_VOID;
@@ -287,7 +525,7 @@ i::Address* V8::GlobalizeReference(i::Isolate* isolate, i::Address* obj) {
   return reinterpret_cast<i::Address*>(persistent);
 #endif
 
-  IsolateWrap::fromV8(isolate)->globalHandles()->Create(VAL(obj));
+  IsolateWrap::fromV8(isolate)->global_handles()->create(VAL(obj));
   return obj;
 }
 
@@ -352,7 +590,8 @@ void* V8::ClearWeak(i::Address* location) {
 #if defined(LWNODE_ENABLE_EXPERIMENTAL)
   return GlobalHandles::ClearWeakness(VAL(location));
 #else
-  LWNODE_RETURN_NULLPTR;
+  LWNODE_ONCE(LWNODE_UNIMPLEMENT);
+  return nullptr;
 #endif
 }
 
index 496c4f18c66021834073815b9ff5ecdf3b46cee7..3dcc71cc18fbd11bfdf0c4f7a085295c383d79c8 100644 (file)
@@ -29,6 +29,7 @@
 #include "v8-util.h"
 
 #include "api/context.h"
+#include "api/error-message.h"
 #include "api/es-helper.h"
 #include "api/es-v8-helper.h"
 #include "api/extra-data.h"
@@ -38,6 +39,7 @@
 #include "api/isolate.h"
 #include "api/module.h"
 #include "api/object.h"
+#include "api/serializer.h"
 #include "api/utils/string-util.h"
 
 namespace i = v8::internal;
@@ -117,7 +119,7 @@ class Utils {
 };
 
 // @lwnode
-struct v8::PropertyDescriptor::PrivateData {
+class v8::PropertyDescriptor::PrivateData {
  public:
   PrivateData() = default;
   PrivateData(Escargot::ObjectPropertyDescriptorRef& esDescriptor);
@@ -130,11 +132,130 @@ struct v8::PropertyDescriptor::PrivateData {
   Escargot::ObjectPropertyDescriptorRef* descriptor() { return descriptor_; }
 
  private:
-  bool isExternalDescriptor{false};
+  bool isExternalDescriptor_{false};
   Escargot::ObjectPropertyDescriptorRef* descriptor_{nullptr};
 };
 // end @lwnode
 
+// v8 Extension
+class RegisteredExtension {
+ public:
+  static void registerExtension(std::unique_ptr<Extension> extension);
+  static void unregisterAll();
+  static void applyAll(ContextRef* context);
+
+ private:
+  explicit RegisteredExtension(Extension*) {}
+  explicit RegisteredExtension(std::unique_ptr<Extension>) {}
+
+  static bool isLwExtension(Extension* extension);
+  static void applyV8Extension(ContextRef* context, Extension* extension);
+
+  static std::vector<std::unique_ptr<Extension>> extensions;
+};
+
+class LwExtension : public v8::Extension {
+ public:
+  LwExtension(const char* name,
+              const char* source = nullptr,
+              int dep_count = 0,
+              const char** deps = nullptr,
+              int source_length = -1)
+      : v8::Extension(name, source, dep_count, deps, source_length) {}
+
+  v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
+      v8::Isolate* isolate, v8::Local<v8::String> name) override {
+    return Local<FunctionTemplate>();
+  };
+
+  virtual bool isRegisteredExtension() = 0;
+  virtual void apply(ContextRef* context) = 0;
+};
+
+class ExternalizeStringExtension : public LwExtension {
+ public:
+  ExternalizeStringExtension() : LwExtension("v8/externalize") {}
+  v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
+      v8::Isolate* isolate, v8::Local<v8::String> name) override;
+
+  bool isRegisteredExtension() override;
+  void apply(ContextRef* context) override;
+
+  FunctionTemplateRef* createExternalizeString(
+      EscargotShim::IsolateWrap* isolate);
+  FunctionTemplateRef* createIsOneByteString(
+      EscargotShim::IsolateWrap* isolate);
+  FunctionTemplateRef* createXFunction(EscargotShim::IsolateWrap* isolate);
+
+  static ValueRef* externalizeStringCallback(ExecutionStateRef* state,
+                                             ValueRef* thisValue,
+                                             size_t argc,
+                                             ValueRef** argv,
+                                             bool isConstructCall);
+  static ValueRef* externalizeString(ExecutionStateRef* state,
+                                     ValueRef* thisValue,
+                                     size_t argc,
+                                     ValueRef** argv,
+                                     OptionalRef<ObjectRef> newTarget) {
+    return externalizeStringCallback(state, thisValue, argc, argv, false);
+  }
+
+  static ValueRef* isOneByteStringCallback(ExecutionStateRef* state,
+                                           ValueRef* thisValue,
+                                           size_t argc,
+                                           ValueRef** argv,
+                                           bool isConstructCall);
+  static ValueRef* isOneByteString(ExecutionStateRef* state,
+                                   ValueRef* thisValue,
+                                   size_t argc,
+                                   ValueRef** argv,
+                                   OptionalRef<ObjectRef> newTarget) {
+    return isOneByteStringCallback(state, thisValue, argc, argv, false);
+  }
+
+  static ValueRef* xFunctionCallback(ExecutionStateRef* state,
+                                     ValueRef* thisValue,
+                                     size_t argc,
+                                     ValueRef** argv,
+                                     bool isConstructCall);
+  static ValueRef* xFunction(ExecutionStateRef* state,
+                             ValueRef* thisValue,
+                             size_t argc,
+                             ValueRef** argv,
+                             OptionalRef<ObjectRef> newTarget) {
+    return xFunctionCallback(state, thisValue, argc, argv, false);
+  }
+
+ private:
+};
+
+class ExternalizeGcExtension : public LwExtension {
+ public:
+  ExternalizeGcExtension() : LwExtension("v8/gc") {}
+  v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
+      v8::Isolate* isolate, v8::Local<v8::String> name) override;
+
+  bool isRegisteredExtension() override;
+  void apply(ContextRef* context) override;
+
+  FunctionTemplateRef* createGcFunctionTemplate(
+      EscargotShim::IsolateWrap* isolate);
+
+  static ValueRef* gcCallback(ExecutionStateRef* state,
+                              ValueRef* thisValue,
+                              size_t argc,
+                              ValueRef** argv,
+                              bool isConstructCall);
+
+  static ValueRef* gc(ExecutionStateRef* state,
+                      ValueRef* thisValue,
+                      size_t argc,
+                      ValueRef** argv,
+                      OptionalRef<ObjectRef> newTarget) {
+    return gcCallback(state, thisValue, argc, argv, false);
+  }
+};
+
 }  // namespace v8
 
 namespace {
index fc576a5efde92bef551150ee61f319c4a766ac91..e773d22e5352f5d6e6d681421fa8d3ade9e6e6bf 100644 (file)
  */
 
 #include "context.h"
+
+#include <malloc.h>  // for malloc_trim
 #include "base.h"
 #include "es-helper.h"
 #include "extra-data.h"
 #include "isolate.h"
 #include "stack-trace.h"
 
+#include "api.h"
+#include "api/global.h"
+
 using namespace Escargot;
 
 namespace EscargotShim {
@@ -68,6 +73,36 @@ static bool createGlobals(ContextRef* context) {
             StringRef::createFromASCII("stackTraceLimit"),
             ValueRef::create(
                 20));  // TODO: get number from '--stack-trace-limit' options
+
+        if (!EscargotShim::Global::flags()->isOn(
+                EscargotShim::Flag::Type::AllowCodeGenerationFromString)) {
+          // @note --disallow-code-generation-from-strings as default
+          state->context()->globalObject()->defineDataProperty(
+              state,
+              StringRef::createFromASCII("eval"),
+              FunctionObjectRef::create(
+                  state,
+                  FunctionObjectRef::NativeFunctionInfo(
+                      AtomicStringRef::emptyAtomicString(),
+                      [](ExecutionStateRef* state,
+                         ValueRef* thisValue,
+                         size_t argc,
+                         ValueRef** argv,
+                         bool isConstructCall) -> ValueRef* {
+                        state->throwException(
+                            ExceptionHelper::createErrorObject(
+                                state->context(),
+                                ErrorMessageType::kDisallowCodeGeneration));
+                        return ValueRef::createUndefined();
+                      },
+                      0,
+                      true,
+                      false)),
+              false,
+              false,
+              false);
+        }
+
         return ValueRef::createUndefined();
       });
   LWNODE_CHECK(r.isSuccessful());
@@ -75,14 +110,17 @@ static bool createGlobals(ContextRef* context) {
 }
 
 // ContextWrap
-
-ContextWrap::ContextWrap(IsolateWrap* isolate) {
+ContextWrap::ContextWrap(IsolateWrap* isolate,
+                         v8::ExtensionConfiguration* extensionConfiguration) {
   isolate_ = isolate;
 
   context_ = ContextRef::create(isolate->vmInstance());
 
   callSite_ = new CallSite(context_);
 
+  // NOTE: Not tested with multi initialization
+  initDebugger();
+
   auto globalObjectData = new GlobalObjectData();
   globalObjectData->setInternalFieldCount(
       GlobalObjectData::kInternalFieldCount);
@@ -92,11 +130,21 @@ ContextWrap::ContextWrap(IsolateWrap* isolate) {
 
   val_ = context_;
   type_ = Type::Context;
+
+  RegisteredExtension::applyAll(context_);
+}
+
+void ContextWrap::initDebugger() {
+  if (Global::flags()->isOn(Flag::Type::DebugServer)) {
+    // FIXME: Have a port allocator
+    context_->initDebuggerRemote("--port=6501");
+  }
 }
 
-ContextWrap* ContextWrap::New(IsolateWrap* isolate) {
+ContextWrap* ContextWrap::New(
+    IsolateWrap* isolate, v8::ExtensionConfiguration* extensionConfiguration) {
   LWNODE_CHECK_NOT_NULL(isolate);
-  return new ContextWrap(isolate);
+  return new ContextWrap(isolate, extensionConfiguration);
 }
 
 ContextWrap* ContextWrap::fromEscargot(Escargot::ContextRef* esContext) {
@@ -112,6 +160,10 @@ ContextWrap* ContextWrap::fromEscargot(Escargot::ContextRef* esContext) {
   return lwCreationContext;
 }
 
+ContextWrap* ContextWrap::fromV8(v8::Context* context) {
+  return CVAL(context)->context();
+}
+
 void ContextWrap::Enter() {
   isolate_->Enter();
   isolate_->pushContext(this);
index 4edfa7ca04e54c3f450f668f6f8a2e949564586b..04db035210ea1f93af96d1b9e7fe88aece97b77f 100644 (file)
@@ -28,8 +28,11 @@ typedef GCUnorderedMap<int, void*> EmbedderDataMap;
 
 class ContextWrap : public ValueWrap {
  public:
-  static ContextWrap* New(IsolateWrap* isolate);
+  static ContextWrap* New(
+      IsolateWrap* isolate,
+      v8::ExtensionConfiguration* extensionConfiguration = nullptr);
   static ContextWrap* fromEscargot(Escargot::ContextRef* context);
+  static ContextWrap* fromV8(v8::Context* context);
 
   void Enter();
   void Exit();
@@ -52,10 +55,13 @@ class ContextWrap : public ValueWrap {
 
   CallSite* callSite() { return callSite_; }
 
+  void initDebugger();
+
  private:
   EmbedderDataMap* embedder_data_{nullptr};
 
-  ContextWrap(IsolateWrap* isolate);
+  ContextWrap(IsolateWrap* isolate,
+              v8::ExtensionConfiguration* extensionConfiguration);
   void setEmbedderData(int index, void* value);
   void* getEmbedderData(int index);
 
index eb41639bed3402663ee48695cfd289a99b9a5ee4..e41c16f21714a07ecca02a76106e2a5c4b4bea80 100644 (file)
  */
 
 #include "engine.h"
+
 #include <iomanip>
 #include <sstream>
+
+#include "api/global.h"
 #include "handle.h"
 #include "utils/misc.h"
 #include "utils/string-util.h"
@@ -235,7 +238,7 @@ static void printAddress(
 }
 
 void GCHeap::printStatus(bool forcePrint) {
-  if (Flags::isTraceCallEnabled("GCHEAP") == false) {
+  if (!Global::flags()->isOn(Flag::Type::TraceCall, "GCHEAP")) {
     return;
   }
 
@@ -257,20 +260,24 @@ void GCHeap::printStatus(bool forcePrint) {
   LWNODE_DLOG_INFO("[HOLD]");
   printAddress(persistents_,
                [](std::stringstream& stream, const HeapSegment& iter) {
+                 std::ios_base::fmtflags flags(stream.flags());
                  stream << std::setw(15) << std::right
                         << GC_UNWRAP_PERSISTENT_POINTER(iter.first) << " ("
                         << "S" << std::setw(3) << iter.second.strong << " W"
                         << std::setw(3) << iter.second.weak << ") ";
+                 stream.flags(flags);
                });
 
   LWNODE_DLOG_INFO(CLR_GREEN "------------------" CLR_RESET);
   LWNODE_DLOG_INFO("[PHANTOM]");
   printAddress(weakPhantoms_,
                [](std::stringstream& stream, const HeapSegment& iter) {
+                 std::ios_base::fmtflags flags(stream.flags());
                  stream << std::setw(15) << std::right
                         << GC_UNWRAP_WEAK_POINTER(iter.first) << " ("
                         << "S" << std::setw(3) << iter.second.strong << " W"
                         << std::setw(3) << iter.second.weak << ") ";
+                 stream.flags(flags);
                });
 
   LWNODE_DLOG_INFO(CLR_GREEN "------------------" CLR_RESET);
@@ -351,11 +358,12 @@ void Engine::initialize() {
   Memory::setGCFrequency(GC_FREE_SPACE_DIVISOR);
   gcHeap_.reset(GCHeap::create());
 
-  auto flags = Flags::get();
-  if (Flags::isTraceGCEnabled()) {
+  if (Global::flags()->isOn(Flag::Type::TraceGC)) {
     LWNODE_DLOG_WARN("temporary blocked for postGarbageCollectionProcessing");
     registerGCEventListeners();
   }
+
+  mainThreadId_ = std::this_thread::get_id();
 }
 
 void Engine::dispose() {
@@ -365,7 +373,6 @@ void Engine::dispose() {
   unregisterGCEventListeners();
 
   gcHeap_.release();
-  MemoryUtil::gcFull();
   GC_invoke_finalizers();
 
   Globals::finalize();
@@ -378,6 +385,18 @@ Engine* Engine::current() {
   return s_engine;
 }
 
+void Engine::initializeThread() {
+  if (mainThreadId_ != std::this_thread::get_id()) {
+    Globals::initializeThread();
+  }
+}
+
+void Engine::finalizeThread() {
+  if (mainThreadId_ != std::this_thread::get_id()) {
+    Globals::finalizeThread();
+  }
+}
+
 Engine::State Engine::getState() {
   return s_state;
 }
index e4406ead070b2a51104d3d661ea9e409e3778fb4..6598d89d549fc4548d028f6b687506e878dac8a4 100644 (file)
@@ -19,6 +19,7 @@
 #include <EscargotPublic.h>
 #include <string.h>
 #include <v8.h>
+#include <thread>
 #include <vector>
 
 #include "utils/gc.h"
@@ -48,6 +49,9 @@ class Platform : public PlatformRef {
                                    StringRef* src,
                                    PromiseObjectRef* promise) override;
 
+  void customInfoLogger(const char* format, va_list args) override {}
+  void customErrorLogger(const char* format, va_list args) override {}
+
   std::vector<std::tuple<std::string /* abs path */,
                          ContextRef*,
                          PersistentRefHolder<ScriptRef>>>
@@ -144,6 +148,9 @@ class Engine {
 
   static State getState();
 
+  void initializeThread();
+  void finalizeThread();
+
  private:
   Engine() = default;
   void initialize();
@@ -154,5 +161,6 @@ class Engine {
       s_externalStrings;
 
   PersistentRefHolder<GCHeap> gcHeap_;
+  std::thread::id mainThreadId_;
 };
 }  // namespace EscargotShim
diff --git a/lwnode/code/escargotshim/src/api/error-message-template.h b/lwnode/code/escargotshim/src/api/error-message-template.h
new file mode 100644 (file)
index 0000000..8373532
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace EscargotShim {
+
+#define ERROR_MESSAGE_TEMPLATES(T)                                             \
+  T(None, None, "")                                                            \
+  T(DataCloneErrorOutOfMemory,                                                 \
+    RangeError,                                                                \
+    "Data cannot be cloned, out of memory.")                                   \
+  T(InternalFieldsOutOfRange, RangeError, "Internal field out of bounds.")     \
+  T(NotReadValue, RangeError, "Cannot read value")                             \
+  T(IllegalInvocation, TypeError, "Illegal invocation")                        \
+  T(DisallowCodeGeneration,                                                    \
+    EvalError,                                                                 \
+    "Code generation from strings disallowed for this context")
+}  // namespace EscargotShim
diff --git a/lwnode/code/escargotshim/src/api/error-message.cc b/lwnode/code/escargotshim/src/api/error-message.cc
new file mode 100644 (file)
index 0000000..086fc87
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2022-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "error-message.h"
+#include "utils/misc.h"
+
+using namespace Escargot;
+
+namespace EscargotShim {
+
+ErrorObjectRef::Code ErrorMessage::getErrorCode(ErrorMessageType type) {
+  switch (type) {
+#define CASE(NAME, CODE, STRING)                                               \
+  case ErrorMessageType::k##NAME:                                              \
+    return Escargot::ErrorObjectRef::Code::CODE;
+    ERROR_MESSAGE_TEMPLATES(CASE)
+#undef CASE
+    case ErrorMessageType::kErrorMessageCount:
+    default:
+      return ErrorObjectRef::Code::None;
+  }
+}
+
+const char* ErrorMessage::getErrorString(ErrorMessageType type) {
+  switch (type) {
+#define CASE(NAME, CODE, STRING)                                               \
+  case ErrorMessageType::k##NAME:                                              \
+    return STRING;
+    ERROR_MESSAGE_TEMPLATES(CASE)
+#undef CASE
+    case ErrorMessageType::kErrorMessageCount:
+    default:
+      return nullptr;
+  }
+}
+
+Escargot::StringRef* ErrorMessage::createErrorStringRef(ErrorMessageType type) {
+  auto errorString = ErrorMessage::getErrorString(type);
+  LWNODE_DCHECK_NOT_NULL(errorString);
+  return StringRef::createFromASCII(errorString, strlen(errorString));
+}
+
+}  // namespace EscargotShim
diff --git a/lwnode/code/escargotshim/src/api/error-message.h b/lwnode/code/escargotshim/src/api/error-message.h
new file mode 100644 (file)
index 0000000..774a32b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <EscargotPublic.h>
+#include "error-message-template.h"
+
+namespace Escargot {
+class StringRef;
+}
+
+namespace EscargotShim {
+
+enum class ErrorMessageType {
+#define TEMPLATE(NAME, CODE, STRING) k##NAME,
+  ERROR_MESSAGE_TEMPLATES(TEMPLATE)
+#undef TEMPLATE
+      kErrorMessageCount
+};
+
+class ErrorMessage {
+ public:
+  static Escargot::ErrorObjectRef::Code getErrorCode(ErrorMessageType type);
+  static const char* getErrorString(ErrorMessageType type);
+  static Escargot::StringRef* createErrorStringRef(ErrorMessageType type);
+};
+
+}  // namespace EscargotShim
index 06252681826f1a844211708c6b7be5673cbcafa6..9a865dbd2b84183f87a690ded100fc66cce5acbf 100755 (executable)
  */
 
 #include "es-helper.h"
+
+#include "api/error-message.h"
+#include "base.h"
 #include "context.h"
 #include "extra-data.h"
 #include "isolate.h"
+#include "stack-trace.h"
 #include "utils/misc.h"
 #include "utils/string-util.h"
 
 #include <sstream>
 
 using namespace Escargot;
+using namespace v8;
 
 namespace EscargotShim {
 
@@ -52,13 +57,13 @@ EvalResult ObjectRefHelper::setProperty(ContextRef* context,
       context,
       [](ExecutionStateRef* state,
          ObjectRef* object,
-         ValueRef* param1,
-         ValueRef* param2) -> ValueRef* {
+         ValueRef* key,
+         ValueRef* value) -> ValueRef* {
         // 1. if failed because of its descriptor or strict mode, ObjectRef::set
         // returns false, but evalResult will has no error.
         // 2. if failed because of throwing an exception, evalResult will be an
         // error.
-        return ValueRef::create(object->set(state, param1, param2));
+        return ValueRef::create(object->set(state, key, value));
       },
       object,
       key,
@@ -68,77 +73,77 @@ EvalResult ObjectRefHelper::setProperty(ContextRef* context,
 ValueRef* ObjectRefHelper::getOwnPropertyAttributes(ExecutionStateRef* state,
                                                     ObjectRef* object,
                                                     ValueRef* key) {
-  auto val = object->getOwnPropertyDescriptor(state, key);
-  if (val->isUndefined()) {
+  auto descriptor = object->getOwnPropertyDescriptor(state, key);
+  if (descriptor->isUndefined()) {
     return ValueRef::createUndefined();
   }
 
-  int attr = ObjectRef::PresentAttribute::NotPresent;
+  int attribute = ObjectRef::PresentAttribute::NotPresent;
 
-  bool isWritable = val->asObject()
+  bool isWritable = descriptor->asObject()
                         ->get(state, StringRef::createFromASCII("writable"))
                         ->asBoolean();
-  bool isEnumerable = val->asObject()
+  bool isEnumerable = descriptor->asObject()
                           ->get(state, StringRef::createFromASCII("enumerable"))
                           ->asBoolean();
   bool isConfigurable =
-      val->asObject()
+      descriptor->asObject()
           ->get(state, StringRef::createFromASCII("configurable"))
           ->asBoolean();
 
   if (isWritable) {
-    attr = attr | ObjectRef::PresentAttribute::WritablePresent;
+    attribute = attribute | ObjectRef::PresentAttribute::WritablePresent;
   } else {
-    attr = attr | ObjectRef::PresentAttribute::NonWritablePresent;
+    attribute = attribute | ObjectRef::PresentAttribute::NonWritablePresent;
   }
 
   if (isEnumerable) {
-    attr = attr | ObjectRef::PresentAttribute::EnumerablePresent;
+    attribute = attribute | ObjectRef::PresentAttribute::EnumerablePresent;
   } else {
-    attr = attr | ObjectRef::PresentAttribute::NonEnumerablePresent;
+    attribute = attribute | ObjectRef::PresentAttribute::NonEnumerablePresent;
   }
 
   if (isConfigurable) {
-    attr = attr | ObjectRef::PresentAttribute::ConfigurablePresent;
+    attribute = attribute | ObjectRef::PresentAttribute::ConfigurablePresent;
   } else {
-    attr = attr | ObjectRef::PresentAttribute::NonConfigurablePresent;
+    attribute = attribute | ObjectRef::PresentAttribute::NonConfigurablePresent;
   }
 
-  return ValueRef::create(attr);
+  return ValueRef::create(attribute);
 }
 
-EvalResult ObjectRefHelper::getPropertyAttributes(ContextRef* context,
-                                                  ObjectRef* object,
-                                                  ValueRef* key,
-                                                  bool skipPrototype) {
+EvalResult ObjectRefHelper::getPropertyAttributes(
+    ContextRef* context,
+    ObjectRef* object,
+    ValueRef* key,
+    bool skipTraversingPrototypeChain) {
   LWNODE_DCHECK_NOT_NULL(object);
   LWNODE_DCHECK_NOT_NULL(key);
 
-  EvalResult r = Evaluator::execute(
+  return Evaluator::execute(
       context,
       [](ExecutionStateRef* state,
          ObjectRef* object,
          ValueRef* key,
-         bool skipPrototype) -> ValueRef* {
+         bool skipTraversingPrototypeChain) -> ValueRef* {
         LWNODE_DCHECK_NOT_NULL(object);
         LWNODE_DCHECK_NOT_NULL(key);
 
-        ValueRef* attr = ValueRef::createUndefined();
-        for (ObjectRef* o = object; o;
-             o = o->getPrototypeObject(state).value()) {
-          attr = getOwnPropertyAttributes(state, o, key);
-          if (skipPrototype || !attr->isUndefined()) {
+        ValueRef* attribute = ValueRef::createUndefined();
+
+        for (ObjectRef* currentObject = object; currentObject;
+             currentObject = currentObject->getPrototypeObject(state).value()) {
+          attribute = getOwnPropertyAttributes(state, currentObject, key);
+          if (skipTraversingPrototypeChain || !attribute->isUndefined()) {
             break;
           }
         }
 
-        return attr;
+        return attribute;
       },
       object,
       key,
-      skipPrototype);
-
-  return r;
+      skipTraversingPrototypeChain);
 }
 
 EvalResult ObjectRefHelper::getProperty(ContextRef* context,
@@ -302,16 +307,16 @@ ObjectRef* ObjectRefHelper::getPrototype(ContextRef* context,
 
 EvalResult ObjectRefHelper::setPrototype(ContextRef* context,
                                          ObjectRef* object,
-                                         ValueRef* proto) {
+                                         ValueRef* prototype) {
   auto r = Evaluator::execute(
       context,
       [](ExecutionStateRef* state,
          ObjectRef* object,
-         ValueRef* proto) -> ValueRef* {
-        return ValueRef::create(object->setPrototype(state, proto));
+         ValueRef* prototype) -> ValueRef* {
+        return ValueRef::create(object->setPrototype(state, prototype));
       },
       object,
-      proto);
+      prototype);
 
   LWNODE_CHECK(r.isSuccessful());
   return r;
@@ -354,8 +359,8 @@ EvalResult ObjectRefHelper::setPrivate(ContextRef* context,
          ContextRef* context,
          SymbolRef* privateValueSymbol,
          ObjectRef* object,
-         ValueRef* param1,
-         ValueRef* param2) -> ValueRef* {
+         ValueRef* key,
+         ValueRef* value) -> ValueRef* {
         ValueRef* hiddenValuesRef = object->get(state, privateValueSymbol);
 
         ObjectRef* hiddenValuesObject = nullptr;
@@ -382,7 +387,7 @@ EvalResult ObjectRefHelper::setPrivate(ContextRef* context,
           hiddenValuesObject = hiddenValuesRef->asObject();
         }
 
-        hiddenValuesObject->set(state, param1, param2);
+        hiddenValuesObject->set(state, key, value);
 
         return ValueRef::create(true);
       },
@@ -461,6 +466,96 @@ StringRef* ObjectRefHelper::getConstructorName(ContextRef* context,
   return r.result->asString();
 }
 
+void ObjectRefHelper::addNativeFunction(ContextRef* context,
+                                        ObjectRef* object,
+                                        StringRef* name,
+                                        NativeFunctionPointer function) {
+  Evaluator::execute(
+      context,
+      [](ExecutionStateRef* state,
+         ObjectRef* target,
+         StringRef* name,
+         NativeFunctionPointer nativeFunction) -> ValueRef* {
+        target->defineDataProperty(
+            state,
+            name,
+            FunctionObjectRef::create(state,
+                                      FunctionObjectRef::NativeFunctionInfo(
+                                          AtomicStringRef::emptyAtomicString(),
+                                          nativeFunction,
+                                          0,
+                                          true,
+                                          false)),
+            false,
+            false,
+            false);
+
+        return ValueRef::createUndefined();
+      },
+      object,
+      name,
+      function);
+}
+
+ArrayObjectRef* ArrayObjectRefHelper::create(ContextRef* context,
+                                             const uint64_t length) {
+  auto result = Evaluator::execute(
+      context,
+      [](ExecutionStateRef* state, uint64_t length) -> ValueRef* {
+        return ArrayObjectRef::create(state, length);
+      },
+      length);
+  LWNODE_CHECK(result.isSuccessful());
+  return result.result->asArrayObject();
+}
+
+ArrayObjectRef* ArrayObjectRefHelper::create(ContextRef* context,
+                                             ValueVectorRef* elements) {
+  auto result = Evaluator::execute(
+      context,
+      [](ExecutionStateRef* state, ValueVectorRef* elements) -> ValueRef* {
+        return ArrayObjectRef::create(state, elements);
+      },
+      elements);
+  LWNODE_CHECK(result.isSuccessful());
+  return result.result->asArrayObject();
+}
+
+uint64_t ArrayObjectRefHelper::length(ContextRef* context,
+                                      ArrayObjectRef* object) {
+  uint64_t output = 0;
+  auto result = Evaluator::execute(
+      context,
+      [](ExecutionStateRef* state,
+         ArrayObjectRef* object,
+         uint64_t* output) -> ValueRef* {
+        *output = object->length(state);
+        return ValueRef::createUndefined();
+      },
+      object,
+      &output);
+  LWNODE_CHECK(result.isSuccessful());
+  return output;
+}
+
+ValueRef* ArrayObjectRefHelper::get(ContextRef* context,
+                                    ArrayObjectRef* object,
+                                    ValueRef::ValueIndex index) {
+  auto result =
+      ObjectRefHelper::getProperty(context, object, ValueRef::create(index));
+  LWNODE_CHECK(result.isSuccessful());
+  return result.result;
+}
+
+void ArrayObjectRefHelper::set(ContextRef* context,
+                               ArrayObjectRef* object,
+                               ValueRef::ValueIndex index,
+                               ValueRef* value) {
+  auto result = ObjectRefHelper::setProperty(
+      context, object, ValueRef::create(index), value);
+  LWNODE_CHECK(result.isSuccessful());
+}
+
 static std::string getCodeLine(const std::string& codeString, int errorLine) {
   if (errorLine < 1 || codeString.empty()) {
     return "";
@@ -489,7 +584,7 @@ std::string EvalResultHelper::getCallStackString(
   oss << "Call Stack:" << std::endl;
   for (size_t i = 0; i < maxPrintStackSize; ++i) {
     const auto& iter = traceData[i];
-    const auto& resourceName = iter.src->toStdUTF8String();
+    const auto& resourceName = iter.srcName->toStdUTF8String();
     const auto& codeString = iter.sourceCode->toStdUTF8String();
     const int errorLine = iter.loc.line;
     const int errorColumn = iter.loc.column;
@@ -510,32 +605,9 @@ std::string EvalResultHelper::getCallStackString(
   return oss.str();
 }
 
-std::string EvalResultHelper::getCallStackStringAsNodeStyle(
-    const GCManagedVector<Evaluator::StackTraceData>& traceData,
-    size_t maxStackSize) {
-  std::ostringstream oss;
-  const std::string separator = "    ";
-  size_t maxPrintStackSize = std::min((int)maxStackSize, (int)traceData.size());
-
-  for (size_t i = 0; i < maxPrintStackSize; ++i) {
-    const auto& iter = traceData[i];
-    const auto& resourceName = iter.src->toStdUTF8String();
-    const auto& functionName = iter.functionName->toStdUTF8String();
-    const int errorLine = iter.loc.line;
-    const int errorColumn = iter.loc.column;
-
-    oss << separator << "at "
-        << (functionName == "" ? "Object.<anonymous>" : functionName) << " "
-        << "(" << (resourceName == "" ? "?" : resourceName) << ":" << errorLine
-        << ":" << errorColumn << ")" << std::endl;
-  }
-
-  return oss.str();
-}
-
 std::string EvalResultHelper::getErrorString(
     ContextRef* context, const Evaluator::EvaluatorResult& result) {
-  const auto& traceData = result.stackTraceData;
+  const auto& traceData = result.stackTrace;
   const auto& reasonString =
       result.resultOrErrorToString(context)->toStdUTF8String();
   const std::string separator = "  ";
@@ -544,7 +616,7 @@ std::string EvalResultHelper::getErrorString(
 
   if (traceData.size()) {
     const auto& lastTraceData = traceData[0];
-    const auto& resourceName = lastTraceData.src->toStdUTF8String();
+    const auto& resourceName = lastTraceData.srcName->toStdUTF8String();
     const auto& codeString = lastTraceData.sourceCode->toStdUTF8String();
     const int errorLine = lastTraceData.loc.line;
     const int errorColumn = lastTraceData.loc.column;
@@ -609,8 +681,9 @@ Evaluator::EvaluatorResult EvalResultHelper::compileRun(ContextRef* context,
       compileResult.script.get());
 
   if (r.isSuccessful() == false) {
-    LWNODE_LOG_INTERNAL("Execute:\n  %s (%s:%d)\n%s",
-                        TRACE_ARGS2,
+    LWNODE_LOG_INTERNAL(RAW,
+                        "Execute:\n  %s\n%s",
+                        __CODE_LOCATION__,
                         EvalResultHelper::getErrorString(context, r).c_str());
   }
   return r;
@@ -640,7 +713,7 @@ void EvalResultHelper::attachBuiltinPrint(ContextRef* context,
         ss << " ";
       }
 
-      LWNODE_LOG_INTERNAL("%s", ss.str().c_str());
+      LWNODE_LOG_INTERNAL(RAW, "%s", ss.str().c_str());
     }
     return ValueRef::createUndefined();
   };
@@ -664,7 +737,7 @@ void EvalResultHelper::attachBuiltinPrint(ContextRef* context,
         ss << " ";
       }
 
-      LWNODE_LOG_INTERNAL("%s", ss.str().c_str());
+      LWNODE_LOG_INTERNAL(RAW, "%s", ss.str().c_str());
     }
     return ValueRef::createUndefined();
   };
@@ -681,9 +754,9 @@ void EvalResultHelper::attachBuiltinPrint(ContextRef* context,
     }
 
     LWNODE_LOG_INTERNAL(
+        RAW,
         "%s",
-        getCallStackString(state->computeStackTraceData(), maxStackSize)
-            .c_str());
+        getCallStackString(state->computeStackTrace(), maxStackSize).c_str());
 
     return ValueRef::createUndefined();
   };
@@ -846,17 +919,16 @@ void ExtraDataHelper::setExtraData(ObjectRef* object, ObjectData* data) {
 
 void ObjectTemplateRefHelper::setInternalFieldCount(ObjectTemplateRef* otpl,
                                                     int size) {
-  auto objectTemplateData =
-      ExtraDataHelper::getExtraData(otpl)->asObjectTemplateData();
+  auto objectTemplateData = ExtraDataHelper::getObjectTemplateExtraData(otpl);
   objectTemplateData->setInternalFieldCount(size);
 }
 
 int ObjectTemplateRefHelper::getInternalFieldCount(ObjectTemplateRef* otpl) {
-  auto data = ExtraDataHelper::getExtraData(otpl);
+  auto data = ExtraDataHelper::getObjectTemplateExtraData(otpl);
   if (data == nullptr) {
     return 0;
   }
-  return data->asObjectTemplateData()->internalFieldCount();
+  return data->internalFieldCount();
 }
 
 // --- ExceptionHelper ---
@@ -878,7 +950,7 @@ ErrorObjectRef* ExceptionHelper::createErrorObject(ContextRef* context,
          ErrorObjectRef::Code code,
          StringRef* errorMessage) -> ValueRef* {
         auto errorObject = ErrorObjectRef::create(state, code, errorMessage);
-        ExceptionHelper::setStackPropertyIfNotExist(state, errorObject);
+        ExceptionHelper::addStackPropertyCallback(state, errorObject);
         return errorObject;
       },
       code,
@@ -888,35 +960,49 @@ ErrorObjectRef* ExceptionHelper::createErrorObject(ContextRef* context,
   return r.result->asErrorObject();
 }
 
-void ExceptionHelper::setStackPropertyIfNotExist(ExecutionStateRef* state,
-                                                 Escargot::ValueRef* error) {
+ErrorObjectRef* ExceptionHelper::createErrorObject(ContextRef* context,
+                                                   ErrorMessageType type) {
+  return ExceptionHelper::createErrorObject(
+      context,
+      ErrorMessage::getErrorCode(type),
+      ErrorMessage::createErrorStringRef(type));
+}
+
+void ExceptionHelper::addStackPropertyCallback(ExecutionStateRef* state,
+                                               Escargot::ValueRef* error) {
   if (!error->isObject()) {
     return;
   }
 
+  auto lwIsolate = IsolateWrap::GetCurrent();
   auto errorObject = error->asObject();
-  auto stackString = StringRef::createFromASCII("stack");
-  if (errorObject->has(state, stackString)) {
-    return;
-  }
 
-  auto stack = EvalResultHelper::getCallStackStringAsNodeStyle(
-      state->computeStackTraceData(), 1);
-  auto message = errorObject->toString(state)->toStdUTF8String();
+  ValueRef* formattedStackTrace = StringRef::emptyString();
+  StackTrace stackTrace(state);
+  if (lwIsolate->HasPrepareStackTraceCallback()) {
+    auto lwContext = lwIsolate->GetCurrentContext();
 
-  if (message.length() > 0) {
-    stack = message + "\n" + stack;
+    auto sites = stackTrace.genCallSites();
+    formattedStackTrace = lwIsolate->RunPrepareStackTraceCallback(
+        state, lwContext, errorObject, sites);
+  } else {
+    formattedStackTrace =
+        stackTrace.formatStackTraceStringNodeStyle(errorObject);
   }
 
-  errorObject->set(state,
-                   stackString,
-                   StringRef::createFromASCII(stack.data(), stack.length()));
+  bool ok = errorObject->defineDataProperty(state,
+                                            StringRef::createFromASCII("stack"),
+                                            formattedStackTrace,
+                                            true,
+                                            false,
+                                            true);
+  LWNODE_CHECK(ok);
 }
 
 // --- StringRefHelper ---
 
-bool StringRefHelper::isAsciiString(StringRef* str) {
-  auto bufferData = str->stringBufferAccessData();
+bool StringRefHelper::isAsciiString(StringRef* string) {
+  auto bufferData = string->stringBufferAccessData();
 
   if (!bufferData.has8BitContent) {
     return false;
@@ -934,4 +1020,17 @@ bool StringRefHelper::isAsciiString(StringRef* str) {
   return isAscii;
 }
 
+bool StringRefHelper::isOneByteString(StringRef* str) {
+  auto bufferData = str->stringBufferAccessData();
+
+  for (size_t i = 0; i < bufferData.length; i++) {
+    char16_t c = bufferData.charAt(i);
+    if (c > 255) {  // including all 8 bit code
+      return false;
+    }
+  }
+
+  return true;
+}
+
 }  // namespace EscargotShim
index ea9f249438141d070118935ae53a061d7c33a061..821389a9e311e28edd05e348348f003af2ff879c 100755 (executable)
@@ -29,6 +29,7 @@ class ContextWrap;
 class ObjectData;
 class FunctionData;
 class ValueWrap;
+enum class ErrorMessageType;
 
 typedef Evaluator::EvaluatorResult EvalResult;
 typedef FunctionObjectRef::NativeFunctionPointer NativeFunctionPointer;
@@ -56,10 +57,11 @@ class ObjectRefHelper {
                                    ObjectRef* object,
                                    ValueRef* key);
 
-  static EvalResult getPropertyAttributes(ContextRef* context,
-                                          ObjectRef* object,
-                                          ValueRef* key,
-                                          bool skipPrototype = false);
+  static EvalResult getPropertyAttributes(
+      ContextRef* context,
+      ObjectRef* object,
+      ValueRef* key,
+      bool skipTraversingPrototypeChain = false);
 
   static EvalResult hasProperty(ContextRef* context,
                                 ObjectRef* object,
@@ -118,12 +120,31 @@ class ObjectRefHelper {
   static ObjectRef* toObject(ContextRef* context, ValueRef* value);
   static StringRef* getConstructorName(ContextRef* context, ObjectRef* object);
 
+  static void addNativeFunction(ContextRef* context,
+                                ObjectRef* object,
+                                StringRef* name,
+                                NativeFunctionPointer function);
+
  private:
   static ValueRef* getOwnPropertyAttributes(ExecutionStateRef* state,
                                             ObjectRef* object,
                                             ValueRef* key);
 };
 
+class ArrayObjectRefHelper {
+ public:
+  static ArrayObjectRef* create(ContextRef* context, const uint64_t length);
+  static ArrayObjectRef* create(ContextRef* context, ValueVectorRef* elements);
+  static uint64_t length(ContextRef* context, ArrayObjectRef* object);
+  static ValueRef* get(ContextRef* context,
+                       ArrayObjectRef* object,
+                       ValueRef::ValueIndex index);
+  static void set(ContextRef* context,
+                  ArrayObjectRef* object,
+                  ValueRef::ValueIndex index,
+                  ValueRef* value);
+};
+
 class ObjectTemplateData;
 class FunctionTemplateData;
 class FunctionData;
@@ -133,8 +154,43 @@ class ExtraDataHelper {
     return (ExtraData*)object->extraData();
   }
 
-  static ExtraData* getExtraData(TemplateRef* esTemplate) {
-    return (ExtraData*)esTemplate->instanceExtraData();
+  static FunctionData* getFunctionExtraData(ObjectRef* functionObject) {
+    auto extraData = (ExtraData*)functionObject->extraData();
+    if (extraData) {
+      return extraData->asFunctionData();
+    }
+
+    return nullptr;
+  }
+
+  static ObjectTemplateData* getObjectTemplateExtraData(
+      ObjectRef* objectTemplate) {
+    auto extraData = (ExtraData*)objectTemplate->extraData();
+    if (extraData) {
+      return extraData->asObjectTemplateData();
+    }
+
+    return nullptr;
+  }
+
+  static ObjectTemplateData* getObjectTemplateExtraData(
+      ObjectTemplateRef* objectTemplate) {
+    auto extraData = (ExtraData*)objectTemplate->instanceExtraData();
+    if (extraData) {
+      return extraData->asObjectTemplateData();
+    }
+
+    return nullptr;
+  }
+
+  static FunctionTemplateData* getFunctionTemplateExtraData(
+      FunctionTemplateRef* functionTemplate) {
+    auto extraData = (ExtraData*)functionTemplate->instanceExtraData();
+    if (extraData) {
+      return extraData->asFunctionTemplateData();
+    }
+
+    return nullptr;
   }
 
   // Only allow the following (Object, extraData) pairs when adding extraData
@@ -246,8 +302,10 @@ class ExceptionHelper {
   static ErrorObjectRef* createErrorObject(ContextRef* context,
                                            ErrorObjectRef::Code code,
                                            StringRef* errorMessage);
-  static void setStackPropertyIfNotExist(ExecutionStateRef* state,
-                                         Escargot::ValueRef* error);
+  static ErrorObjectRef* createErrorObject(ContextRef* context,
+                                           ErrorMessageType type);
+  static void addStackPropertyCallback(ExecutionStateRef* state,
+                                       Escargot::ValueRef* error);
 };
 
 class StringRefHelper {
@@ -258,6 +316,7 @@ class StringRefHelper {
   }
 
   static bool isAsciiString(StringRef* str);
+  static bool isOneByteString(StringRef* str);
 };
 
 }  // namespace EscargotShim
index f4f8c7de28fb63a292b80aa599234cd003b11f93..2f42ff43fc436ed72c6aad9deeb68fc8230503f1 100644 (file)
@@ -59,9 +59,10 @@ int InternalFieldData::internalFieldCount() {
 void InternalFieldData::setInternalFieldCount(int size) {
   LWNODE_CALL_TRACE_ID(OBJDATA, "%d", size);
 
-  // TODO: throw internal error
   if (size <= 0) {
-    LWNODE_DLOG_ERROR("InternalField: Invalid field count: %d\n", size);
+    auto lwIsolate = IsolateWrap::GetCurrent();
+    lwIsolate->onFatalError("InternalFieldData::setInternalFieldCount",
+                            "Internal field out of bounds");
     return;
   }
 
@@ -72,10 +73,11 @@ void InternalFieldData::setInternalFieldCount(int size) {
 }
 
 void InternalFieldData::setInternalField(int idx, void* lwValue) {
-  // TODO: throw internal error
   LWNODE_CHECK_NOT_NULL(internalFields_);
   if (!isValidIndex(idx)) {
-    LWNODE_DLOG_ERROR("InternalField: Internal field out of bounds");
+    auto lwIsolate = IsolateWrap::GetCurrent();
+    lwIsolate->onFatalError("InternalFieldData::setInternalField",
+                            "Internal field out of bounds");
     return;
   }
 
@@ -87,10 +89,11 @@ void InternalFieldData::setInternalField(int idx, void* lwValue) {
 }
 
 void* InternalFieldData::internalField(int idx) {
-  // TODO: throw internal error
   LWNODE_CHECK_NOT_NULL(internalFields_);
   if (!isValidIndex(idx)) {
-    LWNODE_DLOG_ERROR("InternalField: Internal field out of bounds");
+    auto lwIsolate = IsolateWrap::GetCurrent();
+    lwIsolate->onFatalError("InternalFieldData::internalField",
+                            "Internal field out of bounds");
     return nullptr;
   }
 
@@ -105,8 +108,7 @@ void* InternalFieldData::internalField(int idx) {
 }
 
 ObjectData::ObjectData(ObjectTemplateRef* objectTemplate)
-    : TemplateData(ExtraDataHelper::getExtraData(objectTemplate)
-                       ->asObjectTemplateData()
+    : TemplateData(ExtraDataHelper::getObjectTemplateExtraData(objectTemplate)
                        ->functionTemplate()),
       objectTemplate_(objectTemplate) {}
 
@@ -136,8 +138,8 @@ ObjectData* ObjectTemplateData::createObjectData(
 
 v8::Isolate* FunctionData::isolate() {
   if (functionTemplate_) {
-    auto functionTemplateData = ExtraDataHelper::getExtraData(functionTemplate_)
-                                    ->asFunctionTemplateData();
+    auto functionTemplateData =
+        ExtraDataHelper::getFunctionTemplateExtraData(functionTemplate_);
     return functionTemplateData->isolate();
   }
 
@@ -146,8 +148,8 @@ v8::Isolate* FunctionData::isolate() {
 
 v8::FunctionCallback FunctionData::callback() {
   if (functionTemplate_) {
-    auto functionTemplateData = ExtraDataHelper::getExtraData(functionTemplate_)
-                                    ->asFunctionTemplateData();
+    auto functionTemplateData =
+        ExtraDataHelper::getFunctionTemplateExtraData(functionTemplate_);
     return functionTemplateData->callback();
   }
 
@@ -156,8 +158,8 @@ v8::FunctionCallback FunctionData::callback() {
 
 v8::Value* FunctionData::callbackData() {
   if (functionTemplate_) {
-    auto functionTemplateData = ExtraDataHelper::getExtraData(functionTemplate_)
-                                    ->asFunctionTemplateData();
+    auto functionTemplateData =
+        ExtraDataHelper::getFunctionTemplateExtraData(functionTemplate_);
     return functionTemplateData->callbackData();
   }
 
@@ -166,8 +168,8 @@ v8::Value* FunctionData::callbackData() {
 
 v8::Signature* FunctionData::signature() {
   if (functionTemplate_) {
-    auto functionTemplateData = ExtraDataHelper::getExtraData(functionTemplate_)
-                                    ->asFunctionTemplateData();
+    auto functionTemplateData =
+        ExtraDataHelper::getFunctionTemplateExtraData(functionTemplate_);
     return functionTemplateData->signature();
   }
 
@@ -239,10 +241,15 @@ ExceptionObjectData::ExceptionObjectData(
 
 GCVector<StackTraceData*>* ExceptionObjectData::stackTrace(
     ObjectRef* exceptionObject) {
-  auto exceptionObjectData =
-      ExtraDataHelper::getExtraData(exceptionObject)->asExceptionObjectData();
-
-  return exceptionObjectData->stackTrace();
+  auto extraData = ExtraDataHelper::getExtraData(exceptionObject);
+  if (extraData) {
+    return extraData->asExceptionObjectData()->stackTrace();
+  } else {
+    // FIXME: Check if missing extradata is ok. We print a warning
+    // here until this issue is investigated
+    LWNODE_LOG_WARN("esException does not have an extraData\n");
+    return new GCVector<StackTraceData*>();
+  }
 }
 
 }  // namespace EscargotShim
index ff09a713051a494c3cf9beb9a730aa4b39f9079d..bf656478b01a054a0cf6350ba6517ee697f2102b 100644 (file)
@@ -225,13 +225,14 @@ class ExternalObjectData : public ObjectData {
 class StackTraceData : public ExtraData {
  public:
   StackTraceData(const Escargot::Evaluator::StackTraceData& data)
-      : src_(data.src),
+      : src_(data.srcName),
         sourceCode_(data.sourceCode),
         loc_(data.loc),
         functionName_(data.functionName),
         isConstructor_(data.isConstructor),
         isAssociatedWithJavaScriptCode_(data.isAssociatedWithJavaScriptCode),
-        isEval_(data.isEval) {}
+        isEval_(data.isEval),
+        callee_(data.callee) {}
 
   bool isStackTraceData() const override { return true; }
 
@@ -245,6 +246,7 @@ class StackTraceData : public ExtraData {
     return isAssociatedWithJavaScriptCode_;
   }
   bool isEval() const { return isEval_; }
+  OptionalRef<FunctionObjectRef> callee() { return callee_; }
 
  private:
   StringRef* src_{nullptr};
@@ -255,6 +257,7 @@ class StackTraceData : public ExtraData {
   bool isConstructor_{false};
   bool isAssociatedWithJavaScriptCode_{false};
   bool isEval_{false};
+  OptionalRef<FunctionObjectRef> callee_;
 };
 
 // NOTE: ExceptionObjectData does not use any InternalFields.
index fd3ff9f69f3b1779331250baaf9fe35694c715cf..dbcf1f47249e00fc18137fc9b9bae7b3793ffbe6 100644 (file)
 #include "base.h"
 #include "global-handles.h"
 
-namespace EscargotShim {
-
-std::vector<GlobalHandles*> g_globalHandlesVector;
-
-class GlobalWeakHandler {
- public:
-  void pushBlock(ValueWrap* lwValue,
-                 std::unique_ptr<GlobalHandles::NodeBlock> block) {
-    auto iter = weakValues_.find(lwValue);
-    if (iter != weakValues_.end()) {
-      // TODO
-      LWNODE_CHECK_NOT_REACH_HERE();
-    }
-    weakValues_.emplace(lwValue, std::move(block));
+#include "api/utils/gc.h"
+
+namespace v8 {
+namespace internal {
+void GlobalHandles::Destroy(EscargotShim::ValueWrap* lwValue) {
+  auto isolate = EscargotShim::IsolateWrap::GetCurrent();
+  if (isolate) {
+    isolate->global_handles()->destroy(lwValue);
   }
-
-  std::unique_ptr<GlobalHandles::NodeBlock> popBlock(ValueWrap* lwValue) {
-    auto iter = weakValues_.find(lwValue);
-    if (iter == weakValues_.end()) {
-      return nullptr;
-    }
-    auto nodeBlock = std::move(iter->second);
-    weakValues_.erase(iter);
-
-    return nodeBlock;
-  }
-
-  size_t clearWeakValue() {
-    auto weakValuesSize = weakValues_.size();
-    if (weakValuesSize == 0) {
-      return 0;
-    }
-    LWNODE_CALL_TRACE_ID(
-        GLOBALHANDLES, "Clear weak values: %ld", weakValuesSize);
-    for (auto& iter : weakValues_) {
-      iter.second->releaseValue();
-    }
-    return weakValuesSize;
-  }
-
-  bool isWeak(ValueWrap* lwValue) {
-    return weakValues_.find(lwValue) != weakValues_.end();
-  }
-
-  void dispose() { weakValues_.clear(); }
-
- private:
-  std::unordered_map<ValueWrap*, std::unique_ptr<GlobalHandles::NodeBlock>>
-      weakValues_;
-};
-
-GlobalWeakHandler g_globalWeakHandler;
-
-GlobalHandles::Node::Node(void* parameter,
-                          v8::WeakCallbackInfo<void>::Callback callback)
-    : parameter_(parameter), callback_(callback) {}
-
-GlobalHandles::Node::~Node() {}
-
-GlobalHandles::NodeBlock::NodeBlock(v8::Isolate* isolate,
-                                    ValueWrap* value,
-                                    uint32_t count)
-    : isolate_(isolate), value_(value), usedNodes_(count) {
-  holder_.reset(value_);
 }
 
-GlobalHandles::NodeBlock::~NodeBlock() {
-  delete firstNode_;
-  holder_.release();
+void GlobalHandles::MakeWeak(EscargotShim::ValueWrap* lwValue,
+                             void* parameter,
+                             v8::WeakCallbackInfo<void>::Callback callback) {
+  auto isolate = EscargotShim::IsolateWrap::GetCurrent();
+  isolate->global_handles()->makeWeak(lwValue, parameter, callback);
 }
 
-GlobalHandles::Node* GlobalHandles::NodeBlock::pushNode(Node* node) {
-  if (firstNode_ == nullptr) {
-    firstNode_ = node;
-  } else {
-    // TODO
-    LWNODE_DLOG_WARN("The weak callback is registered several times.");
-    if (node) {
-      delete node;
-      return nullptr;
-    }
-  }
-
-  return node;
+void* GlobalHandles::ClearWeakness(EscargotShim::ValueWrap* lwValue) {
+  auto isolate = EscargotShim::IsolateWrap::GetCurrent();
+  isolate->global_handles()->clearWeakness(lwValue);
+  return nullptr;
 }
 
-void GlobalHandles::NodeBlock::registerWeakCallback() {
-  MemoryUtil::gcRegisterFinalizer(value_, [](void* self) {
-    LWNODE_CALL_TRACE_GC_START();
-    LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Call weak callback: %p", self);
+}  // namespace internal
+}  // namespace v8
 
-    auto block = g_globalWeakHandler.popBlock(VAL(self));
-    if (!block) {
-      LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Cannot invoke callback: %p", self);
-      return;
-    }
-
-    auto curNode = block->firstNode_;
-    if (curNode) {
-      if (curNode->callback()) {
-        void* embedderFields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
-                                                                   nullptr};
-        v8::WeakCallbackInfo<void> info(
-            block->isolate(), curNode->parameter(), embedderFields, nullptr);
-        LWNODE_CHECK_NOT_NULL(block->isolate());
-        curNode->callback()(info);
-      }
-      // TODO: The weak callback is registered several times.(create nextNode)
-    }
-    LWNODE_CALL_TRACE_GC_END();
-  });
-}
-
-void GlobalHandles::NodeBlock::releaseValue() {
-  registerWeakCallback();
-  holder_.release();
-}
+namespace EscargotShim {
 
-GlobalHandles::GlobalHandles(v8::Isolate* isolate) : isolate_(isolate) {
-  g_globalHandlesVector.push_back(this);
-}
+GlobalHandles::GlobalHandles(IsolateWrap* isolate)
+    : v8::internal::GlobalHandles(isolate), isolate_(isolate) {}
 
-void GlobalHandles::Dispose() {
+void GlobalHandles::dispose() {
   LWNODE_CALL_TRACE_ID(GLOBALHANDLES);
   persistentValues_.clear();
-  auto it = std::find(
-      g_globalHandlesVector.begin(), g_globalHandlesVector.end(), this);
 
-  if (it != g_globalHandlesVector.end()) {
-    g_globalHandlesVector.erase(it);
-  }
-  // TODO: consider multi isolate
-  if (g_globalHandlesVector.size() == 0) {
-    g_globalWeakHandler.dispose();
+  for (auto gcObjectInfo : gcObjectInfos_) {
+    delete gcObjectInfo;
   }
+
+  isolate_ = nullptr;
 }
 
-void GlobalHandles::Create(ValueWrap* lwValue) {
+void GlobalHandles::create(ValueWrap* lwValue) {
   auto iter = persistentValues_.find(lwValue);
   if (iter == persistentValues_.end()) {
     persistentValues_.emplace(lwValue, 1);
@@ -171,15 +77,6 @@ void GlobalHandles::Create(ValueWrap* lwValue) {
   }
 }
 
-void GlobalHandles::Destroy(ValueWrap* lwValue) {
-  for (auto globalHandles : g_globalHandlesVector) {
-    if (globalHandles->destroy(lwValue)) {
-      return;
-    }
-  }
-  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Cannot destroy: %p", lwValue);
-}
-
 bool GlobalHandles::destroy(ValueWrap* lwValue) {
   auto iter = persistentValues_.find(lwValue);
   if (iter != persistentValues_.end()) {
@@ -196,69 +93,167 @@ bool GlobalHandles::destroy(ValueWrap* lwValue) {
 size_t GlobalHandles::PostGarbageCollectionProcessing(
     /*const v8::GCCallbackFlags gc_callback_flags*/) {
 #if defined(LWNODE_ENABLE_EXPERIMENTAL)
-  return g_globalWeakHandler.clearWeakValue();
-#else
-  return 0;
+  clearWeakValues();
 #endif
+
+  return 0;
 }
 
-void GlobalHandles::MakeWeak(ValueWrap* lwValue,
-                             void* parameter,
-                             v8::WeakCallbackInfo<void>::Callback callback) {
-  for (auto globalHandles : g_globalHandlesVector) {
-    if (globalHandles->makeWeak(lwValue, parameter, callback)) {
-      return;
+void GlobalHandles::releaseWeakValues() {
+  std::set<GcObjectInfo*, ObjectInfoComparator> objectsInfoPersistent;
+  std::vector<GcObjectInfo*> objectsInfoWeak;
+
+  for (auto gcObjectInfo : gcObjectInfos_) {
+    if (gcObjectInfo->isPersistent()) {
+      objectsInfoPersistent.insert(gcObjectInfo);
+    } else {
+      // TODO: check if the weak pointer is valid
+      if (gcObjectInfo->hasCallback()) {
+        void* embedderFields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
+                                                                   nullptr};
+        v8::WeakCallbackInfo<void> info(isolate_->toV8(),
+                                        gcObjectInfo->parameter(),
+                                        embedderFields,
+                                        nullptr);
+        gcObjectInfo->runCallback(info);
+      }
+
+      // reset callback
+      MemoryUtil::gcRegisterFinalizer(
+          gcObjectInfo->lwValue(), [](void* self, void* data) {}, nullptr);
+
+      objectsInfoWeak.push_back(gcObjectInfo);
+
+      GC_invoke_finalizers();
     }
   }
-  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Cannot make weak value: %p", lwValue);
+
+  gcObjectInfos_.clear();
+  gcObjectInfos_.insert(objectsInfoPersistent.begin(),
+                        objectsInfoPersistent.end());
+  for (auto objectInfo : objectsInfoWeak) {
+    delete objectInfo;
+  }
 }
 
 bool GlobalHandles::makeWeak(ValueWrap* lwValue,
-                             void* parameter,
+                             void* parameter,  // c++ native object
                              v8::WeakCallbackInfo<void>::Callback callback) {
-  auto iter = persistentValues_.find(lwValue);
-  if (iter == persistentValues_.end()) {
-    return false;
-  }
+  addWeakValue(lwValue, parameter, callback);
+
+  MemoryUtil::gcRegisterFinalizer(
+      lwValue,
+      [](void* self, void* data) {
+        LWNODE_CALL_TRACE_GC_START();
+        auto globalHandles = static_cast<GlobalHandles*>(data);
+
+        LWNODE_CALL_TRACE_ID(GLOBALHANDLES,
+                             "Call weak callback: %p %p",
+                             self,
+                             globalHandles->isolate_);
+        if (!globalHandles->isolate_) {
+          return;
+        }
+
+        auto gcObjectInfo = globalHandles->findGcObjectInfo((ValueWrap*)self);
+        if (gcObjectInfo) {
+          if (gcObjectInfo->hasCallback()) {
+            void* embedderFields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
+                                                                       nullptr};
+            v8::WeakCallbackInfo<void> info(globalHandles->isolate_->toV8(),
+                                            gcObjectInfo->parameter(),
+                                            embedderFields,
+                                            nullptr);
+            LWNODE_CHECK_NOT_NULL(globalHandles->isolate_);
+            gcObjectInfo->runCallback(info);
+          }
+
+          globalHandles->removeGcObjectInfo(gcObjectInfo->lwValue());
+        }
+
+        LWNODE_CALL_TRACE_GC_END();
+      },
+      isolate_->GetCurrent()->global_handles());
 
-  if (g_globalWeakHandler.isWeak(lwValue)) {
-    return false;
+  return true;
+}
+
+bool GlobalHandles::clearWeakness(ValueWrap* lwValue) {
+  setPersistent(lwValue);
+  return true;
+}
+
+void GlobalHandles::addWeakValue(
+    ValueWrap* lwValue,
+    void* parameter,
+    v8::WeakCallbackInfo<void>::Callback callback) {
+  GcObjectInfo objInfo(lwValue, parameter, callback);
+  auto itr = gcObjectInfos_.find(&objInfo);
+  if (itr != gcObjectInfos_.end()) {
+    (*itr)->unsetPersistent();
+    return;
   }
 
-  auto block = std::make_unique<GlobalHandles::NodeBlock>(
-      isolate_, lwValue, iter->second);
-  block->pushNode(new Node(parameter, callback));
-  g_globalWeakHandler.pushBlock(lwValue, std::move(block));
+  GcObjectInfo* newObjInfo = new GcObjectInfo(lwValue, parameter, callback);
+  gcObjectInfos_.insert(newObjInfo);
+}
 
-  LWNODE_CALL_TRACE_ID(
-      GLOBALHANDLES, "MakeWeak: %p(%ld)", lwValue, iter->second);
-  persistentValues_.erase(iter);
-  return true;
+void GlobalHandles::setPersistent(ValueWrap* lwValue) {
+  GcObjectInfo objInfo(lwValue);
+  auto itr = gcObjectInfos_.find(&objInfo);
+  if (itr != gcObjectInfos_.end()) {
+    (*itr)->setPersistent();
+    return;
+  }
+
+  GcObjectInfo* newObjInfo = new GcObjectInfo(lwValue);
+  gcObjectInfos_.insert(newObjInfo);
 }
 
-void* GlobalHandles::ClearWeakness(ValueWrap* lwValue) {
-  for (auto globalHandles : g_globalHandlesVector) {
-    if (globalHandles->clearWeak(lwValue)) {
-      return lwValue;
+void GlobalHandles::clearWeakValues() {
+  std::set<GcObjectInfo*, ObjectInfoComparator> objectsInfoPersistent;
+  for (auto objectInfo : gcObjectInfos_) {
+    if (objectInfo->isPersistent()) {
+      objectsInfoPersistent.insert(objectInfo);
+    } else {
+      // TODO: check validness of a weak pointer, and call finalizer
     }
   }
-  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Cannot clear weak value: %p", lwValue);
+
+  gcObjectInfos_.clear();
+  gcObjectInfos_.insert(objectsInfoPersistent.begin(),
+                        objectsInfoPersistent.end());
+}
+
+GcObjectInfo* GlobalHandles::findGcObjectInfo(ValueWrap* lwValue) {
+  GcObjectInfo objInfo(lwValue);
+  auto itr = gcObjectInfos_.find(&objInfo);
+  if (itr != gcObjectInfos_.end()) {
+    return *itr;
+  }
+
   return nullptr;
 }
 
-bool GlobalHandles::clearWeak(ValueWrap* lwValue) {
-  auto block = g_globalWeakHandler.popBlock(lwValue);
-  if (!block) {
-    return false;
+void GlobalHandles::removeGcObjectInfo(ValueWrap* lwValue) {
+  GcObjectInfo objInfo(lwValue);
+  auto itr = gcObjectInfos_.find(&objInfo);
+  if (itr != gcObjectInfos_.end()) {
+    auto objectInfo = *itr;
+    gcObjectInfos_.erase(itr);
+    delete objectInfo;
   }
-  LWNODE_CHECK(persistentValues_.find(lwValue) == persistentValues_.end());
-  persistentValues_.emplace(lwValue, block->usedNodes());
-  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "ClearWeak: %p", lwValue);
-  return true;
 }
 
-size_t GlobalHandles::handles_count() {
-  return persistentValues_.size();
+size_t GlobalHandles::handles_count() const {
+  size_t count = 0;
+  for (auto gcObjectInfo : gcObjectInfos_) {
+    if (gcObjectInfo->isPersistent()) {
+      count++;
+    }
+  }
+
+  return count;
 }
 
 }  // namespace EscargotShim
index 82eb6451b28c9064413e6c1722a7ac21bb12b23b..fddaad1e8a26adbd0febb09295da1f3dd79a1a08 100644 (file)
 
 #pragma once
 
+#include <set>
+
 #include <EscargotPublic.h>
+
 #include "handle.h"
 #include "utils/gc.h"
 
-namespace EscargotShim {
-
-class GlobalHandles final : public gc {
+namespace v8 {
+namespace internal {
+class GlobalHandles : public gc {
  public:
-  GlobalHandles(v8::Isolate* isolate);
+  GlobalHandles(Isolate* isolate) : isolate_(isolate) {}
 
-  void Create(ValueWrap* lwValue);
-  static void Destroy(ValueWrap* lwValue);
-  static void MakeWeak(ValueWrap* lwValue,
+  static void MakeWeak(EscargotShim::ValueWrap* lwValue,
                        void* parameter,
                        v8::WeakCallbackInfo<void>::Callback callback);
-  static void* ClearWeakness(ValueWrap* lwValue);
-
-  size_t PostGarbageCollectionProcessing(
-      /*const v8::GCCallbackFlags gc_callback_flags*/);
-
-  bool destroy(ValueWrap* lwValue);
 
-  bool makeWeak(ValueWrap* lwValue,
-                void* parameter,
-                v8::WeakCallbackInfo<void>::Callback callback);
-
-  bool clearWeak(ValueWrap* lwValue);
-
-  size_t handles_count();
+  // void Create(EscargotShim::ValueWrap* lwValue);
+  static void Destroy(EscargotShim::ValueWrap* lwValue);
+  static void* ClearWeakness(EscargotShim::ValueWrap* lwValue);
 
-  void Dispose();
+  virtual size_t handles_count() const = 0;
 
-  class Node {
-   public:
-    Node(void* parameter, v8::WeakCallbackInfo<void>::Callback callback);
-    ~Node();
-
-    Node(const Node&) = delete;
-
-    void* parameter() { return parameter_; }
-    v8::WeakCallbackInfo<void>::Callback callback() { return callback_; }
-
-   private:
-    void* parameter_{nullptr};
-    v8::WeakCallbackInfo<void>::Callback callback_;
-  };
+ private:
+  Isolate* const isolate_ = nullptr;
+};
 
-  class NodeBlock {
-   public:
-    NodeBlock(v8::Isolate* isolate, ValueWrap* value, uint32_t count);
+}  // namespace internal
+}  // namespace v8
 
-    ~NodeBlock();
+namespace EscargotShim {
 
-    NodeBlock(const NodeBlock&) = delete;
+class GlobalWeakHandler;
 
-    uint32_t usedNodes() { return usedNodes_; }
+class GcObjectInfo {
+ public:
+  GcObjectInfo(ValueWrap* lwValue,
+               void* parameter = nullptr,
+               v8::WeakCallbackInfo<void>::Callback callback = nullptr)
+      : lwValue_(lwValue), parameter_(parameter), callback_(callback) {}
+
+  void setPersistent() {
+    holder_.reset(lwValue_);
+    isPersistent_ = true;
+  }
+
+  void unsetPersistent() {
+    holder_.reset(nullptr);
+    isPersistent_ = false;
+  }
+
+  bool isPersistent() { return isPersistent_; }
+  ValueWrap* lwValue() const { return lwValue_; }
+  void* parameter() { return parameter_; }
+  bool hasCallback() { return callback_ != nullptr; }
+  void runCallback(v8::WeakCallbackInfo<void>& info) { callback_(info); }
 
-    Node* firstNode() { return firstNode_; }
-    void setFirstNode(Node* node) { firstNode_ = node; }
+ private:
+  ValueWrap* lwValue_ = nullptr;
+  void* parameter_ = nullptr;
+  v8::WeakCallbackInfo<void>::Callback callback_ = nullptr;
+  Escargot::PersistentRefHolder<ValueWrap> holder_;
+  bool isPersistent_ = false;
+};
 
-    Node* pushNode(Node* node);
+class GlobalHandles final : public v8::internal::GlobalHandles {
+ public:
+  GlobalHandles(IsolateWrap* isolate);
 
-    void registerWeakCallback();
+  size_t PostGarbageCollectionProcessing(
+      /*const v8::GCCallbackFlags gc_callback_flags*/);
 
-    void releaseValue();
+  void create(ValueWrap* lwValue);
+  bool makeWeak(ValueWrap* lwValue,
+                void* parameter,
+                v8::WeakCallbackInfo<void>::Callback callback);
+  bool clearWeakness(ValueWrap* lwValue);
+  bool destroy(ValueWrap* lwValue);
+  void dispose();
 
-    v8::Isolate* isolate() { return isolate_; }
+  void releaseWeakValues();
+  size_t handles_count() const override;
 
-   private:
-    v8::Isolate* isolate_{nullptr};
-    ValueWrap* value_{nullptr};
-    uint32_t usedNodes_{0};
-    Node* firstNode_{nullptr};
-    Escargot::PersistentRefHolder<ValueWrap> holder_;
-  };
+  void addWeakValue(ValueWrap* lwValue,
+                    void* parameter,
+                    v8::WeakCallbackInfo<void>::Callback callback);
+  void setPersistent(ValueWrap* lwValue);
+  void clearWeakValues();
+  GcObjectInfo* findGcObjectInfo(ValueWrap* value);
+  void removeGcObjectInfo(ValueWrap* lwValue);
 
  private:
   GCUnorderedMap<ValueWrap*, size_t> persistentValues_;
-  v8::Isolate* isolate_{nullptr};
+  IsolateWrap* isolate_{nullptr};
+  struct ObjectInfoComparator {
+    bool operator()(const GcObjectInfo* a, const GcObjectInfo* b) const {
+      return a->lwValue() < b->lwValue();
+    }
+  };
+
+  // TODO: use std::unique_ptr
+  std::set<GcObjectInfo*, ObjectInfoComparator> gcObjectInfos_;
 };
+
 }  // namespace EscargotShim
diff --git a/lwnode/code/escargotshim/src/api/global.cc b/lwnode/code/escargotshim/src/api/global.cc
new file mode 100644 (file)
index 0000000..e7bd97d
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2021-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "global.h"
+
+namespace EscargotShim {
+std::unique_ptr<Flags> Global::s_flags = std::make_unique<Flags>();
+
+Flags* Global::flags() {
+  return s_flags.get();
+}
+}  // namespace EscargotShim
diff --git a/lwnode/code/escargotshim/src/api/global.h b/lwnode/code/escargotshim/src/api/global.h
new file mode 100644 (file)
index 0000000..5ddf1a0
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "utils/logger/flags.h"
+
+namespace EscargotShim {
+class Flags;
+
+class Global {
+ public:
+  Global() {}
+
+  static Flags* flags();
+
+ private:
+  static std::unique_ptr<Flags> s_flags;
+};
+
+}  // namespace EscargotShim
index 3580aca52cb39952e387a11f3bb43216cbf06ff2..237c4f9993092433d25516fea2b1a27a9a7dd186 100644 (file)
@@ -253,8 +253,7 @@ void* PersistentWrap::GlobalizeReference(v8::Isolate* isolate, void* address) {
 
 void PersistentWrap::DisposeGlobal(void* address) {
   PersistentWrap* persistent = reinterpret_cast<PersistentWrap*>(address);
-  LWNODE_CALL_TRACE_ID(
-      GCHEAP, "%s", persistent->getPersistentInfoString().c_str());
+  LWNODE_CALL_TRACE_ID(GCHEAP, "%s", persistent->getPersistentInfoString());
 
   LWNODE_DCHECK(persistent->location_ != Local);
 
@@ -265,9 +264,9 @@ void PersistentWrap::DisposeGlobal(void* address) {
 
 void PersistentWrap::dispose() {
   LWNODE_CALL_TRACE_ID(GCHEAP,
-                       "%s isFinalizerCalled: %s",
-                       getPersistentInfoString().c_str(),
-                       strBool(isFinalizerCalled));
+                       "%s isFinalizerCalled: %b",
+                       getPersistentInfoString(),
+                       isFinalizerCalled);
   if (isFinalizerCalled) {
     return;
   }
index 80985d71fa66874fdf2e41f256616702fea86ec8..dcfea2f3e736527db5c081dfeb6abce36b02d790 100644 (file)
@@ -15,6 +15,8 @@
  */
 
 #include "handlescope.h"
+
+#include "api/global.h"
 #include "handle.h"
 #include "isolate.h"
 #include "utils/misc.h"
@@ -58,7 +60,7 @@ bool HandleScopeWrap::remove(HandleWrap* value) {
 
 void HandleScopeWrap::clear() {
   LWNODE_CALL_TRACE_ID(HDLSCOPE);
-  if (Flags::isTraceCallEnabled("HDLSCOPE")) {
+  if (Global::flags()->isOn(Flag::Type::TraceCall, "HDLSCOPE")) {
     std::stringstream ss;
     std::vector<std::string> vector;
 
index 989288d926eb7e60499e90aa214f86d43bfbee46..d28d675b2af0e79b5a4948ebb0796370eacee232 100755 (executable)
@@ -56,12 +56,17 @@ void Isolate::ScheduleThrow(Escargot::ValueRef* value) {
   // using v8:tryCatch, etc. In this case, we should not do any exception
   // handling.
 
+  bool rethrow = has_pending_exception();
+
   set_scheduled_exception(value);
+  set_pending_exception(value);
 
-  // Note: No stack data exist
-  GCManagedVector<Escargot::Evaluator::StackTraceData> stackTraceData;
-  SetPendingExceptionAndMessage(value, stackTraceData);
-  PropagatePendingExceptionToExternalTryCatch();
+  if (PropagatePendingExceptionToExternalTryCatch()) {
+    clear_pending_exception();
+    if (!rethrow) {
+      clear_scheduled_exception();
+    }
+  }
 }
 
 void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) {
@@ -91,7 +96,7 @@ Escargot::ValueRef* Isolate::scheduled_exception() {
 
 bool Isolate::has_scheduled_exception() {
   LWNODE_CALL_TRACE_ID(TRYCATCH);
-  return !isHole(scheduled_exception_);
+  return scheduled_exception_ != nullptr;
 }
 
 void Isolate::set_scheduled_exception(Escargot::ValueRef* exception_obj) {
@@ -100,7 +105,7 @@ void Isolate::set_scheduled_exception(Escargot::ValueRef* exception_obj) {
 
 void Isolate::clear_scheduled_exception() {
   LWNODE_CALL_TRACE_ID(TRYCATCH);
-  scheduled_exception_ = hole()->value();
+  scheduled_exception_ = nullptr;
 }
 
 Escargot::ValueRef* Isolate::pending_exception() {
@@ -150,7 +155,7 @@ bool Isolate::PropagatePendingExceptionToExternalTryCatch() {
     if (handler->exception_) {
       LWNODE_CALL_TRACE_ID(TRYCATCH,
                            "The previous exception has not yet been handled.");
-      return true;
+      return false;
     }
 
     handler->can_continue_ = true;
@@ -160,28 +165,39 @@ bool Isolate::PropagatePendingExceptionToExternalTryCatch() {
     // setting them to an external v8::TryCatch handler.
     handler->exception_ = reinterpret_cast<void*>(pending_exception_);
     handler->message_obj_ = reinterpret_cast<void*>(pending_message_obj_);
+
+    return true;
   }
 
-  return true;
+  return false;
 }
 
-void Isolate::ReportPendingMessages() {
+void Isolate::ReportPendingMessages(bool isVerbose) {
   LWNODE_CALL_TRACE_ID(TRYCATCH);
 
-  PropagatePendingExceptionToExternalTryCatch();
-
   bool should_report_exception = true;
+  auto pendingException = pending_exception();
 
-  if (hasExternalTryCatch()) {
-    should_report_exception = getExternalTryCatchOnTop()->is_verbose_;
+  if (!isVerbose) {
+    PropagatePendingExceptionToExternalTryCatch();
+
+    if (try_catch_handler() != nullptr) {
+      should_report_exception = getExternalTryCatchOnTop()->is_verbose_;
+    }
+
+    clear_pending_exception();
+
+    if (pending_exception_ == scheduled_exception_) {
+      clear_scheduled_exception();
+    }
   }
 
   // Actually report the message to all message handlers.
-  if (should_report_exception) {
+  if (isVerbose || should_report_exception) {
     v8::HandleScope scope(EscargotShim::IsolateWrap::toV8(this));
 
     v8::Local<v8::Value> exception = v8::Utils::NewLocal<v8::Value>(
-        EscargotShim::IsolateWrap::toV8(this), pending_exception_);
+        EscargotShim::IsolateWrap::toV8(this), pendingException);
 
     v8::Local<v8::Message> message = v8::Exception::CreateMessage(
         EscargotShim::IsolateWrap::toV8(this), exception);
@@ -192,6 +208,34 @@ void Isolate::ReportPendingMessages() {
   }
 }
 
+void Isolate::RestorePendingMessageFromTryCatch(v8::TryCatch* handler) {
+  LWNODE_DCHECK(handler == try_catch_handler());
+  LWNODE_DCHECK(handler->HasCaught());
+  LWNODE_DCHECK(handler->rethrow_);
+  LWNODE_DCHECK(handler->capture_message_);
+  LWNODE_DCHECK(!has_pending_exception());
+
+  set_pending_exception(VAL(*handler->Exception())->value());
+}
+
+void Isolate::handleException(EscargotShim::EvalResult& evalResult) {
+  LWNODE_DCHECK(!evalResult.isSuccessful());
+
+  auto exception = evalResult.error.get();
+
+  if (hasCallDepth()) {
+    if (exception->isObject()) {
+      ExtraDataHelper::setExtraData(
+          exception->asObject(),
+          new ExceptionObjectData(evalResult.stackTrace));
+    }
+    ScheduleThrow(evalResult.error.get());
+  } else {
+    SetPendingExceptionAndMessage(exception, evalResult.stackTrace);
+    ReportPendingMessages();
+  }
+}
+
 void Isolate::RunPromiseHook(PromiseHookType type,
                              Escargot::PromiseObjectRef* promise,
                              Escargot::ValueRef* parent) {
@@ -204,6 +248,74 @@ void Isolate::RunPromiseHook(PromiseHookType type,
                 v8::Utils::ToLocal<Value>(parent));
 }
 
+void Isolate::SetPromiseRejectCallback(v8::PromiseRejectCallback callback) {
+  promise_reject_callback_ = callback;
+
+  auto fn = [](ExecutionStateRef* state,
+               Escargot::PromiseObjectRef* promise,
+               Escargot::ValueRef* value,
+               Escargot::VMInstanceRef::PromiseRejectEvent event) {
+    IsolateWrap::GetCurrent()->ReportPromiseReject(promise, value, event);
+  };
+
+  IsolateWrap::fromV8(this)->vmInstance()->registerPromiseRejectCallback(fn);
+}
+
+void Isolate::ReportPromiseReject(
+    Escargot::PromiseObjectRef* promise,
+    Escargot::ValueRef* value,
+    Escargot::VMInstanceRef::PromiseRejectEvent event) {
+  PromiseRejectMessage v8Message(v8::Utils::ToLocal<Promise>(promise),
+                                 static_cast<v8::PromiseRejectEvent>(event),
+                                 v8::Utils::ToLocal<Value>(value));
+#ifdef LWNODE_ENABLE_EXPERIMENTAL_PROMISE
+  if (promise_reject_callback_ && !promise->hasRejectHandlers() &&
+      event == Escargot::VMInstanceRef::PromiseRejectEvent::
+                   PromiseRejectWithNoHandler) {
+    promise_reject_callback_(v8Message);
+  }
+#else
+  LWNODE_UNIMPLEMENT;
+#endif
+}
+
+ValueRef* Isolate::RunPrepareStackTraceCallback(ExecutionStateRef* state,
+                                                ContextWrap* lwContext,
+                                                ValueRef* error,
+                                                ArrayObjectRef* sites) {
+  if (prepare_stack_trace_callback_) {
+    LWNODE_CALL_TRACE_ID_LOG(STACKTRACE,
+                             "RunPrepareStackTraceCallback: %p",
+                             PrepareStackTraceCallback());
+
+    auto v8Isolate = lwContext->GetIsolate()->toV8();
+    v8::MaybeLocal<v8::Value> maybyResult = prepare_stack_trace_callback_(
+        v8::Utils::NewLocal<Context>(v8Isolate, lwContext),
+        v8::Utils::NewLocal<Value>(v8Isolate, error),
+        v8::Utils::NewLocal<Array>(v8Isolate, sites));
+
+    if (!maybyResult.IsEmpty()) {
+      Local<Value> v8Result;
+      if (maybyResult.ToLocal(&v8Result)) {
+        return CVAL(*v8Result)->value();
+      }
+    }
+  }
+
+  return nullptr;
+}
+
+bool Isolate::hasCallDepth() {
+  return callDepth() > 0;
+}
+
+bool Isolate::sholdReportPendingMessage(bool isVerbose) {
+  if (has_pending_exception() && (callDepth() == 0 || isVerbose)) {
+    return true;
+  }
+  return false;
+}
+
 }  // namespace internal
 }  // namespace v8
 
@@ -217,7 +329,7 @@ THREAD_LOCAL IsolateWrap* IsolateWrap::s_previousIsolate;
 IsolateWrap::IsolateWrap() {
   LWNODE_CALL_TRACE_ID(ISOWRAP, "malc: %p", this);
 
-  globalHandles_ = new GlobalHandles(toV8());
+  global_handles_ = new GlobalHandles(this);
 
   privateValuesSymbol_ = PersistentRefHolder<SymbolRef>(
       SymbolRef::create(StringRef::createFromUTF8(PRIVATE_VALUES.data(),
@@ -247,10 +359,6 @@ IsolateWrap::IsolateWrap() {
 
 IsolateWrap::~IsolateWrap() {
   LWNODE_CALL_TRACE_ID(ISOWRAP, "free: %p", this);
-  globalHandles_->Dispose();
-  LWNODE_CALL_TRACE_GC_START();
-  // NOTE: Called when this IsolateWrap is deallocated by gc
-  LWNODE_CALL_TRACE_GC_END();
 }
 
 IsolateWrap* IsolateWrap::New() {
@@ -263,6 +371,9 @@ void IsolateWrap::Dispose() {
   LWNODE_CALL_TRACE_GC_START();
   // NOTE: check unlock_gc_release(); is needed (and where)
   // unlock_gc_release();
+
+  global_handles()->dispose();
+
   LWNODE_CALL_TRACE_GC_END();
 }
 
@@ -334,13 +445,11 @@ void IsolateWrap::Initialize(const v8::Isolate::CreateParams& params) {
 
   vmInstance_->registerErrorCreationCallback(
       [](ExecutionStateRef* state, ErrorObjectRef* error) {
-        ExceptionHelper::setStackPropertyIfNotExist(state, error);
+        ExceptionHelper::addStackPropertyCallback(state, error);
       });
 
   InitializeGlobalSlots();
 
-  scheduled_exception_ = hole()->value();
-
   // Register lwnode internal promise hook to create the internal field.
   LWNODE_ONCE(LWNODE_DLOG_INFO("v8::Promise::kEmbedderFieldCount: %d",
                                v8::Promise::kEmbedderFieldCount));
@@ -583,8 +692,12 @@ void IsolateWrap::ClearPendingExceptionAndMessage() {
   clear_pending_message_obj();
 }
 
-void IsolateWrap::CollectGarbage() {
-  globalHandles_->PostGarbageCollectionProcessing();
+void IsolateWrap::CollectGarbage(GarbageCollectionReason reason) {
+  if (reason == GarbageCollectionReason::kTesting) {
+    global_handles_->releaseWeakValues();
+  } else {
+    global_handles_->PostGarbageCollectionProcessing();
+  }
 }
 
 void IsolateWrap::SetPendingExceptionAndMessage(
@@ -593,8 +706,17 @@ void IsolateWrap::SetPendingExceptionAndMessage(
   LWNODE_CALL_TRACE_ID(TRYCATCH);
 
   if (exception->isObject()) {
-    ExtraDataHelper::setExtraData(exception->asObject(),
-                                  new ExceptionObjectData(stackTraceData));
+    auto extraData = ExtraDataHelper::getExtraData(exception->asObject());
+
+    if (extraData) {
+      LWNODE_CHECK(extraData->isExceptionObjectData());
+      // NOTE: Exception has created in the `else` below.
+      LWNODE_LOG_WARN("esException already contains an extraData: %p\n",
+                      extraData);
+    } else {
+      ExtraDataHelper::setExtraData(exception->asObject(),
+                                    new ExceptionObjectData(stackTraceData));
+    }
   }
 
   set_pending_exception(exception);
@@ -625,13 +747,19 @@ void IsolateWrap::ThrowErrorIfHasException(Escargot::ExecutionStateRef* state) {
   clear_scheduled_exception();
 
   if (isCatchableByJavascript(state)) {
+    ClearPendingExceptionAndMessage();
     if (hasExternalTryCatch()) {
-      ClearPendingExceptionAndMessage();
       SetTerminationOnExternalTryCatch();
     }
     state->throwException(exception);
+    return;
   } else if (!hasExternalTryCatch()) {
-    state->throwException(exception);
+    ReportPendingMessages();
+    return;
+  }
+
+  if (has_pending_exception()) {
+    ReportPendingMessages();
   }
 }
 
@@ -644,10 +772,6 @@ ValueWrap* IsolateWrap::undefined_value() {
   return globalSlot_[internal::Internals::kUndefinedValueRootIndex];
 }
 
-ValueWrap* IsolateWrap::hole() {
-  return globalSlot_[internal::Internals::kTheHoleValueRootIndex];
-}
-
 ValueWrap* IsolateWrap::null() {
   return globalSlot_[internal::Internals::kNullValueRootIndex];
 }
@@ -668,15 +792,6 @@ ValueWrap* IsolateWrap::defaultReturnValue() {
   return globalSlot_[internal::Internals::kDefaultReturnValueRootIndex];
 }
 
-bool IsolateWrap::isHole(const ValueWrap* wrap) {
-  return globalSlot_[internal::Internals::kTheHoleValueRootIndex] == wrap;
-}
-
-bool IsolateWrap::isHole(const Escargot::ValueRef* ref) {
-  return globalSlot_[internal::Internals::kTheHoleValueRootIndex]->value() ==
-         ref;
-}
-
 void IsolateWrap::onFatalError(const char* location, const char* message) {
   if (fatal_error_callback_) {
     fatal_error_callback_(location, message);
index dae0f40cc1961bce1b1e7899a8c235a214c511a5..0a2ba9c6d74c404413da6eda4565829658bdcecf 100755 (executable)
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include "api/es-helper.h"
 #include "arraybuffer-allocator.h"
 #include "engine.h"
 #include "execution/v8threads.h"
@@ -35,6 +36,7 @@ class Isolate : public gc {
   bool IsExecutionTerminating();
   void CancelScheduledExceptionFromTryCatch(v8::TryCatch* that);
   void ThrowException(Escargot::ValueRef* value);
+  void RestorePendingMessageFromTryCatch(v8::TryCatch* handler);
 
   TryCatch* try_catch_handler();
 
@@ -51,30 +53,31 @@ class Isolate : public gc {
   virtual void SetPendingExceptionAndMessage(
       Escargot::ValueRef* exception,
       GCManagedVector<Escargot::Evaluator::StackTraceData>& stackTraceData) = 0;
-  bool PropagatePendingExceptionToExternalTryCatch();
-  void ReportPendingMessages();
+  virtual bool PropagatePendingExceptionToExternalTryCatch();
+  virtual void ReportPendingMessages(bool isVerbose = false);
 
-  virtual EscargotShim::ValueWrap* hole() = 0;
-  virtual bool isHole(const EscargotShim::ValueWrap* wrap) = 0;
-  virtual bool isHole(const Escargot::ValueRef* ref) = 0;
-
-  void SetPromiseRejectCallback(v8::PromiseRejectCallback callback) {
-    promise_reject_callback_ = callback;
-  }
+  void handleException(EscargotShim::EvalResult& evalResult);
 
   void RunPromiseHook(PromiseHookType type,
                       Escargot::PromiseObjectRef* promise,
                       Escargot::ValueRef* parent);
 
+  virtual void SetPromiseRejectCallback(v8::PromiseRejectCallback callback);
+  virtual void ReportPromiseReject(
+      Escargot::PromiseObjectRef* promise,
+      Escargot::ValueRef* value,
+      Escargot::VMInstanceRef::PromiseRejectEvent event);
+
   void SetFatalErrorHandler(v8::FatalErrorCallback callback) {
     fatal_error_callback_ = callback;
   }
 
-  void SetPrepareStackTraceCallback(v8::PrepareStackTraceCallback callback) {
+  virtual void SetPrepareStackTraceCallback(
+      v8::PrepareStackTraceCallback callback) {
     prepare_stack_trace_callback_ = callback;
   }
 
-  bool HasPrepareStackTraceCallback() const {
+  virtual bool HasPrepareStackTraceCallback() const {
     return prepare_stack_trace_callback_ != nullptr;
   }
 
@@ -82,16 +85,35 @@ class Isolate : public gc {
     return prepare_stack_trace_callback_;
   }
 
+  virtual ValueRef* RunPrepareStackTraceCallback(
+      ExecutionStateRef* state,
+      EscargotShim::ContextWrap* lwContext,
+      ValueRef* error,
+      ArrayObjectRef* sites);
+
   void SetAbortOnUncaughtExceptionCallback(
       v8::Isolate::AbortOnUncaughtExceptionCallback callback) {
     abort_on_uncaught_exception_callback_ = callback;
   }
 
+  v8::Isolate::AbortOnUncaughtExceptionCallback
+  abortOnUncaughtExceptionCallback() {
+    return abort_on_uncaught_exception_callback_;
+  }
+
   void AddMessageListenerWithErrorLevel(v8::MessageCallback callback) {
     LWNODE_DCHECK_NULL(message_callback_);
     message_callback_ = callback;
   }
 
+  void increaseCallDepth() { callDepth_++; }
+  void decreaseCallDepth() { callDepth_--; }
+  size_t callDepth() { return callDepth_; }
+  bool hasCallDepth();
+  bool sholdReportPendingMessage(bool isVerbose);
+
+  EscargotShim::GlobalHandles* global_handles() { return global_handles_; }
+
  protected:
   void set_pending_exception(Escargot::ValueRef* exception_obj);
   void set_pending_message_obj(Escargot::ValueRef* message_obj);
@@ -114,10 +136,13 @@ class Isolate : public gc {
   v8::Isolate::AbortOnUncaughtExceptionCallback
       abort_on_uncaught_exception_callback_{nullptr};
 
+  EscargotShim::GlobalHandles* global_handles_ = nullptr;
+
  private:
   v8::TryCatch* try_catch_handler_{nullptr};
   Escargot::ValueRef* pending_exception_{nullptr};
   Escargot::ValueRef* pending_message_obj_{nullptr};
+  size_t callDepth_ = 0;
 };
 }  // namespace internal
 }  // namespace v8
@@ -206,15 +231,13 @@ class IsolateWrap final : public v8::internal::Isolate {
 
   ValueWrap** getGlobal(const int idex);
   ValueWrap* undefined_value();
-  ValueWrap* hole() override;
   ValueWrap* null();
   ValueWrap* trueValue();
   ValueWrap* falseValue();
   ValueWrap* emptyString();
   ValueWrap* defaultReturnValue();
 
-  bool isHole(const ValueWrap* wrap) override;
-  bool isHole(const Escargot::ValueRef* ref) override;
+  bool isDefaultReturnValue(ValueWrap* value);
 
   SymbolRef* createApiSymbol(StringRef* name);
   SymbolRef* getApiSymbol(StringRef* name);
@@ -222,9 +245,8 @@ class IsolateWrap final : public v8::internal::Isolate {
   SymbolRef* createApiPrivateSymbol(StringRef* name);
   SymbolRef* getApiPrivateSymbol(StringRef* name);
 
-  GlobalHandles* globalHandles() { return globalHandles_; }
-
-  void CollectGarbage();
+  void CollectGarbage(
+      GarbageCollectionReason reason = GarbageCollectionReason::kRuntime);
 
   void SetPendingExceptionAndMessage(
       ValueRef* exception,
@@ -245,6 +267,10 @@ class IsolateWrap final : public v8::internal::Isolate {
 
   ThreadManager* thread_manager() { return threadManager_; }
 
+  void PerformMicrotaskCheckpoint() {
+    v8::MicrotasksScope::PerformCheckpoint(toV8(this));
+  }
+
  private:
   IsolateWrap();
 
@@ -270,10 +296,8 @@ class IsolateWrap final : public v8::internal::Isolate {
 
   VMInstanceRef* vmInstance_ = nullptr;
 
-  GlobalHandles* globalHandles_ = nullptr;
-
   PersistentRefHolder<IsolateWrap> release_lock_;
-  ValueWrap* globalSlot_[internal::Internals::kRootIndexSize];
+  ValueWrap* globalSlot_[internal::Internals::kRootIndexSize]{};
 
   ThreadManager* threadManager_ = nullptr;
 };
diff --git a/lwnode/code/escargotshim/src/api/serializer.cc b/lwnode/code/escargotshim/src/api/serializer.cc
new file mode 100644 (file)
index 0000000..4d2e50c
--- /dev/null
@@ -0,0 +1,906 @@
+/*
+ * Copyright (c) 2021-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(LWNODE_ENABLE_EXPERIMENTAL_SERIALIZATION)
+
+#include <cmath>
+
+#include "base.h"
+#include "context.h"
+#include "es-helper.h"
+#include "isolate.h"
+#include "serializer.h"
+
+using namespace Escargot;
+using namespace v8;
+
+namespace EscargotShim {
+
+// base on v8/src/objects/value-serializer.cc
+enum class SerializationTag : uint8_t {
+  // version:uint32_t (if at beginning of data, sets version > 0)
+  kVersion = 0xFF,
+  // ignore
+  kPadding = '\0',
+  // refTableSize:uint32_t (previously used for sanity checks; safe to ignore)
+  kVerifyObjectCount = '?',
+  // Oddballs (no data).
+  kTheHole = '-',
+  kUndefined = '_',
+  kNull = '0',
+  kTrue = 'T',
+  kFalse = 'F',
+  // Number represented as 32-bit integer, ZigZag-encoded
+  // (like sint32 in protobuf)
+  kInt32 = 'I',
+  // Number represented as 32-bit unsigned integer, varint-encoded
+  // (like uint32 in protobuf)
+  kUint32 = 'U',
+  // Number represented as a 64-bit double.
+  // Host byte order is used (N.B. this makes the format non-portable).
+  kDouble = 'N',
+  // BigInt. Bitfield:uint32_t, then raw digits storage.
+  kBigInt = 'Z',
+  // byteLength:uint32_t, then raw data
+  kUtf8String = 'S',
+  kOneByteString = '"',
+  kTwoByteString = 'c',
+  // Reference to a serialized object. objectID:uint32_t
+  kObjectReference = '^',
+  // Beginning of a JS object.
+  kBeginJSObject = 'o',
+  // End of a JS object. numProperties:uint32_t
+  kEndJSObject = '{',
+  // Beginning of a sparse JS array. length:uint32_t
+  // Elements and properties are written as key/value pairs, like objects.
+  kBeginSparseJSArray = 'a',
+  // End of a sparse JS array. numProperties:uint32_t length:uint32_t
+  kEndSparseJSArray = '@',
+  // Beginning of a dense JS array. length:uint32_t
+  // |length| elements, followed by properties as key/value pairs
+  kBeginDenseJSArray = 'A',
+  // End of a dense JS array. numProperties:uint32_t length:uint32_t
+  kEndDenseJSArray = '$',
+  // Date. millisSinceEpoch:double
+  kDate = 'D',
+  // Boolean object. No data.
+  kTrueObject = 'y',
+  kFalseObject = 'x',
+  // Number object. value:double
+  kNumberObject = 'n',
+  // BigInt object. Bitfield:uint32_t, then raw digits storage.
+  kBigIntObject = 'z',
+  // String object, UTF-8 encoding. byteLength:uint32_t, then raw data.
+  kStringObject = 's',
+  // Regular expression, UTF-8 encoding. byteLength:uint32_t, raw data,
+  // flags:uint32_t.
+  kRegExp = 'R',
+  // Beginning of a JS map.
+  kBeginJSMap = ';',
+  // End of a JS map. length:uint32_t.
+  kEndJSMap = ':',
+  // Beginning of a JS set.
+  kBeginJSSet = '\'',
+  // End of a JS set. length:uint32_t.
+  kEndJSSet = ',',
+  // Array buffer. byteLength:uint32_t, then raw data.
+  kArrayBuffer = 'B',
+  // Array buffer (transferred). transferID:uint32_t
+  kArrayBufferTransfer = 't',
+  // View into an array buffer.
+  // subtag:ArrayBufferViewTag, byteOffset:uint32_t, byteLength:uint32_t
+  // For typed arrays, byteOffset and byteLength must be divisible by the size
+  // of the element.
+  // Note: kArrayBufferView is special, and should have an ArrayBuffer (or an
+  // ObjectReference to one) serialized just before it. This is a quirk arising
+  // from the previous stack-based implementation.
+  kArrayBufferView = 'V',
+  // Shared array buffer. transferID:uint32_t
+  kSharedArrayBuffer = 'u',
+  // A wasm module object transfer. next value is its index.
+  kWasmModuleTransfer = 'w',
+  // The delegate is responsible for processing all following data.
+  // This "escapes" to whatever wire format the delegate chooses.
+  kHostObject = '\\',
+  // A transferred WebAssembly.Memory object. maximumPages:int32_t, then by
+  // SharedArrayBuffer tag and its data.
+  kWasmMemoryTransfer = 'm',
+  // A list of (subtag: ErrorTag, [subtag dependent data]). See ErrorTag for
+  // details.
+  kError = 'r',
+
+  // The following tags are reserved because they were in use in Chromium before
+  // the kHostObject tag was introduced in format version 13, at
+  //   v8           refs/heads/master@{#43466}
+  //   chromium/src refs/heads/master@{#453568}
+  //
+  // They must not be reused without a version check to prevent old values from
+  // starting to deserialize incorrectly. For simplicity, it's recommended to
+  // avoid them altogether.
+  //
+  // This is the set of tags that existed in SerializationTag.h at that time and
+  // still exist at the time of this writing (i.e., excluding those that were
+  // removed on the Chromium side because there should be no real user data
+  // containing them).
+  //
+  // It might be possible to also free up other tags which were never persisted
+  // (e.g. because they were used only for transfer) in the future.
+  kLegacyReservedMessagePort = 'M',
+  kLegacyReservedBlob = 'b',
+  kLegacyReservedBlobIndex = 'i',
+  kLegacyReservedFile = 'f',
+  kLegacyReservedFileIndex = 'e',
+  kLegacyReservedDOMFileSystem = 'd',
+  kLegacyReservedFileList = 'l',
+  kLegacyReservedFileListIndex = 'L',
+  kLegacyReservedImageData = '#',
+  kLegacyReservedImageBitmap = 'g',
+  kLegacyReservedImageBitmapTransfer = 'G',
+  kLegacyReservedOffscreenCanvas = 'H',
+  kLegacyReservedCryptoKey = 'K',
+  kLegacyReservedRTCCertificate = 'k',
+};
+
+enum class ArrayBufferViewTag : uint8_t {
+  kInt8Array = 'b',
+  kUint8Array = 'B',
+  kUint8ClampedArray = 'C',
+  kInt16Array = 'w',
+  kUint16Array = 'W',
+  kInt32Array = 'd',
+  kUint32Array = 'D',
+  kFloat32Array = 'f',
+  kFloat64Array = 'F',
+  kBigInt64Array = 'q',
+  kBigUint64Array = 'Q',
+  kDataView = '?',
+};
+
+ValueSerializer::ValueSerializer(IsolateWrap* lwIsolate,
+                                 v8::ValueSerializer::Delegate* delegate)
+    : lwIsolate_(lwIsolate), delegate_(delegate) {
+  LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Create serializer");
+}
+
+void ValueSerializer::WriteHeader() {}
+
+bool ValueSerializer::WriteValue(ValueRef* value) {
+  if (value->isUndefined()) {
+    WriteTag(SerializationTag::kUndefined);
+  } else if (value->isNull()) {
+    WriteTag(SerializationTag::kNull);
+  } else if (value->isBoolean()) {
+    return WriteBoolean(value->asBoolean());
+  } else if (value->isUInt32()) {
+    return WriteUint32(value->asUInt32());
+  } else if (value->isInt32()) {
+    return WriteInt32(value->asInt32());
+  } else if (value->isNumber()) {
+    return WriteNumber(value->asNumber());
+  } else if (value->isBigInt()) {
+    LWNODE_UNIMPLEMENT;
+  } else if (value->isArrayBufferObject()) {
+    auto arrayBuffer = value->asArrayBufferObject();
+    return WriteArrayBuffer(arrayBuffer->byteLength(),
+                            arrayBuffer->rawBuffer());
+  } else if (value->isDataViewObject()) {
+    LWNODE_UNIMPLEMENT;
+  } else if (value->isString()) {
+    WriteString(value->asString());
+  } else if (value->isTypedArrayObject()) {
+    return WriteTypedArrayObject(value->asArrayBufferView());
+  } else if (value->isArrayObject()) {
+    return WriteJsArray(value->asArrayObject());
+  } else if (value->isSymbol()) {
+    LWNODE_UNIMPLEMENT;
+  } else if (value->isFunctionObject()) {
+    LWNODE_UNIMPLEMENT;
+  } else if (value->isObject()) {
+    if (!WriteObject(value->asObject())) {
+      LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Cannot write object");
+      return false;
+    }
+  } else {
+    LWNODE_UNIMPLEMENT;
+    return false;
+  }
+  return ThrowIfOutOfMemory();
+}
+
+bool ValueSerializer::WriteUint32(uint32_t value) {
+  WriteTag(SerializationTag::kUint32);
+  WriteVarint<uint32_t>(value);
+  return ThrowIfOutOfMemory();
+}
+
+bool ValueSerializer::WriteInt32(int32_t value) {
+  WriteTag(SerializationTag::kInt32);
+  WriteZigZag<int32_t>(value);
+  return ThrowIfOutOfMemory();
+}
+
+bool ValueSerializer::WriteNumber(double value) {
+  WriteTag(SerializationTag::kDouble);
+  WriteRawBytes(&value, sizeof(value));
+  return ThrowIfOutOfMemory();
+}
+
+bool ValueSerializer::WriteBoolean(bool value) {
+  if (value) {
+    WriteTag(SerializationTag::kTrue);
+  } else {
+    WriteTag(SerializationTag::kFalse);
+  }
+  return ThrowIfOutOfMemory();
+}
+
+// base on v8
+void ValueSerializer::WriteTag(SerializationTag tag) {
+  uint8_t raw_tag = static_cast<uint8_t>(tag);
+  LWNODE_CALL_TRACE_ID_LOG(SERIALIZER_TAG, "Write Tag %c", (char)tag);
+  WriteRawBytes(&raw_tag, sizeof(raw_tag));
+}
+
+void ValueSerializer::WriteRawBytes(const void* source, size_t length) {
+  uint8_t* dest = ReserveRawBytes(length);
+  if (dest && length > 0) {
+    memcpy(dest, source, length);
+  }
+}
+
+// base on v8
+uint8_t* ValueSerializer::ReserveRawBytes(size_t bytes) {
+  size_t old_size = buffer_.size;
+  size_t new_size = old_size + bytes;
+  if (LWNODE_UNLIKELY(new_size > buffer_.capacity)) {
+    if (!ExpandBuffer(new_size)) {
+      return nullptr;
+    }
+  }
+  buffer_.size = new_size;
+  return &buffer_.data[old_size];
+}
+
+// base on v8
+template <typename T>
+void ValueSerializer::WriteVarint(T value) {
+  // Writes an unsigned integer as a base-128 varint.
+  // The number is written, 7 bits at a time, from the least significant to the
+  // most significant 7 bits. Each byte, except the last, has the MSB set.
+  // See also https://developers.google.com/protocol-buffers/docs/encoding
+  static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
+                "Only unsigned integer types can be written as varints.");
+  uint8_t stack_buffer[sizeof(T) * 8 / 7 + 1];
+  uint8_t* next_byte = &stack_buffer[0];
+  do {
+    *next_byte = (value & 0x7F) | 0x80;
+    next_byte++;
+    value >>= 7;
+  } while (value);
+  *(next_byte - 1) &= 0x7F;
+  WriteRawBytes(stack_buffer, next_byte - stack_buffer);
+}
+
+template <typename T>
+void ValueSerializer::WriteZigZag(T value) {
+  // Writes a signed integer as a varint using ZigZag encoding (i.e. 0 is
+  // encoded as 0, -1 as 1, 1 as 2, -2 as 3, and so on).
+  // See also https://developers.google.com/protocol-buffers/docs/encoding
+  // Note that this implementation relies on the right shift being arithmetic.
+  static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
+                "Only signed integer types can be written as zigzag.");
+  using UnsignedT = typename std::make_unsigned<T>::type;
+  WriteVarint((static_cast<UnsignedT>(value) << 1) ^
+              (value >> (8 * sizeof(T) - 1)));
+}
+
+void ValueSerializer::WriteString(StringRef* string) {
+  auto bufferData = string->stringBufferAccessData();
+  if (bufferData.has8BitContent) {
+    WriteTag(SerializationTag::kOneByteString);
+    WriteVarint<uint32_t>(bufferData.length);
+    WriteRawBytes(bufferData.buffer, bufferData.length * sizeof(uint8_t));
+  } else {
+    WriteTag(SerializationTag::kTwoByteString);
+    WriteVarint<uint32_t>(bufferData.length);
+    WriteRawBytes(bufferData.buffer, bufferData.length * sizeof(uint16_t));
+  }
+}
+
+bool ValueSerializer::WriteHostObject(ObjectRef* object) {
+  WriteTag(SerializationTag::kHostObject);
+  if (!delegate_) {
+    // @note deps/v8/src/objects/value-serializer.cc(1006) throws an Error
+    LWNODE_CHECK(false);
+    return false;
+  }
+
+  v8::Isolate* v8_isolate = lwIsolate_->toV8();
+  Maybe<bool> result =
+      delegate_->WriteHostObject(v8_isolate, Utils::ToLocal<Object>(object));
+
+  LWNODE_CHECK(!result.IsNothing());
+  LWNODE_CHECK(result.ToChecked());
+  return ThrowIfOutOfMemory();
+}
+
+bool ValueSerializer::WriteObject(ObjectRef* object) {
+  if (ObjectRefHelper::getInternalFieldCount(object) > 0) {
+    return WriteHostObject(object);
+  }
+
+  auto esContext = lwIsolate_->GetCurrentContext()->get();
+  uint32_t propertiesWritten = 0;
+  WriteTag(SerializationTag::kBeginJSObject);
+  Escargot::ValueVectorRef* keys = nullptr;
+  EvalResult r = Evaluator::execute(
+      esContext,
+      [](ExecutionStateRef* state,
+         ObjectRef* object,
+         Escargot::ValueVectorRef** keys) -> ValueRef* {
+        *keys = object->ownPropertyKeys(state);
+        return ValueRef::createUndefined();
+      },
+      object,
+      &keys);
+  LWNODE_CHECK(r.isSuccessful());
+
+  for (size_t i = 0; i < keys->size(); i++) {
+    auto propValueResult =
+        ObjectRefHelper::getProperty(esContext, object, keys->at(i));
+    LWNODE_CHECK(propValueResult.isSuccessful());
+    bool success =
+        WriteValue(keys->at(i)) && WriteValue(propValueResult.result);
+    if (!success) {
+      return false;
+    }
+    propertiesWritten++;
+  }
+
+  WriteTag(SerializationTag::kEndJSObject);
+  WriteVarint<uint32_t>(propertiesWritten);
+
+  return ThrowIfOutOfMemory();
+}
+
+bool ValueSerializer::WriteJsArray(ArrayObjectRef* array) {
+  auto esContext = lwIsolate_->GetCurrentContext()->get();
+
+  uint32_t length = ArrayObjectRefHelper::length(esContext, array);
+  LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "WriteJsArray start: %u", length);
+
+  WriteTag(SerializationTag::kBeginDenseJSArray);
+  WriteVarint<uint32_t>(length);
+
+  for (uint32_t i = 0; i < length; i++) {
+    auto esValue = ArrayObjectRefHelper::get(esContext, array, i);
+    if (!WriteValue(esValue)) {
+      return false;
+    }
+  }
+
+  WriteTag(SerializationTag::kEndDenseJSArray);
+  LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "WriteJsArray end");
+  return true;
+}
+
+bool ValueSerializer::WriteArrayBuffer(size_t length, uint8_t* bytes) {
+  WriteTag(SerializationTag::kArrayBuffer);
+  WriteVarint<uint32_t>(length);
+  WriteRawBytes(bytes, length);
+  return ThrowIfOutOfMemory();
+}
+
+bool ValueSerializer::WriteArrayBufferView(
+    ArrayBufferViewRef* arrayBufferView) {
+  WriteTag(SerializationTag::kArrayBufferView);
+
+  ArrayBufferViewTag typeTag = ArrayBufferViewTag::kInt8Array;
+
+  if (arrayBufferView->isDataViewObject()) {
+    typeTag = ArrayBufferViewTag::kDataView;
+  }
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)                              \
+  else if (arrayBufferView->is##Type##ArrayObject()) {                         \
+    typeTag = ArrayBufferViewTag::k##Type##Array;                              \
+  }
+  TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+  else {
+    LWNODE_DLOG_ERROR("Serializer: Invalid buffer type");
+    return false;
+  }
+
+  WriteVarint(static_cast<uint8_t>(typeTag));
+  WriteVarint(static_cast<uint32_t>(arrayBufferView->byteOffset()));
+  WriteVarint(static_cast<uint32_t>(arrayBufferView->arrayLength()));
+  return ThrowIfOutOfMemory();
+}
+
+bool ValueSerializer::WriteTypedArrayObject(
+    Escargot::ArrayBufferViewRef* bufferView) {
+  auto result =
+      WriteArrayBuffer(bufferView->byteLength(), bufferView->rawBuffer());
+  return result && WriteArrayBufferView(bufferView);
+}
+
+// base on v8
+bool ValueSerializer::ExpandBuffer(size_t required_capacity) {
+  LWNODE_CHECK(required_capacity > buffer_.capacity);
+  size_t requested_capacity =
+      std::max(required_capacity, buffer_.capacity * 2) + 64;
+  size_t provided_capacity = 0;
+  void* new_buffer = nullptr;
+  if (delegate_) {
+    new_buffer = delegate_->ReallocateBufferMemory(
+        buffer_.data, requested_capacity, &provided_capacity);
+  } else {
+    new_buffer = realloc(buffer_.data, requested_capacity);
+    provided_capacity = requested_capacity;
+  }
+  if (new_buffer) {
+    LWNODE_CHECK(provided_capacity >= requested_capacity);
+    buffer_.data = reinterpret_cast<uint8_t*>(new_buffer);
+    buffer_.capacity = provided_capacity;
+    return true;
+  } else {
+    out_of_memory_ = true;
+    return false;
+  }
+}
+
+bool ValueSerializer::ThrowIfOutOfMemory() {
+  if (out_of_memory_) {
+    LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "out of memory");
+    ThrowDataCloneError();
+    return false;
+  }
+  return true;
+}
+
+void ValueSerializer::ThrowDataCloneError() {
+  if (delegate_) {
+    delegate_->ThrowDataCloneError(Utils::NewLocal<String>(
+        lwIsolate_->toV8(),
+        ErrorMessage::createErrorStringRef(
+            ErrorMessageType::kDataCloneErrorOutOfMemory)));
+  } else {
+    auto esContext = lwIsolate_->GetCurrentContext()->get();
+    lwIsolate_->ScheduleThrow(ExceptionHelper::createErrorObject(
+        esContext, ErrorMessageType::kDataCloneErrorOutOfMemory));
+  }
+
+  if (lwIsolate_->sholdReportPendingMessage(false)) {
+    lwIsolate_->ReportPendingMessages();
+  }
+}
+
+std::pair<uint8_t*, size_t> ValueSerializer::Release() {
+  LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "buffer size: %zu", buffer_.size);
+
+  uint8_t* buffer = nullptr;
+  auto size = buffer_.size;
+  if (size > 0) {
+    if (delegate_) {
+      size_t allocatedSize = 0;
+      buffer = static_cast<uint8_t*>(
+          delegate_->ReallocateBufferMemory(buffer, size, &allocatedSize));
+      LWNODE_CHECK(size == allocatedSize);
+    } else {
+      buffer = static_cast<uint8_t*>(malloc(size * sizeof(uint8_t)));
+    }
+
+    memcpy(buffer, buffer_.data, size);
+  }
+
+  free(buffer_.data);
+  buffer_.size = 0;
+
+  return std::make_pair(buffer, size);
+}
+
+ValueDeserializer::ValueDeserializer(IsolateWrap* lwIsolate,
+                                     v8::ValueDeserializer::Delegate* delegate,
+                                     const uint8_t* data,
+                                     const size_t size)
+    : lwIsolate_(lwIsolate), delegate_(delegate), buffer_(data, size) {
+  LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Create deserializer (%zu)", size);
+}
+
+OptionalRef<ValueRef> ValueDeserializer::ReadValue() {
+  SerializationTag tag;
+  if (!ReadTag(tag)) {
+    LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Cannot read tag");
+    return OptionalRef<ValueRef>();
+  }
+
+  if (tag == SerializationTag::kNull) {
+    return OptionalRef<ValueRef>(ValueRef::createNull());
+  } else if (tag == SerializationTag::kUndefined) {
+    return OptionalRef<ValueRef>(ValueRef::createUndefined());
+  } else if (tag == SerializationTag::kTrue) {
+    return OptionalRef<ValueRef>(ValueRef::create(true));
+  } else if (tag == SerializationTag::kFalse) {
+    return OptionalRef<ValueRef>(ValueRef::create(false));
+  } else if (tag == SerializationTag::kDouble) {
+    double number = .0;
+    if (!ReadDouble(number)) {
+      LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Cannot read double value");
+      return OptionalRef<ValueRef>();
+    }
+    return OptionalRef<ValueRef>(ValueRef::create(number));
+  } else if (tag == SerializationTag::kOneByteString) {
+    StringRef* string = nullptr;
+    if (!ReadOneByteString(string)) {
+      LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Cannot read one byte string value");
+      return OptionalRef<ValueRef>();
+    }
+    return OptionalRef<ValueRef>(string);
+  } else if (tag == SerializationTag::kTwoByteString) {
+    StringRef* string = nullptr;
+    if (!ReadTwoByteString(string)) {
+      LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Cannot read two byte string value");
+      return OptionalRef<ValueRef>();
+    }
+    return OptionalRef<ValueRef>(string);
+  } else if (tag == SerializationTag::kUint32) {
+    uint32_t value = 0;
+    if (!ReadVarint<uint32_t>(value)) {
+      LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Cannot read uint32 value");
+      return OptionalRef<ValueRef>();
+    }
+    return OptionalRef<ValueRef>(ValueRef::create(value));
+  } else if (tag == SerializationTag::kInt32) {
+    int32_t value = 0;
+    if (!ReadZigZag<int32_t>(value)) {
+      LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Cannot read int32 value");
+      return OptionalRef<ValueRef>();
+    }
+    return OptionalRef<ValueRef>(ValueRef::create(value));
+  } else if (tag == SerializationTag::kBeginJSObject) {
+    auto esContext = lwIsolate_->GetCurrentContext()->get();
+    auto object = ObjectRefHelper::create(esContext);
+    if (!ReadObject(object)) {
+      LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Cannot read object value");
+      return OptionalRef<ValueRef>();
+    }
+    return OptionalRef<ValueRef>(object);
+  } else if (tag == SerializationTag::kHostObject) {
+    ObjectRef* esObject = nullptr;
+    if (!ReadHostObject(esObject)) {
+      LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Cannot read host object value");
+      return OptionalRef<ValueRef>();
+    }
+    return OptionalRef<ValueRef>(esObject);
+  } else if (tag == SerializationTag::kBeginDenseJSArray) {
+    ArrayObjectRef* array = nullptr;
+    if (!ReadJsArray(array)) {
+      LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Cannot read array value");
+      return OptionalRef<ValueRef>();
+    }
+    return OptionalRef<ValueRef>(array);
+  } else if (tag == SerializationTag::kArrayBuffer) {
+    ValueRef* arrayBuffer = nullptr;
+    if (!ReadJsArrayBuffer(arrayBuffer)) {
+      LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Cannot read array buffer value");
+      return OptionalRef<ValueRef>();
+    }
+    return OptionalRef<ValueRef>(arrayBuffer);
+  } else {
+    LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Fail: %c", (char)tag);
+    LWNODE_UNIMPLEMENT;
+  }
+
+  return OptionalRef<ValueRef>();
+}
+
+// base on v8
+bool ValueDeserializer::ReadTag(SerializationTag& tag) {
+  do {
+    if (buffer_.isOverflow()) {
+      return false;
+    }
+    tag = static_cast<SerializationTag>(buffer_.currentPositionData());
+    buffer_.position++;
+  } while (tag == SerializationTag::kPadding);
+
+  LWNODE_CALL_TRACE_ID_LOG(SERIALIZER_TAG, "Read Tag %c", (char)tag);
+  return true;
+}
+
+bool ValueDeserializer::CheckTag(SerializationTag check) {
+  SerializationTag tag;
+  size_t curPosition = buffer_.position;
+  do {
+    if (buffer_.isOverflow()) {
+      return false;
+    }
+    tag = static_cast<SerializationTag>(buffer_.data[curPosition]);
+    curPosition++;
+  } while (tag == SerializationTag::kPadding);
+
+  return tag == check;
+}
+
+bool ValueDeserializer::ReadUint32(uint32_t*& value) {
+  if (!CheckTag(SerializationTag::kUint32)) {
+    return false;
+  }
+
+  OptionalRef<ValueRef> valueRef = ReadValue();
+  if (valueRef) {
+    *value = valueRef->asUInt32();
+  }
+  return valueRef;
+}
+
+template <typename T>
+bool ValueDeserializer::ReadVarint(T& value) {
+  // Reads an unsigned integer as a base-128 varint.
+  // The number is written, 7 bits at a time, from the least significant to the
+  // most significant 7 bits. Each byte, except the last, has the MSB set.
+  // If the varint is larger than T, any more significant bits are discarded.
+  // See also https://developers.google.com/protocol-buffers/docs/encoding
+  static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
+                "Only unsigned integer types can be read as varints.");
+  value = 0;
+  unsigned shift = 0;
+  bool has_another_byte;
+  do {
+    if (buffer_.isOverflow()) {
+      return false;
+    }
+    uint8_t byte = buffer_.currentPositionData();
+    if (V8_LIKELY(shift < sizeof(T) * 8)) {
+      value |= static_cast<T>(byte & 0x7F) << shift;
+      shift += 7;
+    }
+    has_another_byte = byte & 0x80;
+    buffer_.position++;
+  } while (has_another_byte);
+  return true;
+}
+
+template <typename T>
+bool ValueDeserializer::ReadZigZag(T& value) {
+  // Writes a signed integer as a varint using ZigZag encoding (i.e. 0 is
+  // encoded as 0, -1 as 1, 1 as 2, -2 as 3, and so on).
+  // See also https://developers.google.com/protocol-buffers/docs/encoding
+  static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
+                "Only signed integer types can be read as zigzag.");
+  using UnsignedT = typename std::make_unsigned<T>::type;
+  UnsignedT unsigned_value;
+  if (!ReadVarint<UnsignedT>(unsigned_value)) {
+    return false;
+  }
+  value = static_cast<T>((unsigned_value >> 1) ^
+                         -static_cast<T>(unsigned_value & 1));
+  return true;
+}
+
+bool ValueDeserializer::ReadDouble(double& value) {
+  if (buffer_.position > buffer_.size - sizeof(double)) {
+    return false;
+  }
+  value = 0;
+  memcpy(&value, buffer_.currentPositionAddress(), sizeof(double));
+  buffer_.position += sizeof(double);
+  if (std::isnan(value)) {
+    return false;
+  }
+  return true;
+}
+
+bool ValueDeserializer::ReadOneByteString(StringRef*& string) {
+  uint32_t length = 0;
+  const uint8_t* data;
+  if (!ReadVarint<uint32_t>(length) || !ReadRawBytes(length, data)) {
+    return false;
+  }
+  string = StringRef::createFromUTF8(reinterpret_cast<const char*>(data),
+                                     static_cast<size_t>(length));
+  return true;
+}
+
+bool ValueDeserializer::ReadTwoByteString(StringRef*& string) {
+  uint32_t length = 0;
+  const uint8_t* data;
+  if (!ReadVarint<uint32_t>(length) ||
+      !ReadRawBytes(length * sizeof(uint16_t), data)) {
+    return false;
+  }
+  string = StringRef::createFromUTF16(reinterpret_cast<const char16_t*>(data),
+                                      static_cast<size_t>(length));
+  return true;
+}
+
+bool ValueDeserializer::ReadObject(ObjectRef* object) {
+  size_t propertiesRead = 0;
+
+  while (!CheckTag(SerializationTag::kEndJSObject)) {
+    auto key = ReadValue();
+    if (!key.hasValue() || key.get()->isUndefinedOrNull()) {
+      LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Cannot read key of object");
+      return false;
+    }
+    auto value = ReadValue();
+    if (!value.hasValue()) {
+      LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "Cannot read value of object");
+      return false;
+    }
+
+    ObjectRefHelper::setProperty(
+        lwIsolate_->GetCurrentContext()->context()->get(),
+        object,
+        key.get(),
+        value.get());
+
+    propertiesRead++;
+  }
+
+  SerializationTag tag;
+  if (!ReadTag(tag)) {
+    return false;
+  }
+  if (tag == SerializationTag::kEndJSObject) {
+    uint32_t propertiesWritten;
+    if (ReadVarint<uint32_t>(propertiesWritten)) {
+      return propertiesRead == propertiesWritten;
+    }
+  }
+  return false;
+}
+
+bool ValueDeserializer::ReadHostObject(ObjectRef*& esObject) {
+  esObject = nullptr;
+  if (!delegate_) {
+    return false;
+  }
+  v8::Isolate* v8_isolate = lwIsolate_->toV8();
+  v8::Local<v8::Object> object;
+  if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) {
+    return false;
+  }
+
+  esObject = VAL(*object)->value()->asObject();
+  return true;
+}
+
+bool ValueDeserializer::ReadJsArray(ArrayObjectRef*& array) {
+  uint32_t length = 0;
+  if (!ReadVarint<uint32_t>(length)) {
+    return false;
+  }
+
+  LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "ReadJsArray start: %u", length);
+  auto vector = ValueVectorRef::create();
+
+  for (uint32_t i = 0; i < length; i++) {
+    OptionalRef<ValueRef> valueRef = ReadValue();
+    if (!valueRef.hasValue()) {
+      return false;
+    }
+    vector->pushBack(valueRef.get());
+  }
+
+  auto esContext = lwIsolate_->GetCurrentContext()->get();
+  array = ArrayObjectRefHelper::create(esContext, vector);
+
+  SerializationTag tag;
+  ReadTag(tag);
+
+  LWNODE_CALL_TRACE_ID_LOG(SERIALIZER, "ReadJsArray end");
+
+  return (tag == SerializationTag::kEndDenseJSArray);
+}
+
+bool ValueDeserializer::ReadJsArrayBuffer(ValueRef*& value) {
+  ArrayBufferObjectRef* arrayBuffer = nullptr;
+  if (!ReadArrayBuffer(arrayBuffer)) {
+    return false;
+  }
+
+  if (CheckTag(SerializationTag::kArrayBufferView)) {
+    SerializationTag tag;
+    ReadTag(tag);
+    ArrayBufferViewRef* arrayBufferView = nullptr;
+    if (!ReadArrayBufferView(arrayBufferView, arrayBuffer)) {
+      return false;
+    }
+    value = arrayBufferView;
+    return true;
+  }
+  value = arrayBuffer;
+  return true;
+}
+
+bool ValueDeserializer::ReadArrayBuffer(
+    ArrayBufferObjectRef*& arrayBufferObject) {
+  uint32_t length = 0;
+  const uint8_t* bytes = nullptr;
+  if (!ReadVarint<uint32_t>(length) || !ReadRawBytes(length, bytes)) {
+    return false;
+  }
+
+  auto esContext = lwIsolate_->GetCurrentContext()->get();
+  EvalResult r = Evaluator::execute(
+      esContext,
+      [](ExecutionStateRef* esState, size_t byteLength) -> ValueRef* {
+        auto arrayBuffer = ArrayBufferObjectRef::create(esState);
+        arrayBuffer->allocateBuffer(esState, byteLength);
+        return arrayBuffer;
+      },
+      (size_t)length);
+  LWNODE_CHECK(r.isSuccessful());
+
+  auto backingStore =
+      BackingStoreRef::createDefaultNonSharedBackingStore(length);
+  arrayBufferObject = r.result->asArrayBufferObject();
+  arrayBufferObject->attachBuffer(backingStore);
+
+  memcpy(arrayBufferObject->rawBuffer(), bytes, length);
+
+  return true;
+}
+
+bool ValueDeserializer::ReadArrayBufferView(
+    ArrayBufferViewRef*& arrayBufferView, ArrayBufferObjectRef* abo) {
+  uint8_t tag = 0;
+  uint32_t byteOffset = 0;
+  uint32_t arrayLength = 0;
+
+  if (!ReadVarint<uint8_t>(tag) || !ReadVarint<uint32_t>(byteOffset) ||
+      !ReadVarint<uint32_t>(arrayLength)) {
+    return false;
+  }
+
+  auto esContext = lwIsolate_->GetCurrentContext()->get();
+
+  switch (static_cast<ArrayBufferViewTag>(tag)) {
+    case ArrayBufferViewTag::kDataView: {
+      return false;
+    }
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)                              \
+  case ArrayBufferViewTag::k##Type##Array:                                     \
+    arrayBufferView = ArrayBufferHelper::createView<Type##ArrayObjectRef>(     \
+        esContext,                                                             \
+        abo,                                                                   \
+        byteOffset,                                                            \
+        arrayLength,                                                           \
+        ArrayBufferHelper::ArrayType::kExternal##Type##Array);                 \
+    return true;
+      TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+    default:
+      return false;
+  }
+
+  return false;
+}
+
+bool ValueDeserializer::ReadRawBytes(size_t size, const uint8_t*& data) {
+  if (size > buffer_.size - buffer_.position) {
+    return false;
+  }
+
+  data = buffer_.currentPositionAddress();
+  buffer_.position += size;
+  return true;
+}
+
+}  // namespace EscargotShim
+
+#endif
diff --git a/lwnode/code/escargotshim/src/api/serializer.h b/lwnode/code/escargotshim/src/api/serializer.h
new file mode 100644 (file)
index 0000000..258e236
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2021-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(LWNODE_ENABLE_EXPERIMENTAL_SERIALIZATION)
+
+#pragma once
+
+#include <EscargotPublic.h>
+#include <v8.h>
+
+#include "utils/optional.h"
+
+using namespace Escargot;
+
+namespace EscargotShim {
+
+enum class SerializationTag : uint8_t;
+
+class IsolateWrap;
+
+struct SerializerBuffer {
+  SerializerBuffer() = default;
+  SerializerBuffer(const uint8_t* _data, size_t _size)
+      : data(const_cast<uint8_t*>(_data)), size(_size) {}
+  uint8_t* data = nullptr;
+  size_t size = 0;
+  size_t capacity = 0;
+  size_t position = 0;
+
+  uint8_t currentPositionData() {
+    LWNODE_CHECK(!isOverflow());
+    return data[position];
+  }
+
+  uint8_t* currentPositionAddress() {
+    LWNODE_CHECK(!isOverflow());
+    return &data[position];
+  }
+
+  bool isOverflow() { return position >= size; }
+};
+
+class ValueSerializer {
+ public:
+  ValueSerializer(IsolateWrap* lwIsolate,
+                  v8::ValueSerializer::Delegate* delegate);
+  void WriteHeader();
+  bool WriteValue(ValueRef* value);
+  bool WriteUint32(uint32_t value);
+  bool WriteInt32(int32_t value);
+  bool WriteNumber(double value);
+
+  std::pair<uint8_t*, size_t> Release();
+
+ private:
+  void WriteTag(SerializationTag tag);
+  void WriteRawBytes(const void* source, size_t length);
+  uint8_t* ReserveRawBytes(size_t bytes);
+
+  template <typename T>
+  void WriteVarint(T value);
+  template <typename T>
+  void WriteZigZag(T value);
+  bool WriteBoolean(bool value);
+  void WriteString(StringRef* string);
+  bool WriteObject(ObjectRef* object);
+  bool WriteJsArray(ArrayObjectRef* array);
+  bool WriteHostObject(ObjectRef* object);
+  bool WriteArrayBuffer(size_t length, uint8_t* bytes);
+  bool WriteArrayBufferView(ArrayBufferViewRef* arrayBufferView);
+  bool WriteTypedArrayObject(Escargot::ArrayBufferViewRef* bufferView);
+  bool ExpandBuffer(size_t required_capacity);
+  bool ThrowIfOutOfMemory();
+  void ThrowDataCloneError();
+
+  IsolateWrap* lwIsolate_ = nullptr;
+  v8::ValueSerializer::Delegate* delegate_ = nullptr;
+  SerializerBuffer buffer_;
+  bool out_of_memory_ = false;
+};
+
+class ValueDeserializer {
+ public:
+  ValueDeserializer(IsolateWrap* isolate,
+                    v8::ValueDeserializer::Delegate* delegate,
+                    const uint8_t* data,
+                    const size_t size);
+  ~ValueDeserializer(){};
+
+  OptionalRef<ValueRef> ReadValue();
+  bool ReadUint32(uint32_t*& value);
+
+ private:
+  bool ReadTag(SerializationTag& tag);
+  bool CheckTag(SerializationTag tag);
+  template <typename T>
+  bool ReadVarint(T& value);
+  template <typename T>
+  bool ReadZigZag(T& value);
+  bool ReadDouble(double& value);
+  bool ReadOneByteString(StringRef*& string);
+  bool ReadTwoByteString(StringRef*& string);
+  bool ReadObject(ObjectRef* object);
+  bool ReadHostObject(ObjectRef*& object);
+  bool ReadJsArray(ArrayObjectRef*& array);
+  bool ReadJsArrayBuffer(ValueRef*& value);
+  bool ReadArrayBuffer(ArrayBufferObjectRef*& arayBufferObject);
+  bool ReadArrayBufferView(ArrayBufferViewRef*& arrayBufferView,
+                           ArrayBufferObjectRef* arrayBufferObject);
+
+  bool ReadRawBytes(size_t size, const uint8_t*& data);
+
+  IsolateWrap* lwIsolate_ = nullptr;
+  v8::ValueDeserializer::Delegate* delegate_ = nullptr;
+  SerializerBuffer buffer_;
+};
+
+}  // namespace EscargotShim
+
+#endif
index 8f7ba9a58a8027c1047a996107f015ae5b60512b..3c5bb86d4b6dc5413ebfa75108f69e1e88f74fe5 100644 (file)
@@ -25,29 +25,7 @@ using namespace v8;
 
 namespace EscargotShim {
 
-class NativeDataAccessorPropertyDataForStackTrace
-    : public ObjectRef::NativeDataAccessorPropertyData {
- public:
-  NativeDataAccessorPropertyDataForStackTrace(
-      bool isWritable,
-      bool isEnumerable,
-      bool isConfigurable,
-      ObjectRef::NativeDataAccessorPropertyGetter getter,
-      ObjectRef::NativeDataAccessorPropertySetter setter,
-      ValueVectorRef* stackTraceVector)
-      : NativeDataAccessorPropertyData(
-            isWritable, isEnumerable, isConfigurable, getter, setter),
-        stackTraceVector_(stackTraceVector) {}
-
-  ValueVectorRef* stackTraceVector() { return stackTraceVector_; }
-
-  void* operator new(size_t size) { return GC_MALLOC(size); }
-
- private:
-  ValueVectorRef* stackTraceVector_;
-};
-
-static size_t getStackTraceLimit(ExecutionStateRef* state) {
+size_t StackTrace::getStackTraceLimit(ExecutionStateRef* state) {
   auto errorObject = state->context()->globalObject()->get(
       state, StringRef::createFromASCII("Error"));
   LWNODE_CHECK(errorObject->isObject());
@@ -59,56 +37,50 @@ static size_t getStackTraceLimit(ExecutionStateRef* state) {
   return stackTraceLimitValue->asNumber();
 }
 
-static ValueRef* StackTraceGetter(
+ValueRef* StackTrace::StackTraceGetter(
     ExecutionStateRef* state,
     ObjectRef* self,
     ValueRef* receiver,
     ObjectRef::NativeDataAccessorPropertyData* data) {
   auto lwIsolate = IsolateWrap::GetCurrent();
   auto lwContext = lwIsolate->GetCurrentContext();
-  auto accessorData =
-      reinterpret_cast<NativeDataAccessorPropertyDataForStackTrace*>(data);
+  auto accessorData = reinterpret_cast<NativeAccessorProperty*>(data);
 
   if (lwIsolate->HasPrepareStackTraceCallback()) {
     auto sites =
         ArrayObjectRef::create(state, accessorData->stackTraceVector());
-    v8::MaybeLocal<v8::Value> callbackResult =
-        lwIsolate->PrepareStackTraceCallback()(
-            v8::Utils::NewLocal<Context>(lwIsolate->toV8(), lwContext),
-            v8::Utils::NewLocal<Value>(lwIsolate->toV8(), self),
-            v8::Utils::NewLocal<Array>(lwIsolate->toV8(), sites));
-
-    if (!callbackResult.IsEmpty()) {
-      Local<Value> callbackResultLocal;
-      if (callbackResult.ToLocal(&callbackResultLocal)) {
-        return CVAL(*callbackResultLocal)->value();
-      }
+
+    auto formattedStackTrace =
+        lwIsolate->RunPrepareStackTraceCallback(state, lwContext, self, sites);
+    if (formattedStackTrace) {
+      return formattedStackTrace;
     }
   }
 
   return ValueRef::createUndefined();
 }
 
-static bool StackTraceSetter(ExecutionStateRef* state,
-                             ObjectRef* self,
-                             ValueRef* receiver,
-                             ObjectRef::NativeDataAccessorPropertyData* data,
-                             ValueRef* setterInputData) {
+bool StackTrace::StackTraceSetter(
+    ExecutionStateRef* state,
+    ObjectRef* self,
+    ValueRef* receiver,
+    ObjectRef::NativeDataAccessorPropertyData* data,
+    ValueRef* setterInputData) {
   LWNODE_RETURN_FALSE;
 }
 
-static ValueRef* captureStackTraceCallback(ExecutionStateRef* state,
-                                           ValueRef* thisValue,
-                                           size_t argc,
-                                           ValueRef** argv,
-                                           bool isConstructCall) {
+ValueRef* StackTrace::captureStackTraceCallback(ExecutionStateRef* state,
+                                                ValueRef* thisValue,
+                                                size_t argc,
+                                                ValueRef** argv,
+                                                bool isConstructCall) {
   if (argc < 1 || !argv[0]->isObject()) {
     return ValueRef::createUndefined();
   }
 
   auto exceptionObject = argv[0]->asObject();
   auto callSite = IsolateWrap::GetCurrent()->GetCurrentContext()->callSite();
-  auto stackTrace = state->computeStackTraceData();
+  auto stackTrace = state->computeStackTrace();
   auto stackTraceVector = ValueVectorRef::create();
 
   std::string filterFunctionName;
@@ -137,19 +109,28 @@ static ValueRef* captureStackTraceCallback(ExecutionStateRef* state,
         callSite->instantiate(state->context(), stackTrace[i]));
   }
 
-  exceptionObject->defineNativeDataAccessorProperty(
-      state,
-      StringRef::createFromUTF8("stack"),
-      new NativeDataAccessorPropertyDataForStackTrace(false,
-                                                      false,
-                                                      false,
-                                                      StackTraceGetter,
-                                                      StackTraceSetter,
-                                                      stackTraceVector));
+  // FIXME: it seems there are some cases where we need to freeze the
+  // stack string here. Investigate further
+  addStackProperty(state, exceptionObject, stackTraceVector);
 
   return ValueRef::createUndefined();
 }
 
+void StackTrace::addStackProperty(ExecutionStateRef* state,
+                                  ObjectRef* object,
+                                  ValueVectorRef* stackTraceVector) {
+  // NOTE: either Error or Exception contains stack.
+  object->defineNativeDataAccessorProperty(
+      state,
+      StringRef::createFromUTF8("stack"),
+      new NativeAccessorProperty(false,
+                                 false,
+                                 false,
+                                 StackTraceGetter,
+                                 StackTraceSetter,
+                                 stackTraceVector));
+}
+
 ValueRef* StackTrace::createCaptureStackTrace(
     Escargot::ExecutionStateRef* state) {
   FunctionObjectRef::NativeFunctionInfo info(
@@ -162,41 +143,105 @@ ValueRef* StackTrace::createCaptureStackTrace(
   return FunctionObjectRef::create(state, info);
 }
 
-static void setCallSitePrototype(
-    ContextRef* context,
-    ObjectTemplateRef* otpl,
-    const char* name,
-    Escargot::FunctionObjectRef::NativeFunctionPointer fn) {
-  auto length = strlen(name);
+ValueRef* StackTrace::createPrepareStackTrace(
+    Escargot::ExecutionStateRef* state) {
+  FunctionObjectRef::NativeFunctionInfo info(
+      AtomicStringRef::create(state->context(), "prepareStackTrace"),
+      prepareStackTraceCallback,
+      2,
+      true,
+      false);
 
-  EvalResult r = Evaluator::execute(
-      context,
-      [](ExecutionStateRef* state,
-         const char* name,
-         size_t length,
-         Escargot::FunctionObjectRef::NativeFunctionPointer fn) -> ValueRef* {
-        return FunctionObjectRef::create(
-            state,
-            FunctionObjectRef::NativeFunctionInfo(
-                AtomicStringRef::create(state->context(), name, length),
-                fn,
-                0,
-                true,
-                false));
-      },
-      name,
-      length,
-      fn);
-  LWNODE_CHECK(r.isSuccessful());
+  return FunctionObjectRef::create(state, info);
+}
+
+ValueRef* StackTrace::prepareStackTraceCallback(ExecutionStateRef* state,
+                                                ValueRef* thisValue,
+                                                size_t argc,
+                                                ValueRef** argv,
+                                                bool isConstructCall) {
+  // TODO: JS registers prepareStackTrace() to reformat StackTrace.
+  LWNODE_UNIMPLEMENT;
+  return StringRef::emptyString();
+}
+
+StringRef* StackTrace::formatStackTraceStringNodeStyle(ObjectRef* errorObject,
+                                                       size_t maxStackSize) {
+  std::ostringstream oss;
+  auto message = errorObject->toString(state_)->toStdUTF8String();
+  if (message.length() > 0) {
+    oss << message << "\n";
+  }
+
+  auto traceData = state_->computeStackTrace();
+  size_t maxPrintStackSize = std::min((int)maxStackSize, (int)traceData.size());
+
+  const std::string separator = "    ";
+  for (size_t i = 0; i < maxPrintStackSize; ++i) {
+    oss << separator << "at " << formatStackTraceLine(traceData[i])
+        << std::endl;
+  }
+
+  auto stringNodeStyle = oss.str();
+  return StringRef::createFromUTF8(stringNodeStyle.c_str(),
+                                   stringNodeStyle.length());
+}
+
+std::string StackTrace::formatStackTraceLine(
+    const Evaluator::StackTraceData& line) {
+  std::ostringstream oss;
+
+  const auto& iter = line;
+  const auto& resourceName = iter.srcName->toStdUTF8String();
+  const auto& functionName = iter.functionName->toStdUTF8String();
+  const int errorLine = iter.loc.line;
+  const int errorColumn = iter.loc.column;
+
+  oss << (functionName == "" ? "Object.<anonymous>" : functionName) << " "
+      << "(" << (resourceName == "" ? "?" : resourceName) << ":" << errorLine
+      << ":" << errorColumn << ")";
+
+  return oss.str();
+}
+
+ArrayObjectRef* StackTrace::genCallSites() {
+  auto stackTrace = state_->computeStackTrace();
+  auto stackTraceVector = ValueVectorRef::create();
+  auto callSite = IsolateWrap::GetCurrent()->GetCurrentContext()->callSite();
+
+  for (size_t i = 0; i < stackTrace.size(); i++) {
+    stackTraceVector->pushBack(
+        callSite->instantiate(state_->context(), stackTrace[i]));
+  }
+
+  return ArrayObjectRef::create(state_, stackTraceVector);
+}
 
-  otpl->set(
-      StringRef::createFromUTF8(name, length), r.result, false, false, true);
+CallSite::CallSite(ContextRef* context) : context_(context) {
+  template_ = FunctionTemplateRef::create(
+      AtomicStringRef::create(context, "CallSite"),
+      0,
+      true,
+      true,
+      [](ExecutionStateRef* state,
+         ValueRef* thisValue,
+         size_t argc,
+         ValueRef** argv,
+         OptionalRef<ObjectRef> newTarget) -> ValueRef* {
+        return ValueRef::createUndefined();
+      });
+  injectSitePrototype();
 }
 
-static void injectSitePrototype(ContextRef* context, ObjectTemplateRef* otpl) {
+ValueRef* CallSite::instantiate(ContextRef* context,
+                                const Evaluator::StackTraceData& data) {
+  auto callSite = template_->instanceTemplate()->instantiate(context);
+  ExtraDataHelper::setExtraData(callSite, new StackTraceData(data));
+  return callSite;
+};
+
+void CallSite::injectSitePrototype() {
   setCallSitePrototype(
-      context,
-      otpl,
       "getFunctionName",
       [](ExecutionStateRef* state,
          ValueRef* thisValue,
@@ -209,8 +254,6 @@ static void injectSitePrototype(ContextRef* context, ObjectTemplateRef* otpl) {
       });
 
   setCallSitePrototype(
-      context,
-      otpl,
       "getFileName",
       [](ExecutionStateRef* state,
          ValueRef* thisValue,
@@ -223,8 +266,6 @@ static void injectSitePrototype(ContextRef* context, ObjectTemplateRef* otpl) {
       });
 
   setCallSitePrototype(
-      context,
-      otpl,
       "getLineNumber",
       [](ExecutionStateRef* state,
          ValueRef* thisValue,
@@ -237,8 +278,6 @@ static void injectSitePrototype(ContextRef* context, ObjectTemplateRef* otpl) {
       });
 
   setCallSitePrototype(
-      context,
-      otpl,
       "getColumnNumber",
       [](ExecutionStateRef* state,
          ValueRef* thisValue,
@@ -251,8 +290,6 @@ static void injectSitePrototype(ContextRef* context, ObjectTemplateRef* otpl) {
       });
 
   setCallSitePrototype(
-      context,
-      otpl,
       "isEval",
       [](ExecutionStateRef* state,
          ValueRef* thisValue,
@@ -265,8 +302,6 @@ static void injectSitePrototype(ContextRef* context, ObjectTemplateRef* otpl) {
       });
 
   setCallSitePrototype(
-      context,
-      otpl,
       "toString",
       [](ExecutionStateRef* state,
          ValueRef* thisValue,
@@ -282,29 +317,52 @@ static void injectSitePrototype(ContextRef* context, ObjectTemplateRef* otpl) {
         auto string = stream.str();
         return StringRef::createFromUTF8(string.data(), string.length());
       });
-}
 
-CallSite::CallSite(ContextRef* context) {
-  template_ = FunctionTemplateRef::create(
-      AtomicStringRef::create(context, "CallSite"),
-      0,
-      true,
-      true,
+  setCallSitePrototype(
+      "getFunction",
       [](ExecutionStateRef* state,
          ValueRef* thisValue,
          size_t argc,
          ValueRef** argv,
-         OptionalRef<ObjectRef> newTarget) -> ValueRef* {
+         bool isNewExpression) -> ValueRef* {
+        auto data = ObjectRefHelper::getExtraData(thisValue->asObject())
+                        ->asStackTraceData();
+        auto esFunction = data->callee();
+        if (esFunction.hasValue()) {
+          return esFunction.get();
+        }
         return ValueRef::createUndefined();
       });
-  injectSitePrototype(context, template_->prototypeTemplate());
 }
 
-ValueRef* CallSite::instantiate(ContextRef* context,
-                                const Evaluator::StackTraceData& data) {
-  auto callSite = template_->instanceTemplate()->instantiate(context);
-  ExtraDataHelper::setExtraData(callSite, new StackTraceData(data));
-  return callSite;
-};
+void CallSite::setCallSitePrototype(
+    const std::string& name,
+    Escargot::FunctionObjectRef::NativeFunctionPointer fn) {
+  EvalResult r = Evaluator::execute(
+      context_,
+      [](ExecutionStateRef* state,
+         const std::string* name,
+         Escargot::FunctionObjectRef::NativeFunctionPointer fn) -> ValueRef* {
+        return FunctionObjectRef::create(
+            state,
+            FunctionObjectRef::NativeFunctionInfo(
+                AtomicStringRef::create(
+                    state->context(), name->c_str(), name->length()),
+                fn,
+                0,
+                true,
+                false));
+      },
+      &name,
+      fn);
+  LWNODE_CHECK(r.isSuccessful());
+
+  template_->prototypeTemplate()->set(
+      StringRef::createFromUTF8(name.c_str(), name.length()),
+      r.result,
+      false,
+      false,
+      true);
+}
 
 }  // namespace EscargotShim
index 4853f086d8b2536202009d5554d80870d6c90578..a26da904705c9ba3e67d9c8137b71320f97ef4e6 100644 (file)
@@ -25,7 +25,77 @@ namespace EscargotShim {
 
 class StackTrace {
  public:
+  class NativeAccessorProperty
+      : public ObjectRef::NativeDataAccessorPropertyData {
+   public:
+    NativeAccessorProperty(bool isWritable,
+                           bool isEnumerable,
+                           bool isConfigurable,
+                           ObjectRef::NativeDataAccessorPropertyGetter getter,
+                           ObjectRef::NativeDataAccessorPropertySetter setter,
+                           ValueVectorRef* stackTraceVector)
+        : NativeDataAccessorPropertyData(
+              isWritable, isEnumerable, isConfigurable, getter, setter),
+          stackTraceVector_(stackTraceVector) {}
+
+    ValueVectorRef* stackTraceVector() { return stackTraceVector_; }
+
+    void* operator new(size_t size) { return GC_MALLOC(size); }
+
+   private:
+    ValueVectorRef* stackTraceVector_ = nullptr;
+  };
+
+  StackTrace(ExecutionStateRef* state) : state_(state) {}
+
   static ValueRef* createCaptureStackTrace(ExecutionStateRef* state);
+  static ValueRef* captureStackTraceCallback(ExecutionStateRef* state,
+                                             ValueRef* thisValue,
+                                             size_t argc,
+                                             ValueRef** argv,
+                                             bool isConstructCall);
+
+  static ValueRef* createPrepareStackTrace(Escargot::ExecutionStateRef* state);
+  static ValueRef* prepareStackTraceCallback(ExecutionStateRef* state,
+                                             ValueRef* thisValue,
+                                             size_t argc,
+                                             ValueRef** argv,
+                                             bool isConstructCall);
+
+  static ValueRef* StackTraceGetter(
+      ExecutionStateRef* state,
+      ObjectRef* self,
+      ValueRef* receiver,
+      ObjectRef::NativeDataAccessorPropertyData* data);
+  static bool StackTraceSetter(ExecutionStateRef* state,
+                               ObjectRef* self,
+                               ValueRef* receiver,
+                               ObjectRef::NativeDataAccessorPropertyData* data,
+                               ValueRef* setterInputData);
+
+  static void addStackProperty(ExecutionStateRef* state,
+                               ObjectRef* object,
+                               ValueVectorRef* stackTraceVector);
+
+  ArrayObjectRef* genCallSites();
+
+  // FIXME: Having maxStackSize=1 does not print full stack. Find the right
+  // value
+  StringRef* formatStackTraceStringNodeStyle(ObjectRef* errorObject,
+                                             size_t maxStackSize = 1);
+
+ private:
+  ExecutionStateRef* state_ = nullptr;
+
+  static size_t getStackTraceLimit(ExecutionStateRef* state);
+
+  std::string formatStackTraceLine(const Evaluator::StackTraceData& line);
+
+  // NOTE: StackTrace can only be initialized as a local variable
+  void* operator new(size_t size);
+  void* operator new[](size_t size);
+  void operator delete(void*, size_t);
+  void operator delete[](void*, size_t);
 };
 
 class CallSite : public gc {
@@ -36,7 +106,13 @@ class CallSite : public gc {
                         const Evaluator::StackTraceData& data);
 
  private:
-  FunctionTemplateRef* template_;
+  ContextRef* context_ = nullptr;
+  FunctionTemplateRef* template_ = nullptr;
+
+  void injectSitePrototype();
+  void setCallSitePrototype(
+      const std::string& name,
+      Escargot::FunctionObjectRef::NativeFunctionPointer fn);
 };
 
 }  // namespace EscargotShim
index 0d4f4804624c42bfa71815959e278e7b689588d1..38ce8dd9e707c2f86f22ce83a21460b7dc7fac7d 100644 (file)
 #if defined(LWNODE_PLATFORM_LINUX)
 #include <execinfo.h>
 #endif
+
+#include "api/context.h"
+#include "api/es-helper.h"
+#include "api/global.h"
+#include "api/isolate.h"
 #include "debug.h"
 #include "misc.h"
 
+using namespace Escargot;
+using namespace v8;
+
 namespace EscargotShim {
 
 #if defined(LWNODE_PLATFORM_LINUX)
@@ -44,7 +52,8 @@ static const char* getCurrentProcessName() {
 
 void DebugUtils::printStackTrace() {
 #if defined(NDEBUG)
-  if (EscargotShim::Flags::isInternalLogEnabled() == false) {
+  if (!EscargotShim::Global::flags()->isOn(
+          EscargotShim::Flag::Type::InternalLog)) {
     return;
   }
 #endif
@@ -67,7 +76,7 @@ void DebugUtils::printStackTrace() {
     return;
   }
 
-  LWNODE_LOG_RAW("\n[Backtrace]");
+  LWNODE_LOGR("\n[Backtrace]");
   for (int i = 1; i < frameSize - 2; ++i) {
     char cmd[kStackTraceBufferSize];
     snprintf(cmd,
@@ -82,19 +91,81 @@ void DebugUtils::printStackTrace() {
       while (fgets(line, sizeof(line), stream)) {
         line[strnlen(line, kStackTraceBufferSize) - 1] = 0;
         if (isFirstLine) {
-          LWNODE_LOG_RAW("#%-2d: %s", i - 1, line);
+          LWNODE_LOGR("#%-2d: %s", i - 1, line);
           isFirstLine = false;
         } else {
-          LWNODE_LOG_RAW("%s", line);
+          LWNODE_LOGR("%s", line);
         }
       }
-      LWNODE_LOG_RAW("");
+      LWNODE_LOGR("");
       pclose(stream);
     } else if (symbols[i]) {
-      LWNODE_LOG_RAW("#%-2d: %s", i - 1, symbols[i]);
+      LWNODE_LOGR("#%-2d: %s", i - 1, symbols[i]);
     }
   }
 #endif
 }
 
+static void printObjectProperties(ExecutionStateRef* state,
+                                  ObjectRef* object,
+                                  int depth = 0) {
+  auto propertyNames = object->ownPropertyKeys(state);
+  LWNODE_LOGR("%*s[prop(%zu)]\n", depth, "", propertyNames->size());
+  for (size_t i = 0; i < propertyNames->size(); i++) {
+    auto propertyValue = object->getOwnProperty(state, propertyNames->at(i));
+    auto propertyNameString = propertyNames->at(i)->toString(state);
+    auto propertyValueString = propertyValue->toString(state);
+    LWNODE_LOGR("  %*s%s: %s\n",
+                depth,
+                "",
+                propertyNameString->toStdUTF8String().data(),
+                propertyValueString->toStdUTF8String().data());
+  }
+}
+
+void DebugUtils::printObject(ObjectRef* value, int depth) {
+  auto lwIsolate = IsolateWrap::GetCurrent();
+  auto r = Evaluator::execute(
+      lwIsolate->GetCurrentContext()->get(),
+      [](ExecutionStateRef* state, ObjectRef* object, int depth) -> ValueRef* {
+        printObjectProperties(state, object, depth);
+
+        OptionalRef<ObjectRef> maybePrototype =
+            object->getPrototypeObject(state);
+        if (maybePrototype.hasValue()) {
+          auto prototype = maybePrototype.value();
+          printObjectProperties(state, prototype, depth);
+
+          OptionalRef<ObjectRef> maybePrototype =
+              prototype->getPrototypeObject(state);
+          if (maybePrototype.hasValue()) {
+            printObject(maybePrototype.value(), depth + 2);
+          }
+        }
+        return ValueRef::createNull();
+      },
+      value,
+      depth);
+  LWNODE_CHECK(r.isSuccessful());
+}
+
+void DebugUtils::printToString(ValueRef* value) {
+  auto context = IsolateWrap::GetCurrent()->GetCurrentContext()->get();
+  EvalResult r = Evaluator::execute(
+      context,
+      [](ExecutionStateRef* state, ValueRef* value) -> ValueRef* {
+        auto valueString = value->toString(state);
+        LWNODE_LOGR("toString: %s\n", valueString->toStdUTF8String().c_str());
+        return value;
+      },
+      value);
+}
+
+std::string DebugUtils::v8StringToStd(Isolate* isolate, Local<Value> value) {
+  Local<String> s;
+  value->ToString(isolate->GetCurrentContext()).ToLocal(&s);
+  v8::String::Utf8Value utf8String(isolate, s);
+  return std::string(*utf8String);
+}
+
 }  // namespace EscargotShim
index ca11e292474455a83550c1d64d8db275c5b4baa3..0a110029367ebda9683b6bf7341afb6b9fa2fd80 100644 (file)
 
 #pragma once
 
+#include "EscargotPublic.h"
+#include "v8.h"
+
 namespace EscargotShim {
 class DebugUtils {
  public:
   static void printStackTrace();
+  static void printObject(Escargot::ObjectRef* value, int depth = 0);
+  static void printToString(Escargot::ValueRef* value);
+  static std::string v8StringToStd(v8::Isolate* isolate,
+                                   v8::Local<v8::Value> value);
 };
 }  // namespace EscargotShim
index 88956f9cc4a21fb8c15846aad7e62f08730ec339..6f298221b6ba9f59c6fda3f573991a6de1cbae1c 100644 (file)
 #include "gc.h"
 
 #include <EscargotPublic.h>
+#include "api/global.h"
 #include "misc.h"
 
 using namespace Escargot;
 
 #define LOG_HANDLER(msg, ...)                                                  \
   do {                                                                         \
-    if (EscargotShim::Flags::isTraceGCEnabled()) {                             \
-      LWNODE_LOG_RAW(CLR_DIM msg CLR_RESET, ##__VA_ARGS__);                    \
+    if (EscargotShim::Global::flags()->isOn(                                   \
+            EscargotShim::Flag::Type::TraceGC)) {                              \
+      LWNODE_LOGR(CLR_DIM msg CLR_RESET, ##__VA_ARGS__);                       \
     }                                                                          \
   } while (0)
 
index a23bbac3029232ad31ee5072e3fcde5a1838edeb..4e8252870b3e381d955f319debd72d6eb9c561fa 100644 (file)
@@ -33,7 +33,7 @@ template <typename T,
           typename Allocator = GCUtil::gc_malloc_allocator<T>>
 using GCVectorT = Starfish::Vector<T, Allocator, isEraseStrategyStrict>;
 
-#if !defined(NDEBUG)
+#if defined(GC_DEBUG)
 template <typename T,
           bool isEraseStrategyStrict = true,
           typename Allocator = GCUtil::gc_malloc_allocator<T>>
@@ -165,6 +165,36 @@ enum WarnEventType {
   OUT_OF_MEMORY,
 };
 
+enum class GarbageCollectionReason {
+  // NOTE: From the following enum values from v8,
+  // we only use a few.
+  // kUnknown = 0,
+  // kAllocationFailure = 1,
+  // kAllocationLimit = 2,
+  // kContextDisposal = 3,
+  // kCountersExtension = 4,
+  // kDebugger = 5,
+  // kDeserializer = 6,
+  // kExternalMemoryPressure = 7,
+  // kFinalizeMarkingViaStackGuard = 8,
+  // kFinalizeMarkingViaTask = 9,
+  // kFullHashtable = 10,
+  // kHeapProfiler = 11,
+  // kTask = 12,
+  // kLastResort = 13,
+  // kLowMemoryNotification = 14,
+  // kMakeHeapIterable = 15,
+  // kMemoryPressure = 16,
+  // kMemoryReducer = 17,
+  kRuntime = 18,
+  // kSamplingProfiler = 19,
+  // kSnapshotCreator = 20,
+  kTesting = 21,
+  // kExternalFinalize = 22,
+  // kGlobalAllocationLimit = 23,
+  // kMeasureMemory = 24
+};
+
 class ESCARGOT_EXPORT MemoryUtil {
  public:
   typedef void (*OnGCWarnEventListener)(WarnEventType type);
diff --git a/lwnode/code/escargotshim/src/api/utils/logger/color.h b/lwnode/code/escargotshim/src/api/utils/logger/color.h
new file mode 100644 (file)
index 0000000..fa54681
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define CLR_RESET "\033[0m"
+#define CLR_DIM "\033[0;2m"
+#define CLR_RED "\033[0;31m"
+#define CLR_GREEN "\033[0;32m"
+#define CLR_GREY "\033[0;37m"
+#define CLR_BLACK "\033[0;30m"
+#define CLR_YELLOW "\033[0;33m"
+#define CLR_BLUE "\033[0;34m"
+#define CLR_MAGENTA "\033[0;35m"
+#define CLR_CYAN "\033[0;36m"
+#define CLR_DARKGREY "\033[01;30m"
+#define CLR_BRED "\033[01;31m"
+#define CLR_BYELLOW "\033[01;33m"
+#define CLR_BBLUE "\033[01;34m"
+#define CLR_BMAGENTA "\033[01;35m"
+#define CLR_BCYAN "\033[01;36m"
+#define CLR_BGREEN "\033[01;32m"
+#define CLR_WHITE "\033[01;37m"
+#define CLR_REDBG "\033[0;41m"
index 2407b15c0dbab40280b783123f022ec9be87f65b..1a97d04b86f511e06d44b7e65a69155e544cd90f 100644 (file)
 
 #include "flags.h"
 
+#include <algorithm>
+
+#include "api/utils/string-util.h"
+
 namespace EscargotShim {
 
-flag_t Flags::s_flags = FlagType::Empty;
-std::set<std::string> Flags::s_trace_ids;
-std::set<std::string> Flags::s_negative_trace_ids;
+std::vector<Flag> Flags::s_validFlags = {
+    // v8 flags
+    Flag("--expose-gc", Flag::Type::ExposeGC),
+    Flag("--use-strict", Flag::Type::UseStrict),
+    Flag("--off-idlegc", Flag::Type::DisableIdleGC),
+    Flag("--harmony-top-level-await", Flag::Type::TopLevelWait),
+    Flag("--allow-code-generation-from-strings",
+         Flag::Type::AllowCodeGenerationFromString),
+    Flag("--abort-on-uncaught-exception", Flag::Type::AbortOnUncaughtException),
+    Flag("--expose-externalize-string", Flag::Type::ExposeExternalizeString),
+    FlagWithValues("--unhandled-rejections=", Flag::Type::UnhandledRejections),
+    Flag("--trace-debug", Flag::Type::LWNodeOther, true),
+    Flag("--debug", Flag::Type::LWNodeOther, true),
+    Flag("--stack-size=", Flag::Type::LWNodeOther, true),
+    Flag("--nolazy", Flag::Type::LWNodeOther, true),
+    // lwnode flags
+    Flag("--trace-gc", Flag::Type::TraceGC),
+    FlagWithNegativeValues("--trace-call=", Flag::Type::TraceCall, true),
+    Flag("--internal-log", Flag::Type::InternalLog),
+    Flag("--start-debug-server", Flag::Type::DebugServer),
+};
 
-bool Flags::isTraceCallEnabled(std::string id) {
-  if (!(s_flags & FlagType::TraceCall)) {
-    return false;
+bool Flag::isPrefixOf(const std::string& name) {
+  if (useAsPrefix_ && (name.find(name_) != std::string::npos)) {
+    return true;
+  }
+
+  return false;
+}
+
+Flag* Flags::findFlagObject(const std::string& name) {
+  std::string normalized = name;
+  std::replace(normalized.begin(), normalized.end(), '_', '-');
+
+  for (size_t i = 0; i < s_validFlags.size(); i++) {
+    Flag* flag = &s_validFlags[i];
+    if ((flag->name() == normalized) || flag->isPrefixOf(normalized)) {
+      return flag;
+    }
   }
 
-  if (!s_trace_ids.empty()) {
-    if (s_trace_ids.find(id) == s_trace_ids.end()) {
-      return false;
+  return nullptr;
+}
+
+Flag* Flags::findFlagObject(Flag::Type type) {
+  for (size_t i = 0; i < s_validFlags.size(); i++) {
+    Flag* flag = &s_validFlags[i];
+    if (flag->type() == type) {
+      return flag;
     }
   }
 
-  if (!s_negative_trace_ids.empty()) {
-    if (s_negative_trace_ids.find(id) != s_negative_trace_ids.end()) {
-      return false;
+  return nullptr;
+}
+
+void Flags::add(const std::string& userOption) {
+  // @check https://github.sec.samsung.net/lws/node-escargot/issues/394
+  Flag* flag = findFlagObject(userOption);
+  if (!flag || flag->type() == Flag::Empty) {
+    LWNODE_DLOG_WARN("Ignore flag: '%s'\n", flag ? flag->name().c_str() : "");
+    return;
+  }
+
+  add(flag);
+
+  if (flag->type() == Flag::Type::TraceCall ||
+      flag->type() == Flag::Type::UnhandledRejections) {
+    std::string optionValues = userOption.substr(userOption.find_first_of('=') +
+                                                 1);  // +1 for skipping '='
+    auto tokens = strSplit(optionValues, ',');
+    for (auto token : tokens) {
+      flag->addValue(token);
     }
   }
+}
+
+void Flags::add(Flag::Type type) {
+  add(findFlagObject(type));
+}
+
+void Flags::add(Flag* flag) {
+  if (!flag || flag->type() == Flag::Type::LWNodeOther) {
+    return;
+  }
+
+  flags_.insert(flag);
+}
+
+Flag* Flags::getFlag(Flag::Type type) {
+  Flag flag("", type);
+  auto itr = flags_.find(&flag);
+  if (itr == flags_.end()) {
+    return nullptr;
+  }
+
+  return *itr;
+}
+
+bool Flags::isOn(Flag::Type type, const std::string& value) {
+  Flag* flag = getFlag(type);
+  if (!flag) {
+    return false;
+  }
+
+  if (value == "") {
+    return true;
+  }
 
-  return true;
+  return flag->hasValue(value);
+}
+
+void Flags::shrinkArgumentList(int* argc, char** argv) {
+  int count = 0;
+  for (int idx = 0; idx < *argc; idx++) {
+    if (argv[idx]) {
+      argv[count++] = argv[idx];
+    }
+  }
+  *argc = count;
 }
 
 }  // namespace EscargotShim
index e6b613f3c75161847dce4ffa3e2b62e0ab9efc55..f27fa2602632370effabce2db5a9e90b5604848d 100644 (file)
 #pragma once
 
 #include <cstdint>
+#include <memory>
 #include <set>
 #include <string>
+#include <vector>
 
 #if !defined(LWNODE_EXPORT)
 #define LWNODE_EXPORT __attribute__((visibility("default")))
@@ -29,37 +31,106 @@ namespace EscargotShim {
 
 typedef uint16_t flag_t;
 
-enum FlagType : flag_t {
-  Empty = 0,
-  ExposeGC = 1 << 1,
-  UseStrict = 1 << 2,
-  DisableIdleGC = 1 << 3,
-  TopLevelWait = 1 << 4,
-  // lwnode
-  TraceCall = 1 << 5,
-  TraceGC = 1 << 6,
-  InternalLog = 1 << 7,
+class Flag {
+ public:
+  enum Type : flag_t {
+    Empty = 0,
+    ExposeGC,
+    UseStrict,
+    DisableIdleGC,
+    TopLevelWait,
+    AllowCodeGenerationFromString,
+    AbortOnUncaughtException,
+    ExposeExternalizeString,
+    UnhandledRejections,
+    // lwnode
+    TraceCall,
+    TraceGC,
+    InternalLog,
+    LWNodeOther,
+    DebugServer,
+  };
+
+  Flag(const std::string& name, Type type, bool useAsPrefix = false)
+      : name_(name), type_(type), useAsPrefix_(useAsPrefix) {}
+
+  virtual std::string name() { return name_; }
+  virtual Type type() const { return type_; }
+  virtual bool isPrefixOf(const std::string& name);
+
+  virtual void addValue(const std::string& value){};
+  virtual bool hasValue(const std::string& value) { return false; }
+
+  virtual void addNegativeValue(const std::string& value) {}
+  virtual bool hasNegativeValue(const std::string& value) { return false; }
+
+ protected:
+  std::string name_;
+  Type type_ = Type::Empty;
+  bool useAsPrefix_ = false;
 };
 
-class LWNODE_EXPORT Flags {
+class FlagWithValues : public Flag {
  public:
-  static void set(flag_t flags) { s_flags = flags; }
-  static void add(flag_t flags) { s_flags |= flags; }
-  static flag_t get() { return s_flags; };
+  FlagWithValues(const std::string& name, Type type, bool useAsPrefix = false)
+      : Flag(name, type, useAsPrefix) {}
 
-  static bool isTraceCallEnabled(std::string id = "*");
-  static bool isTraceGCEnabled() { return s_flags & FlagType::TraceGC; }
-  static bool isInternalLogEnabled() { return s_flags & FlagType::InternalLog; }
+  virtual void addValue(const std::string& value) override {
+    values_.insert(value);
+  }
 
-  static void setTraceCallId(std::string id) { s_trace_ids.insert(id); }
-  static void setNagativeTraceCallId(std::string id) {
-    s_negative_trace_ids.insert(id);
+  virtual bool hasValue(const std::string& value) override {
+    return values_.find(value) != values_.end();
   }
 
  private:
-  static std::set<std::string> s_trace_ids;
-  static std::set<std::string> s_negative_trace_ids;
-  static flag_t s_flags;
+  std::set<std::string> values_;
+};
+
+class FlagWithNegativeValues : public FlagWithValues {
+ public:
+  FlagWithNegativeValues(const std::string& name,
+                         Type type,
+                         bool useAsPrefix = false)
+      : FlagWithValues(name, type, useAsPrefix) {}
+
+  void addNegativeValue(const std::string& value) override {
+    negativeValues_.insert(value);
+  }
+
+  bool hasNegativeValue(const std::string& value) override {
+    return negativeValues_.find(value) != negativeValues_.end();
+  }
+
+ private:
+  std::set<std::string> negativeValues_;
+};
+
+class LWNODE_EXPORT Flags {
+ public:
+  static std::vector<Flag> s_validFlags;
+  struct FlagComparator {
+    bool operator()(const Flag* a, const Flag* b) const {
+      return a->type() < b->type();
+    }
+  };
+
+  void add(const std::string& flag);
+  void add(Flag::Type type);
+  void add(Flag* flag);
+
+  bool isOn(Flag::Type type, const std::string& value = "");
+  void shrinkArgumentList(int* argc, char** argv);
+
+  std::set<Flag*, FlagComparator> get() { return flags_; };
+  void set(std::set<Flag*, FlagComparator> flags) { flags_ = flags; }
+
+ private:
+  Flag* findFlagObject(const std::string& name);
+  Flag* findFlagObject(Flag::Type type);
+
+  Flag* getFlag(Flag::Type type);
+  std::set<Flag*, FlagComparator> flags_;
 };
 
 }  // namespace EscargotShim
diff --git a/lwnode/code/escargotshim/src/api/utils/logger/logger-impl.cc b/lwnode/code/escargotshim/src/api/utils/logger/logger-impl.cc
new file mode 100644 (file)
index 0000000..afa5cc1
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2022-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "logger-impl.h"
+
+#include <iomanip>  // for setfill and setw
+#include <map>
+#include <thread>
+
+#include "api/global.h"
+#include "color.h"
+#include "flags.h"
+#include "logger.h"
+
+// --- Formatter ---
+
+#define PADDING(N) std::left << std::setfill(' ') << std::setw(N)
+#define DISPLAY_TYPE_LENGTH_LIMIT 5
+#define DISPLAY_TRACE_ID_LENGTH_LIMIT 10
+
+std::map<std::thread::id, int> s_thread_ids;
+
+void printThreadIdentifier(std::stringstream& stream) {
+  static int s_id = 0;
+
+  auto id = std::this_thread::get_id();
+  if (s_thread_ids.find(id) == s_thread_ids.end()) {
+    s_thread_ids[id] = ++s_id;
+  }
+
+  stream << "[" << s_thread_ids[id] << "] ";
+}
+
+std::string LogFormatter::header() {
+  std::stringstream stream;
+
+  printThreadIdentifier(stream);
+  printHeader(stream);
+
+  return stream.str();
+}
+
+void LogTYPED::printHeader(std::stringstream& stream) {
+  switch (type_) {
+    case Type::INFO:
+      stream << PADDING(DISPLAY_TYPE_LENGTH_LIMIT) << "INFO"
+             << " ";
+      break;
+    case Type::WARN:
+      stream << CLR_YELLOW << PADDING(DISPLAY_TYPE_LENGTH_LIMIT) << "WARN"
+             << " ";
+      break;
+    case Type::ERROR:
+      stream << CLR_RED << PADDING(DISPLAY_TYPE_LENGTH_LIMIT) << "ERROR"
+             << " ";
+      break;
+
+    default:
+      break;
+  }
+}
+
+LogINTERNAL::LogINTERNAL(Type type) : LogTYPED(type) {
+#if defined(NDEBUG)
+  isEnabled_ = EscargotShim::Global::flags()->isOn(
+      EscargotShim::Flag::Type::InternalLog);
+#endif
+}
+
+LogTRACE::LogTRACE(std::string id,
+                   const char* functionName,
+                   const char* filename,
+                   const int line) {
+  if (!EscargotShim::Global::flags()->isOn(EscargotShim::Flag::Type::TraceCall,
+                                           id)) {
+    isEnabled_ = false;
+    return;
+  }
+
+  id_ = id;
+  functionName_ = createCodeLocation(functionName, filename, line);
+}
+
+void LogTRACE::printHeader(std::stringstream& stream) {
+  stream << CLR_DIM << PADDING(DISPLAY_TYPE_LENGTH_LIMIT) << "TRACE ("
+         << PADDING(DISPLAY_TRACE_ID_LENGTH_LIMIT)
+         << std::string(id_).substr(0, DISPLAY_TRACE_ID_LENGTH_LIMIT).c_str()
+         << ") ";
+
+  stream << IndentCounter::getString(id_) << functionName_ << " " << CLR_RESET;
+}
+
+// --- Logger ---
+thread_local std::shared_ptr<StdOut> s_loggerOutput;
+
+Logger::Logger(const std::string& header, std::shared_ptr<Output> out)
+    : out_(out) {
+  initialize(header, out);
+}
+
+Logger::Logger(LogFormatter&& formatter, std::shared_ptr<Output> out)
+    : out_(out) {
+  if (formatter.isEnabled()) {
+    initialize(formatter.header(), out_);
+  }
+}
+
+Logger::~Logger() {
+  if (out_ == nullptr) {
+    return;
+  }
+  stream_ << CLR_RESET << std::endl;
+  out_->flush(stream_);
+}
+
+void Logger::initialize(const std::string& header,
+                        std::shared_ptr<Output> out) {
+  if (out_ == nullptr) {
+    if (s_loggerOutput == nullptr) {
+      s_loggerOutput = std::make_shared<StdOut>();
+    }
+    out_ = s_loggerOutput;
+  }
+  stream_ << header;
+}
+
+Logger& Logger::print(const char* string_without_format_specifiers) {
+  if (out_ == nullptr) {
+    return *this;
+  }
+
+  while (*string_without_format_specifiers) {
+    if (*string_without_format_specifiers == '%' &&
+        *(++string_without_format_specifiers) != '%') {
+      assert(((void)"runtime error: invalid format-string", false));
+    }
+    stream_ << *string_without_format_specifiers++;
+  }
+  return *this;
+}
+
+Logger& Logger::flush() {
+  if (out_) {
+    out_->flush(stream_);
+  }
+  stream_.str("");
+  return *this;
+}
+// --- Output ---
+
+void StdOut::flush(std::stringstream& stream) {
+  std::cout << stream.str();
+}
diff --git a/lwnode/code/escargotshim/src/api/utils/logger/logger-impl.h b/lwnode/code/escargotshim/src/api/utils/logger/logger-impl.h
new file mode 100644 (file)
index 0000000..2a5caaa
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2022-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cassert>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+
+class LogFormatter {
+ public:
+  std::string header();
+  bool isEnabled() { return isEnabled_; }
+
+ protected:
+  virtual void printHeader(std::stringstream& stream) = 0;
+  bool isEnabled_{true};
+};
+
+class LogTYPED : public LogFormatter {
+ public:
+  enum class Type {
+    RAW,
+    INFO,
+    WARN,
+    ERROR,
+  };
+  LogTYPED(Type type = Type::RAW) : type_(type) {}
+  void printHeader(std::stringstream& stream) override;
+
+ protected:
+  Type type_{Type::RAW};
+};
+
+class LogINTERNAL : public LogTYPED {
+ public:
+  LogINTERNAL(Type type = Type::RAW);
+};
+
+class LogTRACE : public LogFormatter {
+ public:
+  LogTRACE(std::string id,
+           const char* functionName,
+           const char* filename,
+           const int line);
+  void printHeader(std::stringstream& stream) override;
+
+ private:
+  std::string id_;
+  std::string functionName_;
+};
+
+class Logger {
+ public:
+  class Output {
+   public:
+    virtual void flush(std::stringstream& ss) = 0;
+  };
+
+  Logger(const std::string& header = "", std::shared_ptr<Output> out = nullptr);
+  Logger(LogFormatter&& formatter, std::shared_ptr<Output> out = nullptr);
+  ~Logger();
+
+  template <class T>
+  Logger& operator<<(const T& msg) {
+    stream_ << msg;
+    return *this;
+  }
+
+  template <typename T, typename... Args>
+  Logger& print(const char* format, T value, Args... args) {
+    if (out_ == nullptr) {
+      return *this;
+    }
+
+    while (*format) {
+      if (*format == '%' && *(++format) != '%') {
+        stream_ << value;
+
+        // handle sub-specifiers
+        if ((*format == 'z')) {
+          format++;
+        } else if ((*format == 'l') || (*format == 'h')) {
+          format++;
+          if (*format == *(format + 1)) {
+            format++;
+          }
+        }
+        format++;
+
+        print(format, args...);
+        return *this;
+      }
+      stream_ << *format++;
+    }
+    assert(((void)"logical error: should not come here", false));
+    return *this;
+  };
+
+  Logger& print(const char* string_without_format_specifiers = "");
+  Logger& flush();
+
+ private:
+  std::shared_ptr<Output> out_;
+  std::stringstream stream_;
+
+  void initialize(const std::string& header, std::shared_ptr<Output> out);
+};
+
+class StdOut : public Logger::Output {
+ public:
+  void flush(std::stringstream& ss) override;
+};
diff --git a/lwnode/code/escargotshim/src/api/utils/logger/logger-util.cc b/lwnode/code/escargotshim/src/api/utils/logger/logger-util.cc
new file mode 100644 (file)
index 0000000..ba4872f
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2022-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "logger-util.h"
+
+#include <assert.h>
+#include <regex>
+#include <set>
+#include <sstream>
+
+#include "api/global.h"
+
+std::string getPrettyFunctionName(const std::string fullname) {
+  std::smatch match;
+  const std::regex re(R"(([\w\:~]+)\()");
+
+  if (std::regex_search(fullname, match, re) && match.size() > 1) {
+    return match.str(1);
+  }
+  return "";
+}
+
+std::string createCodeLocation(const char* functionName,
+                               const char* filename,
+                               const int line) {
+  std::ostringstream oss;
+  oss << getPrettyFunctionName(functionName) << " (" << filename << ":" << line
+      << ")";
+  return oss.str();
+}
+
+thread_local int s_indentCount = 0;
+thread_local int s_deltaCount = 0;
+thread_local std::set<std::string> s_counterIds;
+
+#define FORCE_ENABLE_INDENT_ID "NODE"
+
+static bool isIndentIdEnabled(std::string id) {
+  if (id == FORCE_ENABLE_INDENT_ID) {
+    return true;
+  }
+
+  return EscargotShim::Global::flags()->isOn(
+      EscargotShim::Flag::Type::TraceCall, id);
+}
+
+void IndentCounter::indent(std::string id) {
+  if (isIndentIdEnabled(id) == false) {
+    return;
+  }
+  s_deltaCount++;
+}
+
+void IndentCounter::unIndent(std::string id) {
+  if (isIndentIdEnabled(id) == false) {
+    return;
+  }
+  s_deltaCount--;
+}
+
+IndentCounter::IndentCounter(std::string id) {
+  id_ = id;
+
+  if (isIndentIdEnabled(id) == false) {
+    return;
+  }
+
+  s_indentCount++;
+  s_counterIds.insert(id);
+}
+
+IndentCounter::~IndentCounter() {
+  if (isIndentIdEnabled(id_) == false) {
+    return;
+  }
+
+  s_indentCount--;
+  s_counterIds.erase(id_);
+}
+
+std::string IndentCounter::getString(std::string id) {
+  if (s_counterIds.find(id) == s_counterIds.end()) {
+    return "";
+  }
+
+  assert(s_indentCount >= 0);
+
+  std::ostringstream oss;
+  int indentCount = s_indentCount + s_deltaCount;
+
+  if (s_deltaCount > 0) {
+    oss << s_deltaCount << " ";
+  }
+
+  for (int i = 1; i < std::min(30, indentCount); ++i) {
+    oss << "  ";
+  }
+
+  return oss.str();
+}
diff --git a/lwnode/code/escargotshim/src/api/utils/logger/logger-util.h b/lwnode/code/escargotshim/src/api/utils/logger/logger-util.h
new file mode 100644 (file)
index 0000000..f3f2aca
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022-present Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#define __FILE_NAME__                                                          \
+  (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
+
+#define __FUNCTION_NAME__ getPrettyFunctionName(__PRETTY_FUNCTION__)
+
+#define __CODE_LOCATION__                                                      \
+  createCodeLocation(__PRETTY_FUNCTION__, __FILE_NAME__, __LINE__).c_str()
+
+std::string createCodeLocation(const char* functionName,
+                               const char* filename,
+                               const int line);
+
+std::string getPrettyFunctionName(const std::string fullname);
+
+class IndentCounter {
+ public:
+  IndentCounter(std::string id);
+  ~IndentCounter();
+  static std::string getString(std::string id = "");
+  static void indent(std::string id);
+  static void unIndent(std::string id);
+
+ private:
+  std::string id_;
+};
diff --git a/lwnode/code/escargotshim/src/api/utils/logger/logger.cc b/lwnode/code/escargotshim/src/api/utils/logger/logger.cc
deleted file mode 100644 (file)
index 88ee28c..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2021-present Samsung Electronics Co., Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "logger.h"
-#include <assert.h>
-#include <regex>
-#include <set>
-#include <sstream>
-
-std::string getPrettyFunctionName(const std::string fullname) {
-  std::smatch match;
-  const std::regex re(R"(([\w\:~]+)\()");
-
-  if (std::regex_search(fullname, match, re) && match.size() > 1) {
-    return match.str(1);
-  }
-  return "";
-}
-
-std::string createCodeLocation(const char* functionName,
-                               const char* filename,
-                               const int line) {
-  std::ostringstream oss;
-  oss << getPrettyFunctionName(functionName) << " (" << filename << ":" << line
-      << ")" << std::endl;
-  return oss.str();
-}
-
-thread_local int s_indentCount = 0;
-thread_local int s_deltaCount = 0;
-thread_local std::set<std::string> s_counterIds;
-
-#define FORCE_ENABLE_INDENT_ID "NODE"
-
-static bool isIndentIdEnabled(std::string id) {
-  if (id == FORCE_ENABLE_INDENT_ID) {
-    return true;
-  }
-  return EscargotShim::Flags::isTraceCallEnabled(id);
-}
-
-void IndentCounter::indent(std::string id) {
-  if (isIndentIdEnabled(id) == false) return;
-  s_deltaCount++;
-}
-
-void IndentCounter::unIndent(std::string id) {
-  if (isIndentIdEnabled(id) == false) return;
-  s_deltaCount--;
-}
-
-IndentCounter::IndentCounter(std::string id) {
-  id_ = id;
-
-  if (isIndentIdEnabled(id) == false) return;
-
-  s_indentCount++;
-  s_counterIds.insert(id);
-}
-
-IndentCounter::~IndentCounter() {
-  if (isIndentIdEnabled(id_) == false) return;
-
-  s_indentCount--;
-  s_counterIds.erase(id_);
-}
-
-std::string IndentCounter::getString(std::string id) {
-  if (s_counterIds.find(id) == s_counterIds.end()) {
-    return "";
-  }
-
-  assert(s_indentCount >= 0);
-
-  std::ostringstream oss;
-  int indentCount = s_indentCount + s_deltaCount;
-
-  if (s_deltaCount > 0) {
-    oss << s_deltaCount << " ";
-  }
-
-  for (int i = 1; i < std::min(30, indentCount); ++i) {
-    oss << "  ";
-  }
-
-  return oss.str();
-}
index 5ba6d71b69ac40d248f57360223be66591d205a9..8b823efd5c41437bb52f09333487ee1575509abd 100644 (file)
 
 #pragma once
 
-#include <string.h>
-#include <cstdio>
-
-#include "flags.h"
-
-#define CLR_RESET "\033[0m"
-#define CLR_DIM "\033[0;2m"
-#define CLR_RED "\033[0;31m"
-#define CLR_GREEN "\033[0;32m"
-#define CLR_GREY "\033[0;37m"
-#define CLR_BLACK "\033[0;30m"
-#define CLR_YELLOW "\033[0;33m"
-#define CLR_BLUE "\033[0;34m"
-#define CLR_MAGENTA "\033[0;35m"
-#define CLR_CYAN "\033[0;36m"
-#define CLR_DARKGREY "\033[01;30m"
-#define CLR_BRED "\033[01;31m"
-#define CLR_BYELLOW "\033[01;33m"
-#define CLR_BBLUE "\033[01;34m"
-#define CLR_BMAGENTA "\033[01;35m"
-#define CLR_BCYAN "\033[01;36m"
-#define CLR_BGREEN "\033[01;32m"
-#define CLR_WHITE "\033[01;37m"
-#define CLR_REDBG "\033[0;41m"
-
-std::string getPrettyFunctionName(const std::string fullname);
-std::string createCodeLocation(const char* functionName,
-                               const char* filename,
-                               const int line);
-inline const char* strBool(bool value) {
-  return value ? "True" : "False";
-}
-
-class IndentCounter {
- public:
-  IndentCounter(std::string id);
-  ~IndentCounter();
-  static std::string getString(std::string id = "");
-  static void indent(std::string id);
-  static void unIndent(std::string id);
-
- private:
-  std::string id_;
-};
-
-#define __FILENAME__                                                           \
-  (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
-#define TRACE_FMT "%s (%s:%d)"
-#define TRACE_ARGS __PRETTY_FUNCTION__, __FILENAME__, __LINE__
-#define TRACE_ARGS2                                                            \
-  getPrettyFunctionName(__PRETTY_FUNCTION__).c_str(), __FILENAME__, __LINE__
-
-#define LWNODE_LOG_RAW(fmt, ...)                                               \
-  do {                                                                         \
-    fprintf(stderr, fmt "\n", ##__VA_ARGS__);                                  \
-  } while (0);
-
-#if !defined(NDEBUG)
-#define LWNODE_LOG_INTERNAL(fmt, ...) LWNODE_LOG_RAW(fmt, ##__VA_ARGS__);
-#else
-#define LWNODE_LOG_INTERNAL(fmt, ...)                                          \
-  if (EscargotShim::Flags::isInternalLogEnabled()) {                           \
-    LWNODE_LOG_RAW(fmt, ##__VA_ARGS__);                                        \
-  }
-#endif
-
-#define LWNODE_LOG_INFO(fmt, ...)                                              \
-  LWNODE_LOG_INTERNAL("INFO " fmt CLR_RESET, ##__VA_ARGS__);
-
-#define LWNODE_LOG_WARN(fmt, ...)                                              \
-  LWNODE_LOG_INTERNAL(CLR_YELLOW "WARN " fmt CLR_RESET, ##__VA_ARGS__);
-
+#include "color.h"
+#include "logger-impl.h"
+#include "logger-util.h"
+
+// loggers (release)
+#define LWNODE_LOG(tag) Logger(LogTYPED(LogTYPED::Type::tag))
+#define LWNODE_LOGF(tag, fmt, ...) LWNODE_LOG(tag).print(fmt, ##__VA_ARGS__)
+
+#define LWNODE_LOGR(fmt, ...) LWNODE_LOGF(RAW, fmt, ##__VA_ARGS__)
+#define LWNODE_LOGI(fmt, ...) LWNODE_LOGF(INFO, fmt, ##__VA_ARGS__)
+#define LWNODE_LOGW(fmt, ...) LWNODE_LOGF(WARN, fmt, ##__VA_ARGS__)
+#define LWNODE_LOGE(fmt, ...) LWNODE_LOGF(ERROR, fmt, ##__VA_ARGS__)
+
+// loggers (internal)
+// enabled if running with debug build or force-logging option
+#define LWNODE_LOG_INTERNAL(tag, fmt, ...)                                     \
+  Logger(LogINTERNAL(LogTYPED::Type::tag)).print(fmt, ##__VA_ARGS__)
+
+#define LWNODE_LOG_RAW(fmt, ...) LWNODE_LOG_INTERNAL(RAW, fmt, ##__VA_ARGS__)
+#define LWNODE_LOG_INFO(fmt, ...) LWNODE_LOG_INTERNAL(INFO, fmt, ##__VA_ARGS__)
+#define LWNODE_LOG_WARN(fmt, ...) LWNODE_LOG_INTERNAL(WARN, fmt, ##__VA_ARGS__)
 #define LWNODE_LOG_ERROR(fmt, ...)                                             \
-  LWNODE_LOG_INTERNAL(CLR_BRED "ERROR " fmt CLR_RESET, ##__VA_ARGS__);
+  LWNODE_LOG_INTERNAL(ERROR, fmt, ##__VA_ARGS__)
 
 #define LWNODE_UNIMPLEMENT                                                     \
-  LWNODE_LOG_INTERNAL(CLR_RED "UNIMPLEMENTED " TRACE_FMT CLR_RESET,            \
-                      TRACE_ARGS2);
+  LWNODE_LOG_INTERNAL(RAW, CLR_RED "UNIMPLEMENTED " CLR_RESET)                 \
+      << CLR_RESET << __CODE_LOCATION__
 
 #define LWNODE_UNIMPLEMENT_IGNORED                                             \
-  LWNODE_LOG_INTERNAL(CLR_DIM "UNIMPLEMENTED (IGNORED) " TRACE_FMT CLR_RESET,  \
-                      TRACE_ARGS2);
+  LWNODE_LOG_INTERNAL(RAW, CLR_DIM "UNIMPLEMENTED (IGNORED) ")                 \
+      << CLR_RESET << __CODE_LOCATION__
 
 #define LWNODE_UNIMPLEMENT_WORKAROUND                                          \
-  LWNODE_LOG_INTERNAL(CLR_DIM                                                  \
-                      "UNIMPLEMENTED (USE WORKAROUND) " TRACE_FMT CLR_RESET,   \
-                      TRACE_ARGS2);
-
-// conditional loggers
+  LWNODE_LOG_INTERNAL(RAW, CLR_DIM "UNIMPLEMENTED (USE WORKAROUND) ")          \
+      << CLR_RESET << __CODE_LOCATION__
 
+// loggers (debug)
 #if !defined(NDEBUG)
 #define LWNODE_DLOG_RAW(fmt, ...) LWNODE_LOG_RAW(fmt, ##__VA_ARGS__)
 #define LWNODE_DLOG_INFO(fmt, ...) LWNODE_LOG_INFO(fmt, ##__VA_ARGS__)
index aec155d139b97cc1d907e2b4db7555bed2019cde..393f6a62753359fbbf9e1fde8ccc5f01be61a1bb 100644 (file)
 
 #pragma once
 
-#include "flags.h"
 #include "logger.h"
 
 #if !defined(NDEBUG)
 
-#define FIRST_ARG(N, ...) N
-#define LEFT_ARGS(N, ...) , ##__VA_ARGS__
-#define TRACE_TAG_FMT CLR_DIM "TRACE (%-10s)"
-#define TRACE_TAG_ARG(id) std::string(id).substr(0, 10).c_str()
-#define COUNTER_FMT "%s"
-#define COUNTER_ARG(id) IndentCounter::getString(id).c_str()
-
+// LWNODE_CALL_TRACE with ID
 #define LWNODE_CALL_TRACE_ID_LOG(id, ...)                                      \
-  if (EscargotShim::Flags::isTraceCallEnabled(#id)) {                          \
-    LWNODE_DLOG_RAW(TRACE_TAG_FMT " " COUNTER_FMT TRACE_FMT                    \
-                                  " " CLR_RESET FIRST_ARG(__VA_ARGS__)         \
-                                      CLR_RESET,                               \
-                    TRACE_TAG_ARG(#id),                                        \
-                    COUNTER_ARG(#id),                                          \
-                    TRACE_ARGS2 LEFT_ARGS(__VA_ARGS__));                       \
-  }
+  Logger(LogTRACE(#id, __PRETTY_FUNCTION__, __FILE_NAME__, __LINE__))          \
+      .print(__VA_ARGS__)
 
 #define LWNODE_CALL_TRACE_ID(id, ...)                                          \
   IndentCounter __counter(#id);                                                \
 #define LWNODE_CALL_TRACE_ID_INDENT(id) IndentCounter::indent(#id);
 #define LWNODE_CALL_TRACE_ID_UNINDENT(id) IndentCounter::unIndent(#id);
 
+// LWNODE_CALL_TRACE == LWNODE_CALL_TRACE_ID(COMMON, ...)
 #define LWNODE_CALL_TRACE(msg, ...)                                            \
   LWNODE_CALL_TRACE_ID(COMMON, msg, ##__VA_ARGS__);
+
 #define LWNODE_CALL_TRACE_LOG(msg, ...)                                        \
   LWNODE_CALL_TRACE_ID_LOG(COMMON, msg, ##__VA_ARGS__);
+
 #define LWNODE_CALL_TRACE_INDENT() LWNODE_CALL_TRACE_ID_INDENT(COMMON);
 #define LWNODE_CALL_TRACE_UNINDENT() LWNODE_CALL_TRACE_ID_UNINDENT(COMMON);
 
+// GC
 #define LWNODE_CALL_TRACE_GC_START(msg, ...)                                   \
-  if (EscargotShim::Flags::isTraceCallEnabled("gc")) {                         \
-    LWNODE_DLOG_INFO("GC: %s (%s:%d): " msg, TRACE_ARGS, ##__VA_ARGS__);       \
-  }
+  LWNODE_CALL_TRACE_ID_LOG(GC, "GC: %s", ##__VA_ARGS__)
 
 #define LWNODE_CALL_TRACE_GC_END(msg, ...)                                     \
-  if (EscargotShim::Flags::isTraceCallEnabled("gc")) {                         \
-    LWNODE_DLOG_INFO("GC: /%s (%s:%d): " msg, TRACE_ARGS, ##__VA_ARGS__);      \
-  }
+  LWNODE_CALL_TRACE_ID_LOG(GC, "GC: /%s", ##__VA_ARGS__)
 
 #else
 #define LWNODE_CALL_TRACE_ID(...)
index 5205bca170ce950ed2b851a27b2d9a824171f785..77c253e0bf7af3210bede69afcfb2e03172c69ca 100644 (file)
 #endif
 #endif
 
+#if !defined(FALLTHROUGH) && defined(__has_cpp_attribute)
+#if __has_cpp_attribute(fallthrough)
+#define FALLTHROUGH [[fallthrough]]
+#elif __has_cpp_attribute(gnu::fallthrough)
+#define FALLTHROUGH [[gnu::fallthrough]]
+#endif
+#endif
+
+#if !defined(FALLTHROUGH) && defined(__has_attribute)
+#if __has_attribute(__fallthrough__)
+#define FALLTHROUGH __attribute__((__fallthrough__))
+#endif
+#endif
+
+#if !defined(FALLTHROUGH)
+#define FALLTHROUGH /* fallthrough */
+#endif
+
 /* CHECK */
 // Use CHECK when abort should occurs if the condition fails
 #define CHECK_FMT CLR_REDBG "CHECK FAILED" CLR_RESET " "
 
 #define _LWNODE_CHECK_FAILED_HANDLER(msg, ...)                                 \
   LWNODE_LOG_INTERNAL(                                                         \
-      CHECK_FMT msg "\n\t " TRACE_FMT, ##__VA_ARGS__, TRACE_ARGS);             \
+      RAW, CHECK_FMT msg "\n\t %s", ##__VA_ARGS__, __CODE_LOCATION__);         \
   EscargotShim::DebugUtils::printStackTrace();                                 \
   std::abort();
 
index 57813ad6bb07ea3bc09e616cfb5cb99ce084e2c5..181c4c1595223e322dfe5950c0203bcfecb4b819 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "string-util.h"
 
+#include <sstream>
+
 // Magic values subtracted from a buffer value during UTF8 conversion.
 // This table contains as many values as there might be trailing bytes
 // in a UTF-8 sequence.
@@ -50,3 +52,15 @@ bool UTF8Sequence::convertUTF8ToLatin1(
 
   return true;
 }
+
+std::vector<std::string> strSplit(const std::string& str, char delimiter) {
+  std::vector<std::string> tokens;
+  std::stringstream ss(str);
+  std::string token;
+
+  while (getline(ss, token, delimiter)) {
+    tokens.push_back(token);
+  }
+
+  return tokens;
+}
index c8aba73f907493903819c0d6bc74cb8b7cd6f74e..c1e31abca839e1331aa948c48a3a93ce05e458fe 100644 (file)
@@ -22,6 +22,8 @@
 
 #include "misc.h"
 
+#include <vector>
+
 namespace EscargotShim {
 class Constants {
  public:
@@ -56,6 +58,8 @@ bool strStartsWith(const char* str, const char (&prefix)[N]) {
   return strncmp(str, prefix, N - 1) == 0;
 }
 
+std::vector<std::string> strSplit(const std::string& str, char delimiter);
+
 class UTF8Sequence {
  public:
   static inline bool isASCII(uint16_t character) {
@@ -81,19 +85,24 @@ class UTF8Sequence {
     switch (length) {
       case 6:
         character += static_cast<uint8_t>(*sequence++);
-        character <<= 6;  // Fall through.
+        character <<= 6;
+        FALLTHROUGH;
       case 5:
         character += static_cast<uint8_t>(*sequence++);
-        character <<= 6;  // Fall through.
+        character <<= 6;
+        FALLTHROUGH;
       case 4:
         character += static_cast<uint8_t>(*sequence++);
-        character <<= 6;  // Fall through.
+        character <<= 6;
+        FALLTHROUGH;
       case 3:
         character += static_cast<uint8_t>(*sequence++);
-        character <<= 6;  // Fall through.
+        character <<= 6;
+        FALLTHROUGH;
       case 2:
         character += static_cast<uint8_t>(*sequence++);
-        character <<= 6;  // Fall through.
+        character <<= 6;
+        FALLTHROUGH;
       case 1:
         character += static_cast<uint8_t>(*sequence++);
     }
diff --git a/lwnode/code/escargotshim/src/base.cc b/lwnode/code/escargotshim/src/base.cc
new file mode 100644 (file)
index 0000000..04dd2b3
--- /dev/null
@@ -0,0 +1,31 @@
+#include "base.h"
+
+#include "api.h"
+
+using namespace v8;
+
+namespace EscargotShim {
+
+EsScope::EsScope(v8::Isolate* isolate, const v8::Value* self) {
+  isolate_ = isolate != nullptr ? IsolateWrap::fromV8(isolate)
+                                : IsolateWrap::GetCurrent();
+  initSelf(self);
+}
+
+EsScope::EsScope(const Local<Context>& context, const v8::Value* self) {
+  isolate_ = context.IsEmpty() ? IsolateWrap::GetCurrent()
+                               : VAL(*context)->context()->GetIsolate();
+  initSelf(self);
+}
+
+EsScopeTemplate::EsScopeTemplate(const v8::Template* self) : EsScope() {
+  initSelf(self);
+}
+
+EsScopeTemplate::EsScopeTemplate(const v8::Local<v8::Context>& context,
+                                 const v8::Template* self)
+    : EsScope(context, nullptr) {
+  initSelf(self);
+}
+
+}  // namespace EscargotShim
index 846daf46ab5f9c7ec096343fedb438bcfc3e606e..eb3c0aba1ae4930fd82fa036138bffc37e65c776 100644 (file)
 
 #pragma once
 
+#include "api.h"
 #include "unimplemented.h"
 
+#include <EscargotPublic.h>
+#include <v8.h>
+
 namespace EscargotShim {
 class ValueWrap;
 }
@@ -28,15 +32,15 @@ class ValueWrap;
 #define __TERMINATION_CHECK(lwIsolate, bailout_value)                          \
   if (lwIsolate->IsExecutionTerminating()) {                                   \
     LWNODE_DLOG_WARN(                                                          \
-        "%s (%s:%d) is ignored due to script execution being terminated.",     \
-        TRACE_ARGS2);                                                          \
+        "%s is ignored due to script execution being terminated.",             \
+        __CODE_LOCATION__);                                                    \
     return bailout_value;                                                      \
   }
 
 #if !defined(NDEBUG)
 #define __DLOG_EVAL_EXCEPTION(eval_result)                                     \
-  LWNODE_DLOG_RAW("Execute:\n  %s (%s:%d)\n%s",                                \
-                  TRACE_ARGS2,                                                 \
+  LWNODE_DLOG_RAW("Execute:\n  %s\n%s",                                        \
+                  __CODE_LOCATION__,                                           \
                   EvalResultHelper::getErrorString(                            \
                       lwIsolate->GetCurrentContext()->get(), eval_result)      \
                       .c_str());
@@ -65,12 +69,25 @@ class ValueWrap;
 #define API_HANDLE_EXCEPTION(eval_result, lwIsolate, bailout_value)            \
   if (!eval_result.isSuccessful()) {                                           \
     __DLOG_EVAL_EXCEPTION(eval_result);                                        \
-    lwIsolate->SetPendingExceptionAndMessage(eval_result.error.get(),          \
-                                             eval_result.stackTraceData);      \
-    lwIsolate->ReportPendingMessages();                                        \
+    lwIsolate->handleException(eval_result);                                   \
     return bailout_value;                                                      \
   }
 
+#define API_ENTER_AND_EXIT_IF_TERMINATING(ScopeType, context, returnValue)     \
+  ScopeType scope(context, this);                                              \
+  if (scope.isTerminating()) {                                                 \
+    return returnValue;                                                        \
+  }
+
+#define API_ENTER_NO_TERMINATION_CHECK(ScopeType, isolate)                     \
+  ScopeType scope(isolate, this);
+
+#define API_EXIT_IF_EXCEPTION_OCCURRED(r, returnValue)                         \
+  if (!scope.isSuccessful(r)) {                                                \
+    scope.printDebug(r);                                                       \
+    return returnValue;                                                        \
+  }
+
 // V has parameters (Type, type, TYPE, C type)
 #define TYPED_ARRAYS(V)                                                        \
   V(Uint8, uint8, UINT8, uint8_t)                                              \
@@ -84,3 +101,124 @@ class ValueWrap;
   V(Uint8Clamped, uint8_clamped, UINT8_CLAMPED, uint8_t)                       \
   V(BigUint64, biguint64, BIGUINT64, uint64_t)                                 \
   V(BigInt64, bigint64, BIGINT64, int64_t)
+
+namespace EscargotShim {
+
+class EsScope {
+ public:
+  EsScope(const v8::Value* self = nullptr) : EsScope(nullptr, self) {}
+  EsScope(v8::Isolate* isolate, const v8::Value* self = nullptr);
+  EsScope(const v8::Local<v8::Context>& context,
+          const v8::Value* self = nullptr);
+
+  Escargot::ValueRef* self() { return self_; }
+  virtual EscargotShim::IsolateWrap* lwIsolate() { return isolate_; }
+  virtual v8::Isolate* v8Isolate() { return isolate_->toV8(); }
+  virtual Escargot::ContextRef* context() {
+    if (context_) {
+      return context_->get();
+    }
+    return isolate_->GetCurrentContext()->get();
+  }
+
+  virtual ValueRef* asValue(const v8::Local<v8::Value>& value) {
+    return CVAL(*value)->value();
+  }
+
+  virtual ValueRef* asValue(const v8::Local<v8::Name>& value) {
+    return CVAL(*value)->value();
+  }
+
+  virtual StringRef* asValue(const v8::Local<v8::String>& value) {
+    return CVAL(*value)->value()->asString();
+  }
+
+  void printDebug(Escargot::Evaluator::EvaluatorResult& r) {
+#if !defined(NDEBUG)
+    LWNODE_DLOG_RAW("Execute:\n  %s\n%s",
+                    __CODE_LOCATION__,
+                    EvalResultHelper::getErrorString(context(), r).c_str());
+#endif
+  }
+
+  bool isTerminating() { return isolate_->IsExecutionTerminating(); }
+
+  bool isSuccessful(Escargot::Evaluator::EvaluatorResult& r) {
+    if (!r.isSuccessful()) {
+      isolate_->SetPendingExceptionAndMessage(r.error.get(), r.stackTrace);
+      isolate_->ReportPendingMessages();
+      return false;
+    }
+    return true;
+  }
+
+ protected:
+  EscargotShim::IsolateWrap* isolate_ = nullptr;
+  EscargotShim::ContextWrap* context_ = nullptr;
+
+ private:
+  Escargot::ValueRef* self_ = nullptr;
+
+  void initSelf(const v8::Value* self) {
+    if (self) {
+      self_ = CVAL(self)->value();
+    }
+  }
+};
+
+class EsScopeTemplate : public EsScope {
+ public:
+  EsScopeTemplate(const v8::Template* self = nullptr);
+  EsScopeTemplate(const v8::Local<v8::Context>& context,
+                  const v8::Template* self = nullptr);
+  EscargotShim::TemplateRef* self() { return self_; }
+
+  virtual FunctionTemplateRef* asFunctionTemplate(
+      const v8::Local<v8::FunctionTemplate>& value) {
+    return CVAL(*value)->ftpl();
+  }
+
+ protected:
+  EscargotShim::TemplateRef* self_ = nullptr;
+
+ private:
+  void initSelf(const v8::Template* self) {
+    if (self) {
+      self_ = CVAL(self)->tpl();
+    }
+  }
+};
+
+class EsScopeFunctionTemplate : public EsScopeTemplate {
+ public:
+  EsScopeFunctionTemplate(const v8::FunctionTemplate* self)
+      : EsScopeTemplate(self) {}
+  EsScopeFunctionTemplate(const v8::Local<v8::Context>& context,
+                          const v8::FunctionTemplate* self)
+      : EsScopeTemplate(context, self) {}
+
+  EscargotShim::FunctionTemplateRef* self() {
+    LWNODE_CHECK(self_->isFunctionTemplate());
+    return reinterpret_cast<EscargotShim::FunctionTemplateRef*>(self_);
+  }
+
+ private:
+};
+
+class EsScopeObjectTemplate : public EsScopeTemplate {
+ public:
+  EsScopeObjectTemplate(const v8::ObjectTemplate* self)
+      : EsScopeTemplate(self) {}
+  EsScopeObjectTemplate(const v8::Local<v8::Context>& context,
+                        const v8::ObjectTemplate* self)
+      : EsScopeTemplate(context, self) {}
+
+  EscargotShim::ObjectTemplateRef* self() {
+    LWNODE_CHECK(self_->isObjectTemplate());
+    return reinterpret_cast<EscargotShim::ObjectTemplateRef*>(self_);
+  }
+
+ private:
+};
+
+}  // namespace EscargotShim
index f716535250e559be46078c104d92c48427418413..5eaedbf0e0ff5c6c37c6312799c1cc0bc35e7680 100644 (file)
@@ -150,7 +150,7 @@ FileData Loader::createFileDataForReloadableString(
     // Treat non-latin1 as UTF-8 and encode it as UTF-16 Little Endian.
     if (encodingHint == Encoding::kUnknown) {
       LWNODE_LOG_INFO("%s contains characters outside of the Latin1 range.",
-                      filename.c_str());
+                      filename);
     }
 
     char* newStringBuffer = nullptr;
@@ -161,6 +161,7 @@ FileData Loader::createFileDataForReloadableString(
                                             (const char*)bufferHolder.get(),
                                             bufferSize);
     if (isConverted == false) {
+      LWNODE_LOG_ERROR("convertUTF8ToUTF16le failed (%s)", filename);
       return FileData();
     }
 
@@ -169,11 +170,12 @@ FileData Loader::createFileDataForReloadableString(
   } else {
     if (encoding == Encoding::kLatin1) {
       if (encodingHint == Encoding::kUnknown) {
-        LWNODE_LOG_INFO("%s contains Latin1 characters.", filename.c_str());
+        LWNODE_LOG_INFO("%s contains Latin1 characters.", filename);
       }
 
       bufferSize = latin1String.length();
       bufferHolder.reset(allocateStringBuffer(bufferSize + 1));
+      LWNODE_CHECK(bufferHolder.get() != nullptr);
       ((uint8_t*)bufferHolder.get())[bufferSize] = '\0';
 
       memcpy(bufferHolder.get(), latin1String.data(), bufferSize);
@@ -210,9 +212,11 @@ FileData SourceReader::read(std::string filename, const Encoding encodingHint) {
   std::unique_ptr<void, std::function<void(void*)>> bufferHolder(
       buffer, freeStringBuffer);
 
-  if (std::fread(buffer, sizeof(uint8_t), bufferSize, file) == 0) {
+  size_t readBytes = std::fread(buffer, sizeof(uint8_t), bufferSize, file);
+  if (readBytes == 0) {
     return FileData();
   }
+  LWNODE_CHECK(readBytes == bufferSize);
 
   return Loader::createFileDataForReloadableString(
       filename, std::move(bufferHolder), bufferSize, encodingHint);
@@ -281,12 +285,13 @@ MaybeLocal<String> Loader::NewReloadableString(Isolate* isolate,
       loadCallback = [](void* userData) -> void* {
         auto data = reinterpret_cast<Loader::ReloadableSourceData*>(userData);
 
-        LWNODE_LOG_INFO("  Load: %d (%d) %p %s (+%.2f kB)",
-                        ++s_stat.loaded,
-                        s_stat.reloaded,
-                        data->preloadedData,
-                        data->path(),
-                        (float)data->preloadedDataLength() / 1024);
+        LWNODE_CALL_TRACE_ID(LOADER,
+                             "  Load: %d (%d) %p %s (+%.2f kB)",
+                             ++s_stat.loaded,
+                             s_stat.reloaded,
+                             data->preloadedData,
+                             data->path(),
+                             (float)data->preloadedDataLength() / 1024);
 
         if (data->preloadedData) {
           auto buffer = data->preloadedData;
@@ -305,12 +310,13 @@ MaybeLocal<String> Loader::NewReloadableString(Isolate* isolate,
       unloadCallback = [](void* preloadedData, void* userData) -> void {
         auto data = reinterpret_cast<Loader::ReloadableSourceData*>(userData);
 
-        LWNODE_LOG_INFO(" Unload: %d (%d) %p %s (-%.2f kB)",
-                        --s_stat.loaded,
-                        s_stat.reloaded,
-                        preloadedData,
-                        data->path(),
-                        (float)data->preloadedDataLength() / 1024);
+        LWNODE_CALL_TRACE_ID(LOADER,
+                             "Unload: %d (%d) %p %s (-%.2f kB)",
+                             --s_stat.loaded,
+                             s_stat.reloaded,
+                             preloadedData,
+                             data->path(),
+                             (float)data->preloadedDataLength() / 1024);
 
         if (data->preloadedData) {
           freeStringBuffer(data->preloadedData);
index 8b899a870ca61cb4d22d62cbacfd5a5249f1fbac..8611513e855928ab9c72252d189c6505eb34ab9e 100644 (file)
@@ -158,6 +158,17 @@ static ValueRef* CreateReloadableSourceFromFile(ExecutionStateRef* state,
   return ValueRef::createUndefined();
 }
 
+static ValueRef* checkIfHandledAsOneByteString(ExecutionStateRef* state,
+                                               ValueRef* thisValue,
+                                               size_t argc,
+                                               ValueRef** argv,
+                                               bool isConstructCall) {
+  if (argc > 0 && argv[0]->isString()) {
+    return ValueRef::create(argv[0]->asString()->has8BitContent());
+  }
+  return ValueRef::createUndefined();
+}
+
 void InitializeProcessMethods(Local<Object> target, Local<Context> context) {
   auto esContext = CVAL(*context)->context()->get();
   auto esTarget = CVAL(*target)->value()->asObject();
@@ -168,6 +179,10 @@ void InitializeProcessMethods(Local<Object> target, Local<Context> context) {
   SetMethod(esContext, esTarget, "RssUsage", RssUsage);
   SetMethod(esContext, esTarget, "PssSwapUsage", PssSwapUsage);
   SetMethod(esContext, esTarget, "MemSnapshot", MemSnapshot);
+  SetMethod(esContext,
+            esTarget,
+            "checkIfHandledAsOneByteString",
+            checkIfHandledAsOneByteString);
 #ifdef LWNODE_USE_RELOAD_SCRIPT
   SetMethod(esContext,
             esTarget,
@@ -178,11 +193,20 @@ void InitializeProcessMethods(Local<Object> target, Local<Context> context) {
 
 void IdleGC(v8::Isolate* isolate) {
   LWNODE_LOG_INFO("IdleGC");
-  IsolateWrap::fromV8(isolate)->vmInstance()->enterIdleMode();
+  if (isolate) {
+    IsolateWrap::fromV8(isolate)->vmInstance()->enterIdleMode();
+  }
   Escargot::Memory::gc();
   malloc_trim(0);
 }
 
+void initDebugger() {
+  auto lwIsolate = IsolateWrap::GetCurrent();
+  if (lwIsolate) {
+    lwIsolate->GetCurrentContext()->initDebugger();
+  }
+}
+
 class MessageLoop::Internal {
  public:
   Internal() { gcStrategy_ = std::make_unique<DelayedGC>(); }
@@ -215,4 +239,13 @@ void MessageLoop::onPrepare(v8::Isolate* isolate) {
   internal_->handleGC(isolate);
 }
 
+Escargot::ContextRef* Utils::ToEsContext(v8::Context* context) {
+  return ContextWrap::fromV8(context)->get();
+}
+
+v8::Local<v8::Value> Utils::NewLocal(v8::Isolate* isolate,
+                                     Escargot::ValueRef* ptr) {
+  return v8::Utils::NewLocal<v8::Value>(isolate, ptr);
+}
+
 }  // namespace LWNode
diff --git a/lwnode/code/tizen/src/node_bindings.cc b/lwnode/code/tizen/src/node_bindings.cc
deleted file mode 100644 (file)
index 90c683f..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (c) 2019-present Samsung Electronics Co., Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <glib.h>
-#include <cassert>
-#include "uv.h"
-#include "node_bindings.h"
-#include "node_escargot_logger.h"
-#ifdef HOST_TIZEN
-#include "Extension.h"
-#endif
-
-namespace glib {
-
-using namespace nescargot;
-
-struct SourceData {
-  GSource source;
-  gpointer tag;
-  NodeBindings* node_bindings;
-};
-
-// TODO: classify EventLoop if needed
-
-static GMainContext* gcontext;
-static GMainLoop* gmainLoop;
-static GSource* uvsource;
-static GSourceFuncs source_funcs;
-static bool gmainLoopDone = false;
-
-static gboolean GmainLoopPrepareCallback(GSource* source, gint* timeout) {
-  uv_update_time(uv_default_loop());
-  *timeout = uv_backend_timeout(uv_default_loop());
-
-  if (!uv_watcher_queue_empty(uv_default_loop())) {
-    return TRUE;
-  }
-
-  return 0 == *timeout;
-}
-
-static gboolean GmainLoopCheckCallback(GSource* source) {
-  if (!uv_backend_timeout(uv_default_loop())) {
-    return TRUE;
-  }
-
-  return (G_IO_IN ==
-          g_source_query_unix_fd(source, ((SourceData*)source)->tag));
-}
-
-static gboolean GmainLoopDispatchCallback(GSource* source, GSourceFunc callback,
-                                          gpointer user_data) {
-  assert(gcontext);
-  g_main_context_iteration(gcontext, FALSE);
-
-  if (gmainLoopDone) {
-    return G_SOURCE_REMOVE;
-  }
-
-  NodeBindings* node_bindings = ((SourceData*)source)->node_bindings;
-
-  node_bindings->RunOnce();
-
-  if (!node_bindings->HasMoreTasks()) {
-    g_main_loop_quit(gmainLoop);
-    return G_SOURCE_REMOVE;
-  }
-  return G_SOURCE_CONTINUE;
-}
-
-void GmainLoopInit(NodeBindings* self) {
-  gcontext = g_main_context_default();
-  gmainLoop = g_main_loop_new(gcontext, FALSE);
-  source_funcs = {
-      .prepare = GmainLoopPrepareCallback,
-      .check = GmainLoopCheckCallback,
-      .dispatch = GmainLoopDispatchCallback,
-  };
-
-  uvsource = g_source_new(&source_funcs, sizeof(SourceData));
-  ((SourceData*)uvsource)->tag = g_source_add_unix_fd(
-      uvsource, uv_backend_fd(uv_default_loop()),
-      (GIOCondition)(G_IO_IN | G_IO_OUT | G_IO_ERR | G_IO_PRI));
-  ((SourceData*)uvsource)->node_bindings = self;
-
-  g_source_attach(uvsource, gcontext);
-  g_source_unref(uvsource);
-
-#ifdef HOST_TIZEN
-  DeviceAPI::ESPostMessageListener::SetMainThreadIdlerRegister(
-      [](DeviceAPI::ESPostMessageListener::Idler_t idler, void* data) {
-        g_idle_add(idler, data);
-      });
-#endif
-}
-
-void GmainLoopStart() {
-  assert(gmainLoop);
-  assert(gcontext);
-
-  g_main_loop_run(gmainLoop);
-  gmainLoopDone = true;
-  g_main_context_iteration(gcontext, TRUE);
-}
-
-void GmainLoopExit() {
-  if (uvsource) {
-    g_source_destroy(uvsource);
-  }
-  if (gmainLoop) {
-    g_main_loop_unref(gmainLoop);
-  }
-  if (gcontext) {
-    g_main_context_unref(gcontext);
-  }
-}
-
-}  // namespace glib
-
-#ifdef HOST_TIZEN
-#include "Queue.hpp"
-#include <mutex>
-#include <thread>
-
-#define NESCARGOT_AUL_TERMINATION_MESSAGE "AUL_TERMINATION"
-
-namespace nescargot {
-
-struct Task {
-  std::string data;
-};
-
-Queue<Task> g_queue;
-
-static void UvNoOp(uv_async_t* handle) {
-  uv_close((uv_handle_t*)handle,
-           [](uv_handle_t* handle) { delete (uv_async_t*)handle; });
-}
-
-void push_aul_message(const char* message) {
-  g_queue.push({.data = message});
-  // wake up the uv queue
-  uv_async_t* async = new uv_async_t;
-  uv_async_init(uv_default_loop(), async, UvNoOp);
-  uv_async_send(async);
-}
-
-void push_aul_termination_message() {
-  push_aul_message(NESCARGOT_AUL_TERMINATION_MESSAGE);
-}
-}  // namespace nescargot
-#endif
-
-namespace nescargot {
-
-static void pump_aul_message(v8::Isolate* isolate, NodeBindings* bindings) {
-#ifdef HOST_TIZEN
-  // TODO: move the following to m_platform.PumpMessageLoop(isolate)
-  if (!g_queue.empty()) {
-    auto task = g_queue.pop();
-    node::EmitMessage(isolate, task.data.c_str());
-    if (task.data == std::string(NESCARGOT_AUL_TERMINATION_MESSAGE)) {
-      bindings->TerminateGMainLoop();
-    }
-  }
-#endif
-}
-
-NodeBindings::NodeBindings() {}
-
-void NodeBindings::Initialize(Environment&& env, Platform&& platform,
-                              Node&& node) {
-  assert(platform.PumpMessageLoop);
-  assert(platform.EnterIdleMode);
-
-  m_env = std::move(env);
-  m_platform = std::move(platform);
-  m_node = std::move(node);
-  m_isInitialize = true;
-}
-
-void NodeBindings::StartEventLoop() {
-  assert(m_isInitialize);
-
-  glib::GmainLoopInit(this);
-
-  RunOnce();
-
-  // NOTE: We try an intense memory saving mode called Idle Mode.
-  // It will be exited once any javascript operation runs.
-  m_platform.EnterIdleMode(m_env.isolate());
-
-  if (HasMoreTasks()) {
-    glib::GmainLoopStart();
-  }
-
-  glib::GmainLoopExit();
-}
-
-bool NodeBindings::HasMoreTasks() {
-  return (m_hasMoreNodeTasks && !m_isTerminated);
-}
-
-void NodeBindings::RunOnce() {
-  auto isolate = m_env.isolate();
-  auto event_loop = m_env.event_loop();
-
-  m_platform.PumpMessageLoop(isolate);
-  pump_aul_message(isolate, this);
-
-  bool more = uv_run(event_loop, UV_RUN_NOWAIT);
-
-  if (more == false) {
-    m_platform.PumpMessageLoop(isolate);
-    pump_aul_message(isolate, this);
-
-    m_node.EmitBeforeExit();
-
-    // Emit `beforeExit` if the loop became alive either after emitting
-    // event, or after running some callbacks.
-    more = uv_loop_alive(event_loop);
-    if (uv_run(event_loop, UV_RUN_NOWAIT) != 0) {
-      more = true;
-    }
-  }
-  m_hasMoreNodeTasks = more;
-
-  if (m_idleCheckTimeoutID) {
-    g_source_remove(m_idleCheckTimeoutID);
-  }
-
-#ifndef IDLE_CHECK_TIMEOUT
-#define IDLE_CHECK_TIMEOUT 500
-#endif
-  m_idleCheckTimeoutID = g_timeout_add(
-      IDLE_CHECK_TIMEOUT,
-      [](gpointer data) -> gboolean {
-        NodeBindings* self = (NodeBindings*)data;
-        self->m_idleCheckTimeoutID = 0;
-        self->m_platform.EnterIdleMode(self->m_env.isolate());
-        return G_SOURCE_REMOVE;
-      },
-      this);
-}
-
-}  // namespace nescargot
diff --git a/lwnode/code/tizen/src/node_bindings.h b/lwnode/code/tizen/src/node_bindings.h
deleted file mode 100644 (file)
index 1b63f3e..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2019-present Samsung Electronics Co., Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NODE_BINDINGS_H
-#define NODE_BINDINGS_H
-
-#include <functional>
-
-namespace v8 {
-class Isolate;
-}
-
-namespace node {
-class Environment;
-void EmitMessage(v8::Isolate* isolate, const char* fmt, ...);
-}  // namespace node
-
-typedef struct uv_loop_s uv_loop_t;
-
-namespace nescargot {
-
-void push_aul_message(const char* message);
-void push_aul_termination_message();
-
-class NodeBindings {
- public:
-  NodeBindings();
-  virtual ~NodeBindings(){};
-
-  struct Platform {
-    void (*PumpMessageLoop)(v8::Isolate* isolate);
-    void (*EnterIdleMode)(v8::Isolate* isolate);
-  };
-
-  struct Environment {
-    std::function<v8::Isolate*()> isolate;
-    std::function<uv_loop_t*()> event_loop;
-  };
-
-  struct Node {
-    std::function<void()> EmitBeforeExit;
-  };
-
-  void Initialize(Environment&& env, Platform&& platform, Node&& node);
-  void StartEventLoop();
-  void RunOnce();
-  bool HasMoreTasks();
-  void TerminateGMainLoop() { m_isTerminated = true; }
-
- private:
-  Environment m_env;
-  Platform m_platform;
-  Node m_node;
-  bool m_isInitialize = {false};
-  bool m_hasMoreNodeTasks = {true};
-  bool m_isTerminated = {false};
-  unsigned int m_idleCheckTimeoutID = {0};
-};
-
-}  // namespace nescargot
-
-#endif
diff --git a/lwnode/test.sh b/lwnode/test.sh
new file mode 100755 (executable)
index 0000000..5d57fd9
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+# Copyright (c) 2020-present Samsung Electronics Co., Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+[[ -z $TEST_ROOT ]] && TEST_ROOT=$(pwd)/test
+[[ -z $SKIP_TESTS_PATH ]] && SKIP_TESTS_PATH=$TEST_ROOT/skip_tests.txt
+[[ -z $UNSUPPORTED_TESTS_PATH ]] && UNSUPPORTED_TESTS_PATH=$TEST_ROOT/skip_features.txt
+# SKIP_TESTS_PATH=./skip_list.gen.txt
+
+echo root: $TEST_ROOT
+echo skip: $SKIP_TESTS_PATH
+echo drop: $UNSUPPORTED_TESTS_PATH
+
+function cleanup()
+{
+  local user=$(whoami)
+
+  rm -rf $TEST_ROOT/.tmp.*
+
+  if [[ -z $VM_PATH ]]; then
+    ps -fu $user | grep 'Release\/lwnode' | grep -v grep | awk '{print $2" "$3}' | xargs -r kill -9
+  else
+    ps -fu $user | grep $VM_PATH | grep -v grep | awk '{print $2" "$3}' | xargs -r kill -9
+  fi
+  # ps -fu $user | grep '.tmp.' | grep -v grep | awk '{print $2" "$3}' | xargs -r kill -9
+  ps -fu $user | grep 'defunct' | grep -v grep | awk '{print $2" "$3}' | xargs -r kill -9
+
+  echo -e "cleanup remaining processes"
+}
+
+trap cleanup SIGINT EXIT
+
+cleanup
+
+ARGS=$*
+SKIP_TEST_OPTION=
+UNSUPPORTED_TEST_OPTION=
+
+[[ -f $SKIP_TESTS_PATH ]] && \
+  SKIP_TEST_OPTION="--skip-tests=$(sed 's/\s#.*//g' $SKIP_TESTS_PATH | paste -sd,)"
+[[ -f $UNSUPPORTED_TESTS_PATH ]] && \
+  UNSUPPORTED_TEST_OPTION="--unsupported-tests=$(sed '/#\|^$/d' $UNSUPPORTED_TESTS_PATH | paste -sd,)"
+
+if [[ -z ${ARGS[0]} ]]; then
+  ARGS="test/parallel test/regression"
+else
+  SKIP_TEST_OPTION=""
+fi
+
+tools/test.py -J -p color --report --time \
+  --timeout 60 --repeat 1 \
+  --test-root=$TEST_ROOT \
+  $SKIP_TEST_OPTION \
+  $UNSUPPORTED_TEST_OPTION \
+  $ARGS
index a0fad83500d7f0013e69845542a98d4cd8223705..69835864ea53f443bd1f5d2bdcffbabf92aabc53 100644 (file)
@@ -25,6 +25,7 @@ BuildRequires: make
 BuildRequires: python
 BuildRequires: ninja
 BuildRequires: zip
+BuildRequires: rsync
 BuildRequires: pkgconfig(dlog)
 BuildRequires: pkgconfig(aul)
 BuildRequires: pkgconfig(capi-appfw-app-common)
@@ -35,6 +36,7 @@ BuildRequires: pkgconfig(icu-uc)
 BuildRequires: pkgconfig(glib-2.0)
 BuildRequires: nghttp2-devel
 BuildRequires: pkgconfig(libcares)
+BuildRequires: pkgconfig(sqlite3)
 
 %if (0%{?tizen_version_major} >= 6)
 BuildRequires: pkgconfig(openssl1.1)
@@ -46,6 +48,10 @@ BuildRequires: pkgconfig(openssl)
   %endif
 %endif
 
+%if 0%{?asan} == 1
+BuildRequires: libasan
+%endif
+
 ##############################################
 # Packages for profiles
 ##############################################
@@ -58,9 +64,10 @@ Requires:    %{name} = %{version}
 Development files for Lightweight node.js.
 
 # Initialize the variables
-%{!?node_engine: %define node_engine escargot}
+%{!?target: %define target lwnode} #taget = [lwnode/v8/modules/apps]
 %{!?lib_type: %define lib_type shared}
 %{!?feature_mode: %define feature_mode production}
+%{!?app_name: %define app_name unkown}
 
 %description
 Node.js on Escargot is a memory efficient node.js implementation,
@@ -68,6 +75,23 @@ which runs on top of Escargot, a memory optimized JavaScript Engine developed
 by Samsung Research, instead of the default V8 JS engine.
 
 
+# Add subpackage for apps
+%if "%{target}" == "apps"
+%package %{app_name}
+Summary: lwnode apps
+%description %{app_name}
+lwnode %{app_name} app
+
+# variables related to app
+%define project_path %{_builddir}/%{name}-%{version}
+%define local_app_path %{project_path}/lwnode/apps/%{app_name}
+%define app_out_path %{project_path}/out/apps/%{app_name}
+%define app_files_path /tmp/%{app_name}/files
+%define target_app_path /usr/apps/lwnode/apps/%{app_name}
+%define app_variables BUILD_OUT_PATH=%{app_out_path} APP_PATH=%{local_app_path} FILES_PATH=%{buildroot}%{app_files_path}
+%define app_post_variables APP_PATH=%{target_app_path} FILES_PATH=%{app_files_path}
+%endif
+
 %prep
 %setup -q
 
@@ -98,17 +122,21 @@ gcc --version
 %endif
 
 %if 0%{?asan} == 1
-CFLAGS+="-fsanitize=address -fsanitize-recover=address -U_FORTIFY_SOURCE -fno-omit-frame-pointer -fno-common"
-CXXFLAGS+="-fsanitize=address -fsanitize-recover=address -U_FORTIFY_SOURCE -fno-omit-frame-pointer -fno-common"
-LDFLAGS+="-fsanitize=address"
+%define asan_config --enable-asan
 %endif
 
-%if "%{node_engine}" == "escargot"
-%define target lwnode
+%if "%{target}" == "lwnode"
 %define target_lib liblwnode
 %define target_src out/tizen/Release
-%define engine_config --without-bundled-v8 --engine escargot
+
+%if %{?static_escargot:0}%{!?static_escargot:1}
+  %define engine_config --without-bundled-v8 --engine escargot
 %else
+  %define engine_config --without-bundled-v8 --engine escargot --static-escargot
+%endif
+%endif
+
+%if "%{target}" == "v8"
 %define target node
 %define target_src out/v8/Release
 %endif
@@ -130,20 +158,24 @@ LDFLAGS+="-fsanitize=address"
   %define extra_config --escargot-threading
 %endif
 
-echo "Building:" %{target}
 
-CFLAGS+=' -Os '
-CXXFLAGS+=' -Os '
+echo "Build Target:" %{target}
+echo $CFLAGS
+
+%if "%{target}" == "modules"
+./lwnode/build-modules.sh %{?modules_list} --os=tizen
+%endif
 
+%if "%{target}" == "lwnode" || "%{target}" == "v8"
 # building liblwnode.so
 ./configure --tizen --without-npm \
             --without-inspector --without-node-code-cache --without-node-snapshot \
             --with-intl none %{?libshared} \
             --enable-reload-script --enable-external-builtin-script \
             --dest-os linux --dest-cpu '%{tizen_arch}' \
-            --ninja %{?engine_config} %{?extra_config} %{?lib_type_config}
+            --ninja %{?engine_config} %{?extra_config} %{?lib_type_config} %{?asan_config}
 
-%if "%{node_engine}" == "escargot" && "%{lib_type}" == "shared"
+%if "%{target}" == "lwnode" && "%{lib_type}" == "shared"
   ninja -C %{target_src} %{target_lib}
 %endif
 
@@ -153,8 +185,13 @@ CXXFLAGS+=' -Os '
             --with-intl none %{?libshared} \
             --enable-reload-script --enable-external-builtin-script \
             --dest-os linux --dest-cpu '%{tizen_arch}' \
-            --ninja %{?engine_config} %{?extra_config}
+            --ninja %{?engine_config} %{?extra_config} %{?asan_config}
 ninja -C %{target_src} %{target}
+%endif
+
+%if "%{target}" == "apps"
+%{app_variables} %{local_app_path}/build/build.sh
+%endif
 
 
 ##############################################
@@ -167,18 +204,35 @@ mkdir -p %{buildroot}%{_bindir}
 mkdir -p %{buildroot}%{_libdir}
 
 rm -f %{target_src}/lib/*.tmp %{target_src}/lib/*.TOC
-%if "%{node_engine}" == "escargot"
-  cp %{target_src}/gen/escargot/libescargot.so %{buildroot}%{_libdir}
+%if "%{target}" == "lwnode"
+  %if %{?static_escargot:0}%{!?static_escargot:1}
+    cp %{target_src}/gen/escargot/libescargot.so %{buildroot}%{_libdir}
+  %endif
   %if "%{lib_type}" == "shared"
     cp %{target_src}/lib/liblwnode.so* %{buildroot}%{_libdir}
   %endif
-%endif
 
 # for devel files
-strip -v -g %{target_src}/%{target}
+%if %{?debug_symbols:0}%{!?debug_symbols:1}
+  strip -v -g %{target_src}/%{target}
+%endif
+
 cp %{target_src}/%{target} %{buildroot}%{_bindir}
 cp %{target_src}/%{target}.dat %{buildroot}%{_bindir}
 
+%endif # "%{target}" == "lwnode"
+
+%if "%{target}" == "apps"
+rm -rf %{buildroot}%{app_files_path}
+mkdir -p %{buildroot}%{app_files_path}
+
+%{app_variables} %{local_app_path}/build/install.sh
+mkdir -p %{buildroot}%{target_app_path}/build
+cp %{local_app_path}/build/post.sh %{buildroot}%{target_app_path}/build
+cp %{local_app_path}/build/%{app_name}.manifest %{buildroot}%{target_app_path}
+
+%endif
+
 %clean
 rm -fr ./*.list
 rm -fr ./*.manifest
@@ -189,7 +243,6 @@ rm -fr ./*.manifest
 %postun
 /sbin/ldconfig
 
-
 ##############################################
 ## Packaging rpms
 ##############################################
@@ -197,8 +250,10 @@ rm -fr ./*.manifest
 %files
 %manifest packaging/%{name}.manifest
 %defattr(-,root,root,-)
-%if "%{node_engine}" == "escargot"
-  %{_libdir}/libescargot.so
+%if "%{target}" == "lwnode"
+  %if %{?static_escargot:0}%{!?static_escargot:1}
+    %{_libdir}/libescargot.so
+  %endif
   %if "%{lib_type}" == "shared"
     %{_libdir}/liblwnode.so*
   %endif
@@ -207,5 +262,16 @@ rm -fr ./*.manifest
 
 %files devel
 %manifest packaging/%{name}.manifest
-%{_bindir}/%{target}
-%{_bindir}/%{target}.dat
+%if "%{target}" == "lwnode"
+  %{_bindir}/%{target}
+  %{_bindir}/%{target}.dat
+%endif
+
+%if "%{target}" == "apps"
+%post %{app_name}
+%{app_post_variables} %{target_app_path}/build/post.sh
+
+%files %{app_name}
+%{target_app_path}
+%{app_files_path}
+%endif
index 7011c80e671a15451bc3df7bd78664727072f33f..e87128ba2391f7d9fc009e923a7d276c2433a77b 100644 (file)
@@ -152,8 +152,8 @@ typedef enum {
 
 #ifdef NAPI_EXPERIMENTAL
 typedef struct {
-  uint64_t lower;
-  uint64_t upper;
+  uint64_t lower = 0;
+  uint64_t upper = 0;
 } napi_type_tag;
 #endif  // NAPI_EXPERIMENTAL
 
index b0f947c7176ced14c0a0c41f778b30bc0dd237b0..d037c2473439fa8344e8d9e99f61f91648947a75 100644 (file)
@@ -39,6 +39,9 @@
 #include "node_revert.h"
 #include "node_v8_platform-inl.h"
 #include "node_version.h"
+#ifdef LWNODE // @lwnode
+#include "node_main_lw_runner-inl.h"
+#endif
 
 #if HAVE_OPENSSL
 #include "allocated_buffer-inl.h"  // Inlined functions needed by node_crypto.h
@@ -1071,10 +1074,9 @@ int Start(int argc, char** argv) {
   if (result.early_return) {
     return result.exit_code;
   }
-#ifdef LWNODE
-  // @lwndoe
-  ArrayBufferAllocator* allocator = nullptr;
-  // end of @lwnode
+
+  #if defined(LWNODE)
+  LWNode::LWNodeMainRunner nodeMainRunner; // @lwndoe
   {
     Isolate::CreateParams params;
     const std::vector<size_t>* indexes = nullptr;
@@ -1102,19 +1104,10 @@ int Start(int argc, char** argv) {
                                    result.exec_args,
                                    indexes);
 
-    // @lwnode
-    allocator = main_instance.arrayBufferAllocator();
-    // endof @lwnode
-    result.exit_code = main_instance.Run();
+    result.exit_code = nodeMainRunner.Run(main_instance); // @lwndoe
   }
-
-  TearDownOncePerProcess();
-  // @lwnode
-  v8::V8::ShutdownPlatform();
-  delete allocator;
-  // end of @lwnode
 #else
- {
 {
     Isolate::CreateParams params;
     const std::vector<size_t>* indexes = nullptr;
     std::vector<intptr_t> external_references;
@@ -1142,9 +1135,9 @@ int Start(int argc, char** argv) {
                                    indexes);
     result.exit_code = main_instance.Run();
   }
+#endif
 
   TearDownOncePerProcess();
-#endif
   return result.exit_code;
 }
 
index 52468401367051778dcaffcfa8737504281b001b..f638e26dba5a043107e81f87b47d143893d366c3 100644 (file)
@@ -51,7 +51,6 @@ std::unique_ptr<NodeMainInstance> NodeMainInstance::Create(
       new NodeMainInstance(isolate, event_loop, platform, args, exec_args));
 }
 
-#ifdef LWNODE
 NodeMainInstance::NodeMainInstance(
     Isolate::CreateParams* params,
     uv_loop_t* event_loop,
@@ -61,20 +60,12 @@ NodeMainInstance::NodeMainInstance(
     const std::vector<size_t>* per_isolate_data_indexes)
     : args_(args),
       exec_args_(exec_args),
-// @lwnode
-#if 0
       array_buffer_allocator_(ArrayBufferAllocator::Create()),
-#endif
-      array_buffer_allocator_(ArrayBufferAllocator::Create().release()),
       isolate_(nullptr),
       platform_(platform),
       isolate_data_(nullptr),
       owns_isolate_(true) {
-// @lwnode
-#if 0
   params->array_buffer_allocator = array_buffer_allocator_.get();
-#endif
-  params->array_buffer_allocator = array_buffer_allocator_;
   isolate_ = Isolate::Allocate();
   CHECK_NOT_NULL(isolate_);
   // Register the isolate on the platform before the isolate gets initialized,
@@ -89,11 +80,7 @@ NodeMainInstance::NodeMainInstance(
   isolate_data_ = std::make_unique<IsolateData>(isolate_,
                                                 event_loop,
                                                 platform,
-// @lwnode
-#if 0
                                                 array_buffer_allocator_.get(),
-#endif
-                                                array_buffer_allocator_,
                                                 per_isolate_data_indexes);
   IsolateSettings s;
   SetIsolateMiscHandlers(isolate_, s);
@@ -104,50 +91,6 @@ NodeMainInstance::NodeMainInstance(
   }
 }
 
-#else
-
-NodeMainInstance::NodeMainInstance(
-    Isolate::CreateParams* params,
-    uv_loop_t* event_loop,
-    MultiIsolatePlatform* platform,
-    const std::vector<std::string>& args,
-    const std::vector<std::string>& exec_args,
-    const std::vector<size_t>* per_isolate_data_indexes)
-    : args_(args),
-      exec_args_(exec_args),
-      array_buffer_allocator_(ArrayBufferAllocator::Create()),
-      isolate_(nullptr),
-      platform_(platform),
-      isolate_data_(nullptr),
-      owns_isolate_(true) {
-  params->array_buffer_allocator = array_buffer_allocator_.get();
-  isolate_ = Isolate::Allocate();
-  CHECK_NOT_NULL(isolate_);
-  // Register the isolate on the platform before the isolate gets initialized,
-  // so that the isolate can access the platform during initialization.
-  platform->RegisterIsolate(isolate_, event_loop);
-  SetIsolateCreateParamsForNode(params);
-  Isolate::Initialize(isolate_, *params);
-
-  deserialize_mode_ = per_isolate_data_indexes != nullptr;
-  // If the indexes are not nullptr, we are not deserializing
-  CHECK_IMPLIES(deserialize_mode_, params->external_references != nullptr);
-  isolate_data_ = std::make_unique<IsolateData>(isolate_,
-                                                event_loop,
-                                                platform,
-                                                array_buffer_allocator_.get(),
-                                                per_isolate_data_indexes);
-  IsolateSettings s;
-  SetIsolateMiscHandlers(isolate_, s);
-  if (!deserialize_mode_) {
-    // If in deserialize mode, delay until after the deserialization is
-    // complete.
-    SetIsolateErrorHandlers(isolate_, s);
-  }
-}
-
-#endif
-
 void NodeMainInstance::Dispose() {
   CHECK(!owns_isolate_);
   platform_->DrainTasks(isolate_);
@@ -222,13 +165,8 @@ int NodeMainInstance::Run() {
   }
 #endif
 
-// @lwnode
-// We prevent premature termination when detecting leak,
-// as our GC runs after shutting down node platform.
-#if 0
 #if defined(LEAK_SANITIZER)
   __lsan_do_leak_check();
-#endif
 #endif
 
   return exit_code;
index 682b1ac5a140d40da7d97ddb66d73d863a38573a..abe0bda765bd515c4abc2b3f38c4c73716ce077f 100644 (file)
 #include "uv.h"
 #include "v8.h"
 
+// @lwnodes
+namespace LWNode {
+  class LWNodeMainRunner;
+}
+
 namespace node {
 
 // TODO(joyeecheung): align this with the Worker/WorkerThreadData class.
@@ -82,24 +87,15 @@ class NodeMainInstance {
 
   std::vector<std::string> args_;
   std::vector<std::string> exec_args_;
-#if LWNODE
-  // @lwnode
- public:
-  ArrayBufferAllocator* arrayBufferAllocator() {
-    return array_buffer_allocator_;
-  }
-
- private:
-  ArrayBufferAllocator* array_buffer_allocator_;
-#else
   std::unique_ptr<ArrayBufferAllocator> array_buffer_allocator_;
-#endif
 
   v8::Isolate* isolate_;
   MultiIsolatePlatform* platform_;
   std::unique_ptr<IsolateData> isolate_data_;
   bool owns_isolate_ = false;
   bool deserialize_mode_ = false;
+
+  friend class LWNode::LWNodeMainRunner; // @lwnodes
 };
 
 }  // namespace node
diff --git a/src/node_main_lw_runner-inl.h b/src/node_main_lw_runner-inl.h
new file mode 100644 (file)
index 0000000..37a1a5b
--- /dev/null
@@ -0,0 +1,161 @@
+#pragma once
+#include "node_bindings.h"
+#include "node_internals.h"
+#include "node_main_instance.h"
+#include "node_options-inl.h"
+#include "node_v8_platform-inl.h"
+#include "util-inl.h"
+
+#if defined(LEAK_SANITIZER)
+#include <sanitizer/lsan_interface.h>
+#endif
+
+using v8::Context;
+using v8::HandleScope;
+using v8::Isolate;
+using v8::Local;
+using v8::Locker;
+using v8::SealHandleScope;
+using namespace node;
+
+namespace LWNode {
+
+class MainLoopStrategy {
+ public:
+  virtual void RunLoop(node::Environment* env) = 0;
+};
+
+class GmainLoopStrategy : public MainLoopStrategy, public GmainLoopWork {
+ public:
+  void RunLoop(node::Environment* env) override {
+    CHECK_NOT_NULL(env);
+    env_ = env;
+
+    LWNode::GmainLoopNodeBindings node_bindings(this);
+    node_bindings.StartEventLoop();
+  }
+
+  bool RunOnce() override {
+    CHECK_NOT_NULL(env_);
+
+    auto event_loop = env_->event_loop();
+
+    uv_run(event_loop, UV_RUN_NOWAIT);
+
+    per_process::v8_platform.DrainVMTasks(env_->isolate());
+
+    bool more = uv_loop_alive(event_loop);
+    if (more && !env_->is_stopping()) {
+      return true;
+    }
+
+    if (!uv_loop_alive(event_loop)) {
+      EmitBeforeExit(env_);
+    }
+
+    more = uv_loop_alive(event_loop);
+
+    return (more == true && !env_->is_stopping());
+  }
+
+ private:
+  node::Environment* env_ = nullptr;
+};
+
+class LoopStrategy : public MainLoopStrategy {
+  void RunLoop(node::Environment* env) override {
+    bool more;
+    do {
+      uv_run(env->event_loop(), UV_RUN_DEFAULT);
+
+      per_process::v8_platform.DrainVMTasks(env->isolate());
+
+      more = uv_loop_alive(env->event_loop());
+      if (more && !env->is_stopping()) continue;
+
+      if (!uv_loop_alive(env->event_loop())) {
+        EmitBeforeExit(env);
+      }
+
+      // Emit `beforeExit` if the loop became alive either after emitting
+      // event, or after running some callbacks.
+      more = uv_loop_alive(env->event_loop());
+    } while (more == true && !env->is_stopping());
+  }
+};
+
+class LWNodeMainRunner {
+ public:
+  ~LWNodeMainRunner() { v8::V8::ShutdownPlatform(); }
+
+  int Run(node::NodeMainInstance& nodeMainInstance) {
+    // To release array buffer allocator after node is finished,
+    // this runner should has it.
+    array_buffer_allocator_ =
+        std::move(nodeMainInstance.array_buffer_allocator_);
+
+    v8::Isolate* isolate_ = nodeMainInstance.isolate_;
+
+    Locker locker(isolate_);
+    Isolate::Scope isolate_scope(isolate_);
+    HandleScope handle_scope(isolate_);
+
+    int exit_code = 0;
+    DeleteFnPtr<Environment, FreeEnvironment> env_ =
+        nodeMainInstance.CreateMainEnvironment(&exit_code);
+
+    CHECK_NOT_NULL(env_);
+    Context::Scope context_scope(env_->context());
+
+    if (exit_code == 0) {
+      LoadEnvironment(env_.get());
+
+      env_->set_trace_sync_io(env_->options()->trace_sync_io);
+
+      {
+        SealHandleScope seal(isolate_);
+        env_->performance_state()->Mark(
+            node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
+
+        // Run main loop
+        std::unique_ptr<MainLoopStrategy> mainLoop =
+            std::make_unique<LoopStrategy>();
+        mainLoop->RunLoop(env_.get());
+
+        env_->performance_state()->Mark(
+            node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
+      }
+
+      env_->set_trace_sync_io(false);
+      exit_code = EmitExit(env_.get());
+    }
+
+    ResetStdio();
+
+    // TODO(addaleax): Neither NODE_SHARED_MODE nor HAVE_INSPECTOR really
+    // make sense here.
+#if HAVE_INSPECTOR && defined(__POSIX__) && !defined(NODE_SHARED_MODE)
+    struct sigaction act;
+    memset(&act, 0, sizeof(act));
+    for (unsigned nr = 1; nr < kMaxSignal; nr += 1) {
+      if (nr == SIGKILL || nr == SIGSTOP || nr == SIGPROF) continue;
+      act.sa_handler = (nr == SIGPIPE) ? SIG_IGN : SIG_DFL;
+      CHECK_EQ(0, sigaction(nr, &act, nullptr));
+    }
+#endif
+
+    // @lwnode
+    // We prevent premature termination when detecting leak,
+    // as our GC runs after shutting down node platform.
+    LWNode::IdleGC();
+#if defined(LEAK_SANITIZER)
+    __lsan_do_leak_check();
+#endif
+    return exit_code;
+  }
+
+ private:
+  std::unique_ptr<node::ArrayBufferAllocator> array_buffer_allocator_;
+};
+
+}  // namespace LWNode
index d687af470949a22f993e9e0ed9801b2114cefde2..8ee7311b9cf6e587fcbb17f1e1c0f1b1d95a7906 100644 (file)
@@ -206,10 +206,6 @@ static std::string OnDiskFileName(const char* id) {
 
 MaybeLocal<String> NativeModuleLoader::LoadBuiltinModuleSource(Isolate* isolate,
                                                                const char* id) {
-#ifdef LWNODE_EXTERNAL_BUILTINS_FILENAME
-  return LoadExternalBuiltinSource(isolate, id);
-#endif
-
 #ifdef NODE_BUILTIN_MODULES_PATH
   std::string filename = OnDiskFileName(id);
 
@@ -242,7 +238,9 @@ MaybeLocal<String> NativeModuleLoader::LoadBuiltinModuleSource(Isolate* isolate,
 
   return String::NewFromUtf8(
       isolate, contents.c_str(), v8::NewStringType::kNormal, contents.length());
-#else
+#elif defined(LWNODE_EXTERNAL_BUILTINS_FILENAME)
+  return LoadExternalBuiltinSource(isolate, id);
+#else   // LWNODE_EXTERNAL_BUILTINS_FILENAME
   const auto source_it = source_.find(id);
   CHECK_NE(source_it, source_.end());
   return source_it->second.ToStringChecked(isolate);
index 7efb9dcf7bbd9cda868767ca862b8b83168db491..f8df33aa3d54cb03435982ab192dddffa1e2d349 100644 (file)
@@ -62,8 +62,19 @@ struct UnzFileCachedInfo {
   uLong uncompressedSize{0};
 };
 
-static ArchiveFileScope s_archiveFileScope;
-static std::map<std::string, UnzFileCachedInfo> s_unzFileInfoDictionary;
+enum class ReaderError {
+  NO_ERROR = 0,
+  UNZ_OPEN_CURRENTFILE,
+  UNZ_GOTO_FIRSTFILE,
+  UNZ_GET_CURRENTFILEINFO,
+  READ_CURRENTFILE_FROMARCHIVE,
+  READ_FILE_FROMARCHIVE
+};
+
+static thread_local ArchiveFileScope s_archiveFileScope;
+static thread_local std::map<std::string, UnzFileCachedInfo>
+    s_unzFileInfoDictionary;
+static thread_local ReaderError s_lastError = ReaderError::NO_ERROR;
 
 std::string getSelfProcPath() {
   char path[PATH_MAX + 1];
@@ -75,11 +86,17 @@ std::string getSelfProcPath() {
   return std::string(path);
 }
 
+void setError(ReaderError error) {
+  s_lastError = error;
+  ERROR_AND_ABORT(s_lastError);
+}
+
 bool readCurrentFileFromArchive(const unzFile file,
                                 uLong uncompressedSize,
                                 char** buffer,
                                 size_t* fileSize) {
   if (unzOpenCurrentFile(file) < 0) {
+    setError(ReaderError::UNZ_OPEN_CURRENTFILE);
     return false;
   }
 
@@ -127,6 +144,7 @@ bool readFileFromArchive(const std::string& archiveFilename,
 
   // 2. read the data by searching the file position from the first one.
   if (unzGoToFirstFile(file) < 0) {
+    setError(ReaderError::UNZ_OPEN_CURRENTFILE);
     return false;
   }
 
@@ -143,6 +161,7 @@ bool readFileFromArchive(const std::string& archiveFilename,
                               0,
                               nullptr,
                               0) < 0) {
+      setError(ReaderError::UNZ_GET_CURRENTFILEINFO);
       return false;
     }
 
@@ -152,6 +171,7 @@ bool readFileFromArchive(const std::string& archiveFilename,
       // 2.1 read the data from the current file poistion
       if (readCurrentFileFromArchive(
               file, fileInfo.uncompressed_size, buffer, fileSize) == false) {
+        setError(ReaderError::READ_CURRENTFILE_FROMARCHIVE);
         return false;
       }
 
@@ -187,6 +207,7 @@ FileData readFileFromArchive(std::string filename,
 
   if (readFileFromArchive(
           s_externalBuiltinsPath, filename, &buffer, &bufferSize) == false) {
+    setError(ReaderError::READ_FILE_FROMARCHIVE);
     return FileData();
   }
 
@@ -241,6 +262,8 @@ class SourceReaderOnArchive : public SourceReaderInterface {
 
     if (readFileFromArchive(
             s_externalBuiltinsPath, filename, &buffer, &bufferSize) == false) {
+      LWNODE_LOG_ERROR("readFileFromArchive (%s) failed:", filename);
+      setError(ReaderError::READ_FILE_FROMARCHIVE);
       return FileData();
     }
 
index dad60367cd958a00b2fdf76fe05f1586983aee77..055a49d26ecc5cc26fc31fa34fd796f13b4e23a0 100644 (file)
@@ -4,7 +4,8 @@ const fs = require('fs');
 const path = require('path');
 const { isDefiningError } = require('./rules-utils.js');
 
-const doc = fs.readFileSync(path.resolve(__dirname, '../../doc/api/errors.md'),
+// @lwnode
+const doc = fs.readFileSync(path.resolve(__dirname, './errors.md'),
                             'utf8');
 
 function isInDoc(code) {
diff --git a/tools/eslint-rules/errors.md b/tools/eslint-rules/errors.md
new file mode 100644 (file)
index 0000000..79a5ac2
--- /dev/null
@@ -0,0 +1,2581 @@
+# Errors
+
+<!--introduced_in=v4.0.0-->
+<!--type=misc-->
+
+Applications running in Node.js will generally experience four categories of
+errors:
+
+* Standard JavaScript errors such as {EvalError}, {SyntaxError}, {RangeError},
+  {ReferenceError}, {TypeError}, and {URIError}.
+* System errors triggered by underlying operating system constraints such
+  as attempting to open a file that does not exist or attempting to send data
+  over a closed socket.
+* User-specified errors triggered by application code.
+* `AssertionError`s are a special class of error that can be triggered when
+  Node.js detects an exceptional logic violation that should never occur. These
+  are raised typically by the `assert` module.
+
+All JavaScript and system errors raised by Node.js inherit from, or are
+instances of, the standard JavaScript {Error} class and are guaranteed
+to provide *at least* the properties available on that class.
+
+## Error propagation and interception
+
+<!--type=misc-->
+
+Node.js supports several mechanisms for propagating and handling errors that
+occur while an application is running. How these errors are reported and
+handled depends entirely on the type of `Error` and the style of the API that is
+called.
+
+All JavaScript errors are handled as exceptions that *immediately* generate
+and throw an error using the standard JavaScript `throw` mechanism. These
+are handled using the [`try…catch` construct][try-catch] provided by the
+JavaScript language.
+
+```js
+// Throws with a ReferenceError because z is not defined.
+try {
+  const m = 1;
+  const n = m + z;
+} catch (err) {
+  // Handle the error here.
+}
+```
+
+Any use of the JavaScript `throw` mechanism will raise an exception that
+*must* be handled using `try…catch` or the Node.js process will exit
+immediately.
+
+With few exceptions, _Synchronous_ APIs (any blocking method that does not
+accept a `callback` function, such as [`fs.readFileSync`][]), will use `throw`
+to report errors.
+
+Errors that occur within _Asynchronous APIs_ may be reported in multiple ways:
+
+* Most asynchronous methods that accept a `callback` function will accept an
+  `Error` object passed as the first argument to that function. If that first
+  argument is not `null` and is an instance of `Error`, then an error occurred
+  that should be handled.
+
+<!-- eslint-disable no-useless-return -->
+  ```js
+  const fs = require('fs');
+  fs.readFile('a file that does not exist', (err, data) => {
+    if (err) {
+      console.error('There was an error reading the file!', err);
+      return;
+    }
+    // Otherwise handle the data
+  });
+  ```
+
+* When an asynchronous method is called on an object that is an
+  [`EventEmitter`][], errors can be routed to that object's `'error'` event.
+
+  ```js
+  const net = require('net');
+  const connection = net.connect('localhost');
+
+  // Adding an 'error' event handler to a stream:
+  connection.on('error', (err) => {
+    // If the connection is reset by the server, or if it can't
+    // connect at all, or on any sort of error encountered by
+    // the connection, the error will be sent here.
+    console.error(err);
+  });
+
+  connection.pipe(process.stdout);
+  ```
+
+* A handful of typically asynchronous methods in the Node.js API may still
+  use the `throw` mechanism to raise exceptions that must be handled using
+  `try…catch`. There is no comprehensive list of such methods; please
+  refer to the documentation of each method to determine the appropriate
+  error handling mechanism required.
+
+The use of the `'error'` event mechanism is most common for [stream-based][]
+and [event emitter-based][] APIs, which themselves represent a series of
+asynchronous operations over time (as opposed to a single operation that may
+pass or fail).
+
+For *all* [`EventEmitter`][] objects, if an `'error'` event handler is not
+provided, the error will be thrown, causing the Node.js process to report an
+uncaught exception and crash unless either: The [`domain`][domains] module is
+used appropriately or a handler has been registered for the
+[`'uncaughtException'`][] event.
+
+```js
+const EventEmitter = require('events');
+const ee = new EventEmitter();
+
+setImmediate(() => {
+  // This will crash the process because no 'error' event
+  // handler has been added.
+  ee.emit('error', new Error('This will crash'));
+});
+```
+
+Errors generated in this way *cannot* be intercepted using `try…catch` as
+they are thrown *after* the calling code has already exited.
+
+Developers must refer to the documentation for each method to determine
+exactly how errors raised by those methods are propagated.
+
+### Error-first callbacks
+
+<!--type=misc-->
+
+Most asynchronous methods exposed by the Node.js core API follow an idiomatic
+pattern referred to as an _error-first callback_. With this pattern, a callback
+function is passed to the method as an argument. When the operation either
+completes or an error is raised, the callback function is called with the
+`Error` object (if any) passed as the first argument. If no error was raised,
+the first argument will be passed as `null`.
+
+```js
+const fs = require('fs');
+
+function errorFirstCallback(err, data) {
+  if (err) {
+    console.error('There was an error', err);
+    return;
+  }
+  console.log(data);
+}
+
+fs.readFile('/some/file/that/does-not-exist', errorFirstCallback);
+fs.readFile('/some/file/that/does-exist', errorFirstCallback);
+```
+
+The JavaScript `try…catch` mechanism **cannot** be used to intercept errors
+generated by asynchronous APIs. A common mistake for beginners is to try to
+use `throw` inside an error-first callback:
+
+```js
+// THIS WILL NOT WORK:
+const fs = require('fs');
+
+try {
+  fs.readFile('/some/file/that/does-not-exist', (err, data) => {
+    // Mistaken assumption: throwing here...
+    if (err) {
+      throw err;
+    }
+  });
+} catch (err) {
+  // This will not catch the throw!
+  console.error(err);
+}
+```
+
+This will not work because the callback function passed to `fs.readFile()` is
+called asynchronously. By the time the callback has been called, the
+surrounding code, including the `try…catch` block, will have already exited.
+Throwing an error inside the callback **can crash the Node.js process** in most
+cases. If [domains][] are enabled, or a handler has been registered with
+`process.on('uncaughtException')`, such errors can be intercepted.
+
+## Class: `Error`
+
+<!--type=class-->
+
+A generic JavaScript {Error} object that does not denote any specific
+circumstance of why the error occurred. `Error` objects capture a "stack trace"
+detailing the point in the code at which the `Error` was instantiated, and may
+provide a text description of the error.
+
+All errors generated by Node.js, including all system and JavaScript errors,
+will either be instances of, or inherit from, the `Error` class.
+
+### `new Error(message)`
+
+* `message` {string}
+
+Creates a new `Error` object and sets the `error.message` property to the
+provided text message. If an object is passed as `message`, the text message
+is generated by calling `message.toString()`. The `error.stack` property will
+represent the point in the code at which `new Error()` was called. Stack traces
+are dependent on [V8's stack trace API][]. Stack traces extend only to either
+(a) the beginning of *synchronous code execution*, or (b) the number of frames
+given by the property `Error.stackTraceLimit`, whichever is smaller.
+
+### `Error.captureStackTrace(targetObject[, constructorOpt])`
+
+* `targetObject` {Object}
+* `constructorOpt` {Function}
+
+Creates a `.stack` property on `targetObject`, which when accessed returns
+a string representing the location in the code at which
+`Error.captureStackTrace()` was called.
+
+```js
+const myObject = {};
+Error.captureStackTrace(myObject);
+myObject.stack;  // Similar to `new Error().stack`
+```
+
+The first line of the trace will be prefixed with
+`${myObject.name}: ${myObject.message}`.
+
+The optional `constructorOpt` argument accepts a function. If given, all frames
+above `constructorOpt`, including `constructorOpt`, will be omitted from the
+generated stack trace.
+
+The `constructorOpt` argument is useful for hiding implementation
+details of error generation from the user. For instance:
+
+```js
+function MyError() {
+  Error.captureStackTrace(this, MyError);
+}
+
+// Without passing MyError to captureStackTrace, the MyError
+// frame would show up in the .stack property. By passing
+// the constructor, we omit that frame, and retain all frames below it.
+new MyError().stack;
+```
+
+### `Error.stackTraceLimit`
+
+* {number}
+
+The `Error.stackTraceLimit` property specifies the number of stack frames
+collected by a stack trace (whether generated by `new Error().stack` or
+`Error.captureStackTrace(obj)`).
+
+The default value is `10` but may be set to any valid JavaScript number. Changes
+will affect any stack trace captured *after* the value has been changed.
+
+If set to a non-number value, or set to a negative number, stack traces will
+not capture any frames.
+
+### `error.code`
+
+* {string}
+
+The `error.code` property is a string label that identifies the kind of error.
+`error.code` is the most stable way to identify an error. It will only change
+between major versions of Node.js. In contrast, `error.message` strings may
+change between any versions of Node.js. See [Node.js error codes][] for details
+about specific codes.
+
+### `error.message`
+
+* {string}
+
+The `error.message` property is the string description of the error as set by
+calling `new Error(message)`. The `message` passed to the constructor will also
+appear in the first line of the stack trace of the `Error`, however changing
+this property after the `Error` object is created *may not* change the first
+line of the stack trace (for example, when `error.stack` is read before this
+property is changed).
+
+```js
+const err = new Error('The message');
+console.error(err.message);
+// Prints: The message
+```
+
+### `error.stack`
+
+* {string}
+
+The `error.stack` property is a string describing the point in the code at which
+the `Error` was instantiated.
+
+```console
+Error: Things keep happening!
+   at /home/gbusey/file.js:525:2
+   at Frobnicator.refrobulate (/home/gbusey/business-logic.js:424:21)
+   at Actor.<anonymous> (/home/gbusey/actors.js:400:8)
+   at increaseSynergy (/home/gbusey/actors.js:701:6)
+```
+
+The first line is formatted as `<error class name>: <error message>`, and
+is followed by a series of stack frames (each line beginning with "at ").
+Each frame describes a call site within the code that lead to the error being
+generated. V8 attempts to display a name for each function (by variable name,
+function name, or object method name), but occasionally it will not be able to
+find a suitable name. If V8 cannot determine a name for the function, only
+location information will be displayed for that frame. Otherwise, the
+determined function name will be displayed with location information appended
+in parentheses.
+
+Frames are only generated for JavaScript functions. If, for example, execution
+synchronously passes through a C++ addon function called `cheetahify` which
+itself calls a JavaScript function, the frame representing the `cheetahify` call
+will not be present in the stack traces:
+
+```js
+const cheetahify = require('./native-binding.node');
+
+function makeFaster() {
+  // `cheetahify()` *synchronously* calls speedy.
+  cheetahify(function speedy() {
+    throw new Error('oh no!');
+  });
+}
+
+makeFaster();
+// will throw:
+//   /home/gbusey/file.js:6
+//       throw new Error('oh no!');
+//           ^
+//   Error: oh no!
+//       at speedy (/home/gbusey/file.js:6:11)
+//       at makeFaster (/home/gbusey/file.js:5:3)
+//       at Object.<anonymous> (/home/gbusey/file.js:10:1)
+//       at Module._compile (module.js:456:26)
+//       at Object.Module._extensions..js (module.js:474:10)
+//       at Module.load (module.js:356:32)
+//       at Function.Module._load (module.js:312:12)
+//       at Function.Module.runMain (module.js:497:10)
+//       at startup (node.js:119:16)
+//       at node.js:906:3
+```
+
+The location information will be one of:
+
+* `native`, if the frame represents a call internal to V8 (as in `[].forEach`).
+* `plain-filename.js:line:column`, if the frame represents a call internal
+   to Node.js.
+* `/absolute/path/to/file.js:line:column`, if the frame represents a call in
+  a user program, or its dependencies.
+
+The string representing the stack trace is lazily generated when the
+`error.stack` property is **accessed**.
+
+The number of frames captured by the stack trace is bounded by the smaller of
+`Error.stackTraceLimit` or the number of available frames on the current event
+loop tick.
+
+## Class: `AssertionError`
+
+* Extends: {errors.Error}
+
+Indicates the failure of an assertion. For details, see
+[`Class: assert.AssertionError`][].
+
+## Class: `RangeError`
+
+* Extends: {errors.Error}
+
+Indicates that a provided argument was not within the set or range of
+acceptable values for a function; whether that is a numeric range, or
+outside the set of options for a given function parameter.
+
+```js
+require('net').connect(-1);
+// Throws "RangeError: "port" option should be >= 0 and < 65536: -1"
+```
+
+Node.js will generate and throw `RangeError` instances *immediately* as a form
+of argument validation.
+
+## Class: `ReferenceError`
+
+* Extends: {errors.Error}
+
+Indicates that an attempt is being made to access a variable that is not
+defined. Such errors commonly indicate typos in code, or an otherwise broken
+program.
+
+While client code may generate and propagate these errors, in practice, only V8
+will do so.
+
+```js
+doesNotExist;
+// Throws ReferenceError, doesNotExist is not a variable in this program.
+```
+
+Unless an application is dynamically generating and running code,
+`ReferenceError` instances indicate a bug in the code or its dependencies.
+
+## Class: `SyntaxError`
+
+* Extends: {errors.Error}
+
+Indicates that a program is not valid JavaScript. These errors may only be
+generated and propagated as a result of code evaluation. Code evaluation may
+happen as a result of `eval`, `Function`, `require`, or [vm][]. These errors
+are almost always indicative of a broken program.
+
+```js
+try {
+  require('vm').runInThisContext('binary ! isNotOk');
+} catch (err) {
+  // 'err' will be a SyntaxError.
+}
+```
+
+`SyntaxError` instances are unrecoverable in the context that created them –
+they may only be caught by other contexts.
+
+## Class: `SystemError`
+
+* Extends: {errors.Error}
+
+Node.js generates system errors when exceptions occur within its runtime
+environment. These usually occur when an application violates an operating
+system constraint. For example, a system error will occur if an application
+attempts to read a file that does not exist.
+
+* `address` {string} If present, the address to which a network connection
+  failed
+* `code` {string} The string error code
+* `dest` {string} If present, the file path destination when reporting a file
+  system error
+* `errno` {number} The system-provided error number
+* `info` {Object} If present, extra details about the error condition
+* `message` {string} A system-provided human-readable description of the error
+* `path` {string} If present, the file path when reporting a file system error
+* `port` {number} If present, the network connection port that is not available
+* `syscall` {string} The name of the system call that triggered the error
+
+### `error.address`
+
+* {string}
+
+If present, `error.address` is a string describing the address to which a
+network connection failed.
+
+### `error.code`
+
+* {string}
+
+The `error.code` property is a string representing the error code.
+
+### `error.dest`
+
+* {string}
+
+If present, `error.dest` is the file path destination when reporting a file
+system error.
+
+### `error.errno`
+
+* {number}
+
+The `error.errno` property is a negative number which corresponds
+to the error code defined in [`libuv Error handling`][].
+
+On Windows the error number provided by the system will be normalized by libuv.
+
+To get the string representation of the error code, use
+[`util.getSystemErrorName(error.errno)`][].
+
+### `error.info`
+
+* {Object}
+
+If present, `error.info` is an object with details about the error condition.
+
+### `error.message`
+
+* {string}
+
+`error.message` is a system-provided human-readable description of the error.
+
+### `error.path`
+
+* {string}
+
+If present, `error.path` is a string containing a relevant invalid pathname.
+
+### `error.port`
+
+* {number}
+
+If present, `error.port` is the network connection port that is not available.
+
+### `error.syscall`
+
+* {string}
+
+The `error.syscall` property is a string describing the [syscall][] that failed.
+
+### Common system errors
+
+This is a list of system errors commonly-encountered when writing a Node.js
+program. For a comprehensive list, see the [`errno`(3) man page][].
+
+* `EACCES` (Permission denied): An attempt was made to access a file in a way
+  forbidden by its file access permissions.
+
+* `EADDRINUSE` (Address already in use): An attempt to bind a server
+  ([`net`][], [`http`][], or [`https`][]) to a local address failed due to
+  another server on the local system already occupying that address.
+
+* `ECONNREFUSED` (Connection refused): No connection could be made because the
+  target machine actively refused it. This usually results from trying to
+  connect to a service that is inactive on the foreign host.
+
+* `ECONNRESET` (Connection reset by peer): A connection was forcibly closed by
+  a peer. This normally results from a loss of the connection on the remote
+  socket due to a timeout or reboot. Commonly encountered via the [`http`][]
+  and [`net`][] modules.
+
+* `EEXIST` (File exists): An existing file was the target of an operation that
+  required that the target not exist.
+
+* `EISDIR` (Is a directory): An operation expected a file, but the given
+  pathname was a directory.
+
+* `EMFILE` (Too many open files in system): Maximum number of
+  [file descriptors][] allowable on the system has been reached, and
+  requests for another descriptor cannot be fulfilled until at least one
+  has been closed. This is encountered when opening many files at once in
+  parallel, especially on systems (in particular, macOS) where there is a low
+  file descriptor limit for processes. To remedy a low limit, run
+  `ulimit -n 2048` in the same shell that will run the Node.js process.
+
+* `ENOENT` (No such file or directory): Commonly raised by [`fs`][] operations
+  to indicate that a component of the specified pathname does not exist. No
+  entity (file or directory) could be found by the given path.
+
+* `ENOTDIR` (Not a directory): A component of the given pathname existed, but
+  was not a directory as expected. Commonly raised by [`fs.readdir`][].
+
+* `ENOTEMPTY` (Directory not empty): A directory with entries was the target
+  of an operation that requires an empty directory, usually [`fs.unlink`][].
+
+* `ENOTFOUND` (DNS lookup failed): Indicates a DNS failure of either
+  `EAI_NODATA` or `EAI_NONAME`. This is not a standard POSIX error.
+
+* `EPERM` (Operation not permitted): An attempt was made to perform an
+  operation that requires elevated privileges.
+
+* `EPIPE` (Broken pipe): A write on a pipe, socket, or FIFO for which there is
+  no process to read the data. Commonly encountered at the [`net`][] and
+  [`http`][] layers, indicative that the remote side of the stream being
+  written to has been closed.
+
+* `ETIMEDOUT` (Operation timed out): A connect or send request failed because
+  the connected party did not properly respond after a period of time. Usually
+  encountered by [`http`][] or [`net`][]. Often a sign that a `socket.end()`
+  was not properly called.
+
+## Class: `TypeError`
+
+* Extends {errors.Error}
+
+Indicates that a provided argument is not an allowable type. For example,
+passing a function to a parameter which expects a string would be a `TypeError`.
+
+```js
+require('url').parse(() => { });
+// Throws TypeError, since it expected a string.
+```
+
+Node.js will generate and throw `TypeError` instances *immediately* as a form
+of argument validation.
+
+## Exceptions vs. errors
+
+<!--type=misc-->
+
+A JavaScript exception is a value that is thrown as a result of an invalid
+operation or as the target of a `throw` statement. While it is not required
+that these values are instances of `Error` or classes which inherit from
+`Error`, all exceptions thrown by Node.js or the JavaScript runtime *will* be
+instances of `Error`.
+
+Some exceptions are *unrecoverable* at the JavaScript layer. Such exceptions
+will *always* cause the Node.js process to crash. Examples include `assert()`
+checks or `abort()` calls in the C++ layer.
+
+## OpenSSL errors
+
+Errors originating in `crypto` or `tls` are of class `Error`, and in addition to
+the standard `.code` and `.message` properties, may have some additional
+OpenSSL-specific properties.
+
+### `error.opensslErrorStack`
+
+An array of errors that can give context to where in the OpenSSL library an
+error originates from.
+
+### `error.function`
+
+The OpenSSL function the error originates in.
+
+### `error.library`
+
+The OpenSSL library the error originates in.
+
+### `error.reason`
+
+A human-readable string describing the reason for the error.
+
+<a id="nodejs-error-codes"></a>
+## Node.js error codes
+
+<a id="ERR_AMBIGUOUS_ARGUMENT"></a>
+### `ERR_AMBIGUOUS_ARGUMENT`
+
+A function argument is being used in a way that suggests that the function
+signature may be misunderstood. This is thrown by the `assert` module when the
+`message` parameter in `assert.throws(block, message)` matches the error message
+thrown by `block` because that usage suggests that the user believes `message`
+is the expected message rather than the message the `AssertionError` will
+display if `block` does not throw.
+
+<a id="ERR_ARG_NOT_ITERABLE"></a>
+### `ERR_ARG_NOT_ITERABLE`
+
+An iterable argument (i.e. a value that works with `for...of` loops) was
+required, but not provided to a Node.js API.
+
+<a id="ERR_ASSERTION"></a>
+### `ERR_ASSERTION`
+
+A special type of error that can be triggered whenever Node.js detects an
+exceptional logic violation that should never occur. These are raised typically
+by the `assert` module.
+
+<a id="ERR_ASYNC_CALLBACK"></a>
+### `ERR_ASYNC_CALLBACK`
+
+An attempt was made to register something that is not a function as an
+`AsyncHooks` callback.
+
+<a id="ERR_ASYNC_TYPE"></a>
+### `ERR_ASYNC_TYPE`
+
+The type of an asynchronous resource was invalid. Users are also able
+to define their own types if using the public embedder API.
+
+<a id="ERR_BROTLI_COMPRESSION_FAILED"></a>
+### `ERR_BROTLI_COMPRESSION_FAILED`
+
+Data passed to a Brotli stream was not successfully compressed.
+
+<a id="ERR_BROTLI_INVALID_PARAM"></a>
+### `ERR_BROTLI_INVALID_PARAM`
+
+An invalid parameter key was passed during construction of a Brotli stream.
+
+<a id="ERR_BUFFER_CONTEXT_NOT_AVAILABLE"></a>
+### `ERR_BUFFER_CONTEXT_NOT_AVAILABLE`
+
+An attempt was made to create a Node.js `Buffer` instance from addon or embedder
+code, while in a JS engine Context that is not associated with a Node.js
+instance. The data passed to the `Buffer` method will have been released
+by the time the method returns.
+
+When encountering this error, a possible alternative to creating a `Buffer`
+instance is to create a normal `Uint8Array`, which only differs in the
+prototype of the resulting object. `Uint8Array`s are generally accepted in all
+Node.js core APIs where `Buffer`s are; they are available in all Contexts.
+
+<a id="ERR_BUFFER_OUT_OF_BOUNDS"></a>
+### `ERR_BUFFER_OUT_OF_BOUNDS`
+
+An operation outside the bounds of a `Buffer` was attempted.
+
+<a id="ERR_BUFFER_TOO_LARGE"></a>
+### `ERR_BUFFER_TOO_LARGE`
+
+An attempt has been made to create a `Buffer` larger than the maximum allowed
+size.
+
+<a id="ERR_CANNOT_WATCH_SIGINT"></a>
+### `ERR_CANNOT_WATCH_SIGINT`
+
+Node.js was unable to watch for the `SIGINT` signal.
+
+<a id="ERR_CHILD_CLOSED_BEFORE_REPLY"></a>
+### `ERR_CHILD_CLOSED_BEFORE_REPLY`
+
+A child process was closed before the parent received a reply.
+
+<a id="ERR_CHILD_PROCESS_IPC_REQUIRED"></a>
+### `ERR_CHILD_PROCESS_IPC_REQUIRED`
+
+Used when a child process is being forked without specifying an IPC channel.
+
+<a id="ERR_CHILD_PROCESS_STDIO_MAXBUFFER"></a>
+### `ERR_CHILD_PROCESS_STDIO_MAXBUFFER`
+
+Used when the main process is trying to read data from the child process's
+STDERR/STDOUT, and the data's length is longer than the `maxBuffer` option.
+
+<a id="ERR_CONSOLE_WRITABLE_STREAM"></a>
+### `ERR_CONSOLE_WRITABLE_STREAM`
+
+`Console` was instantiated without `stdout` stream, or `Console` has a
+non-writable `stdout` or `stderr` stream.
+
+<a id="ERR_CONSTRUCT_CALL_INVALID"></a>
+### `ERR_CONSTRUCT_CALL_INVALID`
+<!--
+added: v12.5.0
+-->
+
+A class constructor was called that is not callable.
+
+<a id="ERR_CONSTRUCT_CALL_REQUIRED"></a>
+### `ERR_CONSTRUCT_CALL_REQUIRED`
+
+A constructor for a class was called without `new`.
+
+<a id="ERR_CONTEXT_NOT_INITIALIZED"></a>
+### `ERR_CONTEXT_NOT_INITIALIZED`
+
+The vm context passed into the API is not yet initialized. This could happen
+when an error occurs (and is caught) during the creation of the
+context, for example, when the allocation fails or the maximum call stack
+size is reached when the context is created.
+
+<a id="ERR_CPU_USAGE"></a>
+### `ERR_CPU_USAGE`
+
+The native call from `process.cpuUsage` could not be processed.
+
+<a id="ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED"></a>
+### `ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED`
+
+A client certificate engine was requested that is not supported by the version
+of OpenSSL being used.
+
+<a id="ERR_CRYPTO_ECDH_INVALID_FORMAT"></a>
+### `ERR_CRYPTO_ECDH_INVALID_FORMAT`
+
+An invalid value for the `format` argument was passed to the `crypto.ECDH()`
+class `getPublicKey()` method.
+
+<a id="ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY"></a>
+### `ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY`
+
+An invalid value for the `key` argument has been passed to the
+`crypto.ECDH()` class `computeSecret()` method. It means that the public
+key lies outside of the elliptic curve.
+
+<a id="ERR_CRYPTO_ENGINE_UNKNOWN"></a>
+### `ERR_CRYPTO_ENGINE_UNKNOWN`
+
+An invalid crypto engine identifier was passed to
+[`require('crypto').setEngine()`][].
+
+<a id="ERR_CRYPTO_FIPS_FORCED"></a>
+### `ERR_CRYPTO_FIPS_FORCED`
+
+The [`--force-fips`][] command-line argument was used but there was an attempt
+to enable or disable FIPS mode in the `crypto` module.
+
+<a id="ERR_CRYPTO_FIPS_UNAVAILABLE"></a>
+### `ERR_CRYPTO_FIPS_UNAVAILABLE`
+
+An attempt was made to enable or disable FIPS mode, but FIPS mode was not
+available.
+
+<a id="ERR_CRYPTO_HASH_FINALIZED"></a>
+### `ERR_CRYPTO_HASH_FINALIZED`
+
+[`hash.digest()`][] was called multiple times. The `hash.digest()` method must
+be called no more than one time per instance of a `Hash` object.
+
+<a id="ERR_CRYPTO_HASH_UPDATE_FAILED"></a>
+### `ERR_CRYPTO_HASH_UPDATE_FAILED`
+
+[`hash.update()`][] failed for any reason. This should rarely, if ever, happen.
+
+<a id="ERR_CRYPTO_INCOMPATIBLE_KEY"></a>
+### `ERR_CRYPTO_INCOMPATIBLE_KEY`
+
+The given crypto keys are incompatible with the attempted operation.
+
+<a id="ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS"></a>
+### `ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS`
+
+The selected public or private key encoding is incompatible with other options.
+
+<a id="ERR_CRYPTO_INVALID_DIGEST"></a>
+### `ERR_CRYPTO_INVALID_DIGEST`
+
+An invalid [crypto digest algorithm][] was specified.
+
+<a id="ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE"></a>
+### `ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE`
+
+The given crypto key object's type is invalid for the attempted operation.
+
+<a id="ERR_CRYPTO_INVALID_STATE"></a>
+### `ERR_CRYPTO_INVALID_STATE`
+
+A crypto method was used on an object that was in an invalid state. For
+instance, calling [`cipher.getAuthTag()`][] before calling `cipher.final()`.
+
+<a id="ERR_CRYPTO_PBKDF2_ERROR"></a>
+### `ERR_CRYPTO_PBKDF2_ERROR`
+
+The PBKDF2 algorithm failed for unspecified reasons. OpenSSL does not provide
+more details and therefore neither does Node.js.
+
+<a id="ERR_CRYPTO_SCRYPT_INVALID_PARAMETER"></a>
+### `ERR_CRYPTO_SCRYPT_INVALID_PARAMETER`
+
+One or more [`crypto.scrypt()`][] or [`crypto.scryptSync()`][] parameters are
+outside their legal range.
+
+<a id="ERR_CRYPTO_SCRYPT_NOT_SUPPORTED"></a>
+### `ERR_CRYPTO_SCRYPT_NOT_SUPPORTED`
+
+Node.js was compiled without `scrypt` support. Not possible with the official
+release binaries but can happen with custom builds, including distro builds.
+
+<a id="ERR_CRYPTO_SIGN_KEY_REQUIRED"></a>
+### `ERR_CRYPTO_SIGN_KEY_REQUIRED`
+
+A signing `key` was not provided to the [`sign.sign()`][] method.
+
+<a id="ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH"></a>
+### `ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH`
+
+[`crypto.timingSafeEqual()`][] was called with `Buffer`, `TypedArray`, or
+`DataView` arguments of different lengths.
+
+<a id="ERR_CRYPTO_UNKNOWN_CIPHER"></a>
+### `ERR_CRYPTO_UNKNOWN_CIPHER`
+
+An unknown cipher was specified.
+
+<a id="ERR_CRYPTO_UNKNOWN_DH_GROUP"></a>
+### `ERR_CRYPTO_UNKNOWN_DH_GROUP`
+
+An unknown Diffie-Hellman group name was given. See
+[`crypto.getDiffieHellman()`][] for a list of valid group names.
+
+<a id="ERR_DIR_CLOSED"></a>
+### `ERR_DIR_CLOSED`
+
+The [`fs.Dir`][] was previously closed.
+
+<a id="ERR_DIR_CONCURRENT_OPERATION"></a>
+### `ERR_DIR_CONCURRENT_OPERATION`
+<!-- YAML
+added: v14.3.0
+-->
+
+A synchronous read or close call was attempted on an [`fs.Dir`][] which has
+ongoing asynchronous operations.
+
+<a id="ERR_DNS_SET_SERVERS_FAILED"></a>
+### `ERR_DNS_SET_SERVERS_FAILED`
+
+`c-ares` failed to set the DNS server.
+
+<a id="ERR_DOMAIN_CALLBACK_NOT_AVAILABLE"></a>
+### `ERR_DOMAIN_CALLBACK_NOT_AVAILABLE`
+
+The `domain` module was not usable since it could not establish the required
+error handling hooks, because
+[`process.setUncaughtExceptionCaptureCallback()`][] had been called at an
+earlier point in time.
+
+<a id="ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE"></a>
+### `ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE`
+
+[`process.setUncaughtExceptionCaptureCallback()`][] could not be called
+because the `domain` module has been loaded at an earlier point in time.
+
+The stack trace is extended to include the point in time at which the
+`domain` module had been loaded.
+
+<a id="ERR_ENCODING_INVALID_ENCODED_DATA"></a>
+### `ERR_ENCODING_INVALID_ENCODED_DATA`
+
+Data provided to `TextDecoder()` API was invalid according to the encoding
+provided.
+
+<a id="ERR_ENCODING_NOT_SUPPORTED"></a>
+### `ERR_ENCODING_NOT_SUPPORTED`
+
+Encoding provided to `TextDecoder()` API was not one of the
+[WHATWG Supported Encodings][].
+
+<a id="ERR_EVAL_ESM_CANNOT_PRINT"></a>
+### `ERR_EVAL_ESM_CANNOT_PRINT`
+
+`--print` cannot be used with ESM input.
+
+<a id="ERR_EVENT_RECURSION"></a>
+### `ERR_EVENT_RECURSION`
+
+Thrown when an attempt is made to recursively dispatch an event on `EventTarget`.
+
+<a id="ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE"></a>
+### `ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE`
+
+The JS execution context is not associated with a Node.js environment.
+This may occur when Node.js is used as an embedded library and some hooks
+for the JS engine are not set up properly.
+
+<a id="ERR_FALSY_VALUE_REJECTION"></a>
+### `ERR_FALSY_VALUE_REJECTION`
+
+A `Promise` that was callbackified via `util.callbackify()` was rejected with a
+falsy value.
+
+<a id="ERR_FEATURE_UNAVAILABLE_ON_PLATFORM"></a>
+### `ERR_FEATURE_UNAVAILABLE_ON_PLATFORM`
+<!-- YAML
+added: v14.0.0
+-->
+
+Used when a feature that is not available
+to the current platform which is running Node.js is used.
+
+<a id="ERR_FS_EISDIR"></a>
+### `ERR_FS_EISDIR`
+
+Path is a directory.
+
+<a id="ERR_FS_FILE_TOO_LARGE"></a>
+### `ERR_FS_FILE_TOO_LARGE`
+
+An attempt has been made to read a file whose size is larger than the maximum
+allowed size for a `Buffer`.
+
+<a id="ERR_FS_INVALID_SYMLINK_TYPE"></a>
+### `ERR_FS_INVALID_SYMLINK_TYPE`
+
+An invalid symlink type was passed to the [`fs.symlink()`][] or
+[`fs.symlinkSync()`][] methods.
+
+<a id="ERR_HTTP_HEADERS_SENT"></a>
+### `ERR_HTTP_HEADERS_SENT`
+
+An attempt was made to add more headers after the headers had already been sent.
+
+<a id="ERR_HTTP_INVALID_HEADER_VALUE"></a>
+### `ERR_HTTP_INVALID_HEADER_VALUE`
+
+An invalid HTTP header value was specified.
+
+<a id="ERR_HTTP_INVALID_STATUS_CODE"></a>
+### `ERR_HTTP_INVALID_STATUS_CODE`
+
+Status code was outside the regular status code range (100-999).
+
+<a id="ERR_HTTP_TRAILER_INVALID"></a>
+### `ERR_HTTP_TRAILER_INVALID`
+
+The `Trailer` header was set even though the transfer encoding does not support
+that.
+
+<a id="ERR_HTTP2_ALTSVC_INVALID_ORIGIN"></a>
+### `ERR_HTTP2_ALTSVC_INVALID_ORIGIN`
+
+HTTP/2 ALTSVC frames require a valid origin.
+
+<a id="ERR_HTTP2_ALTSVC_LENGTH"></a>
+### `ERR_HTTP2_ALTSVC_LENGTH`
+
+HTTP/2 ALTSVC frames are limited to a maximum of 16,382 payload bytes.
+
+<a id="ERR_HTTP2_CONNECT_AUTHORITY"></a>
+### `ERR_HTTP2_CONNECT_AUTHORITY`
+
+For HTTP/2 requests using the `CONNECT` method, the `:authority` pseudo-header
+is required.
+
+<a id="ERR_HTTP2_CONNECT_PATH"></a>
+### `ERR_HTTP2_CONNECT_PATH`
+
+For HTTP/2 requests using the `CONNECT` method, the `:path` pseudo-header is
+forbidden.
+
+<a id="ERR_HTTP2_CONNECT_SCHEME"></a>
+### `ERR_HTTP2_CONNECT_SCHEME`
+
+For HTTP/2 requests using the `CONNECT` method, the `:scheme` pseudo-header is
+forbidden.
+
+<a id="ERR_HTTP2_ERROR"></a>
+### `ERR_HTTP2_ERROR`
+
+A non-specific HTTP/2 error has occurred.
+
+<a id="ERR_HTTP2_GOAWAY_SESSION"></a>
+### `ERR_HTTP2_GOAWAY_SESSION`
+
+New HTTP/2 Streams may not be opened after the `Http2Session` has received a
+`GOAWAY` frame from the connected peer.
+
+<a id="ERR_HTTP2_HEADER_SINGLE_VALUE"></a>
+### `ERR_HTTP2_HEADER_SINGLE_VALUE`
+
+Multiple values were provided for an HTTP/2 header field that was required to
+have only a single value.
+
+<a id="ERR_HTTP2_HEADERS_AFTER_RESPOND"></a>
+### `ERR_HTTP2_HEADERS_AFTER_RESPOND`
+
+An additional headers was specified after an HTTP/2 response was initiated.
+
+<a id="ERR_HTTP2_HEADERS_SENT"></a>
+### `ERR_HTTP2_HEADERS_SENT`
+
+An attempt was made to send multiple response headers.
+
+<a id="ERR_HTTP2_INFO_STATUS_NOT_ALLOWED"></a>
+### `ERR_HTTP2_INFO_STATUS_NOT_ALLOWED`
+
+Informational HTTP status codes (`1xx`) may not be set as the response status
+code on HTTP/2 responses.
+
+<a id="ERR_HTTP2_INVALID_CONNECTION_HEADERS"></a>
+### `ERR_HTTP2_INVALID_CONNECTION_HEADERS`
+
+HTTP/1 connection specific headers are forbidden to be used in HTTP/2
+requests and responses.
+
+<a id="ERR_HTTP2_INVALID_HEADER_VALUE"></a>
+### `ERR_HTTP2_INVALID_HEADER_VALUE`
+
+An invalid HTTP/2 header value was specified.
+
+<a id="ERR_HTTP2_INVALID_INFO_STATUS"></a>
+### `ERR_HTTP2_INVALID_INFO_STATUS`
+
+An invalid HTTP informational status code has been specified. Informational
+status codes must be an integer between `100` and `199` (inclusive).
+
+<a id="ERR_HTTP2_INVALID_ORIGIN"></a>
+### `ERR_HTTP2_INVALID_ORIGIN`
+
+HTTP/2 `ORIGIN` frames require a valid origin.
+
+<a id="ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH"></a>
+### `ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH`
+
+Input `Buffer` and `Uint8Array` instances passed to the
+`http2.getUnpackedSettings()` API must have a length that is a multiple of
+six.
+
+<a id="ERR_HTTP2_INVALID_PSEUDOHEADER"></a>
+### `ERR_HTTP2_INVALID_PSEUDOHEADER`
+
+Only valid HTTP/2 pseudoheaders (`:status`, `:path`, `:authority`, `:scheme`,
+and `:method`) may be used.
+
+<a id="ERR_HTTP2_INVALID_SESSION"></a>
+### `ERR_HTTP2_INVALID_SESSION`
+
+An action was performed on an `Http2Session` object that had already been
+destroyed.
+
+<a id="ERR_HTTP2_INVALID_SETTING_VALUE"></a>
+### `ERR_HTTP2_INVALID_SETTING_VALUE`
+
+An invalid value has been specified for an HTTP/2 setting.
+
+<a id="ERR_HTTP2_INVALID_STREAM"></a>
+### `ERR_HTTP2_INVALID_STREAM`
+
+An operation was performed on a stream that had already been destroyed.
+
+<a id="ERR_HTTP2_MAX_PENDING_SETTINGS_ACK"></a>
+### `ERR_HTTP2_MAX_PENDING_SETTINGS_ACK`
+
+Whenever an HTTP/2 `SETTINGS` frame is sent to a connected peer, the peer is
+required to send an acknowledgment that it has received and applied the new
+`SETTINGS`. By default, a maximum number of unacknowledged `SETTINGS` frames may
+be sent at any given time. This error code is used when that limit has been
+reached.
+
+<a id="ERR_HTTP2_NESTED_PUSH"></a>
+### `ERR_HTTP2_NESTED_PUSH`
+
+An attempt was made to initiate a new push stream from within a push stream.
+Nested push streams are not permitted.
+
+<a id="ERR_HTTP2_NO_SOCKET_MANIPULATION"></a>
+### `ERR_HTTP2_NO_SOCKET_MANIPULATION`
+
+An attempt was made to directly manipulate (read, write, pause, resume, etc.) a
+socket attached to an `Http2Session`.
+
+<a id="ERR_HTTP2_ORIGIN_LENGTH"></a>
+### `ERR_HTTP2_ORIGIN_LENGTH`
+
+HTTP/2 `ORIGIN` frames are limited to a length of 16382 bytes.
+
+<a id="ERR_HTTP2_OUT_OF_STREAMS"></a>
+### `ERR_HTTP2_OUT_OF_STREAMS`
+
+The number of streams created on a single HTTP/2 session reached the maximum
+limit.
+
+<a id="ERR_HTTP2_PAYLOAD_FORBIDDEN"></a>
+### `ERR_HTTP2_PAYLOAD_FORBIDDEN`
+
+A message payload was specified for an HTTP response code for which a payload is
+forbidden.
+
+<a id="ERR_HTTP2_PING_CANCEL"></a>
+### `ERR_HTTP2_PING_CANCEL`
+
+An HTTP/2 ping was canceled.
+
+<a id="ERR_HTTP2_PING_LENGTH"></a>
+### `ERR_HTTP2_PING_LENGTH`
+
+HTTP/2 ping payloads must be exactly 8 bytes in length.
+
+<a id="ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED"></a>
+### `ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED`
+
+An HTTP/2 pseudo-header has been used inappropriately. Pseudo-headers are header
+key names that begin with the `:` prefix.
+
+<a id="ERR_HTTP2_PUSH_DISABLED"></a>
+### `ERR_HTTP2_PUSH_DISABLED`
+
+An attempt was made to create a push stream, which had been disabled by the
+client.
+
+<a id="ERR_HTTP2_SEND_FILE"></a>
+### `ERR_HTTP2_SEND_FILE`
+
+An attempt was made to use the `Http2Stream.prototype.responseWithFile()` API to
+send a directory.
+
+<a id="ERR_HTTP2_SEND_FILE_NOSEEK"></a>
+### `ERR_HTTP2_SEND_FILE_NOSEEK`
+
+An attempt was made to use the `Http2Stream.prototype.responseWithFile()` API to
+send something other than a regular file, but `offset` or `length` options were
+provided.
+
+<a id="ERR_HTTP2_SESSION_ERROR"></a>
+### `ERR_HTTP2_SESSION_ERROR`
+
+The `Http2Session` closed with a non-zero error code.
+
+<a id="ERR_HTTP2_SETTINGS_CANCEL"></a>
+### `ERR_HTTP2_SETTINGS_CANCEL`
+
+The `Http2Session` settings canceled.
+
+<a id="ERR_HTTP2_SOCKET_BOUND"></a>
+### `ERR_HTTP2_SOCKET_BOUND`
+
+An attempt was made to connect a `Http2Session` object to a `net.Socket` or
+`tls.TLSSocket` that had already been bound to another `Http2Session` object.
+
+<a id="ERR_HTTP2_SOCKET_UNBOUND"></a>
+### `ERR_HTTP2_SOCKET_UNBOUND`
+
+An attempt was made to use the `socket` property of an `Http2Session` that
+has already been closed.
+
+<a id="ERR_HTTP2_STATUS_101"></a>
+### `ERR_HTTP2_STATUS_101`
+
+Use of the `101` Informational status code is forbidden in HTTP/2.
+
+<a id="ERR_HTTP2_STATUS_INVALID"></a>
+### `ERR_HTTP2_STATUS_INVALID`
+
+An invalid HTTP status code has been specified. Status codes must be an integer
+between `100` and `599` (inclusive).
+
+<a id="ERR_HTTP2_STREAM_CANCEL"></a>
+### `ERR_HTTP2_STREAM_CANCEL`
+
+An `Http2Stream` was destroyed before any data was transmitted to the connected
+peer.
+
+<a id="ERR_HTTP2_STREAM_ERROR"></a>
+### `ERR_HTTP2_STREAM_ERROR`
+
+A non-zero error code was been specified in an `RST_STREAM` frame.
+
+<a id="ERR_HTTP2_STREAM_SELF_DEPENDENCY"></a>
+### `ERR_HTTP2_STREAM_SELF_DEPENDENCY`
+
+When setting the priority for an HTTP/2 stream, the stream may be marked as
+a dependency for a parent stream. This error code is used when an attempt is
+made to mark a stream and dependent of itself.
+
+<a id="ERR_HTTP2_TRAILERS_ALREADY_SENT"></a>
+### `ERR_HTTP2_TRAILERS_ALREADY_SENT`
+
+Trailing headers have already been sent on the `Http2Stream`.
+
+<a id="ERR_HTTP2_TRAILERS_NOT_READY"></a>
+### `ERR_HTTP2_TRAILERS_NOT_READY`
+
+The `http2stream.sendTrailers()` method cannot be called until after the
+`'wantTrailers'` event is emitted on an `Http2Stream` object. The
+`'wantTrailers'` event will only be emitted if the `waitForTrailers` option
+is set for the `Http2Stream`.
+
+<a id="ERR_HTTP2_UNSUPPORTED_PROTOCOL"></a>
+### `ERR_HTTP2_UNSUPPORTED_PROTOCOL`
+
+`http2.connect()` was passed a URL that uses any protocol other than `http:` or
+`https:`.
+
+<a id="ERR_INCOMPATIBLE_OPTION_PAIR"></a>
+### `ERR_INCOMPATIBLE_OPTION_PAIR`
+
+An option pair is incompatible with each other and cannot be used at the same
+time.
+
+<a id="ERR_INPUT_TYPE_NOT_ALLOWED"></a>
+### `ERR_INPUT_TYPE_NOT_ALLOWED`
+
+> Stability: 1 - Experimental
+
+The `--input-type` flag was used to attempt to execute a file. This flag can
+only be used with input via `--eval`, `--print` or `STDIN`.
+
+<a id="ERR_INSPECTOR_ALREADY_ACTIVATED"></a>
+### `ERR_INSPECTOR_ALREADY_ACTIVATED`
+
+While using the `inspector` module, an attempt was made to activate the
+inspector when it already started to listen on a port. Use `inspector.close()`
+before activating it on a different address.
+
+<a id="ERR_INSPECTOR_ALREADY_CONNECTED"></a>
+### `ERR_INSPECTOR_ALREADY_CONNECTED`
+
+While using the `inspector` module, an attempt was made to connect when the
+inspector was already connected.
+
+<a id="ERR_INSPECTOR_CLOSED"></a>
+### `ERR_INSPECTOR_CLOSED`
+
+While using the `inspector` module, an attempt was made to use the inspector
+after the session had already closed.
+
+<a id="ERR_INSPECTOR_COMMAND"></a>
+### `ERR_INSPECTOR_COMMAND`
+
+An error occurred while issuing a command via the `inspector` module.
+
+<a id="ERR_INSPECTOR_NOT_ACTIVE"></a>
+### `ERR_INSPECTOR_NOT_ACTIVE`
+
+The `inspector` is not active when `inspector.waitForDebugger()` is called.
+
+<a id="ERR_INSPECTOR_NOT_AVAILABLE"></a>
+### `ERR_INSPECTOR_NOT_AVAILABLE`
+
+The `inspector` module is not available for use.
+
+<a id="ERR_INSPECTOR_NOT_CONNECTED"></a>
+### `ERR_INSPECTOR_NOT_CONNECTED`
+
+While using the `inspector` module, an attempt was made to use the inspector
+before it was connected.
+
+<a id="ERR_INSPECTOR_NOT_WORKER"></a>
+### `ERR_INSPECTOR_NOT_WORKER`
+
+An API was called on the main thread that can only be used from
+the worker thread.
+
+<a id="ERR_INTERNAL_ASSERTION"></a>
+### `ERR_INTERNAL_ASSERTION`
+
+There was a bug in Node.js or incorrect usage of Node.js internals.
+To fix the error, open an issue at <https://github.com/nodejs/node/issues>.
+
+<a id="ERR_INVALID_ADDRESS_FAMILY"></a>
+### `ERR_INVALID_ADDRESS_FAMILY`
+
+The provided address family is not understood by the Node.js API.
+
+<a id="ERR_INVALID_ARG_TYPE"></a>
+### `ERR_INVALID_ARG_TYPE`
+
+An argument of the wrong type was passed to a Node.js API.
+
+<a id="ERR_INVALID_ARG_VALUE"></a>
+### `ERR_INVALID_ARG_VALUE`
+
+An invalid or unsupported value was passed for a given argument.
+
+<a id="ERR_INVALID_ASYNC_ID"></a>
+### `ERR_INVALID_ASYNC_ID`
+
+An invalid `asyncId` or `triggerAsyncId` was passed using `AsyncHooks`. An id
+less than -1 should never happen.
+
+<a id="ERR_INVALID_BUFFER_SIZE"></a>
+### `ERR_INVALID_BUFFER_SIZE`
+
+A swap was performed on a `Buffer` but its size was not compatible with the
+operation.
+
+<a id="ERR_INVALID_CALLBACK"></a>
+### `ERR_INVALID_CALLBACK`
+
+A callback function was required but was not been provided to a Node.js API.
+
+<a id="ERR_INVALID_CHAR"></a>
+### `ERR_INVALID_CHAR`
+
+Invalid characters were detected in headers.
+
+<a id="ERR_INVALID_CURSOR_POS"></a>
+### `ERR_INVALID_CURSOR_POS`
+
+A cursor on a given stream cannot be moved to a specified row without a
+specified column.
+
+<a id="ERR_INVALID_FD"></a>
+### `ERR_INVALID_FD`
+
+A file descriptor ('fd') was not valid (e.g. it was a negative value).
+
+<a id="ERR_INVALID_FD_TYPE"></a>
+### `ERR_INVALID_FD_TYPE`
+
+A file descriptor ('fd') type was not valid.
+
+<a id="ERR_INVALID_FILE_URL_HOST"></a>
+### `ERR_INVALID_FILE_URL_HOST`
+
+A Node.js API that consumes `file:` URLs (such as certain functions in the
+[`fs`][] module) encountered a file URL with an incompatible host. This
+situation can only occur on Unix-like systems where only `localhost` or an empty
+host is supported.
+
+<a id="ERR_INVALID_FILE_URL_PATH"></a>
+### `ERR_INVALID_FILE_URL_PATH`
+
+A Node.js API that consumes `file:` URLs (such as certain functions in the
+[`fs`][] module) encountered a file URL with an incompatible path. The exact
+semantics for determining whether a path can be used is platform-dependent.
+
+<a id="ERR_INVALID_HANDLE_TYPE"></a>
+### `ERR_INVALID_HANDLE_TYPE`
+
+An attempt was made to send an unsupported "handle" over an IPC communication
+channel to a child process. See [`subprocess.send()`][] and [`process.send()`][]
+for more information.
+
+<a id="ERR_INVALID_HTTP_TOKEN"></a>
+### `ERR_INVALID_HTTP_TOKEN`
+
+An invalid HTTP token was supplied.
+
+<a id="ERR_INVALID_IP_ADDRESS"></a>
+### `ERR_INVALID_IP_ADDRESS`
+
+An IP address is not valid.
+
+<a id="ERR_INVALID_MODULE_SPECIFIER"></a>
+### `ERR_INVALID_MODULE_SPECIFIER`
+
+The imported module string is an invalid URL, package name, or package subpath
+specifier.
+
+<a id="ERR_INVALID_OPT_VALUE"></a>
+### `ERR_INVALID_OPT_VALUE`
+
+An invalid or unexpected value was passed in an options object.
+
+<a id="ERR_INVALID_OPT_VALUE_ENCODING"></a>
+### `ERR_INVALID_OPT_VALUE_ENCODING`
+
+An invalid or unknown file encoding was passed.
+
+<a id="ERR_INVALID_PACKAGE_CONFIG"></a>
+### `ERR_INVALID_PACKAGE_CONFIG`
+
+An invalid [`package.json`][] file was found which failed parsing.
+
+<a id="ERR_INVALID_PACKAGE_TARGET"></a>
+### `ERR_INVALID_PACKAGE_TARGET`
+
+The `package.json` [`"exports"`][] field contains an invalid target mapping
+value for the attempted module resolution.
+
+<a id="ERR_INVALID_PERFORMANCE_MARK"></a>
+### `ERR_INVALID_PERFORMANCE_MARK`
+
+While using the Performance Timing API (`perf_hooks`), a performance mark is
+invalid.
+
+<a id="ERR_INVALID_PROTOCOL"></a>
+### `ERR_INVALID_PROTOCOL`
+
+An invalid `options.protocol` was passed to `http.request()`.
+
+<a id="ERR_INVALID_REPL_EVAL_CONFIG"></a>
+### `ERR_INVALID_REPL_EVAL_CONFIG`
+
+Both `breakEvalOnSigint` and `eval` options were set in the [`REPL`][] config,
+which is not supported.
+
+<a id="ERR_INVALID_REPL_INPUT"></a>
+### `ERR_INVALID_REPL_INPUT`
+
+The input may not be used in the [`REPL`][]. All prohibited inputs are
+documented in the [`REPL`][]'s documentation.
+
+<a id="ERR_INVALID_RETURN_PROPERTY"></a>
+### `ERR_INVALID_RETURN_PROPERTY`
+
+Thrown in case a function option does not provide a valid value for one of its
+returned object properties on execution.
+
+<a id="ERR_INVALID_RETURN_PROPERTY_VALUE"></a>
+### `ERR_INVALID_RETURN_PROPERTY_VALUE`
+
+Thrown in case a function option does not provide an expected value
+type for one of its returned object properties on execution.
+
+<a id="ERR_INVALID_RETURN_VALUE"></a>
+### `ERR_INVALID_RETURN_VALUE`
+
+Thrown in case a function option does not return an expected value
+type on execution, such as when a function is expected to return a promise.
+
+<a id="ERR_INVALID_SYNC_FORK_INPUT"></a>
+### `ERR_INVALID_SYNC_FORK_INPUT`
+
+A `Buffer`, `TypedArray`, `DataView` or `string` was provided as stdio input to
+an asynchronous fork. See the documentation for the [`child_process`][] module
+for more information.
+
+<a id="ERR_INVALID_THIS"></a>
+### `ERR_INVALID_THIS`
+
+A Node.js API function was called with an incompatible `this` value.
+
+```js
+const urlSearchParams = new URLSearchParams('foo=bar&baz=new');
+
+const buf = Buffer.alloc(1);
+urlSearchParams.has.call(buf, 'foo');
+// Throws a TypeError with code 'ERR_INVALID_THIS'
+```
+
+<a id="ERR_INVALID_TRANSFER_OBJECT"></a>
+### `ERR_INVALID_TRANSFER_OBJECT`
+
+An invalid transfer object was passed to `postMessage()`.
+
+<a id="ERR_INVALID_TUPLE"></a>
+### `ERR_INVALID_TUPLE`
+
+An element in the `iterable` provided to the [WHATWG][WHATWG URL API]
+[`URLSearchParams` constructor][`new URLSearchParams(iterable)`] did not
+represent a `[name, value]` tuple – that is, if an element is not iterable, or
+does not consist of exactly two elements.
+
+<a id="ERR_INVALID_URI"></a>
+### `ERR_INVALID_URI`
+
+An invalid URI was passed.
+
+<a id="ERR_INVALID_URL"></a>
+### `ERR_INVALID_URL`
+
+An invalid URL was passed to the [WHATWG][WHATWG URL API]
+[`URL` constructor][`new URL(input)`] to be parsed. The thrown error object
+typically has an additional property `'input'` that contains the URL that failed
+to parse.
+
+<a id="ERR_INVALID_URL_SCHEME"></a>
+### `ERR_INVALID_URL_SCHEME`
+
+An attempt was made to use a URL of an incompatible scheme (protocol) for a
+specific purpose. It is only used in the [WHATWG URL API][] support in the
+[`fs`][] module (which only accepts URLs with `'file'` scheme), but may be used
+in other Node.js APIs as well in the future.
+
+<a id="ERR_IPC_CHANNEL_CLOSED"></a>
+### `ERR_IPC_CHANNEL_CLOSED`
+
+An attempt was made to use an IPC communication channel that was already closed.
+
+<a id="ERR_IPC_DISCONNECTED"></a>
+### `ERR_IPC_DISCONNECTED`
+
+An attempt was made to disconnect an IPC communication channel that was already
+disconnected. See the documentation for the [`child_process`][] module
+for more information.
+
+<a id="ERR_IPC_ONE_PIPE"></a>
+### `ERR_IPC_ONE_PIPE`
+
+An attempt was made to create a child Node.js process using more than one IPC
+communication channel. See the documentation for the [`child_process`][] module
+for more information.
+
+<a id="ERR_IPC_SYNC_FORK"></a>
+### `ERR_IPC_SYNC_FORK`
+
+An attempt was made to open an IPC communication channel with a synchronously
+forked Node.js process. See the documentation for the [`child_process`][] module
+for more information.
+
+<a id="ERR_MANIFEST_ASSERT_INTEGRITY"></a>
+### `ERR_MANIFEST_ASSERT_INTEGRITY`
+
+An attempt was made to load a resource, but the resource did not match the
+integrity defined by the policy manifest. See the documentation for [policy][]
+manifests for more information.
+
+<a id="ERR_MANIFEST_DEPENDENCY_MISSING"></a>
+### `ERR_MANIFEST_DEPENDENCY_MISSING`
+
+An attempt was made to load a resource, but the resource was not listed as a
+dependency from the location that attempted to load it. See the documentation
+for [policy][] manifests for more information.
+
+<a id="ERR_MANIFEST_INTEGRITY_MISMATCH"></a>
+### `ERR_MANIFEST_INTEGRITY_MISMATCH`
+
+An attempt was made to load a policy manifest, but the manifest had multiple
+entries for a resource which did not match each other. Update the manifest
+entries to match in order to resolve this error. See the documentation for
+[policy][] manifests for more information.
+
+<a id="ERR_MANIFEST_INVALID_RESOURCE_FIELD"></a>
+### `ERR_MANIFEST_INVALID_RESOURCE_FIELD`
+
+A policy manifest resource had an invalid value for one of its fields. Update
+the manifest entry to match in order to resolve this error. See the
+documentation for [policy][] manifests for more information.
+
+<a id="ERR_MANIFEST_PARSE_POLICY"></a>
+### `ERR_MANIFEST_PARSE_POLICY`
+
+An attempt was made to load a policy manifest, but the manifest was unable to
+be parsed. See the documentation for [policy][] manifests for more information.
+
+<a id="ERR_MANIFEST_TDZ"></a>
+### `ERR_MANIFEST_TDZ`
+
+An attempt was made to read from a policy manifest, but the manifest
+initialization has not yet taken place. This is likely a bug in Node.js.
+
+<a id="ERR_MANIFEST_UNKNOWN_ONERROR"></a>
+### `ERR_MANIFEST_UNKNOWN_ONERROR`
+
+A policy manifest was loaded, but had an unknown value for its "onerror"
+behavior. See the documentation for [policy][] manifests for more information.
+
+<a id="ERR_MEMORY_ALLOCATION_FAILED"></a>
+### `ERR_MEMORY_ALLOCATION_FAILED`
+
+An attempt was made to allocate memory (usually in the C++ layer) but it
+failed.
+
+<a id="ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE"></a>
+### `ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE`
+<!-- YAML
+added: v14.5.0
+-->
+
+A message posted to a [`MessagePort`][] could not be deserialized in the target
+[vm][] `Context`. Not all Node.js objects can be successfully instantiated in
+any context at this time, and attempting to transfer them using `postMessage()`
+can fail on the receiving side in that case.
+
+<a id="ERR_METHOD_NOT_IMPLEMENTED"></a>
+### `ERR_METHOD_NOT_IMPLEMENTED`
+
+A method is required but not implemented.
+
+<a id="ERR_MISSING_ARGS"></a>
+### `ERR_MISSING_ARGS`
+
+A required argument of a Node.js API was not passed. This is only used for
+strict compliance with the API specification (which in some cases may accept
+`func(undefined)` but not `func()`). In most native Node.js APIs,
+`func(undefined)` and `func()` are treated identically, and the
+[`ERR_INVALID_ARG_TYPE`][] error code may be used instead.
+
+<a id="ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST"></a>
+### `ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST`
+
+An object that needs to be explicitly listed in the `transferList` argument
+is in the object passed to a `postMessage()` call, but is not provided
+in the `transferList` for that call. Usually, this is a `MessagePort`.
+
+<a id="ERR_MISSING_OPTION"></a>
+### `ERR_MISSING_OPTION`
+
+For APIs that accept options objects, some options might be mandatory. This code
+is thrown if a required option is missing.
+
+<a id="ERR_MISSING_PASSPHRASE"></a>
+### `ERR_MISSING_PASSPHRASE`
+
+An attempt was made to read an encrypted key without specifying a passphrase.
+
+<a id="ERR_MISSING_PLATFORM_FOR_WORKER"></a>
+### `ERR_MISSING_PLATFORM_FOR_WORKER`
+
+The V8 platform used by this instance of Node.js does not support creating
+Workers. This is caused by lack of embedder support for Workers. In particular,
+this error will not occur with standard builds of Node.js.
+
+<a id="ERR_MODULE_NOT_FOUND"></a>
+### `ERR_MODULE_NOT_FOUND`
+
+> Stability: 1 - Experimental
+
+An [ES Module][] could not be resolved.
+
+<a id="ERR_MULTIPLE_CALLBACK"></a>
+### `ERR_MULTIPLE_CALLBACK`
+
+A callback was called more than once.
+
+A callback is almost always meant to only be called once as the query
+can either be fulfilled or rejected but not both at the same time. The latter
+would be possible by calling a callback more than once.
+
+<a id="ERR_NAPI_CONS_FUNCTION"></a>
+### `ERR_NAPI_CONS_FUNCTION`
+
+While using `N-API`, a constructor passed was not a function.
+
+<a id="ERR_NAPI_INVALID_DATAVIEW_ARGS"></a>
+### `ERR_NAPI_INVALID_DATAVIEW_ARGS`
+
+While calling `napi_create_dataview()`, a given `offset` was outside the bounds
+of the dataview or `offset + length` was larger than a length of given `buffer`.
+
+<a id="ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT"></a>
+### `ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT`
+
+While calling `napi_create_typedarray()`, the provided `offset` was not a
+multiple of the element size.
+
+<a id="ERR_NAPI_INVALID_TYPEDARRAY_LENGTH"></a>
+### `ERR_NAPI_INVALID_TYPEDARRAY_LENGTH`
+
+While calling `napi_create_typedarray()`, `(length * size_of_element) +
+byte_offset` was larger than the length of given `buffer`.
+
+<a id="ERR_NAPI_TSFN_CALL_JS"></a>
+### `ERR_NAPI_TSFN_CALL_JS`
+
+An error occurred while invoking the JavaScript portion of the thread-safe
+function.
+
+<a id="ERR_NAPI_TSFN_GET_UNDEFINED"></a>
+### `ERR_NAPI_TSFN_GET_UNDEFINED`
+
+An error occurred while attempting to retrieve the JavaScript `undefined`
+value.
+
+<a id="ERR_NAPI_TSFN_START_IDLE_LOOP"></a>
+### `ERR_NAPI_TSFN_START_IDLE_LOOP`
+
+On the main thread, values are removed from the queue associated with the
+thread-safe function in an idle loop. This error indicates that an error
+has occurred when attempting to start the loop.
+
+<a id="ERR_NAPI_TSFN_STOP_IDLE_LOOP"></a>
+### `ERR_NAPI_TSFN_STOP_IDLE_LOOP`
+
+Once no more items are left in the queue, the idle loop must be suspended. This
+error indicates that the idle loop has failed to stop.
+
+<a id="ERR_NO_CRYPTO"></a>
+### `ERR_NO_CRYPTO`
+
+An attempt was made to use crypto features while Node.js was not compiled with
+OpenSSL crypto support.
+
+<a id="ERR_NO_ICU"></a>
+### `ERR_NO_ICU`
+
+An attempt was made to use features that require [ICU][], but Node.js was not
+compiled with ICU support.
+
+<a id="ERR_NON_CONTEXT_AWARE_DISABLED"></a>
+### `ERR_NON_CONTEXT_AWARE_DISABLED`
+
+A non-context-aware native addon was loaded in a process that disallows them.
+
+<a id="ERR_OUT_OF_RANGE"></a>
+### `ERR_OUT_OF_RANGE`
+
+A given value is out of the accepted range.
+
+<a id="ERR_PACKAGE_IMPORT_NOT_DEFINED"></a>
+### `ERR_PACKAGE_IMPORT_NOT_DEFINED`
+
+The `package.json` [`"imports"`][] field does not define the given internal
+package specifier mapping.
+
+<a id="ERR_PACKAGE_PATH_NOT_EXPORTED"></a>
+### `ERR_PACKAGE_PATH_NOT_EXPORTED`
+
+The `package.json` [`"exports"`][] field does not export the requested subpath.
+Because exports are encapsulated, private internal modules that are not exported
+cannot be imported through the package resolution, unless using an absolute URL.
+
+<a id="ERR_PROTO_ACCESS"></a>
+### `ERR_PROTO_ACCESS`
+
+Accessing `Object.prototype.__proto__` has been forbidden using
+[`--disable-proto=throw`][]. [`Object.getPrototypeOf`][] and
+[`Object.setPrototypeOf`][] should be used to get and set the prototype of an
+object.
+
+<a id="ERR_REQUIRE_ESM"></a>
+### `ERR_REQUIRE_ESM`
+
+> Stability: 1 - Experimental
+
+An attempt was made to `require()` an [ES Module][].
+
+<a id="ERR_SCRIPT_EXECUTION_INTERRUPTED"></a>
+### `ERR_SCRIPT_EXECUTION_INTERRUPTED`
+
+Script execution was interrupted by `SIGINT` (For example,
+<kbd>Ctrl</kbd>+<kbd>C</kbd> was pressed.)
+
+<a id="ERR_SCRIPT_EXECUTION_TIMEOUT"></a>
+### `ERR_SCRIPT_EXECUTION_TIMEOUT`
+
+Script execution timed out, possibly due to bugs in the script being executed.
+
+<a id="ERR_SERVER_ALREADY_LISTEN"></a>
+### `ERR_SERVER_ALREADY_LISTEN`
+
+The [`server.listen()`][] method was called while a `net.Server` was already
+listening. This applies to all instances of `net.Server`, including HTTP, HTTPS,
+and HTTP/2 `Server` instances.
+
+<a id="ERR_SERVER_NOT_RUNNING"></a>
+### `ERR_SERVER_NOT_RUNNING`
+
+The [`server.close()`][] method was called when a `net.Server` was not
+running. This applies to all instances of `net.Server`, including HTTP, HTTPS,
+and HTTP/2 `Server` instances.
+
+<a id="ERR_SOCKET_ALREADY_BOUND"></a>
+### `ERR_SOCKET_ALREADY_BOUND`
+
+An attempt was made to bind a socket that has already been bound.
+
+<a id="ERR_SOCKET_BAD_BUFFER_SIZE"></a>
+### `ERR_SOCKET_BAD_BUFFER_SIZE`
+
+An invalid (negative) size was passed for either the `recvBufferSize` or
+`sendBufferSize` options in [`dgram.createSocket()`][].
+
+<a id="ERR_SOCKET_BAD_PORT"></a>
+### `ERR_SOCKET_BAD_PORT`
+
+An API function expecting a port >= 0 and < 65536 received an invalid value.
+
+<a id="ERR_SOCKET_BAD_TYPE"></a>
+### `ERR_SOCKET_BAD_TYPE`
+
+An API function expecting a socket type (`udp4` or `udp6`) received an invalid
+value.
+
+<a id="ERR_SOCKET_BUFFER_SIZE"></a>
+### `ERR_SOCKET_BUFFER_SIZE`
+
+While using [`dgram.createSocket()`][], the size of the receive or send `Buffer`
+could not be determined.
+
+<a id="ERR_SOCKET_CLOSED"></a>
+### `ERR_SOCKET_CLOSED`
+
+An attempt was made to operate on an already closed socket.
+
+<a id="ERR_SOCKET_DGRAM_IS_CONNECTED"></a>
+### `ERR_SOCKET_DGRAM_IS_CONNECTED`
+
+A [`dgram.connect()`][] call was made on an already connected socket.
+
+<a id="ERR_SOCKET_DGRAM_NOT_CONNECTED"></a>
+### `ERR_SOCKET_DGRAM_NOT_CONNECTED`
+
+A [`dgram.disconnect()`][] or [`dgram.remoteAddress()`][] call was made on a
+disconnected socket.
+
+<a id="ERR_SOCKET_DGRAM_NOT_RUNNING"></a>
+### `ERR_SOCKET_DGRAM_NOT_RUNNING`
+
+A call was made and the UDP subsystem was not running.
+
+<a id="ERR_SRI_PARSE"></a>
+### `ERR_SRI_PARSE`
+
+A string was provided for a Subresource Integrity check, but was unable to be
+parsed. Check the format of integrity attributes by looking at the
+[Subresource Integrity specification][].
+
+<a id="ERR_STREAM_ALREADY_FINISHED"></a>
+### `ERR_STREAM_ALREADY_FINISHED`
+
+A stream method was called that cannot complete because the stream was
+finished.
+
+<a id="ERR_STREAM_CANNOT_PIPE"></a>
+### `ERR_STREAM_CANNOT_PIPE`
+
+An attempt was made to call [`stream.pipe()`][] on a [`Writable`][] stream.
+
+<a id="ERR_STREAM_DESTROYED"></a>
+### `ERR_STREAM_DESTROYED`
+
+A stream method was called that cannot complete because the stream was
+destroyed using `stream.destroy()`.
+
+<a id="ERR_STREAM_NULL_VALUES"></a>
+### `ERR_STREAM_NULL_VALUES`
+
+An attempt was made to call [`stream.write()`][] with a `null` chunk.
+
+<a id="ERR_STREAM_PREMATURE_CLOSE"></a>
+### `ERR_STREAM_PREMATURE_CLOSE`
+
+An error returned by `stream.finished()` and `stream.pipeline()`, when a stream
+or a pipeline ends non gracefully with no explicit error.
+
+<a id="ERR_STREAM_PUSH_AFTER_EOF"></a>
+### `ERR_STREAM_PUSH_AFTER_EOF`
+
+An attempt was made to call [`stream.push()`][] after a `null`(EOF) had been
+pushed to the stream.
+
+<a id="ERR_STREAM_UNSHIFT_AFTER_END_EVENT"></a>
+### `ERR_STREAM_UNSHIFT_AFTER_END_EVENT`
+
+An attempt was made to call [`stream.unshift()`][] after the `'end'` event was
+emitted.
+
+<a id="ERR_STREAM_WRAP"></a>
+### `ERR_STREAM_WRAP`
+
+Prevents an abort if a string decoder was set on the Socket or if the decoder
+is in `objectMode`.
+
+```js
+const Socket = require('net').Socket;
+const instance = new Socket();
+
+instance.setEncoding('utf8');
+```
+
+<a id="ERR_STREAM_WRITE_AFTER_END"></a>
+### `ERR_STREAM_WRITE_AFTER_END`
+
+An attempt was made to call [`stream.write()`][] after `stream.end()` has been
+called.
+
+<a id="ERR_STRING_TOO_LONG"></a>
+### `ERR_STRING_TOO_LONG`
+
+An attempt has been made to create a string longer than the maximum allowed
+length.
+
+<a id="ERR_SYNTHETIC"></a>
+### `ERR_SYNTHETIC`
+
+An artificial error object used to capture the call stack for diagnostic
+reports.
+
+<a id="ERR_SYSTEM_ERROR"></a>
+### `ERR_SYSTEM_ERROR`
+
+An unspecified or non-specific system error has occurred within the Node.js
+process. The error object will have an `err.info` object property with
+additional details.
+
+<a id="ERR_TLS_CERT_ALTNAME_INVALID"></a>
+### `ERR_TLS_CERT_ALTNAME_INVALID`
+
+While using TLS, the host name/IP of the peer did not match any of the
+`subjectAltNames` in its certificate.
+
+<a id="ERR_TLS_DH_PARAM_SIZE"></a>
+### `ERR_TLS_DH_PARAM_SIZE`
+
+While using TLS, the parameter offered for the Diffie-Hellman (`DH`)
+key-agreement protocol is too small. By default, the key length must be greater
+than or equal to 1024 bits to avoid vulnerabilities, even though it is strongly
+recommended to use 2048 bits or larger for stronger security.
+
+<a id="ERR_TLS_HANDSHAKE_TIMEOUT"></a>
+### `ERR_TLS_HANDSHAKE_TIMEOUT`
+
+A TLS/SSL handshake timed out. In this case, the server must also abort the
+connection.
+
+<a id="ERR_TLS_INVALID_CONTEXT"></a>
+### `ERR_TLS_INVALID_CONTEXT`
+<!-- YAML
+added: v13.3.0
+-->
+
+The context must be a `SecureContext`.
+
+<a id="ERR_TLS_INVALID_PROTOCOL_METHOD"></a>
+### `ERR_TLS_INVALID_PROTOCOL_METHOD`
+
+The specified  `secureProtocol` method is invalid. It is  either unknown, or
+disabled because it is insecure.
+
+<a id="ERR_TLS_INVALID_PROTOCOL_VERSION"></a>
+### `ERR_TLS_INVALID_PROTOCOL_VERSION`
+
+Valid TLS protocol versions are `'TLSv1'`, `'TLSv1.1'`, or `'TLSv1.2'`.
+
+<a id="ERR_TLS_INVALID_STATE"></a>
+### `ERR_TLS_INVALID_STATE`
+<!-- YAML
+added:
+ - v13.10.0
+ - v12.17.0
+-->
+
+The TLS socket must be connected and securily established. Ensure the 'secure'
+event is emitted before continuing.
+
+<a id="ERR_TLS_PROTOCOL_VERSION_CONFLICT"></a>
+### `ERR_TLS_PROTOCOL_VERSION_CONFLICT`
+
+Attempting to set a TLS protocol `minVersion` or `maxVersion` conflicts with an
+attempt to set the `secureProtocol` explicitly. Use one mechanism or the other.
+
+<a id="ERR_TLS_PSK_SET_IDENTIY_HINT_FAILED"></a>
+### `ERR_TLS_PSK_SET_IDENTIY_HINT_FAILED`
+
+Failed to set PSK identity hint. Hint may be too long.
+
+<a id="ERR_TLS_RENEGOTIATION_DISABLED"></a>
+### `ERR_TLS_RENEGOTIATION_DISABLED`
+
+An attempt was made to renegotiate TLS on a socket instance with TLS disabled.
+
+<a id="ERR_TLS_REQUIRED_SERVER_NAME"></a>
+### `ERR_TLS_REQUIRED_SERVER_NAME`
+
+While using TLS, the `server.addContext()` method was called without providing
+a host name in the first parameter.
+
+<a id="ERR_TLS_SESSION_ATTACK"></a>
+### `ERR_TLS_SESSION_ATTACK`
+
+An excessive amount of TLS renegotiations is detected, which is a potential
+vector for denial-of-service attacks.
+
+<a id="ERR_TLS_SNI_FROM_SERVER"></a>
+### `ERR_TLS_SNI_FROM_SERVER`
+
+An attempt was made to issue Server Name Indication from a TLS server-side
+socket, which is only valid from a client.
+
+<a id="ERR_TRACE_EVENTS_CATEGORY_REQUIRED"></a>
+### `ERR_TRACE_EVENTS_CATEGORY_REQUIRED`
+
+The `trace_events.createTracing()` method requires at least one trace event
+category.
+
+<a id="ERR_TRACE_EVENTS_UNAVAILABLE"></a>
+### `ERR_TRACE_EVENTS_UNAVAILABLE`
+
+The `trace_events` module could not be loaded because Node.js was compiled with
+the `--without-v8-platform` flag.
+
+<a id="ERR_TRANSFORM_ALREADY_TRANSFORMING"></a>
+### `ERR_TRANSFORM_ALREADY_TRANSFORMING`
+
+A `Transform` stream finished while it was still transforming.
+
+<a id="ERR_TRANSFORM_WITH_LENGTH_0"></a>
+### `ERR_TRANSFORM_WITH_LENGTH_0`
+
+A `Transform` stream finished with data still in the write buffer.
+
+<a id="ERR_TTY_INIT_FAILED"></a>
+### `ERR_TTY_INIT_FAILED`
+
+The initialization of a TTY failed due to a system error.
+
+<a id="ERR_UNAVAILABLE_DURING_EXIT"></a>
+### `ERR_UNAVAILABLE_DURING_EXIT`
+
+Function was called within a [`process.on('exit')`][] handler that shouldn't be
+called within [`process.on('exit')`][] handler.
+
+<a id="ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET"></a>
+### `ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET`
+
+[`process.setUncaughtExceptionCaptureCallback()`][] was called twice,
+without first resetting the callback to `null`.
+
+This error is designed to prevent accidentally overwriting a callback registered
+from another module.
+
+<a id="ERR_UNESCAPED_CHARACTERS"></a>
+### `ERR_UNESCAPED_CHARACTERS`
+
+A string that contained unescaped characters was received.
+
+<a id="ERR_UNHANDLED_ERROR"></a>
+### `ERR_UNHANDLED_ERROR`
+
+An unhandled error occurred (for instance, when an `'error'` event is emitted
+by an [`EventEmitter`][] but an `'error'` handler is not registered).
+
+<a id="ERR_UNKNOWN_BUILTIN_MODULE"></a>
+### `ERR_UNKNOWN_BUILTIN_MODULE`
+
+Used to identify a specific kind of internal Node.js error that should not
+typically be triggered by user code. Instances of this error point to an
+internal bug within the Node.js binary itself.
+
+<a id="ERR_UNKNOWN_CREDENTIAL"></a>
+### `ERR_UNKNOWN_CREDENTIAL`
+
+A Unix group or user identifier that does not exist was passed.
+
+<a id="ERR_UNKNOWN_ENCODING"></a>
+### `ERR_UNKNOWN_ENCODING`
+
+An invalid or unknown encoding option was passed to an API.
+
+<a id="ERR_UNKNOWN_FILE_EXTENSION"></a>
+### `ERR_UNKNOWN_FILE_EXTENSION`
+
+> Stability: 1 - Experimental
+
+An attempt was made to load a module with an unknown or unsupported file
+extension.
+
+<a id="ERR_UNKNOWN_MODULE_FORMAT"></a>
+### `ERR_UNKNOWN_MODULE_FORMAT`
+
+> Stability: 1 - Experimental
+
+An attempt was made to load a module with an unknown or unsupported format.
+
+<a id="ERR_UNKNOWN_SIGNAL"></a>
+### `ERR_UNKNOWN_SIGNAL`
+
+An invalid or unknown process signal was passed to an API expecting a valid
+signal (such as [`subprocess.kill()`][]).
+
+<a id="ERR_UNSUPPORTED_DIR_IMPORT"></a>
+### `ERR_UNSUPPORTED_DIR_IMPORT`
+
+`import` a directory URL is unsupported. Instead,
+[self-reference a package using its name][] and [define a custom subpath][] in
+the [`"exports"`][] field of the [`package.json`][] file.
+
+<!-- eslint-skip -->
+```js
+import './'; // unsupported
+import './index.js'; // supported
+import 'package-name'; // supported
+```
+
+<a id="ERR_UNSUPPORTED_ESM_URL_SCHEME"></a>
+### `ERR_UNSUPPORTED_ESM_URL_SCHEME`
+
+`import` with URL schemes other than `file` and `data` is unsupported.
+
+<a id="ERR_VALID_PERFORMANCE_ENTRY_TYPE"></a>
+### `ERR_VALID_PERFORMANCE_ENTRY_TYPE`
+
+While using the Performance Timing API (`perf_hooks`), no valid performance
+entry types are found.
+
+<a id="ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING"></a>
+### `ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`
+
+A dynamic import callback was not specified.
+
+<a id="ERR_VM_MODULE_ALREADY_LINKED"></a>
+### `ERR_VM_MODULE_ALREADY_LINKED`
+
+The module attempted to be linked is not eligible for linking, because of one of
+the following reasons:
+
+* It has already been linked (`linkingStatus` is `'linked'`)
+* It is being linked (`linkingStatus` is `'linking'`)
+* Linking has failed for this module (`linkingStatus` is `'errored'`)
+
+<a id="ERR_VM_MODULE_CACHED_DATA_REJECTED"></a>
+### `ERR_VM_MODULE_CACHED_DATA_REJECTED`
+
+The `cachedData` option passed to a module constructor is invalid.
+
+<a id="ERR_VM_MODULE_CANNOT_CREATE_CACHED_DATA"></a>
+### `ERR_VM_MODULE_CANNOT_CREATE_CACHED_DATA`
+
+Cached data cannot be created for modules which have already been evaluated.
+
+<a id="ERR_VM_MODULE_DIFFERENT_CONTEXT"></a>
+### `ERR_VM_MODULE_DIFFERENT_CONTEXT`
+
+The module being returned from the linker function is from a different context
+than the parent module. Linked modules must share the same context.
+
+<a id="ERR_VM_MODULE_LINKING_ERRORED"></a>
+### `ERR_VM_MODULE_LINKING_ERRORED`
+
+The linker function returned a module for which linking has failed.
+
+<a id="ERR_VM_MODULE_NOT_MODULE"></a>
+### `ERR_VM_MODULE_NOT_MODULE`
+
+The fulfilled value of a linking promise is not a `vm.Module` object.
+
+<a id="ERR_VM_MODULE_STATUS"></a>
+### `ERR_VM_MODULE_STATUS`
+
+The current module's status does not allow for this operation. The specific
+meaning of the error depends on the specific function.
+
+<a id="ERR_WASI_ALREADY_STARTED"></a>
+### `ERR_WASI_ALREADY_STARTED`
+
+The WASI instance has already started.
+
+<a id="ERR_WASI_NOT_STARTED"></a>
+### `ERR_WASI_NOT_STARTED`
+
+The WASI instance has not been started.
+
+<a id="ERR_WORKER_INIT_FAILED"></a>
+### `ERR_WORKER_INIT_FAILED`
+
+The `Worker` initialization failed.
+
+<a id="ERR_WORKER_INVALID_EXEC_ARGV"></a>
+### `ERR_WORKER_INVALID_EXEC_ARGV`
+
+The `execArgv` option passed to the `Worker` constructor contains
+invalid flags.
+
+<a id="ERR_WORKER_NOT_RUNNING"></a>
+### `ERR_WORKER_NOT_RUNNING`
+
+An operation failed because the `Worker` instance is not currently running.
+
+<a id="ERR_WORKER_OUT_OF_MEMORY"></a>
+### `ERR_WORKER_OUT_OF_MEMORY`
+
+The `Worker` instance terminated because it reached its memory limit.
+
+<a id="ERR_WORKER_PATH"></a>
+### `ERR_WORKER_PATH`
+
+The path for the main script of a worker is neither an absolute path
+nor a relative path starting with `./` or `../`.
+
+<a id="ERR_WORKER_UNSERIALIZABLE_ERROR"></a>
+### `ERR_WORKER_UNSERIALIZABLE_ERROR`
+
+All attempts at serializing an uncaught exception from a worker thread failed.
+
+<a id="ERR_WORKER_UNSUPPORTED_EXTENSION"></a>
+### `ERR_WORKER_UNSUPPORTED_EXTENSION`
+
+The pathname used for the main script of a worker has an
+unknown file extension.
+
+<a id="ERR_WORKER_UNSUPPORTED_OPERATION"></a>
+### `ERR_WORKER_UNSUPPORTED_OPERATION`
+
+The requested functionality is not supported in worker threads.
+
+<a id="ERR_ZLIB_INITIALIZATION_FAILED"></a>
+### `ERR_ZLIB_INITIALIZATION_FAILED`
+
+Creation of a [`zlib`][] object failed due to incorrect configuration.
+
+<a id="HPE_HEADER_OVERFLOW"></a>
+### `HPE_HEADER_OVERFLOW`
+<!-- YAML
+changes:
+  - version:
+     - v11.4.0
+     - v10.15.0
+    pr-url: https://github.com/nodejs/node/commit/186035243fad247e3955f
+    description: Max header size in `http_parser` was set to 8KB.
+-->
+
+Too much HTTP header data was received. In order to protect against malicious or
+malconfigured clients, if more than 8KB of HTTP header data is received then
+HTTP parsing will abort without a request or response object being created, and
+an `Error` with this code will be emitted.
+
+<a id="HPE_UNEXPECTED_CONTENT_LENGTH"></a>
+### `HPE_UNEXPECTED_CONTENT_LENGTH`
+
+Server is sending both a `Content-Length` header and `Transfer-Encoding: chunked`.
+
+`Transfer-Encoding: chunked` allows the server to maintain an HTTP persistent
+connection for dynamically generated content.
+In this case, the `Content-Length` HTTP header cannot be used.
+
+Use `Content-Length` or `Transfer-Encoding: chunked`.
+
+<a id="MODULE_NOT_FOUND"></a>
+### `MODULE_NOT_FOUND`
+<!-- YAML
+changes:
+  - version: v12.0.0
+    pr-url: https://github.com/nodejs/node/pull/25690
+    description: Added `requireStack` property.
+-->
+A module file could not be resolved while attempting a [`require()`][] or
+`import` operation.
+
+## Legacy Node.js error codes
+
+> Stability: 0 - Deprecated. These error codes are either inconsistent, or have
+> been removed.
+
+<a id="ERR_CANNOT_TRANSFER_OBJECT"></a>
+### `ERR_CANNOT_TRANSFER_OBJECT`
+<!--
+added: v10.5.0
+removed: v12.5.0
+-->
+
+The value passed to `postMessage()` contained an object that is not supported
+for transferring.
+
+<a id="ERR_CLOSED_MESSAGE_PORT"></a>
+### `ERR_CLOSED_MESSAGE_PORT`
+<!-- YAML
+added: v10.5.0
+removed: v11.12.0
+-->
+
+There was an attempt to use a `MessagePort` instance in a closed
+state, usually after `.close()` has been called.
+
+<a id="ERR_CRYPTO_HASH_DIGEST_NO_UTF16"></a>
+### `ERR_CRYPTO_HASH_DIGEST_NO_UTF16`
+<!-- YAML
+added: v9.0.0
+removed: v12.12.0
+-->
+
+The UTF-16 encoding was used with [`hash.digest()`][]. While the
+`hash.digest()` method does allow an `encoding` argument to be passed in,
+causing the method to return a string rather than a `Buffer`, the UTF-16
+encoding (e.g. `ucs` or `utf16le`) is not supported.
+
+<a id="ERR_HTTP2_FRAME_ERROR"></a>
+### `ERR_HTTP2_FRAME_ERROR`
+<!-- YAML
+added: v9.0.0
+removed: v10.0.0
+-->
+
+Used when a failure occurs sending an individual frame on the HTTP/2
+session.
+
+<a id="ERR_HTTP2_HEADERS_OBJECT"></a>
+### `ERR_HTTP2_HEADERS_OBJECT`
+<!-- YAML
+added: v9.0.0
+removed: v10.0.0
+-->
+
+Used when an HTTP/2 Headers Object is expected.
+
+<a id="ERR_HTTP2_HEADER_REQUIRED"></a>
+### `ERR_HTTP2_HEADER_REQUIRED`
+<!-- YAML
+added: v9.0.0
+removed: v10.0.0
+-->
+
+Used when a required header is missing in an HTTP/2 message.
+
+<a id="ERR_HTTP2_INFO_HEADERS_AFTER_RESPOND"></a>
+### `ERR_HTTP2_INFO_HEADERS_AFTER_RESPOND`
+<!-- YAML
+added: v9.0.0
+removed: v10.0.0
+-->
+
+HTTP/2 informational headers must only be sent *prior* to calling the
+`Http2Stream.prototype.respond()` method.
+
+<a id="ERR_HTTP2_STREAM_CLOSED"></a>
+### `ERR_HTTP2_STREAM_CLOSED`
+<!-- YAML
+added: v9.0.0
+removed: v10.0.0
+-->
+
+Used when an action has been performed on an HTTP/2 Stream that has already
+been closed.
+
+<a id="ERR_HTTP_INVALID_CHAR"></a>
+### `ERR_HTTP_INVALID_CHAR`
+<!-- YAML
+added: v9.0.0
+removed: v10.0.0
+-->
+
+Used when an invalid character is found in an HTTP response status message
+(reason phrase).
+
+<a id="ERR_HTTP_REQUEST_TIMEOUT"></a>
+### `ERR_HTTP_REQUEST_TIMEOUT`
+
+The client has not sent the entire request within the allowed time.
+
+<a id="ERR_INDEX_OUT_OF_RANGE"></a>
+### `ERR_INDEX_OUT_OF_RANGE`
+<!-- YAML
+  added: v10.0.0
+  removed: v11.0.0
+-->
+A given index was out of the accepted range (e.g. negative offsets).
+
+<a id="ERR_NAPI_CONS_PROTOTYPE_OBJECT"></a>
+### `ERR_NAPI_CONS_PROTOTYPE_OBJECT`
+<!-- YAML
+added: v9.0.0
+removed: v10.0.0
+-->
+
+Used by the `N-API` when `Constructor.prototype` is not an object.
+
+<a id="ERR_NO_LONGER_SUPPORTED"></a>
+### `ERR_NO_LONGER_SUPPORTED`
+
+A Node.js API was called in an unsupported manner, such as
+`Buffer.write(string, encoding, offset[, length])`.
+
+<a id="ERR_OUTOFMEMORY"></a>
+### `ERR_OUTOFMEMORY`
+<!-- YAML
+added: v9.0.0
+removed: v10.0.0
+-->
+
+Used generically to identify that an operation caused an out of memory
+condition.
+
+<a id="ERR_PARSE_HISTORY_DATA"></a>
+### `ERR_PARSE_HISTORY_DATA`
+<!-- YAML
+added: v9.0.0
+removed: v10.0.0
+-->
+
+The `repl` module was unable to parse data from the REPL history file.
+
+<a id="ERR_SOCKET_CANNOT_SEND"></a>
+### `ERR_SOCKET_CANNOT_SEND`
+<!-- YAML
+added: v9.0.0
+removed: v14.0.0
+-->
+
+Data could not be sent on a socket.
+
+<a id="ERR_STDERR_CLOSE"></a>
+### `ERR_STDERR_CLOSE`
+<!-- YAML
+removed: v10.12.0
+changes:
+  - version: v10.12.0
+    pr-url: https://github.com/nodejs/node/pull/23053
+    description: Rather than emitting an error, `process.stderr.end()` now
+                 only closes the stream side but not the underlying resource,
+                 making this error obsolete.
+-->
+
+An attempt was made to close the `process.stderr` stream. By design, Node.js
+does not allow `stdout` or `stderr` streams to be closed by user code.
+
+<a id="ERR_STDOUT_CLOSE"></a>
+### `ERR_STDOUT_CLOSE`
+<!-- YAML
+removed: v10.12.0
+changes:
+  - version: v10.12.0
+    pr-url: https://github.com/nodejs/node/pull/23053
+    description: Rather than emitting an error, `process.stderr.end()` now
+                 only closes the stream side but not the underlying resource,
+                 making this error obsolete.
+-->
+
+An attempt was made to close the `process.stdout` stream. By design, Node.js
+does not allow `stdout` or `stderr` streams to be closed by user code.
+
+<a id="ERR_STREAM_READ_NOT_IMPLEMENTED"></a>
+### `ERR_STREAM_READ_NOT_IMPLEMENTED`
+<!-- YAML
+added: v9.0.0
+removed: v10.0.0
+-->
+
+Used when an attempt is made to use a readable stream that has not implemented
+[`readable._read()`][].
+
+<a id="ERR_TLS_RENEGOTIATION_FAILED"></a>
+### `ERR_TLS_RENEGOTIATION_FAILED`
+<!-- YAML
+added: v9.0.0
+removed: v10.0.0
+-->
+
+Used when a TLS renegotiation request has failed in a non-specific way.
+
+<a id="ERR_TRANSFERRING_EXTERNALIZED_SHAREDARRAYBUFFER"></a>
+### `ERR_TRANSFERRING_EXTERNALIZED_SHAREDARRAYBUFFER`
+<!-- YAML
+added: v10.5.0
+removed: v14.0.0
+-->
+
+A `SharedArrayBuffer` whose memory is not managed by the JavaScript engine
+or by Node.js was encountered during serialization. Such a `SharedArrayBuffer`
+cannot be serialized.
+
+This can only happen when native addons create `SharedArrayBuffer`s in
+"externalized" mode, or put existing `SharedArrayBuffer` into externalized mode.
+
+<a id="ERR_UNKNOWN_STDIN_TYPE"></a>
+### `ERR_UNKNOWN_STDIN_TYPE`
+<!-- YAML
+added: v8.0.0
+removed: v11.7.0
+-->
+
+An attempt was made to launch a Node.js process with an unknown `stdin` file
+type. This error is usually an indication of a bug within Node.js itself,
+although it is possible for user code to trigger it.
+
+<a id="ERR_UNKNOWN_STREAM_TYPE"></a>
+### `ERR_UNKNOWN_STREAM_TYPE`
+<!-- YAML
+added: v8.0.0
+removed: v11.7.0
+-->
+
+An attempt was made to launch a Node.js process with an unknown `stdout` or
+`stderr` file type. This error is usually an indication of a bug within Node.js
+itself, although it is possible for user code to trigger it.
+
+<a id="ERR_V8BREAKITERATOR"></a>
+### `ERR_V8BREAKITERATOR`
+
+The V8 `BreakIterator` API was used but the full ICU data set is not installed.
+
+<a id="ERR_VALUE_OUT_OF_RANGE"></a>
+### `ERR_VALUE_OUT_OF_RANGE`
+<!-- YAML
+added: v9.0.0
+removed: v10.0.0
+-->
+
+Used when a given value is out of the accepted range.
+
+<a id="ERR_VM_MODULE_NOT_LINKED"></a>
+### `ERR_VM_MODULE_NOT_LINKED`
+
+The module must be successfully linked before instantiation.
+
+<a id="ERR_ZLIB_BINDING_CLOSED"></a>
+### `ERR_ZLIB_BINDING_CLOSED`
+<!-- YAML
+added: v9.0.0
+removed: v10.0.0
+-->
+
+Used when an attempt is made to use a `zlib` object after it has already been
+closed.
+
+[ES Module]: esm.md
+[ICU]: intl.md#intl_internationalization_support
+[Node.js error codes]: #nodejs-error-codes
+[Subresource Integrity specification]: https://www.w3.org/TR/SRI/#the-integrity-attribute
+[V8's stack trace API]: https://github.com/v8/v8/wiki/Stack-Trace-API
+[WHATWG Supported Encodings]: util.md#util_whatwg_supported_encodings
+[WHATWG URL API]: url.md#url_the_whatwg_url_api
+[`"exports"`]: packages.md#packages_exports
+[`"imports"`]: packages.md#packages_imports
+[`'uncaughtException'`]: process.md#process_event_uncaughtexception
+[`--disable-proto=throw`]: cli.md#cli_disable_proto_mode
+[`--force-fips`]: cli.md#cli_force_fips
+[`Class: assert.AssertionError`]: assert.md#assert_class_assert_assertionerror
+[`ERR_INVALID_ARG_TYPE`]: #ERR_INVALID_ARG_TYPE
+[`EventEmitter`]: events.md#events_class_eventemitter
+[`MessagePort`]: worker_threads.md#worker_threads_class_messageport
+[`Object.getPrototypeOf`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf
+[`Object.setPrototypeOf`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf
+[`REPL`]: repl.md
+[`Writable`]: stream.md#stream_class_stream_writable
+[`child_process`]: child_process.md
+[`cipher.getAuthTag()`]: crypto.md#crypto_cipher_getauthtag
+[`crypto.getDiffieHellman()`]: crypto.md#crypto_crypto_getdiffiehellman_groupname
+[`crypto.scrypt()`]: crypto.md#crypto_crypto_scrypt_password_salt_keylen_options_callback
+[`crypto.scryptSync()`]: crypto.md#crypto_crypto_scryptsync_password_salt_keylen_options
+[`crypto.timingSafeEqual()`]: crypto.md#crypto_crypto_timingsafeequal_a_b
+[`dgram.connect()`]: dgram.md#dgram_socket_connect_port_address_callback
+[`dgram.createSocket()`]: dgram.md#dgram_dgram_createsocket_options_callback
+[`dgram.disconnect()`]: dgram.md#dgram_socket_disconnect
+[`dgram.remoteAddress()`]: dgram.md#dgram_socket_remoteaddress
+[`errno`(3) man page]: https://man7.org/linux/man-pages/man3/errno.3.html
+[`fs.Dir`]: fs.md#fs_class_fs_dir
+[`fs.readFileSync`]: fs.md#fs_fs_readfilesync_path_options
+[`fs.readdir`]: fs.md#fs_fs_readdir_path_options_callback
+[`fs.symlink()`]: fs.md#fs_fs_symlink_target_path_type_callback
+[`fs.symlinkSync()`]: fs.md#fs_fs_symlinksync_target_path_type
+[`fs.unlink`]: fs.md#fs_fs_unlink_path_callback
+[`fs`]: fs.md
+[`hash.digest()`]: crypto.md#crypto_hash_digest_encoding
+[`hash.update()`]: crypto.md#crypto_hash_update_data_inputencoding
+[`http`]: http.md
+[`https`]: https.md
+[`libuv Error handling`]: https://docs.libuv.org/en/v1.x/errors.html
+[`net`]: net.md
+[`new URL(input)`]: url.md#url_new_url_input_base
+[`new URLSearchParams(iterable)`]: url.md#url_new_urlsearchparams_iterable
+[`package.json`]: packages.md#packages_node_js_package_json_field_definitions
+[`process.on('exit')`]: process.md#Event:-`'exit'`
+[`process.send()`]: process.md#process_process_send_message_sendhandle_options_callback
+[`process.setUncaughtExceptionCaptureCallback()`]: process.md#process_process_setuncaughtexceptioncapturecallback_fn
+[`readable._read()`]: stream.md#stream_readable_read_size_1
+[`require('crypto').setEngine()`]: crypto.md#crypto_crypto_setengine_engine_flags
+[`require()`]: modules.md#modules_require_id
+[`server.close()`]: net.md#net_server_close_callback
+[`server.listen()`]: net.md#net_server_listen
+[`sign.sign()`]: crypto.md#crypto_sign_sign_privatekey_outputencoding
+[`stream.pipe()`]: stream.md#stream_readable_pipe_destination_options
+[`stream.push()`]: stream.md#stream_readable_push_chunk_encoding
+[`stream.unshift()`]: stream.md#stream_readable_unshift_chunk_encoding
+[`stream.write()`]: stream.md#stream_writable_write_chunk_encoding_callback
+[`subprocess.kill()`]: child_process.md#child_process_subprocess_kill_signal
+[`subprocess.send()`]: child_process.md#child_process_subprocess_send_message_sendhandle_options_callback
+[`util.getSystemErrorName(error.errno)`]: util.md#util_util_getsystemerrorname_err
+[`zlib`]: zlib.md
+[crypto digest algorithm]: crypto.md#crypto_crypto_gethashes
+[define a custom subpath]: packages.md#packages_subpath_exports
+[domains]: domain.md
+[event emitter-based]: events.md#events_class_eventemitter
+[file descriptors]: https://en.wikipedia.org/wiki/File_descriptor
+[policy]: policy.md
+[self-reference a package using its name]: packages.md#packages_self_referencing_a_package_using_its_name
+[stream-based]: stream.md
+[syscall]: https://man7.org/linux/man-pages/man2/syscalls.2.html
+[try-catch]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
+[vm]: vm.md
index c55b0a9b8930c7bd6e77f26c90f0e8b690bc44f8..3f7d2661d35518f84dd0239fd2bb4a916e7cf242 100755 (executable)
@@ -920,6 +920,8 @@ class Context(object):
         name = name.replace('out/', '')
       name = os.path.abspath(name + '.exe')
 
+    name = os.environ.get('VM_PATH', name)
+
     if not exists(name):
       raise ValueError('Could not find executable. Should be ' + name)
 
@@ -1583,7 +1585,7 @@ def OuputTestResult(progress, skip_count, excluded_case_paths, options):
   if failed_count:
     skip_tests = options.skip_tests[:]
     skip_tests.extend(failed_case_paths)
-    skip_tests.extend(excluded_case_paths)
+    skip_tests.extend(excluded_case_paths)
     skip_tests = list(set(skip_tests))
     skip_tests.sort()
     WriteFileWithList(SKIP_LIST_FILENAME, skip_tests)
@@ -1831,4 +1833,5 @@ def Main():
 
 
 if __name__ == '__main__':
+  os.environ['LWNODE_RUNNING_ON_TESTS'] = '1'
   sys.exit(Main())