diff --git a/.clang-format b/.clang-format index 3e5f49c..2593ef5 100644 --- a/.clang-format +++ b/.clang-format @@ -1 +1 @@ -BasedOnStyle: Microsoft \ No newline at end of file +BasedOnStyle: Google \ No newline at end of file diff --git a/.gitignore b/.gitignore index de7a6e9..0e5068c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,75 +1,10 @@ -# macOS.gitignore -# General .DS_Store -.AppleDouble -.LSOverride +/third_party/include/folly/boost/ -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -# C++.gitignore -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app +/.vscode/ /out/ -/.vscode/ -/.idea/ -/clion/ -/static_analyze_report/ -/x86_64/ -/i386/ -/armv7/ +/arm/ /arm64/ -/napi/ -/napi_ios.tar.gz -/napi_hermes_android.tar.gz -/napi_qjs_android.tar.gz +/x86/ +/x64/ diff --git a/.gitmodules b/.gitmodules index 0bb9496..23eda91 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,6 +16,15 @@ [submodule "third_party/double-conversion"] path = third_party/double-conversion url = git@github.com:google/double-conversion.git -[submodule "third_party/boost-for-react-native"] - path = third_party/boost-for-react-native - url = git@github.com:react-native-community/boost-for-react-native.git +[submodule "third_party/libevent"] + path = third_party/libevent + url = git@github.com:libevent/libevent.git +[submodule "third_party/fbjni"] + path = third_party/fbjni + url = git@github.com:facebookincubator/fbjni.git +[submodule "third_party/fmt"] + path = third_party/fmt + url = git@github.com:fmtlib/fmt.git +[submodule "third_party/glog"] + path = third_party/glog + url = git@github.com:google/glog.git diff --git a/.gn b/.gn index 2c50d77..c6fefba 100644 --- a/.gn +++ b/.gn @@ -1 +1 @@ -buildconfig = "//BUILDCONFIG.gn" \ No newline at end of file +buildconfig = "//build/config/BUILDCONFIG.gn" diff --git a/BUILD.gn b/BUILD.gn index 73034e5..14f6cce 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1,983 +1,1192 @@ config("minimal_size_build") { - cflags_cc = ["-fno-exceptions", "-fno-rtti"] -} - -config("standard_build") { - configs = [":minimal_size_build"] - cflags_cc = ["-std=c++11"] + cflags_cc = [ + "-fno-exceptions", + "-fno-rtti", + ] } config("new_build") { - configs = [":minimal_size_build"] - cflags_cc = ["-std=c++14"] + cflags_cc = [ + "-std=c++17", + "-fvisibility=hidden", + ] } config("strict_build") { - cflags = ["-Wall", "-Wextra", "-Werror", "-Wpedantic"] -} - -config("exception_build") { - cflags_cc = ["-fexceptions", "-fno-rtti"] -} - -config("rtti_build") { - cflags_cc = ["-fno-exceptions", "-frtti"] -} - -config("exception_rtti_build") { - cflags_cc = ["-fexceptions", "-frtti"] + cflags = [ + "-Wall", + "-Wextra", + "-Werror", + "-Wpedantic", + ] } -config("new_rtti_build") { - configs = [":rtti_build"] - cflags_cc = ["-std=c++14"] +config("quickjs_build") { + include_dirs = [ "third_party/quickjs" ] + cflags_c = [ "-funsigned-char" ] } -config("new_exception_build") { - configs = [":exception_build"] - cflags_cc = ["-std=c++14"] +source_set("quickjs") { + configs = [ ":quickjs_build" ] + cflags_c = [ "-fvisibility=hidden" ] + defines = [ "CONFIG_VERSION=\"\"" ] + sources = [ + "third_party/quickjs/cutils.c", + "third_party/quickjs/libregexp.c", + "third_party/quickjs/libunicode.c", + "third_party/quickjs/quickjs.c", + ] + if (enable_qjs_big_number) { + sources += [ "third_party/quickjs/libbf.c" ] + } } -config("new_exception_rtti_build") { - configs = [":exception_rtti_build"] - cflags_cc = ["-std=c++14"] +source_set("napi_qjs") { + configs = [ + ":quickjs_build", + ":strict_build", + ] + include_dirs = [ "include" ] + cflags_c = [ + "-fvisibility=hidden", + "-Wno-unused-parameter", + "-Wno-pedantic", + ] + sources = [ "src/js_native_api_qjs.c" ] } source_set("dtoa") { - configs = [":minimal_size_build"] - sources = [ - "third_party/hermes/external/dtoa/dtoa.c", - "third_party/hermes/external/dtoa/g_fmt.c", - "third_party/hermes/external/dtoa/locks.cpp", - ] - defines = ["IEEE_8087", "Long=int", "NO_HEX_FP", "NO_INFNAN_CHECK", "MULTIPLE_THREADS"] -} - -config("common_build") { - include_dirs = ["third_party/include"] + configs = [ ":minimal_size_build" ] + cflags = [ "-fvisibility=hidden" ] + sources = [ + "third_party/hermes/external/dtoa/dtoa.c", + "third_party/hermes/external/dtoa/g_fmt.c", + "third_party/hermes/external/dtoa/locks.cpp", + ] + defines = [ + "IEEE_8087", + "Long=int", + "NO_HEX_FP", + "NO_INFNAN_CHECK", + "MULTIPLE_THREADS", + ] } config("llvm_build") { - configs = [":common_build"] - # third_party/include 为 llvh-config.h 和 config.h - # TBD(ChasonTang): config.h 是私有头文件,llvh-config.h 是公开头文件? - # third_party/hermes/external/llvh/gen/include 为 Attributes.inc - include_dirs = ["third_party/hermes/external/llvh/include", "third_party/hermes/external/llvh/gen/include"] -} - -source_set("llvm_demangle") { - sources = [ - "third_party/hermes/external/llvh/lib/Demangle/ItaniumDemangle.cpp", - "third_party/hermes/external/llvh/lib/Demangle/MicrosoftDemangleNodes.cpp", - "third_party/hermes/external/llvh/lib/Demangle/MicrosoftDemangle.cpp" - ] - configs = [":standard_build", ":llvm_build"] + include_dirs = [ + "third_party/hermes/external/llvh/include", + "third_party/hermes/external/llvh/gen/include", + "third_party/include/llvm", + ] + defines = [ + "LLVM_ON_UNIX", + "LLVM_DEFAULT_TARGET_TRIPLE=\"\"", + "LLVM_HOST_TRIPLE=\"\"", + "HAVE_UNISTD_H=1", # ErrorHandling.cpp:117 + "PACKAGE_NAME=\"\"", + "PACKAGE_VERSION=\"\"", + "HAVE_SYS_MMAN_H", # Memory.inc:51 + "HAVE_SYS_STAT_H=1", # Path.inc:286 + "LLVM_ENABLE_CRASH_DUMPS=false", + "HAVE_GETPAGESIZE", # Process.inc:82 + "HAVE_FCNTL_H=1", # Process.inc:216 + "HAVE_SIGNAL_H=1", # Process.inc:232 + "RETSIGTYPE=void", + "HAVE_SYS_PARAM_H", # Path.inc:178 + ] } source_set("llvm_support") { - configs = [":llvm_build", ":standard_build"] - sources = [ - "third_party/hermes/external/llvh/lib/Support/APFloat.cpp", - "third_party/hermes/external/llvh/lib/Support/APInt.cpp", - "third_party/hermes/external/llvh/lib/Support/CommandLine.cpp", - "third_party/hermes/external/llvh/lib/Support/ConvertUTF.cpp", - "third_party/hermes/external/llvh/lib/Support/ConvertUTFWrapper.cpp", - "third_party/hermes/external/llvh/lib/Support/Debug.cpp", - "third_party/hermes/external/llvh/lib/Support/Errno.cpp", - "third_party/hermes/external/llvh/lib/Support/Error.cpp", - "third_party/hermes/external/llvh/lib/Support/ErrorHandling.cpp", - "third_party/hermes/external/llvh/lib/Support/FileCheck.cpp", - "third_party/hermes/external/llvh/lib/Support/FoldingSet.cpp", - "third_party/hermes/external/llvh/lib/Support/GraphWriter.cpp", - "third_party/hermes/external/llvh/lib/Support/Hashing.cpp", - "third_party/hermes/external/llvh/lib/Support/Host.cpp", - "third_party/hermes/external/llvh/lib/Support/InitLLVM.cpp", - "third_party/hermes/external/llvh/lib/Support/LineIterator.cpp", - "third_party/hermes/external/llvh/lib/Support/Locale.cpp", - "third_party/hermes/external/llvh/lib/Support/MD5.cpp", - "third_party/hermes/external/llvh/lib/Support/ManagedStatic.cpp", - "third_party/hermes/external/llvh/lib/Support/Memory.cpp", - "third_party/hermes/external/llvh/lib/Support/MemoryBuffer.cpp", - "third_party/hermes/external/llvh/lib/Support/Mutex.cpp", - "third_party/hermes/external/llvh/lib/Support/NativeFormatting.cpp", - "third_party/hermes/external/llvh/lib/Support/Path.cpp", - "third_party/hermes/external/llvh/lib/Support/PrettyStackTrace.cpp", - "third_party/hermes/external/llvh/lib/Support/Process.cpp", - "third_party/hermes/external/llvh/lib/Support/Program.cpp", - "third_party/hermes/external/llvh/lib/Support/Regex.cpp", - "third_party/hermes/external/llvh/lib/Support/SHA1.cpp", - "third_party/hermes/external/llvh/lib/Support/Signals.cpp", - "third_party/hermes/external/llvh/lib/Support/SmallPtrSet.cpp", - "third_party/hermes/external/llvh/lib/Support/SmallVector.cpp", - "third_party/hermes/external/llvh/lib/Support/SourceMgr.cpp", - "third_party/hermes/external/llvh/lib/Support/Statistic.cpp", - "third_party/hermes/external/llvh/lib/Support/StringExtras.cpp", - "third_party/hermes/external/llvh/lib/Support/StringMap.cpp", - "third_party/hermes/external/llvh/lib/Support/StringRef.cpp", - "third_party/hermes/external/llvh/lib/Support/StringSaver.cpp", - "third_party/hermes/external/llvh/lib/Support/TargetParser.cpp", - "third_party/hermes/external/llvh/lib/Support/Threading.cpp", - "third_party/hermes/external/llvh/lib/Support/Timer.cpp", - "third_party/hermes/external/llvh/lib/Support/Triple.cpp", - "third_party/hermes/external/llvh/lib/Support/Twine.cpp", - "third_party/hermes/external/llvh/lib/Support/Unicode.cpp", - "third_party/hermes/external/llvh/lib/Support/Valgrind.cpp", - "third_party/hermes/external/llvh/lib/Support/Watchdog.cpp", - "third_party/hermes/external/llvh/lib/Support/circular_raw_ostream.cpp", - "third_party/hermes/external/llvh/lib/Support/raw_os_ostream.cpp", - "third_party/hermes/external/llvh/lib/Support/raw_ostream.cpp", - "third_party/hermes/external/llvh/lib/Support/regcomp.c", - "third_party/hermes/external/llvh/lib/Support/regerror.c", - "third_party/hermes/external/llvh/lib/Support/regexec.c", - "third_party/hermes/external/llvh/lib/Support/regfree.c", - "third_party/hermes/external/llvh/lib/Support/regstrlcpy.c", - ] + configs = [ + ":minimal_size_build", + ":llvm_build", + ":new_build", + ] + cflags_c = [ "-fvisibility=hidden" ] + sources = [ + "third_party/hermes/external/llvh/lib/Support/APFloat.cpp", + "third_party/hermes/external/llvh/lib/Support/APInt.cpp", + "third_party/hermes/external/llvh/lib/Support/CommandLine.cpp", + "third_party/hermes/external/llvh/lib/Support/ConvertUTF.cpp", + "third_party/hermes/external/llvh/lib/Support/ConvertUTFWrapper.cpp", + "third_party/hermes/external/llvh/lib/Support/Debug.cpp", + "third_party/hermes/external/llvh/lib/Support/Errno.cpp", + "third_party/hermes/external/llvh/lib/Support/Error.cpp", + "third_party/hermes/external/llvh/lib/Support/ErrorHandling.cpp", + "third_party/hermes/external/llvh/lib/Support/FileCheck.cpp", + "third_party/hermes/external/llvh/lib/Support/FoldingSet.cpp", + "third_party/hermes/external/llvh/lib/Support/GraphWriter.cpp", + "third_party/hermes/external/llvh/lib/Support/Hashing.cpp", + "third_party/hermes/external/llvh/lib/Support/Host.cpp", + "third_party/hermes/external/llvh/lib/Support/InitLLVM.cpp", + "third_party/hermes/external/llvh/lib/Support/LineIterator.cpp", + "third_party/hermes/external/llvh/lib/Support/Locale.cpp", + "third_party/hermes/external/llvh/lib/Support/MD5.cpp", + "third_party/hermes/external/llvh/lib/Support/ManagedStatic.cpp", + "third_party/hermes/external/llvh/lib/Support/Memory.cpp", + "third_party/hermes/external/llvh/lib/Support/MemoryBuffer.cpp", + "third_party/hermes/external/llvh/lib/Support/Mutex.cpp", + "third_party/hermes/external/llvh/lib/Support/NativeFormatting.cpp", + "third_party/hermes/external/llvh/lib/Support/Path.cpp", + "third_party/hermes/external/llvh/lib/Support/PrettyStackTrace.cpp", + "third_party/hermes/external/llvh/lib/Support/Process.cpp", + "third_party/hermes/external/llvh/lib/Support/Program.cpp", + "third_party/hermes/external/llvh/lib/Support/Regex.cpp", + "third_party/hermes/external/llvh/lib/Support/SHA1.cpp", + "third_party/hermes/external/llvh/lib/Support/Signals.cpp", + "third_party/hermes/external/llvh/lib/Support/SmallPtrSet.cpp", + "third_party/hermes/external/llvh/lib/Support/SmallVector.cpp", + "third_party/hermes/external/llvh/lib/Support/SourceMgr.cpp", + "third_party/hermes/external/llvh/lib/Support/Statistic.cpp", + "third_party/hermes/external/llvh/lib/Support/StringExtras.cpp", + "third_party/hermes/external/llvh/lib/Support/StringMap.cpp", + "third_party/hermes/external/llvh/lib/Support/StringRef.cpp", + "third_party/hermes/external/llvh/lib/Support/StringSaver.cpp", + "third_party/hermes/external/llvh/lib/Support/TargetParser.cpp", + "third_party/hermes/external/llvh/lib/Support/Threading.cpp", + "third_party/hermes/external/llvh/lib/Support/Timer.cpp", + "third_party/hermes/external/llvh/lib/Support/Triple.cpp", + "third_party/hermes/external/llvh/lib/Support/Twine.cpp", + "third_party/hermes/external/llvh/lib/Support/Unicode.cpp", + "third_party/hermes/external/llvh/lib/Support/Valgrind.cpp", + "third_party/hermes/external/llvh/lib/Support/Watchdog.cpp", + "third_party/hermes/external/llvh/lib/Support/circular_raw_ostream.cpp", + "third_party/hermes/external/llvh/lib/Support/raw_os_ostream.cpp", + "third_party/hermes/external/llvh/lib/Support/raw_ostream.cpp", + "third_party/hermes/external/llvh/lib/Support/regcomp.c", + "third_party/hermes/external/llvh/lib/Support/regerror.c", + "third_party/hermes/external/llvh/lib/Support/regexec.c", + "third_party/hermes/external/llvh/lib/Support/regfree.c", + "third_party/hermes/external/llvh/lib/Support/regstrlcpy.c", + ] } config("hermes_build") { -# TBD(ChasonTang): hermes/Support/Config.h 公有/私有头文件? - include_dirs = ["third_party/hermes/include", "third_party/hermes/public"] - defines = ["HERMESVM_GC_HADES", "HERMESVM_ALLOW_COMPRESSED_POINTERS", "HERMESVM_HEAP_SEGMENT_SIZE_KB=4096", "HERMESVM_ALLOW_CONCURRENT_GC", "HERMES_ENABLE_DEBUGGER"] - if (build_android) { - defines += ["HERMES_PLATFORM_UNICODE=HERMES_PLATFORM_UNICODE_JAVA"] - } - if (ubsan) { - defines += ["HERMES_UBSAN"] - } -} - -source_set("hermes_frontend_defs") { - configs = [":standard_build", ":hermes_build"] - sources = [ - "third_party/hermes/lib/FrontEndDefs/Builtins.cpp" - ] + include_dirs = [ + "third_party/hermes/include", + "third_party/hermes/public", + ] + defines = [ + "HERMESVM_GC_HADES", + "HERMESVM_INDIRECT_THREADING", + "HERMESVM_ALLOW_COMPRESSED_POINTERS", + "HERMESVM_HEAP_SEGMENT_SIZE_KB=4096", + "HERMESVM_ALLOW_CONCURRENT_GC", + "HERMESVM_ALLOW_INLINE_ASM", + "HERMES_ENABLE_DEBUGGER", + "HERMES_MEMORY_INSTRUMENTATION", + ] + if (target_os == "android") { + defines += [ "HERMES_PLATFORM_UNICODE=HERMES_PLATFORM_UNICODE_JAVA" ] + } + if (ubsan) { + defines += [ "HERMES_UBSAN" ] + } + if (is_debug) { + defines += [ "HERMES_SLOW_DEBUG" ] + } } -source_set("hermes_optimizer") { - configs = [":llvm_build", ":new_build", ":hermes_build"] - sources = [ - "third_party/hermes/lib/Optimizer/PassManager/Pipeline.cpp", - "third_party/hermes/lib/Optimizer/Scalar/SimplifyCFG.cpp", - "third_party/hermes/lib/Optimizer/Scalar/CSE.cpp", - "third_party/hermes/lib/Optimizer/Scalar/CodeMotion.cpp", - "third_party/hermes/lib/Optimizer/Scalar/DCE.cpp", - "third_party/hermes/lib/Optimizer/Scalar/Mem2Reg.cpp", - "third_party/hermes/lib/Optimizer/Scalar/TypeInference.cpp", - "third_party/hermes/lib/Optimizer/Scalar/StackPromotion.cpp", - "third_party/hermes/lib/Optimizer/Scalar/InstSimplify.cpp", - "third_party/hermes/lib/Optimizer/Scalar/Auditor.cpp", - "third_party/hermes/lib/Optimizer/Scalar/SimpleCallGraphProvider.cpp", - "third_party/hermes/lib/Optimizer/Scalar/ResolveStaticRequire.cpp", - "third_party/hermes/lib/Optimizer/Scalar/FuncSigOpts.cpp", - "third_party/hermes/lib/Optimizer/Scalar/Utils.cpp", - "third_party/hermes/lib/Optimizer/Scalar/Inlining.cpp", - "third_party/hermes/lib/Optimizer/Scalar/HoistStartGenerator.cpp", - "third_party/hermes/lib/Optimizer/Scalar/InstructionEscapeAnalysis.cpp", - "third_party/hermes/lib/Optimizer/Scalar/TDZDedup.cpp", - "third_party/hermes/lib/IR/Analysis.cpp", - "third_party/hermes/lib/IR/IREval.cpp", - ] +source_set("hermes_adt") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":new_build", + ] + sources = [ "third_party/hermes/lib/ADT/CompactArray.cpp" ] } -config("fbjni_build") { - include_dirs = [ - "third_party/hermes/first-party/fbjni/cxx" - ] +source_set("hermes_ast") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":new_build", + ] + sources = [ + "third_party/hermes/lib/AST/ASTBuilder.cpp", + "third_party/hermes/lib/AST/CommonJS.cpp", + "third_party/hermes/lib/AST/ESTree.cpp", + "third_party/hermes/lib/AST/ESTreeJSONDumper.cpp", + "third_party/hermes/lib/AST/SemValidate.cpp", + "third_party/hermes/lib/AST/SemanticValidator.cpp", + ] } -source_set("hermes_platform_unicode_java") { - configs = [":hermes_build", ":llvm_build", ":fbjni_build", ":new_exception_build"] - # 按照 Hermes 文档描述应当开启 RTTI 实际上不开启也能编译通过 - sources = ["third_party/hermes/lib/Platform/Unicode/PlatformUnicodeJava.cpp"] +source_set("hermes_backend") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":new_build", + ] + sources = [ + "third_party/hermes/lib/BCGen/BCOpt.cpp", + "third_party/hermes/lib/BCGen/Exceptions.cpp", + "third_party/hermes/lib/BCGen/Lowering.cpp", + "third_party/hermes/lib/BCGen/RegAlloc.cpp", + ] } -source_set("hermes_platform_unicode") { - configs = [":standard_build", ":hermes_build", ":llvm_build"] - sources = [ - "third_party/hermes/lib/Platform/Unicode/CharacterProperties.cpp" - ] - if (!build_android) { - sources += [ - "third_party/hermes/lib/Platform/Unicode/PlatformUnicodeCF.cpp" - ] - frameworks = [ "CoreFoundation.framework" ] - } +source_set("hermes_frontend_defs") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ] + cflags_cc = [ "-fvisibility=hidden" ] + sources = [ "third_party/hermes/lib/FrontEndDefs/Builtins.cpp" ] } -source_set("hermes_regex") { - configs = [":new_build", ":llvm_build", ":hermes_build"] - sources = [ - "third_party/hermes/lib/Regex/RegexParser.cpp", - "third_party/hermes/lib/Regex/Executor.cpp" - ] +source_set("hermes_frontend") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":new_build", + ] + sources = [ + "third_party/hermes/lib/IR/CFG.cpp", + "third_party/hermes/lib/IR/IR.cpp", + "third_party/hermes/lib/IR/IRBuilder.cpp", + "third_party/hermes/lib/IR/IRVerifier.cpp", + "third_party/hermes/lib/IR/Instrs.cpp", + "third_party/hermes/lib/IRGen/ESTreeIRGen-except.cpp", + "third_party/hermes/lib/IRGen/ESTreeIRGen-expr.cpp", + "third_party/hermes/lib/IRGen/ESTreeIRGen-func.cpp", + "third_party/hermes/lib/IRGen/ESTreeIRGen-stmt.cpp", + "third_party/hermes/lib/IRGen/ESTreeIRGen.cpp", + "third_party/hermes/lib/IRGen/IRGen.cpp", + "third_party/hermes/lib/IRGen/IRInstrument.cpp", + "third_party/hermes/lib/Optimizer/Wasm/EmitWasmIntrinsics.cpp", + "third_party/hermes/lib/Optimizer/Wasm/WasmIntrinsics.cpp", + "third_party/hermes/lib/Utils/Dumper.cpp", + ] } -source_set("hermes_platform") { - configs = [":standard_build", ":hermes_build", ":llvm_build"] - sources = [ - "third_party/hermes/lib/Platform/Logging.cpp" - ] +source_set("hermes_hbc_backend") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":new_build", + ] + sources = [ + "third_party/hermes/lib/BCGen/HBC/BackendContext.cpp", + "third_party/hermes/lib/BCGen/HBC/Bytecode.cpp", + "third_party/hermes/lib/BCGen/HBC/BytecodeDataProvider.cpp", + "third_party/hermes/lib/BCGen/HBC/BytecodeDisassembler.cpp", + "third_party/hermes/lib/BCGen/HBC/BytecodeFormConverter.cpp", + "third_party/hermes/lib/BCGen/HBC/BytecodeGenerator.cpp", + "third_party/hermes/lib/BCGen/HBC/BytecodeProviderFromSrc.cpp", + "third_party/hermes/lib/BCGen/HBC/BytecodeStream.cpp", + "third_party/hermes/lib/BCGen/HBC/ConsecutiveStringStorage.cpp", + "third_party/hermes/lib/BCGen/HBC/DebugInfo.cpp", + "third_party/hermes/lib/BCGen/HBC/HBC.cpp", + "third_party/hermes/lib/BCGen/HBC/ISel.cpp", + "third_party/hermes/lib/BCGen/HBC/Passes.cpp", + "third_party/hermes/lib/BCGen/HBC/Passes/FuncCallNOpts.cpp", + "third_party/hermes/lib/BCGen/HBC/Passes/InsertProfilePoint.cpp", + "third_party/hermes/lib/BCGen/HBC/Passes/LowerBuiltinCalls.cpp", + "third_party/hermes/lib/BCGen/HBC/Passes/OptEnvironmentInit.cpp", + "third_party/hermes/lib/BCGen/HBC/SerializedLiteralGenerator.cpp", + "third_party/hermes/lib/BCGen/HBC/SerializedLiteralParserBase.cpp", + "third_party/hermes/lib/BCGen/HBC/SimpleBytecodeBuilder.cpp", + "third_party/hermes/lib/BCGen/HBC/StringKind.cpp", + "third_party/hermes/lib/BCGen/HBC/TraverseLiteralStrings.cpp", + "third_party/hermes/lib/BCGen/HBC/UniquingFilenameTable.cpp", + "third_party/hermes/lib/BCGen/HBC/UniquingStringLiteralTable.cpp", + ] } -source_set("hermes_ast") { - configs = [":new_build", ":hermes_build", ":llvm_build"] - sources = [ - "third_party/hermes/lib/AST/ASTBuilder.cpp", - "third_party/hermes/lib/AST/ESTree.cpp", - "third_party/hermes/lib/AST/ESTreeJSONDumper.cpp", - "third_party/hermes/lib/AST/SemValidate.cpp", - "third_party/hermes/lib/AST/SemanticValidator.cpp", - "third_party/hermes/lib/AST/CommonJS.cpp", - ] +source_set("hermes_inst") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":new_build", + ] + sources = [ + "third_party/hermes/lib/Inst/InstDecode.cpp", + "third_party/hermes/lib/Inst/InstDecode2.cpp", + ] } -config("jsi_build") { - include_dirs = ["third_party/hermes/API/jsi"] +source_set("hermes_internal_bytecode") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":new_build", + ] + defines = [ "HERMES_CMAKE_BUILD" ] + sources = [ "third_party/hermes/lib/InternalBytecode/InternalBytecode.cpp" ] } -source_set("jsi") { - cflags_cc = ["-std=c++11", "-fvisibility=hidden"] - # 正常可以不开启 RTTI,但是 napi_hermes_source_set jsi_hermes 开启了 RTTI - configs = [":jsi_build", ":exception_rtti_build"] - sources = ["third_party/hermes/API/jsi/jsi/jsi.cpp"] +source_set("hermes_optimizer") { + configs = [ + ":minimal_size_build", + ":llvm_build", + ":hermes_build", + ":new_build", + ] + sources = [ + "third_party/hermes/lib/IR/Analysis.cpp", + "third_party/hermes/lib/IR/IREval.cpp", + "third_party/hermes/lib/Optimizer/PassManager/Pipeline.cpp", + "third_party/hermes/lib/Optimizer/Scalar/Auditor.cpp", + "third_party/hermes/lib/Optimizer/Scalar/CSE.cpp", + "third_party/hermes/lib/Optimizer/Scalar/CodeMotion.cpp", + "third_party/hermes/lib/Optimizer/Scalar/DCE.cpp", + "third_party/hermes/lib/Optimizer/Scalar/FuncSigOpts.cpp", + "third_party/hermes/lib/Optimizer/Scalar/HoistStartGenerator.cpp", + "third_party/hermes/lib/Optimizer/Scalar/Inlining.cpp", + "third_party/hermes/lib/Optimizer/Scalar/InstSimplify.cpp", + "third_party/hermes/lib/Optimizer/Scalar/InstructionEscapeAnalysis.cpp", + "third_party/hermes/lib/Optimizer/Scalar/Mem2Reg.cpp", + "third_party/hermes/lib/Optimizer/Scalar/ResolveStaticRequire.cpp", + "third_party/hermes/lib/Optimizer/Scalar/SimpleCallGraphProvider.cpp", + "third_party/hermes/lib/Optimizer/Scalar/SimplifyCFG.cpp", + "third_party/hermes/lib/Optimizer/Scalar/StackPromotion.cpp", + "third_party/hermes/lib/Optimizer/Scalar/TDZDedup.cpp", + "third_party/hermes/lib/Optimizer/Scalar/TypeInference.cpp", + "third_party/hermes/lib/Optimizer/Scalar/Utils.cpp", + "third_party/hermes/lib/Optimizer/Wasm/WasmSimplify.cpp", + ] } -source_set("hermes_frontend") { - configs = [":new_build", ":llvm_build", ":hermes_build"] - sources = [ - "third_party/hermes/lib/IRGen/IRGen.cpp", - "third_party/hermes/lib/IR/CFG.cpp", - "third_party/hermes/lib/IR/IR.cpp", - "third_party/hermes/lib/IR/IRBuilder.cpp", - "third_party/hermes/lib/IR/IRVerifier.cpp", - "third_party/hermes/lib/IR/Instrs.cpp", - "third_party/hermes/lib/IRGen/ESTreeIRGen-except.cpp", - "third_party/hermes/lib/IRGen/ESTreeIRGen-expr.cpp", - "third_party/hermes/lib/IRGen/ESTreeIRGen-func.cpp", - "third_party/hermes/lib/IRGen/ESTreeIRGen-stmt.cpp", - "third_party/hermes/lib/IRGen/ESTreeIRGen.cpp", - "third_party/hermes/lib/IRGen/IRInstrument.cpp", - "third_party/hermes/lib/Utils/Dumper.cpp", - ] +source_set("hermes_parser") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":new_build", + ] + include_dirs = [ "third_party/hermes/external" ] + sources = [ + "third_party/hermes/lib/Parser/FlowHelpers.cpp", + "third_party/hermes/lib/Parser/JSLexer.cpp", + "third_party/hermes/lib/Parser/JSONParser.cpp", + "third_party/hermes/lib/Parser/JSParser.cpp", + "third_party/hermes/lib/Parser/JSParserImpl-flow.cpp", + "third_party/hermes/lib/Parser/JSParserImpl-jsx.cpp", + "third_party/hermes/lib/Parser/JSParserImpl-ts.cpp", + "third_party/hermes/lib/Parser/JSParserImpl.cpp", + "third_party/hermes/lib/Parser/rust-api.cpp", + ] } -source_set("hermes_inst") { - configs = [":standard_build", ":hermes_build", ":llvm_build"] - sources = [ - "third_party/hermes/lib/Inst/InstDecode.cpp", - "third_party/hermes/lib/Inst/InstDecode2.cpp" - ] +source_set("hermes_platform") { + configs = [ + ":minimal_size_build", + ":llvm_build", + ":hermes_build", + ":new_build", + ] + sources = [ "third_party/hermes/lib/Platform/Logging.cpp" ] } -source_set("hermes_adt") { - configs = [":standard_build", ":llvm_build", ":hermes_build"] - sources = [ - "third_party/hermes/lib/ADT/CompactArray.cpp" +source_set("hermes_platform_unicode") { + configs = [ + ":llvm_build", + ":hermes_build", + ":new_build", + ] + sources = + [ "third_party/hermes/lib/Platform/Unicode/CharacterProperties.cpp" ] + if (target_os != "android") { + configs += [ ":minimal_size_build" ] + sources += + [ "third_party/hermes/lib/Platform/Unicode/PlatformUnicodeCF.cpp" ] + frameworks = [ "CoreFoundation.framework" ] + } else { + include_dirs = [ "third_party/fbjni/cxx" ] + cflags_cc = [ + "-fexceptions", + "-fno-rtti", ] + sources += + [ "third_party/hermes/lib/Platform/Unicode/PlatformUnicodeJava.cpp" ] + } } -config("dtoa_build") { - include_dirs = ["third_party/hermes/external"] -} - -source_set("hermes_parser") { - configs = [":new_build", ":llvm_build", ":hermes_build", ":dtoa_build"] - sources = [ - "third_party/hermes/lib/Parser/JSLexer.cpp", - "third_party/hermes/lib/Parser/JSONParser.cpp", - "third_party/hermes/lib/Parser/JSParser.cpp", - "third_party/hermes/lib/Parser/JSParserImpl-flow.cpp", - "third_party/hermes/lib/Parser/JSParserImpl-jsx.cpp", - "third_party/hermes/lib/Parser/JSParserImpl.cpp" - ] +source_set("hermes_regex") { + configs = [ + ":minimal_size_build", + ":llvm_build", + ":hermes_build", + ":new_build", + ] + sources = [ + "third_party/hermes/lib/Regex/Executor.cpp", + "third_party/hermes/lib/Regex/RegexParser.cpp", + ] } source_set("hermes_source_map") { - configs = [":new_build", ":llvm_build", ":hermes_build"] - sources = [ - "third_party/hermes/lib/SourceMap/SourceMap.cpp", - "third_party/hermes/lib/SourceMap/SourceMapGenerator.cpp", - "third_party/hermes/lib/SourceMap/SourceMapParser.cpp", - "third_party/hermes/lib/SourceMap/SourceMapTranslator.cpp" - ] + configs = [ + ":minimal_size_build", + ":llvm_build", + ":hermes_build", + ":new_build", + ] + sources = [ + "third_party/hermes/lib/SourceMap/SourceMap.cpp", + "third_party/hermes/lib/SourceMap/SourceMapGenerator.cpp", + "third_party/hermes/lib/SourceMap/SourceMapParser.cpp", + "third_party/hermes/lib/SourceMap/SourceMapTranslator.cpp", + "third_party/hermes/lib/SourceMap/c-api.cpp", + ] } source_set("hermes_support") { - configs = [":new_build", ":hermes_build", ":llvm_build", ":dtoa_build"] - sources = [ - "third_party/hermes/lib/Support/Allocator.cpp", - "third_party/hermes/lib/Support/Base64.cpp", - "third_party/hermes/lib/Support/Base64vlq.cpp", - "third_party/hermes/lib/Support/CheckedMalloc.cpp", - "third_party/hermes/lib/Support/Conversions.cpp", - "third_party/hermes/lib/Support/ErrorHandling.cpp", - "third_party/hermes/lib/Support/JSONEmitter.cpp", - "third_party/hermes/lib/Support/LEB128.cpp", - "third_party/hermes/lib/Support/OSCompatEmscripten.cpp", - "third_party/hermes/lib/Support/OSCompatPosix.cpp", - "third_party/hermes/lib/Support/OSCompatWindows.cpp", - "third_party/hermes/lib/Support/PageAccessTrackerPosix.cpp", - "third_party/hermes/lib/Support/PerfSection.cpp", - "third_party/hermes/lib/Support/RegExpSerialization.cpp", - "third_party/hermes/lib/Support/SHA1.cpp", - "third_party/hermes/lib/Support/SNPrintfBuf.cpp", - "third_party/hermes/lib/Support/Semaphore.cpp", - "third_party/hermes/lib/Support/SimpleDiagHandler.cpp", - "third_party/hermes/lib/Support/SourceErrorManager.cpp", - "third_party/hermes/lib/Support/StringTable.cpp", - "third_party/hermes/lib/Support/UTF16Stream.cpp", - "third_party/hermes/lib/Support/UTF8.cpp" - ] + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":new_build", + ] + include_dirs = [ "third_party/hermes/external" ] + sources = [ + "third_party/hermes/lib/Support/Allocator.cpp", + "third_party/hermes/lib/Support/Base64.cpp", + "third_party/hermes/lib/Support/Base64vlq.cpp", + "third_party/hermes/lib/Support/BigIntSupport.cpp", + "third_party/hermes/lib/Support/CheckedMalloc.cpp", + "third_party/hermes/lib/Support/Conversions.cpp", + "third_party/hermes/lib/Support/ErrorHandling.cpp", + "third_party/hermes/lib/Support/JSONEmitter.cpp", + "third_party/hermes/lib/Support/LEB128.cpp", + "third_party/hermes/lib/Support/OSCompatEmscripten.cpp", + "third_party/hermes/lib/Support/OSCompatPosix.cpp", + "third_party/hermes/lib/Support/OSCompatWindows.cpp", + "third_party/hermes/lib/Support/PageAccessTrackerPosix.cpp", + "third_party/hermes/lib/Support/PerfSection.cpp", + "third_party/hermes/lib/Support/RegExpSerialization.cpp", + "third_party/hermes/lib/Support/SHA1.cpp", + "third_party/hermes/lib/Support/SNPrintfBuf.cpp", + "third_party/hermes/lib/Support/Semaphore.cpp", + "third_party/hermes/lib/Support/SimpleDiagHandler.cpp", + "third_party/hermes/lib/Support/SourceErrorManager.cpp", + "third_party/hermes/lib/Support/StringTable.cpp", + "third_party/hermes/lib/Support/UTF16Stream.cpp", + "third_party/hermes/lib/Support/UTF8.cpp", + ] } -source_set("hermes_backend") { - configs = [":new_build", ":hermes_build", ":llvm_build"] - sources = [ - "third_party/hermes/lib/BCGen/BCOpt.cpp", - "third_party/hermes/lib/BCGen/Exceptions.cpp", - "third_party/hermes/lib/BCGen/Lowering.cpp", - "third_party/hermes/lib/BCGen/RegAlloc.cpp" - ] +source_set("hermes_vm_runtime") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":new_build", + ] + include_dirs = [ "third_party/hermes/external" ] + sources = [ + "third_party/hermes/lib/VM/ArrayStorage.cpp", + "third_party/hermes/lib/VM/BasicBlockExecutionInfo.cpp", + "third_party/hermes/lib/VM/BigIntPrimitive.cpp", + "third_party/hermes/lib/VM/BoxedDouble.cpp", + "third_party/hermes/lib/VM/BuildMetadata.cpp", + "third_party/hermes/lib/VM/Callable.cpp", + "third_party/hermes/lib/VM/CellKind.cpp", + "third_party/hermes/lib/VM/CheckHeapWellFormedAcceptor.cpp", + "third_party/hermes/lib/VM/CodeBlock.cpp", + "third_party/hermes/lib/VM/Debugger/Debugger.cpp", + "third_party/hermes/lib/VM/DictPropertyMap.cpp", + "third_party/hermes/lib/VM/Domain.cpp", + "third_party/hermes/lib/VM/DummyObject.cpp", + "third_party/hermes/lib/VM/GCBase.cpp", + "third_party/hermes/lib/VM/HandleRootOwner.cpp", + "third_party/hermes/lib/VM/HeapSnapshot.cpp", + "third_party/hermes/lib/VM/HermesValue.cpp", + "third_party/hermes/lib/VM/HiddenClass.cpp", + "third_party/hermes/lib/VM/IdentifierTable.cpp", + "third_party/hermes/lib/VM/Interpreter-slowpaths.cpp", + "third_party/hermes/lib/VM/Interpreter.cpp", + "third_party/hermes/lib/VM/JSArray.cpp", + "third_party/hermes/lib/VM/JSArrayBuffer.cpp", + "third_party/hermes/lib/VM/JSCallSite.cpp", + "third_party/hermes/lib/VM/JSCallableProxy.cpp", + "third_party/hermes/lib/VM/JSDataView.cpp", + "third_party/hermes/lib/VM/JSDate.cpp", + "third_party/hermes/lib/VM/JSError.cpp", + "third_party/hermes/lib/VM/JSGenerator.cpp", + "third_party/hermes/lib/VM/JSLib/Array.cpp", + "third_party/hermes/lib/VM/JSLib/ArrayBuffer.cpp", + "third_party/hermes/lib/VM/JSLib/ArrayIterator.cpp", + "third_party/hermes/lib/VM/JSLib/AsyncFunction.cpp", + "third_party/hermes/lib/VM/JSLib/BigInt.cpp", + "third_party/hermes/lib/VM/JSLib/Boolean.cpp", + "third_party/hermes/lib/VM/JSLib/CallSite.cpp", + "third_party/hermes/lib/VM/JSLib/DataView.cpp", + "third_party/hermes/lib/VM/JSLib/Date.cpp", + "third_party/hermes/lib/VM/JSLib/DateUtil.cpp", + "third_party/hermes/lib/VM/JSLib/DebuggerInternal.cpp", + "third_party/hermes/lib/VM/JSLib/Error.cpp", + "third_party/hermes/lib/VM/JSLib/Function.cpp", + "third_party/hermes/lib/VM/JSLib/GeneratorFunction.cpp", + "third_party/hermes/lib/VM/JSLib/GeneratorPrototype.cpp", + "third_party/hermes/lib/VM/JSLib/GlobalObject.cpp", + "third_party/hermes/lib/VM/JSLib/HermesBuiltin.cpp", + "third_party/hermes/lib/VM/JSLib/HermesInternal.cpp", + "third_party/hermes/lib/VM/JSLib/Instrument.cpp", + "third_party/hermes/lib/VM/JSLib/Intl.cpp", + "third_party/hermes/lib/VM/JSLib/IteratorPrototype.cpp", + "third_party/hermes/lib/VM/JSLib/JSLibInternal.cpp", + "third_party/hermes/lib/VM/JSLib/JSON.cpp", + "third_party/hermes/lib/VM/JSLib/JSONLexer.cpp", + "third_party/hermes/lib/VM/JSLib/Map.cpp", + "third_party/hermes/lib/VM/JSLib/Math.cpp", + "third_party/hermes/lib/VM/JSLib/Number.cpp", + "third_party/hermes/lib/VM/JSLib/Object.cpp", + "third_party/hermes/lib/VM/JSLib/Proxy.cpp", + "third_party/hermes/lib/VM/JSLib/Reflect.cpp", + "third_party/hermes/lib/VM/JSLib/RegExp.cpp", + "third_party/hermes/lib/VM/JSLib/RegExpStringIterator.cpp", + "third_party/hermes/lib/VM/JSLib/RuntimeCommonStorage.cpp", + "third_party/hermes/lib/VM/JSLib/RuntimeJSONUtils.cpp", + "third_party/hermes/lib/VM/JSLib/Set.cpp", + "third_party/hermes/lib/VM/JSLib/Sorting.cpp", + "third_party/hermes/lib/VM/JSLib/String.cpp", + "third_party/hermes/lib/VM/JSLib/StringIterator.cpp", + "third_party/hermes/lib/VM/JSLib/Symbol.cpp", + "third_party/hermes/lib/VM/JSLib/TypedArray.cpp", + "third_party/hermes/lib/VM/JSLib/WeakMap.cpp", + "third_party/hermes/lib/VM/JSLib/WeakRef.cpp", + "third_party/hermes/lib/VM/JSLib/WeakSet.cpp", + "third_party/hermes/lib/VM/JSLib/escape.cpp", + "third_party/hermes/lib/VM/JSLib/eval.cpp", + "third_party/hermes/lib/VM/JSLib/print.cpp", + "third_party/hermes/lib/VM/JSLib/require.cpp", + "third_party/hermes/lib/VM/JSMapImpl.cpp", + "third_party/hermes/lib/VM/JSNativeFunctions.cpp", + "third_party/hermes/lib/VM/JSObject.cpp", + "third_party/hermes/lib/VM/JSProxy.cpp", + "third_party/hermes/lib/VM/JSRegExp.cpp", + "third_party/hermes/lib/VM/JSRegExpStringIterator.cpp", + "third_party/hermes/lib/VM/JSTypedArray.cpp", + "third_party/hermes/lib/VM/JSWeakMapImpl.cpp", + "third_party/hermes/lib/VM/JSWeakRef.cpp", + "third_party/hermes/lib/VM/LimitedStorageProvider.cpp", + "third_party/hermes/lib/VM/Metadata.cpp", + "third_party/hermes/lib/VM/NativeState.cpp", + "third_party/hermes/lib/VM/Operations.cpp", + "third_party/hermes/lib/VM/OrderedHashMap.cpp", + "third_party/hermes/lib/VM/PredefinedStringIDs.cpp", + "third_party/hermes/lib/VM/PrimitiveBox.cpp", + "third_party/hermes/lib/VM/Profiler.cpp", + "third_party/hermes/lib/VM/Profiler/ChromeTraceSerializerPosix.cpp", + "third_party/hermes/lib/VM/Profiler/CodeCoverageProfiler.cpp", + "third_party/hermes/lib/VM/Profiler/InlineCacheProfiler.cpp", + "third_party/hermes/lib/VM/Profiler/SamplingProfilerPosix.cpp", + "third_party/hermes/lib/VM/PropertyAccessor.cpp", + "third_party/hermes/lib/VM/Runtime-profilers.cpp", + "third_party/hermes/lib/VM/Runtime.cpp", + "third_party/hermes/lib/VM/RuntimeModule.cpp", + "third_party/hermes/lib/VM/SegmentedArray.cpp", + "third_party/hermes/lib/VM/SerializedLiteralParser.cpp", + "third_party/hermes/lib/VM/SingleObject.cpp", + "third_party/hermes/lib/VM/StackFrame.cpp", + "third_party/hermes/lib/VM/StackTracesTree.cpp", + "third_party/hermes/lib/VM/StorageProvider.cpp", + "third_party/hermes/lib/VM/StringPrimitive.cpp", + "third_party/hermes/lib/VM/StringRefUtils.cpp", + "third_party/hermes/lib/VM/StringView.cpp", + "third_party/hermes/lib/VM/SymbolRegistry.cpp", + "third_party/hermes/lib/VM/TimeLimitMonitor.cpp", + "third_party/hermes/lib/VM/TwineChar16.cpp", + "third_party/hermes/lib/VM/VTable.cpp", + "third_party/hermes/lib/VM/detail/IdentifierHashTable.cpp", + "third_party/hermes/lib/VM/gcs/AlignedHeapSegment.cpp", + "third_party/hermes/lib/VM/gcs/AlignedStorage.cpp", + "third_party/hermes/lib/VM/gcs/CardTableNC.cpp", + "third_party/hermes/lib/VM/gcs/FillerCell.cpp", + "third_party/hermes/lib/VM/gcs/HadesGC.cpp", + ] } -source_set("hermes_hbc_backend") { - configs = [":new_build", ":hermes_build", ":llvm_build"] - sources = [ - "third_party/hermes/lib/BCGen/HBC/BackendContext.cpp", - "third_party/hermes/lib/BCGen/HBC/Bytecode.cpp", - "third_party/hermes/lib/BCGen/HBC/BytecodeDataProvider.cpp", - "third_party/hermes/lib/BCGen/HBC/BytecodeDisassembler.cpp", - "third_party/hermes/lib/BCGen/HBC/BytecodeFormConverter.cpp", - "third_party/hermes/lib/BCGen/HBC/BytecodeGenerator.cpp", - "third_party/hermes/lib/BCGen/HBC/BytecodeProviderFromSrc.cpp", - "third_party/hermes/lib/BCGen/HBC/BytecodeStream.cpp", - "third_party/hermes/lib/BCGen/HBC/ConsecutiveStringStorage.cpp", - "third_party/hermes/lib/BCGen/HBC/DebugInfo.cpp", - "third_party/hermes/lib/BCGen/HBC/HBC.cpp", - "third_party/hermes/lib/BCGen/HBC/ISel.cpp", - "third_party/hermes/lib/BCGen/HBC/Passes.cpp", - "third_party/hermes/lib/BCGen/HBC/Passes/FuncCallNOpts.cpp", - "third_party/hermes/lib/BCGen/HBC/Passes/InsertProfilePoint.cpp", - "third_party/hermes/lib/BCGen/HBC/Passes/LowerBuiltinCalls.cpp", - "third_party/hermes/lib/BCGen/HBC/Passes/OptEnvironmentInit.cpp", - "third_party/hermes/lib/BCGen/HBC/SerializedLiteralGenerator.cpp", - "third_party/hermes/lib/BCGen/HBC/SerializedLiteralParserBase.cpp", - "third_party/hermes/lib/BCGen/HBC/SimpleBytecodeBuilder.cpp", - "third_party/hermes/lib/BCGen/HBC/StringKind.cpp", - "third_party/hermes/lib/BCGen/HBC/TraverseLiteralStrings.cpp", - "third_party/hermes/lib/BCGen/HBC/UniquingFilenameTable.cpp", - "third_party/hermes/lib/BCGen/HBC/UniquingStringLiteralTable.cpp", - ] +source_set("hermes_vm_runtime_rtti") { + configs = [ + ":hermes_build", + ":llvm_build", + ":new_build", + ] + cflags_cc = [ + "-fno-exceptions", + "-frtti", + ] + if (ubsan) { + cflags_cc += [ "-fno-sanitize=vptr" ] + } + sources = [ + "third_party/hermes/lib/VM/DecoratedObject.cpp", + "third_party/hermes/lib/VM/HostModel.cpp", + ] } -source_set("hermes_internal_bytecode") { - configs = [":standard_build", ":hermes_build", ":llvm_build"] - defines = ["HERMES_CMAKE_BUILD"] - sources = ["third_party/hermes/lib/InternalBytecode/InternalBytecode.cpp"] +source_set("jsi") { + configs = [ ":new_build" ] + cflags_cc = [ + "-fexceptions", + "-frtti", # hermes_api 需要 rtti + ] + include_dirs = [ "third_party/react-native/ReactCommon/jsi" ] + sources = [ "third_party/react-native/ReactCommon/jsi/jsi/jsi.cpp" ] } -source_set("hermes_vm_runtime_rtti") { - configs = [":hermes_build", ":llvm_build", ":new_rtti_build"] - sources = [ - "third_party/hermes/lib/VM/HostModel.cpp", - "third_party/hermes/lib/VM/DecoratedObject.cpp" - ] +config("folly_build") { + defines = [ + "FOLLY_NO_CONFIG", + "FOLLY_MOBILE=1", + "FOLLY_USE_LIBCPP=1", + "FOLLY_HAVE_CLOCK_GETTIME=1", + ] + include_dirs = [ + "third_party/folly", + "third_party/include/folly", + ] } -source_set("hermes_vm_runtime") { - configs = [":hermes_build", ":new_build", ":llvm_build", ":dtoa_build"] - sources = [ - "third_party/hermes/lib/VM/ArrayStorage.cpp", - "third_party/hermes/lib/VM/BasicBlockExecutionInfo.cpp", - "third_party/hermes/lib/VM/BoxedDouble.cpp", - "third_party/hermes/lib/VM/BuildMetadata.cpp", - "third_party/hermes/lib/VM/Callable.cpp", - "third_party/hermes/lib/VM/CellKind.cpp", - "third_party/hermes/lib/VM/CheckHeapWellFormedAcceptor.cpp", - "third_party/hermes/lib/VM/CodeBlock.cpp", - "third_party/hermes/lib/VM/Debugger/Debugger.cpp", - "third_party/hermes/lib/VM/Deserializer.cpp", - "third_party/hermes/lib/VM/DictPropertyMap.cpp", - "third_party/hermes/lib/VM/Domain.cpp", - "third_party/hermes/lib/VM/GCBase.cpp", - "third_party/hermes/lib/VM/GCCell.cpp", - "third_party/hermes/lib/VM/HandleRootOwner.cpp", - "third_party/hermes/lib/VM/HeapSnapshot.cpp", - "third_party/hermes/lib/VM/HermesValue.cpp", - "third_party/hermes/lib/VM/HiddenClass.cpp", - "third_party/hermes/lib/VM/IdentifierTable.cpp", - "third_party/hermes/lib/VM/Interpreter-slowpaths.cpp", - "third_party/hermes/lib/VM/Interpreter.cpp", - "third_party/hermes/lib/VM/JSArray.cpp", - "third_party/hermes/lib/VM/JSArrayBuffer.cpp", - "third_party/hermes/lib/VM/JSCallableProxy.cpp", - "third_party/hermes/lib/VM/JSDataView.cpp", - "third_party/hermes/lib/VM/JSDate.cpp", - "third_party/hermes/lib/VM/JSError.cpp", - "third_party/hermes/lib/VM/JSGenerator.cpp", - "third_party/hermes/lib/VM/JSLib/Array.cpp", - "third_party/hermes/lib/VM/JSLib/ArrayBuffer.cpp", - "third_party/hermes/lib/VM/JSLib/ArrayIterator.cpp", - "third_party/hermes/lib/VM/JSLib/AsyncFunction.cpp", - "third_party/hermes/lib/VM/JSLib/Boolean.cpp", - "third_party/hermes/lib/VM/JSLib/DataView.cpp", - "third_party/hermes/lib/VM/JSLib/Date.cpp", - "third_party/hermes/lib/VM/JSLib/DateUtil.cpp", - "third_party/hermes/lib/VM/JSLib/DebuggerInternal.cpp", - "third_party/hermes/lib/VM/JSLib/Error.cpp", - "third_party/hermes/lib/VM/JSLib/Function.cpp", - "third_party/hermes/lib/VM/JSLib/GeneratorFunction.cpp", - "third_party/hermes/lib/VM/JSLib/GeneratorPrototype.cpp", - "third_party/hermes/lib/VM/JSLib/GlobalObject.cpp", - "third_party/hermes/lib/VM/JSLib/HermesBuiltin.cpp", - "third_party/hermes/lib/VM/JSLib/HermesInternal.cpp", - "third_party/hermes/lib/VM/JSLib/Instrument.cpp", - "third_party/hermes/lib/VM/JSLib/Intl.cpp", - "third_party/hermes/lib/VM/JSLib/IteratorPrototype.cpp", - "third_party/hermes/lib/VM/JSLib/JSLibInternal.cpp", - "third_party/hermes/lib/VM/JSLib/JSON.cpp", - "third_party/hermes/lib/VM/JSLib/JSONLexer.cpp", - "third_party/hermes/lib/VM/JSLib/Map.cpp", - "third_party/hermes/lib/VM/JSLib/Math.cpp", - "third_party/hermes/lib/VM/JSLib/Number.cpp", - "third_party/hermes/lib/VM/JSLib/Object.cpp", - "third_party/hermes/lib/VM/JSLib/Proxy.cpp", - "third_party/hermes/lib/VM/JSLib/Reflect.cpp", - "third_party/hermes/lib/VM/JSLib/RegExp.cpp", - "third_party/hermes/lib/VM/JSLib/RegExpStringIterator.cpp", - "third_party/hermes/lib/VM/JSLib/RuntimeCommonStorage.cpp", - "third_party/hermes/lib/VM/JSLib/RuntimeJSONUtils.cpp", - "third_party/hermes/lib/VM/JSLib/Set.cpp", - "third_party/hermes/lib/VM/JSLib/Sorting.cpp", - "third_party/hermes/lib/VM/JSLib/String.cpp", - "third_party/hermes/lib/VM/JSLib/StringIterator.cpp", - "third_party/hermes/lib/VM/JSLib/Symbol.cpp", - "third_party/hermes/lib/VM/JSLib/TypedArray.cpp", - "third_party/hermes/lib/VM/JSLib/WeakMap.cpp", - "third_party/hermes/lib/VM/JSLib/WeakSet.cpp", - "third_party/hermes/lib/VM/JSLib/escape.cpp", - "third_party/hermes/lib/VM/JSLib/eval.cpp", - "third_party/hermes/lib/VM/JSLib/print.cpp", - "third_party/hermes/lib/VM/JSLib/require.cpp", - "third_party/hermes/lib/VM/JSMapImpl.cpp", - "third_party/hermes/lib/VM/JSNativeFunctions.cpp", - "third_party/hermes/lib/VM/JSObject.cpp", - "third_party/hermes/lib/VM/JSProxy.cpp", - "third_party/hermes/lib/VM/JSRegExp.cpp", - "third_party/hermes/lib/VM/JSRegExpStringIterator.cpp", - "third_party/hermes/lib/VM/JSTypedArray.cpp", - "third_party/hermes/lib/VM/JSWeakMapImpl.cpp", - "third_party/hermes/lib/VM/LimitedStorageProvider.cpp", - "third_party/hermes/lib/VM/Metadata.cpp", - "third_party/hermes/lib/VM/Operations.cpp", - "third_party/hermes/lib/VM/OrderedHashMap.cpp", - "third_party/hermes/lib/VM/PredefinedStringIDs.cpp", - "third_party/hermes/lib/VM/PrimitiveBox.cpp", - "third_party/hermes/lib/VM/Profiler.cpp", - "third_party/hermes/lib/VM/Profiler/ChromeTraceSerializerPosix.cpp", - "third_party/hermes/lib/VM/Profiler/CodeCoverageProfiler.cpp", - "third_party/hermes/lib/VM/Profiler/InlineCacheProfiler.cpp", - "third_party/hermes/lib/VM/Profiler/SamplingProfilerPosix.cpp", - "third_party/hermes/lib/VM/PropertyAccessor.cpp", - "third_party/hermes/lib/VM/Runtime-profilers.cpp", - "third_party/hermes/lib/VM/Runtime.cpp", - "third_party/hermes/lib/VM/RuntimeModule.cpp", - "third_party/hermes/lib/VM/RuntimeStats.cpp", - "third_party/hermes/lib/VM/SegmentedArray.cpp", - "third_party/hermes/lib/VM/SerializedLiteralParser.cpp", - "third_party/hermes/lib/VM/Serializer.cpp", - "third_party/hermes/lib/VM/SingleObject.cpp", - "third_party/hermes/lib/VM/StackFrame.cpp", - "third_party/hermes/lib/VM/StackTracesTree.cpp", - "third_party/hermes/lib/VM/StorageProvider.cpp", - "third_party/hermes/lib/VM/StringPrimitive.cpp", - "third_party/hermes/lib/VM/StringRefUtils.cpp", - "third_party/hermes/lib/VM/StringView.cpp", - "third_party/hermes/lib/VM/SymbolRegistry.cpp", - "third_party/hermes/lib/VM/TimeLimitMonitor.cpp", - "third_party/hermes/lib/VM/TwineChar16.cpp", - "third_party/hermes/lib/VM/VTable.cpp", - "third_party/hermes/lib/VM/detail/IdentifierHashTable.cpp", - "third_party/hermes/lib/VM/gcs/AlignedHeapSegment.cpp", - "third_party/hermes/lib/VM/gcs/AlignedStorage.cpp", - "third_party/hermes/lib/VM/gcs/CardTableNC.cpp", - "third_party/hermes/lib/VM/gcs/FillerCell.cpp", - "third_party/hermes/lib/VM/gcs/HadesGC.cpp" - ] +source_set("jsi_dynamic") { + configs = [ + ":folly_build", + ":glog_build", + ":new_build", + ] + include_dirs = [ "third_party/react-native/ReactCommon/jsi" ] + cflags_cc = [ + "-fexceptions", + "-fno-rtti", + ] + sources = [ "third_party/react-native/ReactCommon/jsi/jsi/JSIDynamic.cpp" ] } -config("jsi_hermes_build") { - configs = [":jsi_build"] - include_dirs = ["third_party/hermes/API"] +source_set("hermes_api") { + configs = [ + ":hermes_build", + ":llvm_build", + ":new_build", + ] + cflags_cc = [ + "-fexceptions", + "-frtti", # std::function -> target 要求 rtti + ] + if (ubsan) { + cflags_cc += [ "-fno-sanitize=vptr" ] + } + include_dirs = [ + "third_party/hermes/API", + "third_party/react-native/ReactCommon/jsi", + ] + sources = [ "third_party/hermes/API/hermes/hermes.cpp" ] } -source_set("jsi_hermes") { - cflags_cc = ["-fvisibility=hidden"] - configs = [":hermes_build", ":llvm_build", ":jsi_hermes_build", ":new_exception_rtti_build"] - sources = [ - "third_party/hermes/API/hermes/DebuggerAPI.cpp", - "third_party/hermes/API/hermes/hermes.cpp", - ] +source_set("hermes_debugger_api") { + configs = [ + ":hermes_build", + ":llvm_build", + ":new_build", + ] + cflags_cc = [ + "-fno-exceptions", + "-frtti", # hermes_inspector -> Inspector.cpp 依赖 + ] + include_dirs = [ + "third_party/hermes/API", + "third_party/react-native/ReactCommon/jsi", + ] + sources = [ "third_party/hermes/API/hermes/DebuggerAPI.cpp" ] } -source_set("double_conversion") { - configs = [":minimal_size_build"] - sources = [ - "third_party/double-conversion/src/bignum-dtoa.cc", - "third_party/double-conversion/src/bignum.cc", - "third_party/double-conversion/src/strtod.cc", - "third_party/double-conversion/src/cached-powers.cc", - "third_party/double-conversion/src/diy-fp.cc", - "third_party/double-conversion/src/fast-dtoa.cc", - "third_party/double-conversion/src/fixed-dtoa.cc", - "third_party/double-conversion/src/double-conversion.cc" - ] +source_set("jsinspector") { + configs = [ + ":minimal_size_build", + ":new_build", + ] + sources = [ + "third_party/react-native/ReactCommon/jsinspector/InspectorInterfaces.cpp", + ] } -config("folly_build") { - configs = [":common_build"] - defines = ["FOLLY_NO_CONFIG", "FOLLY_MOBILE=1", "FOLLY_USE_LIBCPP=1"] - if (build_android) { - defines += ["FOLLY_HAVE_MEMRCHR=1"] - } - # 依赖 DoubleConversion glog - include_dirs = ["third_party/folly", "third_party/boost-for-react-native"] +source_set("double_conversion") { + configs = [ ":minimal_size_build" ] + cflags_cc = [ "-fvisibility=hidden" ] + sources = [ + "third_party/double-conversion/src/bignum-dtoa.cc", + "third_party/double-conversion/src/bignum.cc", + "third_party/double-conversion/src/cached-powers.cc", + "third_party/double-conversion/src/diy-fp.cc", + "third_party/double-conversion/src/double-conversion.cc", + "third_party/double-conversion/src/fast-dtoa.cc", + "third_party/double-conversion/src/fixed-dtoa.cc", + "third_party/double-conversion/src/strtod.cc", + ] } -source_set("folly_json") { - cflags_cc = ["-fvisibility=hidden"] - configs = [":folly_build", ":new_exception_rtti_build"] - sources = [ - "third_party/folly/folly/json.cpp", - "third_party/folly/folly/Unicode.cpp", - "third_party/folly/folly/Conv.cpp", - "third_party/folly/folly/Demangle.cpp", - "third_party/folly/folly/memory/detail/MallocImpl.cpp", - "third_party/folly/folly/String.cpp", - "third_party/folly/folly/dynamic.cpp", - "third_party/folly/folly/FileUtil.cpp", - "third_party/folly/folly/Format.cpp", - "third_party/folly/folly/net/NetOps.cpp", - "third_party/folly/folly/json_pointer.cpp", - "third_party/folly/folly/lang/CString.cpp", - "third_party/folly/folly/lang/SafeAssert.cpp", - "third_party/folly/folly/detail/Demangle.cpp", - "third_party/folly/folly/detail/UniqueInstance.cpp", - "third_party/folly/folly/hash/SpookyHashV2.cpp", - "third_party/folly/folly/container/detail/F14Table.cpp", - "third_party/folly/folly/ScopeGuard.cpp", - "third_party/folly/folly/portability/SysUio.cpp", - "third_party/folly/folly/lang/Assume.cpp" - ] +config("glog_build") { + include_dirs = [ + "third_party/include", + "third_party/include/glog", + ] + defines = [ + "DISABLE_RTTI", + "GOOGLE_NAMESPACE=google", + "HAVE_DLADDR", + "HAVE_FCNTL", + "HAVE_PREAD", + "HAVE_PTHREAD", + "HAVE_PWRITE", + "HAVE_RWLOCK", + "HAVE_SIGACTION", + "HAVE_SYS_SYSCALL_H", + "HAVE_SYS_TIME_H", + "HAVE_SYS_UTSNAME_H", + "HAVE_UNISTD_H", + "HAVE___ATTRIBUTE__", + "HAVE___SYNC_VAL_COMPARE_AND_SWAP", + "_END_GOOGLE_NAMESPACE_=}", + "_START_GOOGLE_NAMESPACE_=namespace google {", + ] } -source_set("folly_futures") { - cflags_cc = ["-fvisibility=hidden"] - configs = [":folly_build", ":new_exception_rtti_build"] - sources = [ - "third_party/folly/folly/ExceptionWrapper.cpp", - "third_party/folly/folly/Executor.cpp", - "third_party/folly/folly/SharedMutex.cpp", - "third_party/folly/folly/concurrency/CacheLocality.cpp", - "third_party/folly/folly/detail/AsyncTrace.cpp", - "third_party/folly/folly/detail/AtFork.cpp", - "third_party/folly/folly/detail/Futex.cpp", - "third_party/folly/folly/detail/MemoryIdler.cpp", - "third_party/folly/folly/detail/StaticSingletonManager.cpp", - "third_party/folly/folly/detail/ThreadLocalDetail.cpp", - "third_party/folly/folly/executors/ExecutorWithPriority.cpp", - "third_party/folly/folly/executors/InlineExecutor.cpp", - "third_party/folly/folly/executors/TimedDrivableExecutor.cpp", - "third_party/folly/folly/executors/QueuedImmediateExecutor.cpp", - "third_party/folly/folly/io/async/Request.cpp", - "third_party/folly/folly/memory/MallctlHelper.cpp", - "third_party/folly/folly/portability/SysMembarrier.cpp", - "third_party/folly/folly/synchronization/AsymmetricMemoryBarrier.cpp", - "third_party/folly/folly/synchronization/Hazptr.cpp", - "third_party/folly/folly/synchronization/ParkingLot.cpp", - "third_party/folly/folly/synchronization/WaitOptions.cpp" - ] +source_set("glog_source") { + configs = [ + ":minimal_size_build", + ":glog_build", + ] + sources = [ + "third_party/glog/src/demangle.cc", + "third_party/glog/src/logging.cc", + "third_party/glog/src/raw_logging.cc", + "third_party/glog/src/signalhandler.cc", + "third_party/glog/src/symbolize.cc", + "third_party/glog/src/utilities.cc", + "third_party/glog/src/vlog_is_on.cc", + ] } -source_set("jsinspector") { - configs = [":new_build"] - # Android 需要 getInspectorInstance 方法,而该方法没有被标记为 JSINSPECTOR_EXPORT,因此需要去除 -fvisibility=hidden - if (!build_android) { - cflags_cc = ["-fvisibility=hidden"] - } - sources = [ - "third_party/react-native/ReactCommon/jsinspector/InspectorInterfaces.cpp" - ] +config("fmt_build") { + include_dirs = [ "third_party/fmt/include" ] + defines = [ + "FMT_EXPORT", + "FMT_SHARED", + ] } -source_set("jsi_dynamic") { - cflags_cc = ["-fvisibility=hidden"] - configs = [":folly_build", ":jsi_build", ":new_exception_build"] - sources = ["third_party/hermes/API/jsi/jsi/JSIDynamic.cpp"] +source_set("fmt_source") { + configs = [ + ":fmt_build", + ":new_build", + ] + cflags_cc = [ + "-fno-exceptions", + "-frtti", # Folly 引用 fmt,Folly 强制开启 rtti + ] + sources = [ "third_party/fmt/src/format.cc" ] } -config("react_native_common_build") { - include_dirs = ["third_party/react-native/ReactCommon"] +source_set("folly") { + configs = [ + ":folly_build", + ":fmt_build", + ":glog_build", + ":new_build", + ] + cflags_cc = [ + "-fexceptions", + "-frtti", + ] + sources = [ + "third_party/folly/folly/Conv.cpp", + "third_party/folly/folly/Demangle.cpp", + "third_party/folly/folly/ExceptionString.cpp", + "third_party/folly/folly/ExceptionWrapper.cpp", + "third_party/folly/folly/Executor.cpp", + "third_party/folly/folly/Format.cpp", + "third_party/folly/folly/ScopeGuard.cpp", + "third_party/folly/folly/SharedMutex.cpp", + "third_party/folly/folly/String.cpp", + "third_party/folly/folly/Try.cpp", + "third_party/folly/folly/Unicode.cpp", + "third_party/folly/folly/concurrency/CacheLocality.cpp", + "third_party/folly/folly/detail/AsyncTrace.cpp", + "third_party/folly/folly/detail/AtFork.cpp", + "third_party/folly/folly/detail/Futex.cpp", + "third_party/folly/folly/detail/StaticSingletonManager.cpp", + "third_party/folly/folly/detail/ThreadLocalDetail.cpp", + "third_party/folly/folly/detail/UniqueInstance.cpp", + "third_party/folly/folly/dynamic.cpp", + "third_party/folly/folly/executors/InlineExecutor.cpp", + "third_party/folly/folly/executors/QueuedImmediateExecutor.cpp", + "third_party/folly/folly/futures/detail/Core.cpp", + "third_party/folly/folly/hash/SpookyHashV2.cpp", + "third_party/folly/folly/io/async/Request.cpp", + "third_party/folly/folly/json.cpp", + "third_party/folly/folly/json_pointer.cpp", + "third_party/folly/folly/lang/CString.cpp", + "third_party/folly/folly/lang/Exception.cpp", + "third_party/folly/folly/lang/SafeAssert.cpp", + "third_party/folly/folly/lang/ToAscii.cpp", + "third_party/folly/folly/memory/detail/MallocImpl.cpp", + "third_party/folly/folly/synchronization/AsymmetricMemoryBarrier.cpp", + "third_party/folly/folly/synchronization/Hazptr.cpp", + "third_party/folly/folly/synchronization/ParkingLot.cpp", + "third_party/folly/folly/synchronization/detail/Sleeper.cpp", + "third_party/folly/folly/system/ThreadId.cpp", + ] + if (is_debug) { + sources += [ "third_party/folly/folly/lang/Assume.cpp" ] + } } -source_set("hermes_inspector_napi") { - cflags_cc = ["-fvisibility=hidden"] - configs = [":hermes_build", ":jsi_hermes_build", ":react_native_common_build", ":new_exception_rtti_build"] - if (build_android) { - # Thread.cpp 需要 - configs += [":fbjni_build"] - } - sources = [ - "src/inspector/js_native_api_hermes_inspector.cpp" - ] +config("libevent_build") { + defines = [ + "EVENT__HAVE_UINT64_T", + "EVENT__HAVE_UINT32_T", + "EVENT__HAVE_UINT16_T", + "EVENT__NUMERIC_VERSION=0x02010c00", + ] + include_dirs = [ + "third_party/libevent/include", + "third_party/include/libevent", + ] } - source_set("hermes_inspector") { - cflags_cc = ["-fvisibility=hidden"] - configs = [":hermes_build", ":folly_build", ":jsi_hermes_build", ":react_native_common_build", ":new_exception_rtti_build"] - if (build_android) { - # Thread.cpp 需要 - configs += [":fbjni_build"] - } - sources = [ - "third_party/react-native/ReactCommon/hermes/inspector/Inspector.cpp", - "third_party/react-native/ReactCommon/hermes/inspector/InspectorState.cpp", - "third_party/react-native/ReactCommon/hermes/inspector/RuntimeAdapter.cpp", - "third_party/react-native/ReactCommon/hermes/inspector/chrome/AutoAttachUtils.cpp", - "third_party/react-native/ReactCommon/hermes/inspector/chrome/Connection.cpp", - "third_party/react-native/ReactCommon/hermes/inspector/chrome/ConnectionDemux.cpp", - "third_party/react-native/ReactCommon/hermes/inspector/chrome/MessageConverters.cpp", - "third_party/react-native/ReactCommon/hermes/inspector/chrome/MessageTypes.cpp", - "third_party/react-native/ReactCommon/hermes/inspector/chrome/Registration.cpp", - "third_party/react-native/ReactCommon/hermes/inspector/chrome/RemoteObjectsTable.cpp", - "third_party/react-native/ReactCommon/hermes/inspector/detail/CallbackOStream.cpp", - "third_party/react-native/ReactCommon/hermes/inspector/detail/SerialExecutor.cpp", - "third_party/react-native/ReactCommon/hermes/inspector/detail/Thread.cpp" - ] + configs = [ + ":folly_build", + ":glog_build", + ":libevent_build", + ":new_build", + ] + include_dirs = [ + "third_party/hermes/API", + "third_party/react-native/ReactCommon/jsi", + "third_party/react-native/ReactCommon", + "third_party/hermes/public", + ] + if (target_os == "android") { + include_dirs += [ "third_party/fbjni/cxx" ] + } + + # Folly 必须开启异常和 rtti + cflags_cc = [ + "-fexceptions", + "-frtti", + ] + defines = [ + "HERMES_ENABLE_DEBUGGER", + "HERMES_MEMORY_INSTRUMENTATION", # 虽然 RN 没有开启 + ] + sources = [ + "third_party/react-native/ReactCommon/hermes/inspector/Inspector.cpp", + "third_party/react-native/ReactCommon/hermes/inspector/InspectorState.cpp", + "third_party/react-native/ReactCommon/hermes/inspector/RuntimeAdapter.cpp", + "third_party/react-native/ReactCommon/hermes/inspector/chrome/AutoAttachUtils.cpp", + "third_party/react-native/ReactCommon/hermes/inspector/chrome/Connection.cpp", + "third_party/react-native/ReactCommon/hermes/inspector/chrome/ConnectionDemux.cpp", + "third_party/react-native/ReactCommon/hermes/inspector/chrome/MessageConverters.cpp", + "third_party/react-native/ReactCommon/hermes/inspector/chrome/MessageTypes.cpp", + "third_party/react-native/ReactCommon/hermes/inspector/chrome/Registration.cpp", + "third_party/react-native/ReactCommon/hermes/inspector/chrome/RemoteObjectsTable.cpp", + "third_party/react-native/ReactCommon/hermes/inspector/detail/CallbackOStream.cpp", + "third_party/react-native/ReactCommon/hermes/inspector/detail/SerialExecutor.cpp", + "third_party/react-native/ReactCommon/hermes/inspector/detail/Thread.cpp", + ] } -source_set("napi_hermes_source_set") { - cflags_cc = ["-std=c++14", "-fvisibility=hidden", "-Wno-unused-parameter", "-Wno-extra-semi", "-Wno-gnu-zero-variadic-macro-arguments", "-Wno-gnu-anonymous-struct", "-Wno-c99-extensions", "-Wno-nested-anon-types"] - if(build_ios){ - cflags_cc += ["-Wno-deprecated-copy"] - } - configs = [":llvm_build", ":hermes_build", ":strict_build", ":napi_build", ":react_native_common_build", ":jsi_hermes_build", ":rtti_build"] - sources = [ - # WithRuntimeDecorator 需要 RTTI - # 正常应当开启 RTTI,是因为 HostModel,JSI 使用了该特性,N-API 实际上没有使用 - "src/js_native_api_hermes.cpp" - ] +source_set("napi_hermes") { + configs = [ + ":minimal_size_build", + ":strict_build", + ":hermes_build", + ":llvm_build", + ":new_build", + ] + include_dirs = [ + "include", + "third_party/hermes/API", + "third_party/react-native/ReactCommon/jsi", + "third_party/react-native/ReactCommon", + ] + cflags_cc = [ + "-Wno-unused-parameter", + "-Wno-gnu-anonymous-struct", + "-Wno-gnu-zero-variadic-macro-arguments", + "-Wno-c99-extensions", + "-Wno-extra-semi", + "-Wno-nested-anon-types", + ] + sources = [ + "src/hermes/External.cpp", + "src/hermes/FunctionInfo.cpp", + "src/hermes/HermesExecutorRuntimeAdapter.cpp", + "src/hermes/OpaqueNAPICallbackInfo.cpp", + "src/hermes/OpaqueNAPIEnv.cpp", + "src/hermes/OpaqueNAPIEscapableHandleScope.cpp", + "src/hermes/OpaqueNAPIHandleScope.cpp", + "src/hermes/OpaqueNAPIRef.cpp", + "src/hermes/js_native_api_hermes_inspector.cpp", + "src/js_native_api_hermes.cpp", + ] } -config("napi_build") { - include_dirs = [ - "include" - ] +source_set("napi_common") { + configs = [ ":strict_build" ] + include_dirs = [ "include" ] + cflags_c = [ "-fvisibility=hidden" ] + sources = [ "src/js_native_api_common.c" ] } -config("quickjs_build") { - include_dirs = [ - "third_party/quickjs" +if (target_os == "android") { + source_set("fbjni") { + cflags_cc = [ + "-fexceptions", + "-frtti", + "-fvisibility=hidden", ] - # TBD(ChasonTang): 是否可以干掉? - cflags_c = ["-funsigned-char"] -} - -source_set("cutils") { - configs = [":quickjs_build"] + include_dirs = [ "third_party/fbjni/cxx" ] sources = [ - "third_party/quickjs/cutils.c", + "third_party/fbjni/cxx/fbjni/ByteBuffer.cpp", + "third_party/fbjni/cxx/fbjni/OnLoad.cpp", + "third_party/fbjni/cxx/fbjni/ReadableByteChannel.cpp", + "third_party/fbjni/cxx/fbjni/detail/Environment.cpp", + "third_party/fbjni/cxx/fbjni/detail/Exceptions.cpp", + "third_party/fbjni/cxx/fbjni/detail/Hybrid.cpp", + "third_party/fbjni/cxx/fbjni/detail/Meta.cpp", + "third_party/fbjni/cxx/fbjni/detail/References.cpp", + "third_party/fbjni/cxx/fbjni/detail/utf8.cpp", + "third_party/fbjni/cxx/fbjni/fbjni.cpp", + "third_party/fbjni/cxx/lyra/cxa_throw.cpp", + "third_party/fbjni/cxx/lyra/lyra.cpp", + "third_party/fbjni/cxx/lyra/lyra_breakpad.cpp", + "third_party/fbjni/cxx/lyra/lyra_exceptions.cpp", ] -} - -source_set("unicode") { - configs = [":quickjs_build"] - sources = [ - "third_party/quickjs/libunicode.c" + } + shared_library("qjs") { + libs = [ "m" ] + deps = [ + ":napi_common", + ":napi_qjs", + ":quickjs", ] -} - -source_set("regexp") { - configs = [":quickjs_build"] - sources = [ - "third_party/quickjs/libregexp.c" + } + shared_library("hermes") { + libs = [ + "c++", + "log", + "m", ] -} - -source_set("bf") { - configs = [":quickjs_build"] - sources = [ - "third_party/quickjs/libbf.c" + deps = [ + ":double_conversion", + ":dtoa", + ":fbjni", + ":fmt_source", + ":folly", + ":glog_source", + ":hermes_adt", + ":hermes_api", + ":hermes_ast", + ":hermes_backend", + ":hermes_debugger_api", + ":hermes_frontend", + ":hermes_frontend_defs", + ":hermes_hbc_backend", + ":hermes_inspector", + ":hermes_inst", + ":hermes_internal_bytecode", + ":hermes_optimizer", + ":hermes_parser", + ":hermes_platform", + ":hermes_platform_unicode", + ":hermes_regex", + ":hermes_source_map", + ":hermes_support", + ":hermes_vm_runtime", + ":hermes_vm_runtime_rtti", + ":jsi", + ":jsi_dynamic", + ":jsinspector", + ":llvm_support", + ":napi_hermes", ] -} + } +} else { + source_set("napi_jsc") { + configs = [ ":strict_build" ] + include_dirs = [ "include" ] + cflags_c = [ "-fvisibility=hidden" ] + frameworks = [ "JavaScriptCore.framework" ] + sources = [ "src/js_native_api_jsc.c" ] + } + if (target_os == "ios") { + static_library("jsc") { + complete_static_lib = true + deps = [ + ":napi_common", + ":napi_jsc", + ] + } -source_set("quickjs_source_set") { - configs = [":quickjs_build"] - defines = ["CONFIG_VERSION=\"2021-03-27\""] - sources = [ - "third_party/quickjs/quickjs.c", - ] -} -source_set("napi_common") { - configs = [":napi_build"] - cflags_c = ["-fvisibility=hidden"] - sources = ["src/js_native_api_common.c"] -} -source_set("napi_qjs_source_set") { - configs = [ - ":quickjs_build", - ":napi_build", - ":strict_build" - ] - cflags_c = ["-fvisibility=hidden", "-Wno-unused-parameter", "-Wno-pedantic"] - sources = [ - "src/js_native_api_qjs.c", - ] -} -if (build_android) { - source_set("fbjni") { - # Android 工具链默认 -ffunction-sections - # 默认 Android 工具链使用 gnu++14 - cflags_cc = ["-fno-omit-frame-pointer"] - configs = [":fbjni_build", ":new_exception_rtti_build"] - defines = ["DISABLE_CPUCAP", "DISABLE_XPLAT"] - sources = [ - "third_party/hermes/first-party/fbjni/cxx/fbjni/ByteBuffer.cpp", - "third_party/hermes/first-party/fbjni/cxx/fbjni/OnLoad.cpp", - "third_party/hermes/first-party/fbjni/cxx/fbjni/ReadableByteChannel.cpp", - "third_party/hermes/first-party/fbjni/cxx/fbjni/fbjni.cpp", - "third_party/hermes/first-party/fbjni/cxx/fbjni/detail/Environment.cpp", - "third_party/hermes/first-party/fbjni/cxx/fbjni/detail/Exceptions.cpp", - "third_party/hermes/first-party/fbjni/cxx/fbjni/detail/Hybrid.cpp", - "third_party/hermes/first-party/fbjni/cxx/fbjni/detail/Meta.cpp", - "third_party/hermes/first-party/fbjni/cxx/fbjni/detail/References.cpp", - "third_party/hermes/first-party/fbjni/cxx/fbjni/detail/utf8.cpp", - "third_party/hermes/first-party/fbjni/cxx/lyra/cxa_throw.cpp", - "third_party/hermes/first-party/fbjni/cxx/lyra/lyra.cpp", - "third_party/hermes/first-party/fbjni/cxx/lyra/lyra_breakpad.cpp", - "third_party/hermes/first-party/fbjni/cxx/lyra/lyra_exceptions.cpp" - ] + static_library("qjs") { + complete_static_lib = true + deps = [ + ":napi_common", + ":napi_qjs", + ":quickjs", + ] } - shared_library("qjs") { - # Android 已有 libquickjs.so,改名 - deps = [":quickjs_source_set", ":cutils", ":unicode", ":regexp", ":napi_common", ":napi_qjs_source_set"] - ldflags = ["-lm"] - if (big_number) { - deps += [":bf"] - } + + static_library("hermes") { + complete_static_lib = true + deps = [ + ":double_conversion", + ":dtoa", + ":fmt_source", + ":folly", + ":glog_source", + ":hermes_adt", + ":hermes_api", + ":hermes_ast", + ":hermes_backend", + ":hermes_debugger_api", + ":hermes_frontend", + ":hermes_frontend_defs", + ":hermes_hbc_backend", + ":hermes_inspector", + ":hermes_inst", + ":hermes_internal_bytecode", + ":hermes_optimizer", + ":hermes_parser", + ":hermes_platform", + ":hermes_platform_unicode", + ":hermes_regex", + ":hermes_source_map", + ":hermes_support", + ":hermes_vm_runtime", + ":hermes_vm_runtime_rtti", + ":jsi", + ":jsi_dynamic", + ":jsinspector", + ":llvm_support", + ":napi_common", + ":napi_hermes", + ] } - shared_library("hermes") { - ldflags = ["-lc++", "-lm", "-llog"] - deps = [ - ":llvm_demangle", - ":llvm_support", - ":hermes_frontend", - ":hermes_optimizer", - ":hermes_inst", - ":hermes_frontend_defs", - ":hermes_ast", - ":hermes_adt", - ":hermes_parser", - ":hermes_source_map", - ":hermes_support", - ":hermes_backend", - ":hermes_hbc_backend", - ":hermes_regex", - ":hermes_platform", - ":hermes_platform_unicode", - ":hermes_platform_unicode_java", - ":dtoa", - ":hermes_internal_bytecode", - ":hermes_vm_runtime_rtti", - ":hermes_vm_runtime", - ":fbjni", - ":jsi", - ":jsi_hermes", - ":hermes_inspector_napi", - - ":hermes_inspector", - ":folly_json", - ":folly_futures", - ":double_conversion", - ":jsi_dynamic", - ":jsinspector", - - ":napi_common", - ":napi_hermes_source_set", - ] + } else { + source_set("gtest") { + testonly = true + configs = [ ":minimal_size_build" ] + include_dirs = [ + "third_party/googletest/googletest/include", + "third_party/googletest/googletest", + ] + cflags_cc = [ + "-fvisibility=hidden", + "-std=c++20", + ] + sources = [ + "third_party/googletest/googletest/src/gtest-assertion-result.cc", + "third_party/googletest/googletest/src/gtest-death-test.cc", + "third_party/googletest/googletest/src/gtest-filepath.cc", + "third_party/googletest/googletest/src/gtest-matchers.cc", + "third_party/googletest/googletest/src/gtest-port.cc", + "third_party/googletest/googletest/src/gtest-printers.cc", + "third_party/googletest/googletest/src/gtest-test-part.cc", + "third_party/googletest/googletest/src/gtest-typed-test.cc", + "third_party/googletest/googletest/src/gtest.cc", + ] } -} else { - source_set("napi_jsc_source_set") { - configs = [ - ":napi_build", - ":strict_build" - ] - cflags_c = ["-fvisibility=hidden"] - frameworks = [ "JavaScriptCore.framework" ] - sources = [ - "src/js_native_api_jsc.c", - ] + + source_set("test") { + testonly = true + include_dirs = [ + "test/include", + "include", + "third_party/googletest/googletest/include", + ] + cflags_cc = [ + "-fvisibility=hidden", + "-std=c++20", + ] + configs = [ + ":minimal_size_build", + ":strict_build", + ] + sources = [ + "test/callable.cpp", + "test/conversion.cpp", + "test/general.cpp", + "test/object.cpp", + "test/reference.cpp", + "test/test.cpp", + "test/typeof.cpp", + ] + deps = [ ":gtest" ] } - if (build_ios) { - static_library("quickjs") { - complete_static_lib = true - deps = [":napi_qjs_source_set", ":napi_common", ":quickjs_source_set", ":cutils", ":unicode", ":regexp"] - if (big_number) { - deps += [":bf"] - } - } - static_library("jsc") { - complete_static_lib = true - deps = [":napi_jsc_source_set", ":napi_common"] - } - static_library("hermes") { - complete_static_lib = true - deps = [ - ":llvm_demangle", - ":llvm_support", - ":hermes_frontend", - ":hermes_optimizer", - ":hermes_inst", - ":hermes_frontend_defs", - ":hermes_ast", - ":hermes_adt", - ":hermes_parser", - ":hermes_source_map", - ":hermes_support", - ":hermes_backend", - ":hermes_hbc_backend", - ":hermes_regex", - ":hermes_platform", - ":hermes_platform_unicode", - ":dtoa", - ":hermes_internal_bytecode", - ":hermes_vm_runtime_rtti", - ":hermes_vm_runtime", - ":jsi", - ":jsi_hermes", - ":hermes_inspector_napi", - - ":hermes_inspector", - ":folly_json", - ":folly_futures", - ":double_conversion", - ":jsi_dynamic", - ":jsinspector", - - ":napi_hermes_source_set", - ":napi_common" - ] - } - } else { - config("gtest_build") { - defines = ["GTEST_HAS_EXCEPTIONS=0", "GTEST_HAS_RTTI=0"] - include_dirs = [ - "third_party/googletest/googletest/include" - ] - } - source_set("test") { - testonly = true - include_dirs = [ - "test/include" - ] - cflags_cc = ["-fvisibility=hidden"] - configs = [":napi_build", ":standard_build", ":gtest_build"] - sources = [ - "test/test.cpp", - "test/general.cpp", - "test/typeof.cpp", - "test/conversion.cpp", - "test/object.cpp", - "test/callable.cpp", - "test/reference.cpp" - ] - deps = [ - ":gtest", - ] - } - - executable("test_jsc") { - testonly = true - ldflags = ["-lc++"] - deps = [ - ":test", - ":napi_jsc_source_set", - ":napi_common" - ] - } - - executable("test_qjs") { - testonly = true - ldflags = ["-lc++"] - deps = [ - ":test", - ":napi_qjs_source_set", - ":napi_common", - ":quickjs_source_set", - ":cutils", - ":unicode", - ":regexp", - ] - } - - executable("test_hermes") { - testonly = true - ldflags = ["-lc++"] - deps = [ - ":test", - ":napi_hermes_source_set", - ":napi_common", - - ":llvm_demangle", - ":llvm_support", - ":hermes_frontend", - ":hermes_optimizer", - ":hermes_inst", - ":hermes_frontend_defs", - ":hermes_ast", - ":hermes_adt", - ":hermes_parser", - ":hermes_source_map", - ":hermes_support", - ":hermes_backend", - ":hermes_hbc_backend", - ":hermes_regex", - ":hermes_platform", - ":hermes_platform_unicode", - ":dtoa", - ":hermes_internal_bytecode", - ":hermes_vm_runtime_rtti", - ":hermes_vm_runtime", - ":jsi", - ":jsi_hermes", - ":hermes_inspector_napi", - - ":hermes_inspector", - ":folly_json", - ":folly_futures", - ":double_conversion", - ":jsi_dynamic", - ":jsinspector", - ] - } - - source_set("gtest") { - testonly = true - cflags_cc = ["-fvisibility=hidden"] - sources = [ - "third_party/googletest/googletest/src/gtest-death-test.cc", - "third_party/googletest/googletest/src/gtest-filepath.cc", - "third_party/googletest/googletest/src/gtest-matchers.cc", - "third_party/googletest/googletest/src/gtest-port.cc", - "third_party/googletest/googletest/src/gtest-printers.cc", - "third_party/googletest/googletest/src/gtest-test-part.cc", - "third_party/googletest/googletest/src/gtest-typed-test.cc", - "third_party/googletest/googletest/src/gtest.cc", - ] - configs = [":gtest_build", ":standard_build"] - # Some files include "src/gtest-internal-inl.h". - include_dirs = [ "third_party/googletest/googletest" ] - } + + executable("test_jsc") { + testonly = true + libs = [ "c++" ] + deps = [ + ":napi_common", + ":napi_jsc", + ":test", + ] } -} \ No newline at end of file + + executable("test_qjs") { + testonly = true + libs = [ "c++" ] + deps = [ + ":napi_common", + ":napi_qjs", + ":quickjs", + ":test", + ] + } + + executable("test_hermes") { + testonly = true + libs = [ + "c++", + "c++abi", + ] + deps = [ + ":double_conversion", + ":dtoa", + ":fmt_source", + ":folly", + ":glog_source", + ":hermes_adt", + ":hermes_api", + ":hermes_ast", + ":hermes_backend", + ":hermes_debugger_api", + ":hermes_frontend", + ":hermes_frontend_defs", + ":hermes_hbc_backend", + ":hermes_inspector", + ":hermes_inst", + ":hermes_internal_bytecode", + ":hermes_optimizer", + ":hermes_parser", + ":hermes_platform", + ":hermes_platform_unicode", + ":hermes_regex", + ":hermes_source_map", + ":hermes_support", + ":hermes_vm_runtime", + ":hermes_vm_runtime_rtti", + ":jsi", + ":jsi_dynamic", + ":jsinspector", + ":llvm_support", + ":napi_common", + ":napi_hermes", + ":test", + ] + } + } +} diff --git a/BUILDCONFIG.gn b/BUILDCONFIG.gn deleted file mode 100644 index 6e06bb2..0000000 --- a/BUILDCONFIG.gn +++ /dev/null @@ -1,36 +0,0 @@ -declare_args() { - # -g - debug_info = true - # -Os/-O0 - debug = false - # 只有 debug=false 的情况才生效 - lto = true - # iOS 平台不开启 lto 的情况下才生效,和 debug 无关 - bitcode = true - - # 是否交叉编译 Android 动态库 - build_android = false - # NDK 路径 - ndk_path = "~/Library/Android/sdk/ndk/21.4.7075529" - - # 交叉编译 iOS Android 生效 - cross_compile_target = "x86_64" - - # 暂时只对 clang 工具链有效 - code_coverage = false - asan = false - ubsan = false - - # iOS 交叉编译,否则编译 macOS 版本 - build_ios = false - # 和 -apple-ios9.0 拼接,作为 -target 参数 - - # QuickJS 专属 - big_number = false -} - -if (build_android) { - set_default_toolchain("//toolchain:android") -} else { - set_default_toolchain("//toolchain:clang") -} \ No newline at end of file diff --git a/LICENSE b/LICENSE index d645695..6caf10b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,202 +1,9 @@ +MIT License - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +Copyright (c) 2021 Chason Tang - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +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: - 1. Definitions. +The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. +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/README.md b/README.md index 190d624..7271ad1 100644 --- a/README.md +++ b/README.md @@ -1,104 +1,77 @@ -## N-API - -Node-API(以前称为 N-API)是一个用于和 JavaScript 引擎交互并独立于 JavaScript 运行时的 API 接口层,旨在将 C 原生代码和 JavaScript 引擎隔离开来。API 通常用于创建和操作 -JavaScript 值,概念和操作通常映射到 ECMA-262 语言规范,API 具有以下特点: +## 介绍 +Node-API(以前称为 N-API)是一个用于和 JavaScript 引擎交互并独立于 JavaScript 运行时的 API 接口层,旨在将 C 原生代码和 JavaScript 引擎隔离开来。API 通常用于创建和操作 JavaScript 值,概念和操作通常映射到 ECMA-262 语言规范,API 具有以下特点: 1. 所有节点API调用都返回类型为 NAPI{Common|Error|Exception}Status 的状态代码。此状态指示 API 调用是成功还是失败。 2. NAPICommonStatus 类型的接口一般情况下不需要检查返回值,NAPIErrorStatus 接口可能抛出内存分配失败错误,NAPIExceptionStatus 代表可能抛出 JavaScript 异常 3. API 的返回值通过 out 参数传递。 4. 所有 JavaScript 值都抽象在一个名为 NAPIValue 的不透明类型后面。 -5. 如果出现 NAPIExceptionPendingException 说明出现 JS 异常,可以通过 napi_get_and_clear_last_exception 获取,或通过 NAPIClearLastException 清除 - -## 代码静态分析 - -### JavaScriptCore - -1. `clang --analyze src/js_native_api_jsc.c --analyzer-output html -o ./static_analyze_report -I./include` - -### QuickJS +5. 如果出现 NAPIExceptionPendingException 说明出现 JS 异常,可以通过 napi_get_and_clear_last_exception 获取或清除。 +6. 内存管理分为栈式和引用计数式两种,大部分情况下栈式自动管理就足够。 -1. `clang --analyze src/js_native_api_qjs.c --analyzer-output html -o ./static_analyze_report -I./include -I./third_party/quickjs` +## Boost +由于 Folly 依赖了 Boost,而 Boost 本身为模块化仓库管理源代码,代码量非常大,因此需要先提前下载,地址为 `https://boostorg.jfrog.io/artifactory/main/release/1.76.0/source/boost_1_76_0.tar.gz` 然后解压后将 boost 文件夹移动到 third_party/include/folly 目录下。 -### Hermes +## 编辑器 +1. VSCode + clangd -1. `clang++ --analyze src/js_native_api_hermes.cpp --analyzer-output html -o ./static_analyze_report -I./include -I./third_party/hermes/include -I./third_party/hermes/public -DHERMESVM_GC_NONCONTIG_GENERATIONAL -DHERMESVM_ALLOW_COMPRESSED_POINTERS -DHERMES_ENABLE_DEBUGGER -std=c++17 -I./third_party/include -I./third_party/hermes/external/llvh/include -I./third_party/hermes/external/llvh/gen/include -I./third_party/hermes/API -I./third_party/hermes/API/jsi -I./third_party/react-native/ReactCommon` +## VSCode 配置工程 +1. gn 添加 --export-compile-commands 即可导出,可能需要设置 VSCode clangd 插件配置,以及单独导入子工程。 ## 单元测试 - -1. `gn gen out --args="debug=true asan=true ubsan=true"`(Release 模式下 assert 失效,会隐藏很多问题,特殊情况下启用 asan + ubsan) -2. `ninja -C out test_{qjs|jsc|hermes}` +1. `gn gen out --args="is_debug=true asan=true ubsan=true"`(Release 模式下 assert 失效,会隐藏很多问题,特殊情况下启用 asan + ubsan) +2. `ninja -C out test_{qjs,jsc,hermes}` 3. `./out/test_{qjs|jsc|hermes}` ### QuickJS 单元测试修改源代码部分 - 1. ubsan/asan 对于 QuickJS 开启,需要注释掉 CONFIG_STACK_CHECK,否则会报告 InternalError: stack overflow 2. QuickJS 单元测试建议开启 DUMP_LEAKS ### Hermes 单元测试修改源代码部分 - 1. include/hermes/VM/HandleRootOwner.h 修改 HERMESVM_DEBUG_MAX_GCSCOPE_HANDLES 为 2^16-1 -> 65535 -## 编辑器配置 - -1. 推荐使用 CLion -2. VSCode - -### CLion - -1. `gn gen clion --ide=json --json-ide-script=../gn_to_cmake.py --script-executable=python3` - -### VSCode - -1. C/C++ 插件 -2. 自行配置头文件搜索路径 - ## 交叉编译 1. `rm -rf napi` 2. `mkdir napi` 3. `cp -r include napi` 4. `cp -r third_party/react-native/ReactCommon/cxxreact/MessageQueueThread.h include/napi` -5. `tar czvf napi.tar.gz -C napi .` 压缩产物 +5. `tar czvf napi.tar.gz -C napi .` 压缩产物。 ### iOS 静态库 -1. `gn gen x86_64 --args="build_ios=true"` -2. `gn gen armv7 --args="build_ios=true cross_compile_target=\"armv7\""` -3. `gn gen arm64 --args="build_ios=true cross_compile_target=\"arm64\""` -4. `ninja -C x86_64 quickjs jsc && ninja -C armv7 quickjs jsc && ninja -C arm64 quickjs jsc` -5. `gn gen x86_64 --args="build_ios=true debug_info=false lto=false bitcode=false"` -6. `gn gen armv7 --args="build_ios=true cross_compile_target=\"armv7\" debug_info=false lto=false bitcode=false"` -7. `gn gen arm64 --args="build_ios=true cross_compile_target=\"arm64\" debug_info=false lto=false bitcode=false"` -8. `ninja -C x86_64 hermes && ninja -C armv7 hermes && ninja -C hermes` -9. `libtool -static x86_64/obj/libquickjs.a armv7/obj/libquickjs.a arm64/obj/libquickjs.a -o napi/libquickjs.a && libtool -static x86_64/obj/libhermes.a armv7/obj/libhermes.a arm64/obj/libhermes.a -o napi/libhermes.a && libtool -static x86_64/obj/libjsc.a armv7/obj/libjsc.a arm64/obj/libjsc.a -o napi/libjsc.a` +1. `gn gen x64 --args='target_os="ios" target_cpu="x64"'` +2. `gn gen arm64 --args='target_os="ios" target_cpu=\"arm64\"'` +3. `ninja -C x64 quickjs jsc && ninja -C arm64 quickjs jsc` +4. `libtool -static x64/obj/libquickjs.a arm64/obj/libquickjs.a -o napi/libquickjs.a && libtool -static x64/obj/libjsc.a arm64/obj/libjsc.a -o napi/libjsc.a` +5. `gn gen x64 --args='target_os="ios" target_cpu="x64" generate_dwarf=false lto=false'` +6. `gn gen arm64 --args='target_os="ios" target_cpu=\"arm64\" generate_dwarf=false lto=false'` +7. `ninja -C x64 hermes && ninja -C arm64 hermes` +8. `libtool -static x64/obj/libhermes.a arm64/obj/libhermes.a -o napi/libhermes.a` ### Android 动态库 -1. `gn gen armv7 --args="build_android=true cross_compile_target=\"armv7\""` -2. `gn gen arm64 --args="build_android=true cross_compile_target=\"arm64\""` -3. `gn gen i386 --args="build_android=true cross_compile_target=\"i386\""` -4. `gn gen x86_64 --args="build_android=true cross_compile_target=\"x86_64\""` -5. `ninja -C armv7 qjs hermes && ninja -C arm64 qjs hermes && ninja -C i386 qjs hermes && ninja -C x86_64 qjs hermes` +1. `gn gen arm --args='target_os="android" target_cpu="arm"'` +2. `gn gen arm64 --args='target_os="android" target_cpu="arm64"'` +3. `gn gen x86 --args='target_os="android" target_cpu="x86"'` +4. `gn gen x64 --args='target_os="android" target_cpu="x64"'` +5. `ninja -C arm qjs hermes && ninja -C arm64 qjs hermes && ninja -C x86 qjs hermes && ninja -C x64 qjs hermes` 6. `mkdir -p napi/libs/armeabi-v7a && mkdir -p napi/libs/arm64-v8a && mkdir -p napi/libs/x86 && mkdir -p napi/libs/x86_64` -7. `cp armv7/obj/lib{hermes,qjs}.so napi/libs/armeabi-v7a && cp arm64/obj/lib{hermes,qjs}.so napi/libs/arm64-v8a && cp i386/obj/lib{hermes,qjs}.so napi/libs/x86 && cp x86_64/obj/lib{hermes,qjs}.so napi/libs/x86_64` +7. `cp arm/obj/lib{hermes,qjs}.so napi/libs/armeabi-v7a && cp arm64/obj/lib{hermes,qjs}.so napi/libs/arm64-v8a && cp x86/obj/lib{hermes,qjs}.so napi/libs/x86 && cp x64/obj/lib{hermes,qjs}.so napi/libs/x86_64` #### 交叉编译注意 - 1. macOS shell 对文件描述符有限制,默认限制 256,会导致链接出问题,可以通过 `ulimit -a` 查看,可以通过 `ulimit -S -n 4096` 临时修改 #### 注意 - 1. 建议使用 BUILDCONFIG.gn 中定义的 LTS NDK 版本 -2. Hermes 引擎需要先 `cd third_party/hermes && git apply ../hermes_patch.diff` +2. Hermes 引擎需要先 `cd third_party/hermes && git apply ../hermes_patch.diff && cd ../glog && git apply ../glog_patch.diff` 3. Android 版本 libhermes.so 包括 fbjni 库,内含 OnLoad.cpp,需要使用 System.load("hermes") 显式加载,不能依赖 Linux 内核的动态库隐式加载 -4. Hermes 引擎 0.8.1 版本内置字节码,需要先编译主机 hermesc,指令 `./utils/build/configure.py`,后输入如下命令 +4. Hermes 引擎 0.8.x 版本内置字节码,需要先编译主机 hermesc,指令 `./utils/build/build-mac-framework.sh`,后输入如下命令 ``` > cd lib/InternalBytecode > cat 00-header.js 01-Promise.js 02-AsyncFn.js 99-footer.js > InternalBytecode.js -> ../../build/bin/hermesc -O -Wno-undefined-variable -fno-enable-tdz -emit-binary -out=./InternalBytecode.hbc ./InternalBytecode.js -> ./xxd.py ./InternalBytecode.hbc > ./InternalBytecode.inc +> ../../build_host_hermesc/bin/hermesc -O -Wno-undefined-variable -emit-binary -out=InternalBytecode.hbc InternalBytecode.js +> python3 xxd.py InternalBytecode.hbc > InternalBytecode.inc ``` ## 注意事项 - 1. 只能在单一线程执行,不跨多线程执行,JavaScriptCore 通过锁机制保证同步,但是其他引擎很可能没有该保证 diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn new file mode 100644 index 0000000..0c1d526 --- /dev/null +++ b/build/config/BUILDCONFIG.gn @@ -0,0 +1,51 @@ +if (target_os == "") { + target_os = host_os +} +if (target_cpu == "") { + target_cpu = host_cpu +} + +if (current_cpu == "") { + current_cpu = target_cpu +} +if (current_os == "") { + current_os = target_os +} + +assert(current_os == "android" || current_os == "ios" || current_os == "mac", + "Unsupported target os.") +if (current_os == "ios" || current_os == "mac") { + assert(current_cpu == "arm64" || current_cpu == "x64", + "Unsupported target cpu.") +} else { + assert(current_cpu == "arm" || current_cpu == "arm64" || + current_cpu == "x86" || current_cpu == "x64", + "Unsupported target cpu.") +} + +if (current_os == "android") { + set_default_toolchain("//build/toolchain:android") +} else { + set_default_toolchain("//build/toolchain:clang") +} + +declare_args() { + generate_dwarf = true + is_debug = false + + if (current_os == "android") { + ndk_path = "~/Library/Android/sdk/ndk/21.4.7075529" + } else if (current_os == "mac") { + collect_code_coverage = false + } + asan = false + ubsan = false + + enable_qjs_big_number = false +} + +declare_args() { + if (!is_debug) { + lto = true + } +} diff --git a/build/toolchain/BUILD.gn b/build/toolchain/BUILD.gn new file mode 100644 index 0000000..1043351 --- /dev/null +++ b/build/toolchain/BUILD.gn @@ -0,0 +1,134 @@ +depfile_string = "{{output}}.d" +compiler_command = "-c {{source}} -o {{output}} -fPIC -funwind-tables -MMD -MF $depfile_string {{include_dirs}} {{defines}} {{cflags}}" +if (generate_dwarf) { + compiler_command = "-g $compiler_command" +} +linker_command = "" +if (asan) { + compiler_command = "-fsanitize=address $compiler_command" + linker_command = "-fsanitize=address $linker_command" +} +if (ubsan) { + compiler_command = "-fsanitize=undefined $compiler_command" + linker_command = "-fsanitize=undefined $linker_command" +} + +if (!is_debug) { + compiler_command = "-Os -DNDEBUG $compiler_command" + if (lto) { + compiler_command = "-flto $compiler_command" + linker_command = "-flto $linker_command" + } +} else { + compiler_command = "-O0 $compiler_command" +} + +if (target_os == "android") { + toolchain("android") { + compiler_command = "--sysroot $ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/sysroot $compiler_command" + + if (current_cpu == "arm") { + target_option = "-target armv7-none-linux-androideabi18 -mthumb" + } else if (current_cpu == "arm64") { + target_option = "-target aarch64-none-linux-android21" + } else if (current_cpu == "x86") { + target_option = "-target i686-none-linux-android18" + } else { + target_option = "-target x86_64-none-linux-android21" + } + + compiler_command = "$target_option $compiler_command" + if (linker_command == "") { + linker_command = target_option + } else { + linker_command = "$target_option $linker_command" + } + + tool("cc") { + command = "$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang $compiler_command {{cflags_c}}" + depfile = depfile_string + depsformat = "gcc" + outputs = [ "{{source_out_dir}}/{{source_name_part}}.o" ] + } + tool("cxx") { + command = "$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++ $compiler_command {{cflags_cc}}" + depfile = depfile_string + depsformat = "gcc" + outputs = [ "{{source_out_dir}}/{{source_name_part}}.o" ] + } + tool("stamp") { + command = "touch {{output}}" + } + tool("solink") { + lib_switch = "-l" + if (is_debug) { + optimize_level = "-O0" + } else { + optimize_level = "-O3" + } + default_output_extension = ".so" + + command = "$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang $linker_command $optimize_level --sysroot $ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/sysroot -Wl,--build-id -Wl,--no-undefined -Wl,--fatal-warnings -shared -Wl,-soname,{{target_output_name}}{{output_extension}} -o {{output}} {{inputs}} {{libs}}" + default_output_dir = "{{target_out_dir}}" + outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ] + output_prefix = "lib" + } + } +} else { + toolchain("clang") { + if (target_os == "mac" && collect_code_coverage) { + compiler_command = + "-fprofile-instr-generate -fcoverage-mapping $compiler_command" + } + if (target_os == "ios") { + if (current_cpu == "x64") { + compiler_command = "-target x86_64-apple-ios11.0-simulator -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk $compiler_command" + } else { + compiler_command = "-target arm64-apple-ios11.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk $compiler_command" + } + } + + tool("cc") { + command = "clang $compiler_command {{cflags_c}}" + depfile = depfile_string + depsformat = "gcc" + outputs = [ "{{source_out_dir}}/{{source_name_part}}.o" ] + } + + tool("cxx") { + command = "clang++ $compiler_command {{cflags_cc}}" + depfile = depfile_string + depsformat = "gcc" + outputs = [ "{{source_out_dir}}/{{source_name_part}}.o" ] + } + + tool("stamp") { + command = "touch {{output}}" + } + + tool("link") { + lib_switch = "-l" + framework_switch = "-framework " + + # TODO(Chason): Add -target x86_64-apple-ios9.0 to make LTO enabled. + # Current we use link to generate unit test executable file. + command = "clang $linker_command -o {{output}} {{inputs}} {{libs}} {{frameworks}}" + if (!is_debug && lto) { + command = "$command -Xlinker -object_path_lto -Xlinker {{output_dir}}/{{target_output_name}}_lto.o" + } + if (target_os == "mac" && collect_code_coverage) { + command = "$command -fprofile-instr-generate" + } + default_output_dir = "{{root_out_dir}}" + outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ] + } + + tool("alink") { + command = "libtool -static -o {{output}} {{inputs}}" + default_output_dir = "{{target_out_dir}}" + outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ] + default_output_extension = ".a" + output_prefix = "lib" + } + } +} diff --git a/gn_to_cmake.py b/gn_to_cmake.py deleted file mode 100644 index 2f378c6..0000000 --- a/gn_to_cmake.py +++ /dev/null @@ -1,610 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2016 Google Inc. -# -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -""" -Usage: gn_to_cmake.py -gn gen out/config --ide=json --json-ide-script=../../gn/gn_to_cmake.py -or -gn gen out/config --ide=json -python gn/gn_to_cmake.py out/config/project.json -The first is recommended, as it will auto-update. -""" -import itertools -import functools -import json -import posixpath -import os -import string -import sys -def CMakeStringEscape(a): - """Escapes the string 'a' for use inside a CMake string. - This means escaping - '\' otherwise it may be seen as modifying the next character - '"' otherwise it will end the string - ';' otherwise the string becomes a list - The following do not need to be escaped - '#' when the lexer is in string state, this does not start a comment - """ - return a.replace('\\', '\\\\').replace(';', '\\;').replace('"', '\\"') -def CMakeTargetEscape(a): - """Escapes the string 'a' for use as a CMake target name. - CMP0037 in CMake 3.0 restricts target names to "^[A-Za-z0-9_.:+-]+$" - The ':' is only allowed for imported targets. - """ - def Escape(c): - if c in string.ascii_letters or c in string.digits or c in '_.+-': - return c - else: - return '__' - return ''.join(map(Escape, a)) -def SetVariable(out, variable_name, value): - """Sets a CMake variable.""" - out.write('set("') - out.write(CMakeStringEscape(variable_name)) - out.write('" "') - out.write(CMakeStringEscape(value)) - out.write('")\n') -def SetVariableList(out, variable_name, values): - """Sets a CMake variable to a list.""" - if not values: - return SetVariable(out, variable_name, "") - if len(values) == 1: - return SetVariable(out, variable_name, values[0]) - out.write('list(APPEND "') - out.write(CMakeStringEscape(variable_name)) - out.write('"\n "') - out.write('"\n "'.join([CMakeStringEscape(value) for value in values])) - out.write('")\n') -def SetFilesProperty(output, variable, property_name, values, sep): - """Given a set of source files, sets the given property on them.""" - output.write('set_source_files_properties(') - WriteVariable(output, variable) - output.write(' PROPERTIES ') - output.write(property_name) - output.write(' "') - for value in values: - output.write(CMakeStringEscape(value)) - output.write(sep) - output.write('")\n') -def SetCurrentTargetProperty(out, property_name, values, sep=''): - """Given a target, sets the given property.""" - out.write('set_target_properties("${target}" PROPERTIES ') - out.write(property_name) - out.write(' "') - for value in values: - out.write(CMakeStringEscape(value)) - out.write(sep) - out.write('")\n') -def WriteVariable(output, variable_name, prepend=None): - if prepend: - output.write(prepend) - output.write('${') - output.write(variable_name) - output.write('}') -# See GetSourceFileType in gn -source_file_types = { - '.cc': 'cxx', - '.cpp': 'cxx', - '.cxx': 'cxx', - '.m': 'objc', - '.mm': 'objcc', - '.c': 'c', - '.s': 'asm', - '.S': 'asm', - '.asm': 'asm', - '.o': 'obj', - '.obj': 'obj', -} -class CMakeTargetType(object): - def __init__(self, command, modifier, property_modifier, is_linkable): - self.command = command - self.modifier = modifier - self.property_modifier = property_modifier - self.is_linkable = is_linkable -CMakeTargetType.custom = CMakeTargetType('add_custom_target', 'SOURCES', - None, False) -# See GetStringForOutputType in gn -cmake_target_types = { - 'unknown': CMakeTargetType.custom, - 'group': CMakeTargetType.custom, - 'executable': CMakeTargetType('add_executable', None, 'RUNTIME', True), - 'loadable_module': CMakeTargetType('add_library', 'MODULE', 'LIBRARY', True), - 'shared_library': CMakeTargetType('add_library', 'SHARED', 'LIBRARY', True), - 'static_library': CMakeTargetType('add_library', 'STATIC', 'ARCHIVE', True), - 'source_set': CMakeTargetType('add_library', 'OBJECT', None, False), - 'copy': CMakeTargetType.custom, - 'action': CMakeTargetType.custom, - 'action_foreach': CMakeTargetType.custom, - 'bundle_data': CMakeTargetType.custom, - 'create_bundle': CMakeTargetType.custom, -} -def FindFirstOf(s, a): - return min(s.find(i) for i in a if i in s) -class Project(object): - def __init__(self, project_json): - self.targets = project_json['targets'] - build_settings = project_json['build_settings'] - self.root_path = build_settings['root_path'] - self.build_path = self.GetAbsolutePath(build_settings['build_dir']) - def GetAbsolutePath(self, path): - if path.startswith('//'): - return posixpath.join(self.root_path, path[2:]) - else: - return path - def GetObjectSourceDependencies(self, gn_target_name, object_dependencies): - """All OBJECT libraries whose sources have not been absorbed.""" - dependencies = self.targets[gn_target_name].get('deps', []) - for dependency in dependencies: - dependency_type = self.targets[dependency].get('type', None) - if dependency_type == 'source_set': - object_dependencies.add(dependency) - if dependency_type not in gn_target_types_that_absorb_objects: - self.GetObjectSourceDependencies(dependency, object_dependencies) - def GetObjectLibraryDependencies(self, gn_target_name, object_dependencies): - """All OBJECT libraries whose libraries have not been absorbed.""" - dependencies = self.targets[gn_target_name].get('deps', []) - for dependency in dependencies: - dependency_type = self.targets[dependency].get('type', None) - if dependency_type == 'source_set': - object_dependencies.add(dependency) - self.GetObjectLibraryDependencies(dependency, object_dependencies) - def GetCMakeTargetName(self, gn_target_name): - # See /src/tools/gn/label.cc#Resolve - # //base/test:test_support(//build/toolchain/win:msvc) - path_separator = FindFirstOf(gn_target_name, (':', '(')) - location = None - name = None - toolchain = None - if not path_separator: - location = gn_target_name[2:] - else: - location = gn_target_name[2:path_separator] - toolchain_separator = gn_target_name.find('(', path_separator) - if toolchain_separator == -1: - name = gn_target_name[path_separator + 1:] - else: - if toolchain_separator > path_separator: - name = gn_target_name[path_separator + 1:toolchain_separator] - assert gn_target_name.endswith(')') - toolchain = gn_target_name[toolchain_separator + 1:-1] - assert location or name - cmake_target_name = None - if location.endswith('/' + name): - cmake_target_name = location - elif location: - cmake_target_name = location + '_' + name - else: - cmake_target_name = name - if toolchain: - cmake_target_name += '--' + toolchain - return CMakeTargetEscape(cmake_target_name) -class Target(object): - def __init__(self, gn_target_name, project): - self.gn_name = gn_target_name - self.properties = project.targets[self.gn_name] - self.cmake_name = project.GetCMakeTargetName(self.gn_name) - self.gn_type = self.properties.get('type', None) - self.cmake_type = cmake_target_types.get(self.gn_type, None) -def WriteAction(out, target, project, sources, synthetic_dependencies): - outputs = [] - output_directories = set() - for output in target.properties.get('outputs', []): - output_abs_path = project.GetAbsolutePath(output) - outputs.append(output_abs_path) - output_directory = posixpath.dirname(output_abs_path) - if output_directory: - output_directories.add(output_directory) - outputs_name = '${target}__output' - SetVariableList(out, outputs_name, outputs) - out.write('add_custom_command(OUTPUT ') - WriteVariable(out, outputs_name) - out.write('\n') - if output_directories: - out.write(' COMMAND ${CMAKE_COMMAND} -E make_directory "') - out.write('" "'.join(map(CMakeStringEscape, output_directories))) - out.write('"\n') - script = target.properties['script'] - arguments = target.properties['args'] - out.write(' COMMAND python "') - out.write(CMakeStringEscape(project.GetAbsolutePath(script))) - out.write('"') - if arguments: - out.write('\n "') - out.write('"\n "'.join(map(CMakeStringEscape, arguments))) - out.write('"') - out.write('\n') - out.write(' DEPENDS ') - for sources_type_name in sources.values(): - WriteVariable(out, sources_type_name, ' ') - out.write('\n') - #TODO: CMake 3.7 is introducing DEPFILE - out.write(' WORKING_DIRECTORY "') - out.write(CMakeStringEscape(project.build_path)) - out.write('"\n') - out.write(' COMMENT "Action: ${target}"\n') - out.write(' VERBATIM)\n') - synthetic_dependencies.add(outputs_name) -def ExpandPlaceholders(source, a): - source_dir, source_file_part = posixpath.split(source) - source_name_part, _ = posixpath.splitext(source_file_part) - #TODO: {{source_gen_dir}}, {{source_out_dir}}, {{response_file_name}} - return a.replace('{{source}}', source) \ - .replace('{{source_file_part}}', source_file_part) \ - .replace('{{source_name_part}}', source_name_part) \ - .replace('{{source_dir}}', source_dir) \ - .replace('{{source_root_relative_dir}}', source_dir) -def WriteActionForEach(out, target, project, sources, synthetic_dependencies): - all_outputs = target.properties.get('outputs', []) - inputs = target.properties.get('sources', []) - # TODO: consider expanding 'output_patterns' instead. - outputs_per_input = len(all_outputs) / len(inputs) - for count, source in enumerate(inputs): - source_abs_path = project.GetAbsolutePath(source) - outputs = [] - output_directories = set() - for output in all_outputs[outputs_per_input * count: - outputs_per_input * (count+1)]: - output_abs_path = project.GetAbsolutePath(output) - outputs.append(output_abs_path) - output_directory = posixpath.dirname(output_abs_path) - if output_directory: - output_directories.add(output_directory) - outputs_name = '${target}__output_' + str(count) - SetVariableList(out, outputs_name, outputs) - out.write('add_custom_command(OUTPUT ') - WriteVariable(out, outputs_name) - out.write('\n') - if output_directories: - out.write(' COMMAND ${CMAKE_COMMAND} -E make_directory "') - out.write('" "'.join(map(CMakeStringEscape, output_directories))) - out.write('"\n') - script = target.properties['script'] - # TODO: need to expand {{xxx}} in arguments - arguments = target.properties['args'] - out.write(' COMMAND python "') - out.write(CMakeStringEscape(project.GetAbsolutePath(script))) - out.write('"') - if arguments: - out.write('\n "') - expand = functools.partial(ExpandPlaceholders, source_abs_path) - out.write('"\n "'.join(map(CMakeStringEscape, map(expand,arguments)))) - out.write('"') - out.write('\n') - out.write(' DEPENDS') - if 'input' in sources: - WriteVariable(out, sources['input'], ' ') - out.write(' "') - out.write(CMakeStringEscape(source_abs_path)) - out.write('"\n') - #TODO: CMake 3.7 is introducing DEPFILE - out.write(' WORKING_DIRECTORY "') - out.write(CMakeStringEscape(project.build_path)) - out.write('"\n') - out.write(' COMMENT "Action ${target} on ') - out.write(CMakeStringEscape(source_abs_path)) - out.write('"\n') - out.write(' VERBATIM)\n') - synthetic_dependencies.add(outputs_name) -def WriteCopy(out, target, project, sources, synthetic_dependencies): - inputs = target.properties.get('sources', []) - raw_outputs = target.properties.get('outputs', []) - # TODO: consider expanding 'output_patterns' instead. - outputs = [] - for output in raw_outputs: - output_abs_path = project.GetAbsolutePath(output) - outputs.append(output_abs_path) - outputs_name = '${target}__output' - SetVariableList(out, outputs_name, outputs) - out.write('add_custom_command(OUTPUT ') - WriteVariable(out, outputs_name) - out.write('\n') - for src, dst in zip(inputs, outputs): - abs_src_path = CMakeStringEscape(project.GetAbsolutePath(src)) - # CMake distinguishes between copying files and copying directories but - # gn does not. We assume if the src has a period in its name then it is - # a file and otherwise a directory. - if "." in os.path.basename(abs_src_path): - out.write(' COMMAND ${CMAKE_COMMAND} -E copy "') - else: - out.write(' COMMAND ${CMAKE_COMMAND} -E copy_directory "') - out.write(abs_src_path) - out.write('" "') - out.write(CMakeStringEscape(dst)) - out.write('"\n') - out.write(' DEPENDS ') - for sources_type_name in sources.values(): - WriteVariable(out, sources_type_name, ' ') - out.write('\n') - out.write(' WORKING_DIRECTORY "') - out.write(CMakeStringEscape(project.build_path)) - out.write('"\n') - out.write(' COMMENT "Copy ${target}"\n') - out.write(' VERBATIM)\n') - synthetic_dependencies.add(outputs_name) -def WriteCompilerFlags(out, target, project, sources): - # Hack, set linker language to c if no c or cxx files present. - if not 'c' in sources and not 'cxx' in sources: - SetCurrentTargetProperty(out, 'LINKER_LANGUAGE', ['C']) - # Mark uncompiled sources as uncompiled. - if 'input' in sources: - SetFilesProperty(out, sources['input'], 'HEADER_FILE_ONLY', ('True',), '') - if 'other' in sources: - SetFilesProperty(out, sources['other'], 'HEADER_FILE_ONLY', ('True',), '') - # Mark object sources as linkable. - if 'obj' in sources: - SetFilesProperty(out, sources['obj'], 'EXTERNAL_OBJECT', ('True',), '') - # TODO: 'output_name', 'output_dir', 'output_extension' - # This includes using 'source_outputs' to direct compiler output. - # Includes - includes = target.properties.get('include_dirs', []) - if includes: - out.write('set_property(TARGET "${target}" ') - out.write('APPEND PROPERTY INCLUDE_DIRECTORIES') - for include_dir in includes: - out.write('\n "') - out.write(project.GetAbsolutePath(include_dir)) - out.write('"') - out.write(')\n') - # Defines - defines = target.properties.get('defines', []) - if defines: - SetCurrentTargetProperty(out, 'COMPILE_DEFINITIONS', defines, ';') - # Compile flags - # "arflags", "asmflags", "cflags", - # "cflags_c", "clfags_cc", "cflags_objc", "clfags_objcc" - # CMake does not have per target lang compile flags. - # TODO: $<$:cflags_cc style generator expression. - # http://public.kitware.com/Bug/view.php?id=14857 - flags = [] - flags.extend(target.properties.get('cflags', [])) - cflags_asm = target.properties.get('asmflags', []) - cflags_c = target.properties.get('cflags_c', []) - cflags_cxx = target.properties.get('cflags_cc', []) - cflags_objc = cflags_c[:] - cflags_objc.extend(target.properties.get('cflags_objc', [])) - cflags_objcc = cflags_cxx[:] - cflags_objcc.extend(target.properties.get('cflags_objcc', [])) - if 'c' in sources and not any(k in sources for k in ('asm', 'cxx', 'objc', 'objcc')): - flags.extend(cflags_c) - elif 'cxx' in sources and not any(k in sources for k in ('asm', 'c', 'objc', 'objcc')): - flags.extend(cflags_cxx) - elif 'objc' in sources and not any(k in sources for k in ('asm', 'c', 'cxx', 'objcc')): - flags.extend(cflags_objc) - elif 'objcc' in sources and not any(k in sources for k in ('asm', 'c', 'cxx', 'objc')): - flags.extend(cflags_objcc) - else: - # TODO: This is broken, one cannot generally set properties on files, - # as other targets may require different properties on the same files. - if 'asm' in sources and cflags_asm: - SetFilesProperty(out, sources['asm'], 'COMPILE_FLAGS', cflags_asm, ' ') - if 'c' in sources and cflags_c: - SetFilesProperty(out, sources['c'], 'COMPILE_FLAGS', cflags_c, ' ') - if 'cxx' in sources and cflags_cxx: - SetFilesProperty(out, sources['cxx'], 'COMPILE_FLAGS', cflags_cxx, ' ') - if 'objc' in sources and cflags_objc: - SetFilesProperty(out, sources['objc'], 'COMPILE_FLAGS', cflags_objc, ' ') - if 'objcc' in sources and cflags_objcc: - SetFilesProperty(out, sources['objcc'], 'COMPILE_FLAGS', cflags_objcc, ' ') - if flags: - SetCurrentTargetProperty(out, 'COMPILE_FLAGS', flags, ' ') - # Linker flags - ldflags = target.properties.get('ldflags', []) - if ldflags: - SetCurrentTargetProperty(out, 'LINK_FLAGS', ldflags, ' ') -gn_target_types_that_absorb_objects = ( - 'executable', - 'loadable_module', - 'shared_library', - 'static_library' -) -def WriteSourceVariables(out, target, project): - # gn separates the sheep from the goats based on file extensions. - # A full separation is done here because of flag handing (see Compile flags). - source_types = {'cxx':[], 'c':[], 'asm':[], 'objc':[], 'objcc':[], - 'obj':[], 'obj_target':[], 'input':[], 'other':[]} - all_sources = target.properties.get('sources', []) - # As of cmake 3.11 add_library must have sources. If there are - # no sources, add empty.cpp as the file to compile. - if len(all_sources) == 0: - all_sources.append(posixpath.join(project.build_path, 'empty.cpp')) - # TODO .def files on Windows - for source in all_sources: - _, ext = posixpath.splitext(source) - source_abs_path = project.GetAbsolutePath(source) - source_types[source_file_types.get(ext, 'other')].append(source_abs_path) - for input_path in target.properties.get('inputs', []): - input_abs_path = project.GetAbsolutePath(input_path) - source_types['input'].append(input_abs_path) - # OBJECT library dependencies need to be listed as sources. - # Only executables and non-OBJECT libraries may reference an OBJECT library. - # https://gitlab.kitware.com/cmake/cmake/issues/14778 - if target.gn_type in gn_target_types_that_absorb_objects: - object_dependencies = set() - project.GetObjectSourceDependencies(target.gn_name, object_dependencies) - for dependency in object_dependencies: - cmake_dependency_name = project.GetCMakeTargetName(dependency) - obj_target_sources = '$' - source_types['obj_target'].append(obj_target_sources) - sources = {} - for source_type, sources_of_type in source_types.items(): - if sources_of_type: - sources[source_type] = '${target}__' + source_type + '_srcs' - SetVariableList(out, sources[source_type], sources_of_type) - return sources -def WriteTarget(out, target, project): - out.write('\n#') - out.write(target.gn_name) - out.write('\n') - if target.cmake_type is None: - print ('Target %s has unknown target type %s, skipping.' % - ( target.gn_name, target.gn_type ) ) - return - SetVariable(out, 'target', target.cmake_name) - sources = WriteSourceVariables(out, target, project) - synthetic_dependencies = set() - if target.gn_type == 'action': - WriteAction(out, target, project, sources, synthetic_dependencies) - if target.gn_type == 'action_foreach': - WriteActionForEach(out, target, project, sources, synthetic_dependencies) - if target.gn_type == 'copy': - WriteCopy(out, target, project, sources, synthetic_dependencies) - out.write(target.cmake_type.command) - out.write('("${target}"') - if target.cmake_type.modifier is not None: - out.write(' ') - out.write(target.cmake_type.modifier) - for sources_type_name in sources.values(): - WriteVariable(out, sources_type_name, ' ') - if synthetic_dependencies: - out.write(' DEPENDS') - for synthetic_dependencie in synthetic_dependencies: - WriteVariable(out, synthetic_dependencie, ' ') - out.write(')\n') - if target.cmake_type.command != 'add_custom_target': - WriteCompilerFlags(out, target, project, sources) - libraries = set() - nonlibraries = set() - dependencies = set(target.properties.get('deps', [])) - # Transitive OBJECT libraries are in sources. - # Those sources are dependent on the OBJECT library dependencies. - # Those sources cannot bring in library dependencies. - object_dependencies = set() - if target.gn_type != 'source_set': - project.GetObjectLibraryDependencies(target.gn_name, object_dependencies) - for object_dependency in object_dependencies: - dependencies.update(project.targets.get(object_dependency).get('deps', [])) - for dependency in dependencies: - gn_dependency_type = project.targets.get(dependency, {}).get('type', None) - cmake_dependency_type = cmake_target_types.get(gn_dependency_type, None) - cmake_dependency_name = project.GetCMakeTargetName(dependency) - if cmake_dependency_type.command != 'add_library': - nonlibraries.add(cmake_dependency_name) - elif cmake_dependency_type.modifier != 'OBJECT': - if target.cmake_type.is_linkable: - libraries.add(cmake_dependency_name) - else: - nonlibraries.add(cmake_dependency_name) - # Non-library dependencies. - if nonlibraries: - out.write('add_dependencies("${target}"') - for nonlibrary in nonlibraries: - out.write('\n "') - out.write(nonlibrary) - out.write('"') - out.write(')\n') - # Non-OBJECT library dependencies. - combined_library_lists = [target.properties.get(key, []) for key in ['libs', 'frameworks']] - external_libraries = list(itertools.chain(*combined_library_lists)) - if target.cmake_type.is_linkable and (external_libraries or libraries): - library_dirs = target.properties.get('lib_dirs', []) - if library_dirs: - SetVariableList(out, '${target}__library_directories', library_dirs) - system_libraries = [] - for external_library in external_libraries: - if '/' in external_library: - libraries.add(project.GetAbsolutePath(external_library)) - else: - if external_library.endswith('.framework'): - external_library = external_library[:-len('.framework')] - system_library = 'library__' + external_library - if library_dirs: - system_library = system_library + '__for_${target}' - out.write('find_library("') - out.write(CMakeStringEscape(system_library)) - out.write('" "') - out.write(CMakeStringEscape(external_library)) - out.write('"') - if library_dirs: - out.write(' PATHS "') - WriteVariable(out, '${target}__library_directories') - out.write('"') - out.write(')\n') - system_libraries.append(system_library) - out.write('target_link_libraries("${target}"') - for library in libraries: - out.write('\n "') - out.write(CMakeStringEscape(library)) - out.write('"') - for system_library in system_libraries: - WriteVariable(out, system_library, '\n "') - out.write('"') - out.write(')\n') -def WriteProject(project): - out = open(posixpath.join(project.build_path, 'CMakeLists.txt'), 'w+') - extName = posixpath.join(project.build_path, 'CMakeLists.ext') - out.write('# Generated by gn_to_cmake.py.\n') - out.write('cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)\n') - out.write('cmake_policy(VERSION 2.8.8)\n') - out.write('project(Skia)\n\n') - out.write('file(WRITE "') - out.write(CMakeStringEscape(posixpath.join(project.build_path, "empty.cpp"))) - out.write('")\n') - # Update the gn generated ninja build. - # If a build file has changed, this will update CMakeLists.ext if - # gn gen out/config --ide=json --json-ide-script=../../gn/gn_to_cmake.py - # style was used to create this config. - out.write('execute_process(COMMAND\n') - out.write(' ninja -C "') - out.write(CMakeStringEscape(project.build_path)) - out.write('" build.ninja\n') - out.write(' RESULT_VARIABLE ninja_result)\n') - out.write('if (ninja_result)\n') - out.write(' message(WARNING ') - out.write('"Regeneration failed running ninja: ${ninja_result}")\n') - out.write('endif()\n') - out.write('include("') - out.write(CMakeStringEscape(extName)) - out.write('")\n') - out.close() - out = open(extName, 'w+') - out.write('# Generated by gn_to_cmake.py.\n') - out.write('cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)\n') - out.write('cmake_policy(VERSION 2.8.8)\n') - # The following appears to be as-yet undocumented. - # http://public.kitware.com/Bug/view.php?id=8392 - out.write('enable_language(ASM)\n\n') - # ASM-ATT does not support .S files. - # output.write('enable_language(ASM-ATT)\n') - # Current issues with automatic re-generation: - # The gn generated build.ninja target uses build.ninja.d - # but build.ninja.d does not contain the ide or gn. - # Currently the ide is not run if the project.json file is not changed - # but the ide needs to be run anyway if it has itself changed. - # This can be worked around by deleting the project.json file. - out.write('file(READ "') - gn_deps_file = posixpath.join(project.build_path, 'build.ninja.d') - out.write(CMakeStringEscape(gn_deps_file)) - out.write('" "gn_deps_string" OFFSET ') - out.write(str(len('build.ninja: '))) - out.write(')\n') - # One would think this would need to worry about escaped spaces - # but gn doesn't escape spaces here (it generates invalid .d files). - out.write('string(REPLACE " " ";" "gn_deps" ${gn_deps_string})\n') - out.write('foreach("gn_dep" ${gn_deps})\n') - out.write(' configure_file("') - out.write(CMakeStringEscape(project.build_path)) - out.write('${gn_dep}" "CMakeLists.devnull" COPYONLY)\n') - out.write('endforeach("gn_dep")\n') - out.write('list(APPEND other_deps "') - out.write(CMakeStringEscape(os.path.abspath(__file__))) - out.write('")\n') - out.write('foreach("other_dep" ${other_deps})\n') - out.write(' configure_file("${other_dep}" "CMakeLists.devnull" COPYONLY)\n') - out.write('endforeach("other_dep")\n') - for target_name in project.targets.keys(): - out.write('\n') - WriteTarget(out, Target(target_name, project), project) -def main(): - if len(sys.argv) != 2: - print('Usage: ' + sys.argv[0] + ' ') - exit(1) - json_path = sys.argv[1] - project = None - with open(json_path, 'r') as json_file: - project = json.loads(json_file.read()) - WriteProject(Project(project)) -if __name__ == "__main__": - main() diff --git a/include/hermes/External.h b/include/hermes/External.h new file mode 100644 index 0000000..1580029 --- /dev/null +++ b/include/hermes/External.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +namespace orangelabs { +class External final : public ::hermes::vm::HostObjectProxy { + public: + explicit External(::hermes::vm::Runtime &runtime, void *data, + NAPIFinalize finalizeCallback, void *finalizeHint); + + [[nodiscard]] void *getData() const; + + ~External() override; + + ::hermes::vm::CallResult<::hermes::vm::HermesValue> get( + ::hermes::vm::SymbolID symbolId) override; + + ::hermes::vm::CallResult set(::hermes::vm::SymbolID symbolId, + ::hermes::vm::HermesValue value) override; + + ::hermes::vm::CallResult<::hermes::vm::Handle<::hermes::vm::JSArray>> + getHostPropertyNames() override; + + External(const External &) = delete; + + External(External &&) = delete; + + External &operator=(const External &) = delete; + + External &operator=(External &&) = delete; + + private: + ::hermes::vm::Runtime &runtime; + void *const data; + const NAPIFinalize finalizeCallback; + void *const finalizeHint; +}; +} // namespace orangelabs diff --git a/include/hermes/FunctionInfo.h b/include/hermes/FunctionInfo.h new file mode 100644 index 0000000..2f13695 --- /dev/null +++ b/include/hermes/FunctionInfo.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +namespace orangelabs { +class FunctionInfo final { + public: + explicit FunctionInfo(NAPIEnv env, NAPICallback callback, void *data); + ~FunctionInfo() = default; + + [[nodiscard]] NAPIEnv getEnv() const; + [[nodiscard]] NAPICallback getCallback() const; + [[nodiscard]] void *getData() const; + + FunctionInfo(const FunctionInfo &) = delete; + + FunctionInfo(FunctionInfo &&) = delete; + + FunctionInfo &operator=(const FunctionInfo &) = delete; + + FunctionInfo &operator=(FunctionInfo &&) = delete; + + private: + NAPIEnv env; + NAPICallback callback; + void *data; +}; +} // namespace orangelabs \ No newline at end of file diff --git a/include/hermes/HermesExecutorRuntimeAdapter.h b/include/hermes/HermesExecutorRuntimeAdapter.h new file mode 100644 index 0000000..83dee02 --- /dev/null +++ b/include/hermes/HermesExecutorRuntimeAdapter.h @@ -0,0 +1,58 @@ +#pragma once + +#ifdef HERMES_ENABLE_DEBUGGER + +namespace facebook { +namespace react { +class MessageQueueThread; +} +namespace jsi { +class Runtime; +} +namespace hermes { +namespace debugger { +class Debugger; +} +class HermesRuntime; +} // namespace hermes +} // namespace facebook + +#include + +namespace orangelabs { + +class HermesExecutorRuntimeAdapter final + : public ::facebook::hermes::inspector::RuntimeAdapter { + public: + explicit HermesExecutorRuntimeAdapter( + ::std::shared_ptr<::facebook::jsi::Runtime> runtime, + ::facebook::hermes::HermesRuntime &hermesRuntime, + ::std::shared_ptr<::facebook::react::MessageQueueThread> + messageQueueThread); + + ~HermesExecutorRuntimeAdapter() override = default; + + HermesExecutorRuntimeAdapter(const HermesExecutorRuntimeAdapter &) = delete; + + HermesExecutorRuntimeAdapter(HermesExecutorRuntimeAdapter &&) = delete; + + HermesExecutorRuntimeAdapter &operator=( + const HermesExecutorRuntimeAdapter &) = delete; + + HermesExecutorRuntimeAdapter &operator=(HermesExecutorRuntimeAdapter &&) = + delete; + + ::facebook::jsi::Runtime &getRuntime() override; + + ::facebook::hermes::debugger::Debugger &getDebugger() override; + + void tickleJs() override; + + private: + const ::std::shared_ptr<::facebook::jsi::Runtime> runtime; + ::facebook::hermes::HermesRuntime &hermesRuntime; + const ::std::shared_ptr<::facebook::react::MessageQueueThread> + messageQueueThread; +}; +} // namespace orangelabs +#endif \ No newline at end of file diff --git a/include/hermes/OpaqueNAPICallbackInfo.h b/include/hermes/OpaqueNAPICallbackInfo.h new file mode 100644 index 0000000..2213030 --- /dev/null +++ b/include/hermes/OpaqueNAPICallbackInfo.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +EXTERN_C_START + +struct OpaqueNAPICallbackInfo final { + explicit OpaqueNAPICallbackInfo(::hermes::vm::NativeArgs nativeArgs, + void *data); + ~OpaqueNAPICallbackInfo() = default; + + [[nodiscard]] const ::hermes::vm::NativeArgs &getNativeArgs() const; + [[nodiscard]] void *getData() const; + + OpaqueNAPICallbackInfo(const OpaqueNAPICallbackInfo &) = delete; + + OpaqueNAPICallbackInfo(OpaqueNAPICallbackInfo &&) = delete; + + OpaqueNAPICallbackInfo &operator=(const OpaqueNAPICallbackInfo &) = delete; + + OpaqueNAPICallbackInfo &operator=(OpaqueNAPICallbackInfo &&) = delete; + + private: + const ::hermes::vm::NativeArgs nativeArgs; + void *const data; +}; + +EXTERN_C_END \ No newline at end of file diff --git a/include/hermes/OpaqueNAPIEnv.h b/include/hermes/OpaqueNAPIEnv.h new file mode 100644 index 0000000..38cfb2d --- /dev/null +++ b/include/hermes/OpaqueNAPIEnv.h @@ -0,0 +1,67 @@ +#pragma once + +#include + +#include + +namespace hermes::vm { +class RuntimeConfig; +class Runtime; +} // namespace hermes::vm + +namespace facebook::react { +class MessageQueueThread; +} + +namespace facebook::hermes { +class HermesRuntime; +} + +EXTERN_C_START + +#include + +struct OpaqueNAPIEnv final { + public: + explicit OpaqueNAPIEnv(const ::hermes::vm::RuntimeConfig &runtimeConfig); + + ~OpaqueNAPIEnv(); + + [[nodiscard]] ::hermes::vm::Runtime &getRuntime() const; + + OpaqueNAPIEnv(const OpaqueNAPIEnv &) = delete; + + OpaqueNAPIEnv(OpaqueNAPIEnv &&) = delete; + + OpaqueNAPIEnv &operator=(const OpaqueNAPIEnv &) = delete; + + OpaqueNAPIEnv &operator=(OpaqueNAPIEnv &&) = delete; + + LIST_HEAD(, OpaqueNAPIRef) valueList; + + LIST_HEAD(, OpaqueNAPIRef) weakRefList; + + LIST_HEAD(, OpaqueNAPIRef) strongRefList; + + SLIST_HEAD(, OpaqueNAPIHandleScope) handleScopeList; + +#ifdef HERMES_ENABLE_DEBUGGER + + void enableDebugger(const char *debuggerTitle, bool waitForDebugger) const; + + void disableDebugger() const; + + void setMessageQueueThread( + ::std::shared_ptr<::facebook::react::MessageQueueThread> jsQueue); + +#endif + + private: + ::std::shared_ptr<::facebook::react::MessageQueueThread> messageQueueThread; + const ::std::shared_ptr<::facebook::hermes::HermesRuntime> + hermesRuntimeSharedPointer; + ::facebook::hermes::HermesRuntime &hermesRuntime; + ::hermes::vm::Runtime &runtime; +}; + +EXTERN_C_END \ No newline at end of file diff --git a/include/hermes/OpaqueNAPIEscapableHandleScope.h b/include/hermes/OpaqueNAPIEscapableHandleScope.h new file mode 100644 index 0000000..c945cdf --- /dev/null +++ b/include/hermes/OpaqueNAPIEscapableHandleScope.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +EXTERN_C_START + +struct OpaqueNAPIEscapableHandleScope final : public OpaqueNAPIHandleScope { + public: + explicit OpaqueNAPIEscapableHandleScope( + ::hermes::vm::HandleRootOwner &runtime, + ::hermes::vm::MutableHandle<::hermes::vm::HermesValue> + preservedMutableHandle); + ~OpaqueNAPIEscapableHandleScope() override = default; + + OpaqueNAPIEscapableHandleScope(const OpaqueNAPIEscapableHandleScope &) = + delete; + + OpaqueNAPIEscapableHandleScope(OpaqueNAPIEscapableHandleScope &&) = delete; + + OpaqueNAPIEscapableHandleScope &operator=( + const OpaqueNAPIEscapableHandleScope &) = delete; + + OpaqueNAPIEscapableHandleScope &operator=(OpaqueNAPIEscapableHandleScope &&) = + delete; + + [[nodiscard]] bool isEscapeCalled() const; + + const ::hermes::vm::PinnedHermesValue *escape( + const ::hermes::vm::HermesValue &hermesValue); + + private: + ::hermes::vm::MutableHandle<::hermes::vm::HermesValue> mutableHandle; + bool escapeCalled; +}; + +EXTERN_C_END \ No newline at end of file diff --git a/include/hermes/OpaqueNAPIHandleScope.h b/include/hermes/OpaqueNAPIHandleScope.h new file mode 100644 index 0000000..91b8ed1 --- /dev/null +++ b/include/hermes/OpaqueNAPIHandleScope.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +EXTERN_C_START + +#include + +struct OpaqueNAPIHandleScope { + public: + explicit OpaqueNAPIHandleScope(::hermes::vm::HandleRootOwner &runtime); + virtual ~OpaqueNAPIHandleScope() = default; + + OpaqueNAPIHandleScope(const OpaqueNAPIHandleScope &) = delete; + + OpaqueNAPIHandleScope(OpaqueNAPIHandleScope &&) = delete; + + OpaqueNAPIHandleScope &operator=(const OpaqueNAPIHandleScope &) = delete; + + OpaqueNAPIHandleScope &operator=(OpaqueNAPIHandleScope &&) = delete; + + SLIST_ENTRY(OpaqueNAPIHandleScope) node; + + private: + ::hermes::vm::GCScope gcScope; +}; + +EXTERN_C_END \ No newline at end of file diff --git a/include/hermes/OpaqueNAPIRef.h b/include/hermes/OpaqueNAPIRef.h new file mode 100644 index 0000000..e5444ee --- /dev/null +++ b/include/hermes/OpaqueNAPIRef.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include + +#include + +namespace hermes::vm { +class JSObject; +} // namespace hermes::vm + +EXTERN_C_START + +#include + +struct OpaqueNAPIRef final { + public: + explicit OpaqueNAPIRef( + NAPIEnv env, const ::hermes::vm::PinnedHermesValue &pinnedHermesValue, + uint8_t referenceCount); + + OpaqueNAPIRef(const OpaqueNAPIRef &) = delete; + + OpaqueNAPIRef(OpaqueNAPIRef &&) = delete; + + OpaqueNAPIRef &operator=(const OpaqueNAPIRef &) = delete; + + OpaqueNAPIRef &operator=(OpaqueNAPIRef &&) = delete; + + ~OpaqueNAPIRef(); + + void ref(); + + void unref(); + + [[nodiscard]] uint8_t getReferenceCount() const; + + [[nodiscard]] const ::hermes::vm::PinnedHermesValue *getHermesValue() const; + + ::std::variant<::std::monostate, ::hermes::vm::PinnedHermesValue, + ::hermes::vm::WeakRoot<::hermes::vm::JSObject>> + storage; + + LIST_ENTRY(OpaqueNAPIRef) node; + + private: + const NAPIEnv env; + uint8_t referenceCount; +}; + +EXTERN_C_END \ No newline at end of file diff --git a/src/inspector/js_native_api_hermes_inspector.h b/include/hermes/js_native_api_hermes_inspector.h similarity index 100% rename from src/inspector/js_native_api_hermes_inspector.h rename to include/hermes/js_native_api_hermes_inspector.h diff --git a/include/napi/js_native_api.h b/include/napi/js_native_api.h index 8c6a7a2..801eeda 100644 --- a/include/napi/js_native_api.h +++ b/include/napi/js_native_api.h @@ -1,5 +1,4 @@ -#ifndef SRC_JS_NATIVE_API_H_ -#define SRC_JS_NATIVE_API_H_ +#pragma once #include @@ -92,11 +91,11 @@ NAPI_EXPORT NAPIErrorStatus napi_get_reference_value(NAPIEnv env, NAPIRef ref, N NAPI_EXPORT NAPIErrorStatus napi_open_handle_scope(NAPIEnv env, NAPIHandleScope *result); -NAPI_EXPORT NAPICommonStatus napi_close_handle_scope(NAPIEnv env, NAPIHandleScope scope); +NAPI_EXPORT NAPIErrorStatus napi_close_handle_scope(NAPIEnv env, NAPIHandleScope scope); NAPI_EXPORT NAPIErrorStatus napi_open_escapable_handle_scope(NAPIEnv env, NAPIEscapableHandleScope *result); -NAPI_EXPORT NAPICommonStatus napi_close_escapable_handle_scope(NAPIEnv env, NAPIEscapableHandleScope scope); +NAPI_EXPORT NAPIErrorStatus napi_close_escapable_handle_scope(NAPIEnv env, NAPIEscapableHandleScope scope); NAPI_EXPORT NAPIErrorStatus napi_escape_handle(NAPIEnv env, NAPIEscapableHandleScope scope, NAPIValue escapee, NAPIValue *result); @@ -150,5 +149,3 @@ NAPI_EXPORT NAPIExceptionStatus napi_strict_equals(NAPIEnv env, NAPIValue lhs, N NAPI_EXPORT NAPIExceptionStatus NAPIParseUTF8JSONString(NAPIEnv env, const char *utf8String, NAPIValue *result); EXTERN_C_END - -#endif // SRC_JS_NATIVE_API_H_ diff --git a/include/napi/js_native_api_types.h b/include/napi/js_native_api_types.h index ed01da6..c2f586c 100644 --- a/include/napi/js_native_api_types.h +++ b/include/napi/js_native_api_types.h @@ -1,10 +1,7 @@ -#ifndef SRC_JS_NATIVE_API_TYPES_H_ -#define SRC_JS_NATIVE_API_TYPES_H_ +#pragma once #ifdef __cplusplus -#define EXTERN_C_START \ - extern "C" \ - { +#define EXTERN_C_START extern "C" { #define EXTERN_C_END } #else #define EXTERN_C_START @@ -23,55 +20,52 @@ typedef struct OpaqueNAPIHandleScope *NAPIHandleScope; typedef struct OpaqueNAPIEscapableHandleScope *NAPIEscapableHandleScope; typedef struct OpaqueNAPICallbackInfo *NAPICallbackInfo; -typedef enum -{ - // { writable: false, enumerable: false, configurable: false } - // napi_set_property 默认为 { writable: true, enumerable: true, configurable: true } - NAPIDefault = 0, - NAPIWritable = 1 << 0, - NAPIEnumerable = 1 << 1, - NAPIConfigurable = 1 << 2, +typedef enum { + // { writable: false, enumerable: false, configurable: false } + // napi_set_property 默认为 { writable: true, enumerable: true, configurable: + // true } + NAPIDefault = 0, + NAPIWritable = 1 << 0, + NAPIEnumerable = 1 << 1, + NAPIConfigurable = 1 << 2, - // napi_define_class 用于区分静态属性和实例属性,napi_define_properties 忽略该枚举 - NAPIStatic = 1 << 10, + // napi_define_class 用于区分静态属性和实例属性,napi_define_properties + // 忽略该枚举 + NAPIStatic = 1 << 10, - // 方法默认 - NAPIDefaultMethod = NAPIWritable | NAPIConfigurable, + // 方法默认 + NAPIDefaultMethod = NAPIWritable | NAPIConfigurable, - // 属性默认 - NAPIDefaultJSProperty = NAPIWritable | NAPIEnumerable | NAPIConfigurable, + // 属性默认 + NAPIDefaultJSProperty = NAPIWritable | NAPIEnumerable | NAPIConfigurable, } NAPIPropertyAttributes; -typedef enum -{ - NAPIUndefined, - NAPINull, - NAPIBoolean, - NAPINumber, - NAPIString, - // 未来建议判断到 Object 即可,提供 NAPIIsFunction 和 NAPIIsExternal - NAPIObject, - NAPIFunction, - NAPIExternal, +typedef enum { + NAPIUndefined, + NAPINull, + NAPIBoolean, + NAPINumber, + NAPIString, + // 未来建议判断到 Object 即可,提供 NAPIIsFunction 和 NAPIIsExternal + NAPIObject, + NAPIFunction, + NAPIExternal, } NAPIValueType; -typedef enum -{ +typedef enum { #define NAPI_STATUS(status) NAPICommon##status, #include #undef NAPI_STATUS } NAPICommonStatus; -typedef enum -{ +typedef enum { #define NAPI_STATUS(status) NAPIError##status, #include #include #undef NAPI_STATUS } NAPIErrorStatus; -typedef enum -{ +typedef enum { #define NAPI_STATUS(status) NAPIException##status, #include #include @@ -84,5 +78,3 @@ typedef NAPIValue (*NAPICallback)(NAPIEnv env, NAPICallbackInfo callbackInfo); typedef void (*NAPIFinalize)(void *finalizeData, void *finalizeHint); EXTERN_C_END - -#endif // SRC_JS_NATIVE_API_TYPES_H_ diff --git a/src/hermes/External.cpp b/src/hermes/External.cpp new file mode 100644 index 0000000..cb855a9 --- /dev/null +++ b/src/hermes/External.cpp @@ -0,0 +1,33 @@ +#include +#include + +orangelabs::External::External(::hermes::vm::Runtime &runtime, void *data, + const NAPIFinalize finalizeCallback, + void *finalizeHint) + : runtime(runtime), + data(data), + finalizeCallback(finalizeCallback), + finalizeHint(finalizeHint) {} + +void *orangelabs::External::getData() const { return this->data; } + +orangelabs::External::~External() { + if (this->finalizeCallback) { + this->finalizeCallback(this->data, this->finalizeHint); + } +} + +::hermes::vm::CallResult<::hermes::vm::HermesValue> orangelabs::External::get( + ::hermes::vm::SymbolID symbolId) { + return ::hermes::vm::Runtime::getUndefinedValue().get(); +} + +::hermes::vm::CallResult orangelabs::External::set( + ::hermes::vm::SymbolID symbolId, ::hermes::vm::HermesValue value) { + return false; +} + +::hermes::vm::CallResult<::hermes::vm::Handle<::hermes::vm::JSArray>> +orangelabs::External::getHostPropertyNames() { + return ::hermes::vm::JSArray::create(this->runtime, 0, 0); +} \ No newline at end of file diff --git a/src/hermes/FunctionInfo.cpp b/src/hermes/FunctionInfo.cpp new file mode 100644 index 0000000..24b7426 --- /dev/null +++ b/src/hermes/FunctionInfo.cpp @@ -0,0 +1,11 @@ +#include + +orangelabs::FunctionInfo::FunctionInfo(NAPIEnv env, NAPICallback callback, + void *data) + : env(env), callback(callback), data(data) {} + +NAPIEnv orangelabs::FunctionInfo::getEnv() const { return env; } + +NAPICallback orangelabs::FunctionInfo::getCallback() const { return callback; } + +void *orangelabs::FunctionInfo::getData() const { return data; } \ No newline at end of file diff --git a/src/hermes/HermesExecutorRuntimeAdapter.cpp b/src/hermes/HermesExecutorRuntimeAdapter.cpp new file mode 100644 index 0000000..348afd9 --- /dev/null +++ b/src/hermes/HermesExecutorRuntimeAdapter.cpp @@ -0,0 +1,34 @@ +#include + +#ifdef HERMES_ENABLE_DEBUGGER + +#include +#include +#include + +orangelabs::HermesExecutorRuntimeAdapter::HermesExecutorRuntimeAdapter( + ::std::shared_ptr<::facebook::jsi::Runtime> runtime, + ::facebook::hermes::HermesRuntime &hermesRuntime, + ::std::shared_ptr<::facebook::react::MessageQueueThread> messageQueueThread) + : runtime(::std::move(runtime)), + hermesRuntime(hermesRuntime), + messageQueueThread(::std::move(messageQueueThread)) {} + +::facebook::jsi::Runtime & +orangelabs::HermesExecutorRuntimeAdapter::getRuntime() { + return *this->runtime; +} + +::facebook::hermes::debugger::Debugger & +orangelabs::HermesExecutorRuntimeAdapter::getDebugger() { + return this->hermesRuntime.getDebugger(); +} + +void orangelabs::HermesExecutorRuntimeAdapter::tickleJs() { + this->messageQueueThread->runOnQueue([&runtime = this->runtime]() { + auto func = runtime->global().getPropertyAsFunction(*runtime, "__tickleJs"); + func.call(*runtime); + }); +} + +#endif \ No newline at end of file diff --git a/src/hermes/OpaqueNAPICallbackInfo.cpp b/src/hermes/OpaqueNAPICallbackInfo.cpp new file mode 100644 index 0000000..db4d375 --- /dev/null +++ b/src/hermes/OpaqueNAPICallbackInfo.cpp @@ -0,0 +1,11 @@ +#include + +OpaqueNAPICallbackInfo::OpaqueNAPICallbackInfo( + ::hermes::vm::NativeArgs nativeArgs, void *data) + : nativeArgs(std::move(nativeArgs)), data(data) {} + +const ::hermes::vm::NativeArgs &OpaqueNAPICallbackInfo::getNativeArgs() const { + return this->nativeArgs; +} + +void *OpaqueNAPICallbackInfo::getData() const { return this->data; } \ No newline at end of file diff --git a/src/hermes/OpaqueNAPIEnv.cpp b/src/hermes/OpaqueNAPIEnv.cpp new file mode 100644 index 0000000..498bf97 --- /dev/null +++ b/src/hermes/OpaqueNAPIEnv.cpp @@ -0,0 +1,104 @@ +#include +#include + +#ifdef HERMES_ENABLE_DEBUGGER +#include +#include +// #include +#include +#endif + +#include +#include +#include + +#ifndef SLIST_FOREACH_SAFE +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); (var) = (tvar)) +#endif + +#ifndef LIST_FOREACH_SAFE +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); (var) = (tvar)) +#endif + +OpaqueNAPIEnv::OpaqueNAPIEnv(const ::hermes::vm::RuntimeConfig &runtimeConfig) + : hermesRuntimeSharedPointer( + ::facebook::hermes::makeHermesRuntime(runtimeConfig)), + hermesRuntime(*this->hermesRuntimeSharedPointer), + runtime(::facebook::hermes::HermesRuntime::getHermesRuntimeFromJSI( + this->hermesRuntime)) { + // 0.8.x 版本开始会执行 runInternalBytecode -> runBytecode -> + // clearThrownValue,0.7.2 版本没有执行,需要手动执行清空 + // Runtime.h 文件定义了 PinnedHermesValue thrownValue_ = + // {} + // => undefined + LIST_INIT(&this->valueList); + LIST_INIT(&this->weakRefList); + LIST_INIT(&this->strongRefList); + SLIST_INIT(&this->handleScopeList); + + this->runtime.addCustomRootsFunction( + [this](::hermes::vm::GC *, ::hermes::vm::RootAcceptor &rootAcceptor) { + NAPIRef ref; + LIST_FOREACH(ref, &this->strongRefList, node) { + rootAcceptor.accept( + ::std::get<::hermes::vm::PinnedHermesValue>(ref->storage)); + } + }); + this->runtime.addCustomWeakRootsFunction( + [this](::hermes::vm::GC *, + ::hermes::vm::WeakRootAcceptor &weakRootAcceptor) { + NAPIRef ref; + LIST_FOREACH(ref, &this->weakRefList, node) { + weakRootAcceptor.acceptWeak( + ::std::get<::hermes::vm::WeakRoot<::hermes::vm::JSObject>>( + ref->storage)); + } + }); +} + +OpaqueNAPIEnv::~OpaqueNAPIEnv() { + this->disableDebugger(); + + { + NAPIHandleScope handleScope, temp; + SLIST_FOREACH_SAFE(handleScope, &this->handleScopeList, node, temp) { + delete handleScope; + } + } + NAPIRef ref, temp; + LIST_FOREACH_SAFE(ref, &this->valueList, node, temp) { delete ref; } + LIST_FOREACH_SAFE(ref, &this->strongRefList, node, temp) { delete ref; } + LIST_FOREACH_SAFE(ref, &this->weakRefList, node, temp) { delete ref; } +} + +::hermes::vm::Runtime &OpaqueNAPIEnv::getRuntime() const { + return this->runtime; +} + +#ifdef HERMES_ENABLE_DEBUGGER + +void OpaqueNAPIEnv::enableDebugger(const char *debuggerTitle, + bool waitForDebugger) const { + auto adapter = ::std::make_unique<::orangelabs::HermesExecutorRuntimeAdapter>( + this->hermesRuntimeSharedPointer, this->hermesRuntime, + this->messageQueueThread); + ::std::string debuggerTitleString = + debuggerTitle ? debuggerTitle : "N-API Hermes"; + ::orangelab::hermes::inspector::chrome::enableDebugging( + ::std::move(adapter), debuggerTitleString, waitForDebugger); +} + +void OpaqueNAPIEnv::disableDebugger() const { + ::orangelab::hermes::inspector::chrome::disableDebugging(this->hermesRuntime); +} + +void OpaqueNAPIEnv::setMessageQueueThread( + ::std::shared_ptr<::facebook::react::MessageQueueThread> jsQueue) { + this->messageQueueThread = ::std::move(jsQueue); +} + +#endif diff --git a/src/hermes/OpaqueNAPIEscapableHandleScope.cpp b/src/hermes/OpaqueNAPIEscapableHandleScope.cpp new file mode 100644 index 0000000..153e5c9 --- /dev/null +++ b/src/hermes/OpaqueNAPIEscapableHandleScope.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +OpaqueNAPIEscapableHandleScope::OpaqueNAPIEscapableHandleScope( + ::hermes::vm::HandleRootOwner &runtime, + ::hermes::vm::MutableHandle<::hermes::vm::HermesValue> + preservedMutableHandle) + : OpaqueNAPIHandleScope(runtime), + mutableHandle(::std::move(preservedMutableHandle)), + escapeCalled(false) {} + +bool OpaqueNAPIEscapableHandleScope::isEscapeCalled() const { + return this->escapeCalled; +} + +const ::hermes::vm::PinnedHermesValue *OpaqueNAPIEscapableHandleScope::escape( + const ::hermes::vm::HermesValue &hermesValue) { + if (this->escapeCalled) { + return nullptr; + } + this->mutableHandle.set(hermesValue); + this->escapeCalled = true; + + return this->mutableHandle.unsafeGetPinnedHermesValue(); +} diff --git a/src/hermes/OpaqueNAPIHandleScope.cpp b/src/hermes/OpaqueNAPIHandleScope.cpp new file mode 100644 index 0000000..894aa0e --- /dev/null +++ b/src/hermes/OpaqueNAPIHandleScope.cpp @@ -0,0 +1,6 @@ +#include +#include + +OpaqueNAPIHandleScope::OpaqueNAPIHandleScope( + ::hermes::vm::HandleRootOwner &runtime) + : gcScope(runtime) {} \ No newline at end of file diff --git a/src/hermes/OpaqueNAPIRef.cpp b/src/hermes/OpaqueNAPIRef.cpp new file mode 100644 index 0000000..8693dc2 --- /dev/null +++ b/src/hermes/OpaqueNAPIRef.cpp @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include + +#include + +OpaqueNAPIRef::OpaqueNAPIRef( + NAPIEnv env, const ::hermes::vm::PinnedHermesValue &pinnedHermesValue, + uint8_t referenceCount) + : env(env), referenceCount(referenceCount) { + if (!referenceCount && !pinnedHermesValue.isObject()) { + LIST_INSERT_HEAD(&this->env->valueList, this, node); + this->storage = ::std::monostate(); + } else if (referenceCount) { + LIST_INSERT_HEAD(&this->env->strongRefList, this, node); + this->storage = pinnedHermesValue; + } else { + LIST_INSERT_HEAD(&this->env->weakRefList, this, node); + this->storage.emplace<::hermes::vm::WeakRoot<::hermes::vm::JSObject>>( + ::hermes::vm::WeakRoot<::hermes::vm::JSObject>( + ::hermes::vm::dyn_vmcast<::hermes::vm::JSObject>(pinnedHermesValue), + this->env->getRuntime())); + } +} + +OpaqueNAPIRef::~OpaqueNAPIRef() { LIST_REMOVE(this, node); } + +void OpaqueNAPIRef::ref() { + if (!this->referenceCount) { + LIST_REMOVE(this, node); + LIST_INSERT_HEAD(&this->env->strongRefList, this, node); + if (!this->storage.index()) { + this->storage = ::hermes::vm::Runtime::getUndefinedValue().get(); + } else { + auto weakRoot = + ::std::get<::hermes::vm::WeakRoot<::hermes::vm::JSObject>>( + this->storage); + auto jsObject = weakRoot.get(this->env->getRuntime(), + this->env->getRuntime().getHeap()); + if (jsObject) { + this->storage = ::hermes::vm::HermesValue::encodeObjectValue(jsObject); + } else { + this->storage = ::hermes::vm::Runtime::getUndefinedValue().get(); + } + } + } + ++this->referenceCount; +} + +void OpaqueNAPIRef::unref() { + assert(this->referenceCount); + if (this->referenceCount == 1) { + LIST_REMOVE(this, node); + if (!::std::get<::hermes::vm::PinnedHermesValue>(this->storage) + .isObject()) { + LIST_INSERT_HEAD(&this->env->valueList, this, node); + this->storage = ::std::monostate(); + } else { + LIST_INSERT_HEAD(&this->env->weakRefList, this, node); + this->storage.emplace<::hermes::vm::WeakRoot<::hermes::vm::JSObject>>( + ::hermes::vm::dyn_vmcast<::hermes::vm::JSObject>( + ::std::get<::hermes::vm::PinnedHermesValue>(this->storage)), + this->env->getRuntime()); + } + } + --this->referenceCount; +} + +uint8_t OpaqueNAPIRef::getReferenceCount() const { + return this->referenceCount; +} + +const ::hermes::vm::PinnedHermesValue *OpaqueNAPIRef::getHermesValue() const { + switch (this->storage.index()) { + case 0: + return nullptr; + case 1: + return this->env->getRuntime() + .makeHandle( + ::std::get<::hermes::vm::PinnedHermesValue>(this->storage)) + .unsafeGetPinnedHermesValue(); + case 2: { + auto weakRoot = + ::std::get<::hermes::vm::WeakRoot<::hermes::vm::JSObject>>( + this->storage); + auto jsObject = weakRoot.get(this->env->getRuntime(), + this->env->getRuntime().getHeap()); + if (!jsObject) { + return nullptr; + } else { + auto handle = + this->env->getRuntime().makeHandle<::hermes::vm::JSObject>( + jsObject); + + return handle.unsafeGetPinnedHermesValue(); + } + } + + default: + return nullptr; + } +} diff --git a/src/inspector/js_native_api_hermes_inspector.cpp b/src/hermes/js_native_api_hermes_inspector.cpp similarity index 99% rename from src/inspector/js_native_api_hermes_inspector.cpp rename to src/hermes/js_native_api_hermes_inspector.cpp index c4024ff..2ffe258 100644 --- a/src/inspector/js_native_api_hermes_inspector.cpp +++ b/src/hermes/js_native_api_hermes_inspector.cpp @@ -5,7 +5,7 @@ #include #include -#include "js_native_api_hermes_inspector.h" +#include namespace orangelab { diff --git a/src/js_native_api_hermes.cpp b/src/js_native_api_hermes.cpp index 03a03d1..1c3f621 100644 --- a/src/js_native_api_hermes.cpp +++ b/src/js_native_api_hermes.cpp @@ -1,1572 +1,1059 @@ #include -#include +#include +#include +#include +#include +#include +#include +#include #include -#include #include #include #include #include #include -#include -#include -#include #include #include +#include #include #include -#include -#include - -// private header -#include "inspector/js_native_api_hermes_inspector.h" - -#ifdef HERMES_ENABLE_DEBUGGER -#include -#include -#endif - -#ifndef LIST_FOREACH_SAFE -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = LIST_FIRST((head)); (var) && ((tvar) = LIST_NEXT((var), field), 1); (var) = (tvar)) -#endif #include -#define RETURN_STATUS_IF_FALSE(condition, status) \ - if (!(condition)) \ - { \ - return status; \ - } - -#define CHECK_ARG(arg, status) \ - if (!arg) \ - { \ - return NAPI##status##InvalidArg; \ - } - -#define CHECK_NAPI(expr, exprStatus, returnStatus) \ - { \ - NAPI##exprStatus##Status status = expr; \ - if (status != NAPI##exprStatus##OK) \ - { \ - return (NAPI##returnStatus##Status)status; \ - } \ - } - -#define CHECK_HERMES(expr) \ - if ((expr) == hermes::vm::ExecutionStatus::EXCEPTION) \ - { \ - return NAPIExceptionPendingException; \ - } - -#define NAPI_PREAMBLE(env) \ - CHECK_ARG(env, Exception) \ - RETURN_STATUS_IF_FALSE(env->getRuntime()->getThrownValue().isEmpty(), NAPIExceptionPendingException) - -namespace -{ -class External final : public hermes::vm::HostObjectProxy -{ - public: - External(hermes::vm::Runtime *runtime, void *data, NAPIFinalize finalizeCallback, void *finalizeHint); - - void *getData() const; - - ~External() override; - - hermes::vm::CallResult get(hermes::vm::SymbolID symbolId) override; - - hermes::vm::CallResult set(hermes::vm::SymbolID symbolId, hermes::vm::HermesValue value) override; - - hermes::vm::CallResult> getHostPropertyNames() override; - - // copy ctor - External(const External &) = delete; - - // move ctor - External(External &&) = delete; - - // copy assign - External &operator=(const External &) = delete; - - // move assign - External &operator=(External &&) = delete; - - private: - hermes::vm::Runtime *runtime; - void *data; - NAPIFinalize finalizeCallback; - void *finalizeHint; -}; - -// hermes.cpp -> kMaxNumRegisters -constexpr unsigned int kMaxNumRegisters = - (512 * 1024 - sizeof(hermes::vm::Runtime) - 4096 * 8) / sizeof(hermes::vm::PinnedHermesValue); - -#ifdef HERMES_ENABLE_DEBUGGER - -class HermesExecutorRuntimeAdapter final : public facebook::hermes::inspector::RuntimeAdapter -{ - public: - HermesExecutorRuntimeAdapter(std::shared_ptr runtime, - facebook::hermes::HermesRuntime &hermesRuntime, - std::shared_ptr thread) - : runtime_(std::move(runtime)), hermesRuntime_(hermesRuntime), thread_(thread ? std::move(thread) : nullptr) - { - } - - ~HermesExecutorRuntimeAdapter() override = default; - - facebook::jsi::Runtime &getRuntime() override - { - return *runtime_; - } - - facebook::hermes::debugger::Debugger &getDebugger() override - { - return hermesRuntime_.getDebugger(); - } - - void tickleJs() override - { - // The queue will ensure that runtime_ is still valid when this - // gets invoked. - if (!this->thread_) - return; - thread_->runOnQueue([runtime = runtime_]() { - auto func = runtime->global().getPropertyAsFunction(*runtime, "__tickleJs"); - func.call(*runtime); - }); - } - - private: - std::shared_ptr runtime_; - facebook::hermes::HermesRuntime &hermesRuntime_; - std::shared_ptr thread_; -}; - -#endif -} // namespace - -External::External(hermes::vm::Runtime *runtime, void *data, NAPIFinalize finalizeCallback, void *finalizeHint) - : runtime(runtime), data(data), finalizeCallback(finalizeCallback), finalizeHint(finalizeHint) -{ -} - -void *External::getData() const -{ - return data; -} -External::~External() -{ - if (finalizeCallback) - { - finalizeCallback(data, finalizeHint); - } -} -hermes::vm::CallResult External::get(hermes::vm::SymbolID symbolId) -{ - return hermes::vm::Runtime::getUndefinedValue().get(); -} -hermes::vm::CallResult External::set(hermes::vm::SymbolID symbolId, hermes::vm::HermesValue value) -{ - return false; -} -hermes::vm::CallResult> External::getHostPropertyNames() -{ - return hermes::vm::JSArray::create(runtime, 0, 0); -} - -EXTERN_C_START - -struct OpaqueNAPIRef; - -struct OpaqueNAPIEnv final -{ - explicit OpaqueNAPIEnv(const hermes::vm::RuntimeConfig &runtimeConfig); - - ~OpaqueNAPIEnv(); - - hermes::vm::Runtime *getRuntime() const - { - return runtime; - } - - OpaqueNAPIEnv(const OpaqueNAPIEnv &) = delete; - - OpaqueNAPIEnv(OpaqueNAPIEnv &&) = delete; - - OpaqueNAPIEnv &operator=(const OpaqueNAPIEnv &) = delete; - - OpaqueNAPIEnv &operator=(OpaqueNAPIEnv &&) = delete; - - LIST_HEAD(, OpaqueNAPIRef) valueList; - - LIST_HEAD(, OpaqueNAPIRef) weakRefList; - - LIST_HEAD(, OpaqueNAPIRef) strongRefList; - - void enableDebugger(const char *debuggerTitle, bool waitForDebugger); - - void disableDebugger(); -#ifdef HERMES_ENABLE_DEBUGGER - void setMessageQueueThread(std::shared_ptr jsQueue) - { - this->thread_ = jsQueue; - } - // 不做持有,直接传递给 runtimeAdapter。 - std::shared_ptr snapGetMessageQueueThread() - { - return std::move(this->thread_); - } -#endif - - private: - hermes::vm::Runtime *runtime; - - std::shared_ptr hermesRuntimeSharedPtr; - - facebook::hermes::HermesRuntime &hermesRuntime; - - std::shared_ptr thread_; -}; - -void OpaqueNAPIEnv::enableDebugger(const char *debuggerTitle, bool waitForDebugger) -{ -#ifdef HERMES_ENABLE_DEBUGGER - - auto adapter = std::make_unique(hermesRuntimeSharedPtr, hermesRuntime, - this->snapGetMessageQueueThread()); - std::string debuggerTitleString = debuggerTitle ? debuggerTitle : "Hummer Hermes"; - orangelab::hermes::inspector::chrome::enableDebugging(std::move(adapter), debuggerTitleString, waitForDebugger); -#endif -} - -void OpaqueNAPIEnv::disableDebugger() -{ -#ifdef HERMES_ENABLE_DEBUGGER - orangelab::hermes::inspector::chrome::disableDebugging(hermesRuntime); -#endif -} - -// 初始状态 -// !referenceCount && !isObject => (undefined, 0) => addValue -// referenceCount > 0 => 强引用 => addStrong -// !referenceCount && isObject => 弱引用 => addWeak - -// 1 + ref => undefined 强引用 => removeValue + addStrong -// 2 + ref => 强引用 -// (2 + unref) && isObject => weakRef => removeStrong + addWeak -// (2 + unref) && !isObject => (undefined, 0) => removeStrong + addValue -// (3 + ref) && 有效 => 强引用 => removeWeak + addStrong -// (3 + ref) && 无效 => undefined 强引用 => removeWeak + addStrong + isObject = false; - -struct OpaqueNAPIRef final -{ - OpaqueNAPIRef(NAPIEnv env, const hermes::vm::PinnedHermesValue &pinnedHermesValue, uint8_t referenceCount) - : env(env), referenceCount(referenceCount), isObject(pinnedHermesValue.isObject()) - { - // 标量 && 弱引用 - if (!referenceCount && !isObject) - { - LIST_INSERT_HEAD(&env->valueList, this, node); - this->pinnedHermesValue = *hermes::vm::Runtime::getUndefinedValue().unsafeGetPinnedHermesValue(); - } - else if (referenceCount) - { - // 强引用 - this->pinnedHermesValue = pinnedHermesValue; - LIST_INSERT_HEAD(&env->strongRefList, this, node); - } - else - { - // 对象 && 弱引用 - // addWeak - // runtime->getHeap() mutable,因此不能使用 const hermes::vm::Runtime * - this->hermesValueWeakRef = - hermes::vm::WeakRef(&env->getRuntime()->getHeap(), pinnedHermesValue); - LIST_INSERT_HEAD(&env->weakRefList, this, node); - } - } - OpaqueNAPIRef(const OpaqueNAPIRef &) = delete; - - OpaqueNAPIRef(OpaqueNAPIRef &&) = delete; - - OpaqueNAPIRef &operator=(const OpaqueNAPIRef &) = delete; - - OpaqueNAPIRef &operator=(OpaqueNAPIRef &&) = delete; - - ~OpaqueNAPIRef() - { - LIST_REMOVE(this, node); - } - void ref() - { - if (!referenceCount) - { - LIST_REMOVE(this, node); - if (!isObject) - { - LIST_INSERT_HEAD(&env->strongRefList, this, node); - } - else - { - auto hermesValueOptional = hermesValueWeakRef.unsafeGetOptional(&env->getRuntime()->getHeap()); - if (hermesValueOptional.hasValue()) - { - pinnedHermesValue = hermesValueOptional.getValue(); - } - else - { - pinnedHermesValue = *hermes::vm::Runtime::getUndefinedValue().unsafeGetPinnedHermesValue(); - isObject = false; - } - LIST_INSERT_HEAD(&env->strongRefList, this, node); - } - } - ++referenceCount; - } - void unref() - { - assert(referenceCount); - if (referenceCount == 1) - { - LIST_REMOVE(this, node); - if (isObject) - { - hermesValueWeakRef = - hermes::vm::WeakRef(&env->getRuntime()->getHeap(), pinnedHermesValue); - LIST_INSERT_HEAD(&env->weakRefList, this, node); - } - else - { - pinnedHermesValue = *hermes::vm::Runtime::getUndefinedValue().unsafeGetPinnedHermesValue(); - LIST_INSERT_HEAD(&env->valueList, this, node); - } - } - --referenceCount; - } - uint8_t getReferenceCount() const - { - return referenceCount; - } - - LIST_ENTRY(OpaqueNAPIRef) node; - - union { - hermes::vm::PinnedHermesValue pinnedHermesValue; // 64 - hermes::vm::WeakRef hermesValueWeakRef; // size_t - }; - const hermes::vm::PinnedHermesValue *getHermesValue() const - { - if (!referenceCount && !isObject) - { - return nullptr; - } - else if (referenceCount) - { - return hermes::vm::Handle::vmcast(env->getRuntime(), pinnedHermesValue) +#define RETURN_STATUS_IF_FALSE(condition, status) \ + if (!(condition)) { \ + return status; \ + } + +#define CHECK_ARG(arg, status) \ + if (!arg) { \ + return NAPI##status##InvalidArg; \ + } + +#define CHECK_NAPI(expr, exprStatus, returnStatus) \ + { \ + NAPI##exprStatus##Status status = expr; \ + if (status != NAPI##exprStatus##OK) { \ + return (NAPI##returnStatus##Status)status; \ + } \ + } + +#define CHECK_HERMES(expr) \ + if ((expr) == ::hermes::vm::ExecutionStatus::EXCEPTION) { \ + return NAPIExceptionPendingException; \ + } + +#define NAPI_PREAMBLE(env) \ + CHECK_ARG(env, Exception) \ + RETURN_STATUS_IF_FALSE(env->getRuntime().getThrownValue().isEmpty(), \ + NAPIExceptionPendingException) + +NAPICommonStatus napi_get_undefined(NAPIEnv /*env*/, NAPIValue *result) { + CHECK_ARG(result, Common) + + *result = (NAPIValue)::hermes::vm::HandleRootOwner::getUndefinedValue() .unsafeGetPinnedHermesValue(); - } - else - { - // 会创建 Handle - auto hermesValueHandleOptional = hermesValueWeakRef.get(env->getRuntime(), &env->getRuntime()->getHeap()); - if (hermesValueHandleOptional.hasValue()) - { - return hermesValueHandleOptional.getValue().unsafeGetPinnedHermesValue(); - } - else - { - return nullptr; - } - } - } - - private: - NAPIEnv env; - uint8_t referenceCount; - bool isObject; -}; - -EXTERN_C_END - -OpaqueNAPIEnv::~OpaqueNAPIEnv() -{ - disableDebugger(); - NAPIRef ref, temp; - LIST_FOREACH_SAFE(ref, &valueList, node, temp) - { - delete ref; - } - LIST_FOREACH_SAFE(ref, &strongRefList, node, temp) - { - delete ref; - } - LIST_FOREACH_SAFE(ref, &weakRefList, node, temp) - { - delete ref; - } -} - -OpaqueNAPIEnv::OpaqueNAPIEnv(const hermes::vm::RuntimeConfig &runtimeConfig) - : hermesRuntimeSharedPtr(facebook::hermes::makeHermesRuntime(runtimeConfig)), hermesRuntime(*hermesRuntimeSharedPtr) -{ - // HermesExecutorFactory -> heapSizeMB 1024 -> HermesExecutor -> initHybrid - // https://github.com/facebook/react-native/blob/v0.64.2/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/OnLoad.cpp#L85 - // https://github.com/facebook/react-native/blob/v0.64.2/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/OnLoad.cpp#L33 - // auto gcConfigBuilder = hermes::vm::GCConfig::Builder() - // .withName("N-API") - // .withAllocInYoung(false) - // .withRevertToYGAtTTI(true) - // .withMaxHeapSize(1024 << 20); - // auto runtimeConfig = hermes::vm::RuntimeConfig::Builder() - // .withGCConfig(gcConfigBuilder.build()) - // .withRegisterStack(nullptr) - // .withMaxNumRegisters(kMaxNumRegisters) - // .build(); - // std::unique_ptr hermesRuntime = - // facebook::hermes::makeHermesRuntime(runtimeConfig); facebook::hermes::HermesRuntime &hermesRuntimeRef = - // *hermesRuntime; decoratedRuntime = std::make_shared(std::move(hermesRuntime), - // hermesRuntimeRef); - runtime = facebook::hermes::HermesRuntime::getHermesRuntimeFromJSI(&hermesRuntime); - // 0.8.x 版本开始会执行 runInternalBytecode -> runBytecode -> clearThrownValue,0.7.2 版本没有执行,需要手动执行清空 - // RuntimeHermesValueFields.def 文件定义了 PinnedHermesValue thrownValue_ = {} => undefined - // runtime->clearThrownValue(); - LIST_INIT(&valueList); - LIST_INIT(&weakRefList); - LIST_INIT(&strongRefList); - - runtime->addCustomRootsFunction([this](hermes::vm::GC *, hermes::vm::RootAcceptor &rootAcceptor) { - NAPIRef ref; - LIST_FOREACH(ref, &this->strongRefList, node) - { - rootAcceptor.accept(ref->pinnedHermesValue); - } - }); - runtime->addCustomWeakRootsFunction([this](hermes::vm::GC *, hermes::vm::WeakRefAcceptor &weakRefAcceptor) { - NAPIRef ref; - LIST_FOREACH(ref, &this->weakRefList, node) - { - weakRefAcceptor.accept(ref->hermesValueWeakRef); - } - }); + return NAPICommonOK; } -namespace -{ - -class FunctionInfo final -{ - public: - FunctionInfo(NAPIEnv env, NAPICallback callback, void *data) : env(env), callback(callback), data(data) - { - } - NAPIEnv getEnv() const - { - return env; - } - NAPICallback getCallback() const - { - return callback; - } - void *getData() const - { - return data; - } - - FunctionInfo(const FunctionInfo &) = delete; - - FunctionInfo(FunctionInfo &&) = delete; - - FunctionInfo &operator=(const FunctionInfo &) = delete; - - FunctionInfo &operator=(FunctionInfo &&) = delete; - - private: - NAPIEnv env; - NAPICallback callback; - void *data; -}; -} // namespace - -EXTERN_C_START +NAPICommonStatus napi_get_null(NAPIEnv /*env*/, NAPIValue *result) { + CHECK_ARG(result, Common) -struct OpaqueNAPICallbackInfo -{ - OpaqueNAPICallbackInfo(const hermes::vm::NativeArgs &nativeArgs, void *data) : nativeArgs(nativeArgs), data(data) - { - } - const hermes::vm::NativeArgs &getNativeArgs() const - { - return nativeArgs; - } - void *getData() const - { - return data; - } - - OpaqueNAPICallbackInfo(const OpaqueNAPICallbackInfo &) = delete; - - OpaqueNAPICallbackInfo(OpaqueNAPICallbackInfo &&) = delete; - - OpaqueNAPICallbackInfo &operator=(const OpaqueNAPICallbackInfo &) = delete; - - OpaqueNAPICallbackInfo &operator=(OpaqueNAPICallbackInfo &&) = delete; - - private: - hermes::vm::NativeArgs nativeArgs; - void *data; -}; - -EXTERN_C_END - -NAPICommonStatus napi_get_undefined(NAPIEnv /*env*/, NAPIValue *result) -{ - CHECK_ARG(result, Common) - - *result = (NAPIValue)hermes::vm::Runtime::getUndefinedValue().unsafeGetPinnedHermesValue(); + *result = (NAPIValue)::hermes::vm::HandleRootOwner::getNullValue() + .unsafeGetPinnedHermesValue(); - return NAPICommonOK; + return NAPICommonOK; } -NAPICommonStatus napi_get_null(NAPIEnv /*env*/, NAPIValue *result) -{ - CHECK_ARG(result, Common) +NAPIErrorStatus napi_get_global(NAPIEnv env, NAPIValue *result) { + CHECK_ARG(env, Error) + CHECK_ARG(result, Error) - *result = (NAPIValue)hermes::vm::Runtime::getNullValue().unsafeGetPinnedHermesValue(); + *result = + (NAPIValue)env->getRuntime().getGlobal().unsafeGetPinnedHermesValue(); - return NAPICommonOK; + return NAPIErrorOK; } -NAPIErrorStatus napi_get_global(NAPIEnv env, NAPIValue *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_get_boolean(NAPIEnv /*env*/, bool value, + NAPIValue *result) { + CHECK_ARG(result, Error) - *result = (NAPIValue)env->getRuntime()->getGlobal().unsafeGetPinnedHermesValue(); + *result = (NAPIValue)::hermes::vm::HandleRootOwner::getBoolValue(value) + .unsafeGetPinnedHermesValue(); - return NAPIErrorOK; + return NAPIErrorOK; } -NAPIErrorStatus napi_get_boolean(NAPIEnv /*env*/, bool value, NAPIValue *result) -{ - CHECK_ARG(result, Error) +NAPIErrorStatus napi_create_double(NAPIEnv env, double value, + NAPIValue *result) { + CHECK_ARG(env, Error) + CHECK_ARG(result, Error) - *result = (NAPIValue)hermes::vm::Runtime::getBoolValue(value).unsafeGetPinnedHermesValue(); + // HermesValue.h -> encodeNumberValue + *result = (NAPIValue)env->getRuntime() + .makeHandle(::hermes::vm::HermesValue::encodeNumberValue(value)) + .unsafeGetPinnedHermesValue(); - return NAPIErrorOK; + return NAPIErrorOK; } -NAPIErrorStatus napi_create_double(NAPIEnv env, double value, NAPIValue *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(result, Error) - - // HermesValue.h -> encodeNumberValue - *result = (NAPIValue)env->getRuntime() - ->makeHandle(::hermes::vm::HermesValue::encodeNumberValue(value)) - .unsafeGetPinnedHermesValue(); +NAPIExceptionStatus napi_create_string_utf8(NAPIEnv env, const char *str, + NAPIValue *result) { + NAPI_PREAMBLE(env) + CHECK_ARG(result, Exception) + + auto callResult = ::hermes::vm::StringPrimitive::createEfficient( + env->getRuntime(), + ::llvh::makeArrayRef( + reinterpret_cast(str), str ? strlen(str) : 0)); + CHECK_HERMES(callResult) + *result = (NAPIValue)env->getRuntime() + .makeHandle(callResult.getValue()) + .unsafeGetPinnedHermesValue(); - return NAPIErrorOK; + return NAPIExceptionOK; } -NAPIExceptionStatus napi_create_string_utf8(NAPIEnv env, const char *str, NAPIValue *result) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(result, Exception) - - if (!str) - { - str = ""; - } - size_t length = strlen(str); - hermes::vm::CallResult callResult(hermes::vm::ExecutionStatus::EXCEPTION); - if (hermes::isAllASCII(str, str + length)) - { - // length 0 也算 ASCII,但是 hermes::vm::createASCIIRef 不能传入 nullptr,因此不能直接使用 (nullptr, 0) 构造 - callResult = hermes::vm::StringPrimitive::createEfficient(env->getRuntime(), hermes::vm::createASCIIRef(str)); - } - else - { - // 多一个 \0 - auto out = static_cast(malloc(sizeof(uint16_t) * (length + 1))); - RETURN_STATUS_IF_FALSE(out, NAPIExceptionMemoryError) - // std::u16string resize 失败会抛出异常,因此使用 malloc - auto sourceStart = (const llvh::UTF8 *)str; - auto sourceEnd = sourceStart + length; - auto targetStart = out; - auto targetEnd = targetStart + length; - llvh::ConversionResult conversionResult; - conversionResult = - llvh::ConvertUTF8toUTF16(&sourceStart, sourceEnd, &targetStart, targetEnd - 1, llvh::lenientConversion); - if (conversionResult == llvh::ConversionResult::targetExhausted) - { - assert(false); - free(out); - - return NAPIExceptionMemoryError; - } - else if (conversionResult != llvh::ConversionResult::conversionOK) - { - free(out); - - return NAPIExceptionMemoryError; - } - *targetStart = '\0'; - // std::u16string 会作为后备存储使用并调用 std::move,但是这里不是 - callResult = hermes::vm::StringPrimitive::createEfficient( - env->getRuntime(), hermes::vm::createUTF16Ref(reinterpret_cast(out))); - free(out); - } +NAPIExceptionStatus napi_create_function(NAPIEnv env, const char *utf8name, + NAPICallback callback, void *data, + NAPIValue *result) { + NAPI_PREAMBLE(env) + CHECK_ARG(callback, Exception) + CHECK_ARG(result, Exception) + + ::hermes::vm::MutableHandle<::hermes::vm::HermesValue> mutableHandle( + env->getRuntime()); + + ::hermes::vm::GCScope gcScope(env->getRuntime()); + + ::hermes::vm::StringPrimitive *stringPrimitive; + { + auto callResult = ::hermes::vm::StringPrimitive::createEfficient( + env->getRuntime(), + ::llvh::makeArrayRef( + reinterpret_cast(utf8name), + utf8name ? strlen(utf8name) : 0)); CHECK_HERMES(callResult) - *result = (NAPIValue)env->getRuntime()->makeHandle(callResult.getValue()).unsafeGetPinnedHermesValue(); - return NAPIExceptionOK; + stringPrimitive = ::hermes::vm::vmcast<::hermes::vm::StringPrimitive>( + callResult.getValue()); + } + RETURN_STATUS_IF_FALSE(stringPrimitive, NAPIExceptionMemoryError) + auto callResult = ::hermes::vm::stringToSymbolID( + env->getRuntime(), ::hermes::vm::createPseudoHandle(stringPrimitive)); + CHECK_HERMES(callResult) + auto symbolId = callResult.getValue().get(); + + auto functionInfo = + new (::std::nothrow)::orangelabs::FunctionInfo(env, callback, data); + RETURN_STATUS_IF_FALSE(functionInfo, NAPIExceptionMemoryError) + + ::hermes::vm::NativeFunctionPtr nativeFunctionPtr = + [](void *context, ::hermes::vm::Runtime &runtime, + ::hermes::vm::NativeArgs args) + -> ::hermes::vm::CallResult<::hermes::vm::HermesValue> { + ::hermes::vm::MutableHandle<::hermes::vm::HermesValue> inlineMutableHandle( + runtime); + + ::hermes::vm::GCScope inlineGCScope(runtime); + + auto innerFunctionInfo = (::orangelabs::FunctionInfo *)context; + if (!innerFunctionInfo->getCallback() || !innerFunctionInfo->getEnv()) { + assert(false); + + return {::hermes::vm::HandleRootOwner::getUndefinedValue().get()}; + } + struct OpaqueNAPICallbackInfo callbackInfo(::std::move(args), + innerFunctionInfo->getData()); + NAPIValue returnValue = innerFunctionInfo->getCallback()( + innerFunctionInfo->getEnv(), &callbackInfo); + RETURN_STATUS_IF_FALSE( + innerFunctionInfo->getEnv()->getRuntime().getThrownValue().isEmpty(), + ::hermes::vm::ExecutionStatus::EXCEPTION) + if (!returnValue) { + return {::hermes::vm::HandleRootOwner::getUndefinedValue().get()}; + } + + inlineMutableHandle.set( + *(const ::hermes::vm::PinnedHermesValue *)returnValue); + + return inlineMutableHandle.get(); + }; + ::hermes::vm::FinalizeNativeFunctionPtr finalizeNativeFunctionPtr = + [](void *context) { delete (::orangelabs::FunctionInfo *)context; }; + auto functionCallResult = + ::hermes::vm::FinalizableNativeFunction::createWithoutPrototype( + env->getRuntime(), functionInfo, nativeFunctionPtr, + finalizeNativeFunctionPtr, symbolId, 0); + if (functionCallResult == ::hermes::vm::ExecutionStatus::EXCEPTION) { + delete functionInfo; + + return NAPIExceptionPendingException; + } + mutableHandle.set(functionCallResult.getValue()); + *result = (NAPIValue)mutableHandle.unsafeGetPinnedHermesValue(); + + return NAPIExceptionOK; } -NAPIExceptionStatus napi_create_function(NAPIEnv env, const char *utf8name, NAPICallback callback, void *data, - NAPIValue *result) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(callback, Exception) - CHECK_ARG(result, Exception) - - hermes::vm::GCScope gcScope(env->getRuntime()); - NAPIValue stringValue; - CHECK_NAPI(napi_create_string_utf8(env, utf8name, &stringValue), Exception, Exception) - auto stringPrimitive = hermes::vm::dyn_vmcast_or_null( - *(const hermes::vm::PinnedHermesValue *)stringValue); - RETURN_STATUS_IF_FALSE(stringPrimitive, NAPIExceptionMemoryError) - auto callResult = hermes::vm::stringToSymbolID(env->getRuntime(), hermes::vm::createPseudoHandle(stringPrimitive)); - CHECK_HERMES(callResult) - auto symbolId = callResult.getValue().get(); - auto functionInfo = new (::std::nothrow) FunctionInfo(env, callback, data); - RETURN_STATUS_IF_FALSE(functionInfo, NAPIExceptionMemoryError) - hermes::vm::NativeFunctionPtr nativeFunctionPtr = - [](void *context, hermes::vm::Runtime *runtime, - hermes::vm::NativeArgs args) -> hermes::vm::CallResult { - hermes::vm::GCScope inlineGCScope(runtime); - auto innerFunctionInfo = (FunctionInfo *)context; - if (!innerFunctionInfo->getCallback() || !innerFunctionInfo->getEnv()) - { - assert(false); - - return {hermes::vm::Runtime::getUndefinedValue().get()}; - } - struct OpaqueNAPICallbackInfo callbackInfo(args, innerFunctionInfo->getData()); - NAPIValue returnValue = innerFunctionInfo->getCallback()(innerFunctionInfo->getEnv(), &callbackInfo); - RETURN_STATUS_IF_FALSE(innerFunctionInfo->getEnv()->getRuntime()->getThrownValue().isEmpty(), - hermes::vm::ExecutionStatus::EXCEPTION) - if (!returnValue) - { - return {hermes::vm::Runtime::getUndefinedValue().get()}; - } - - return {*(const hermes::vm::PinnedHermesValue *)returnValue}; - }; - hermes::vm::FinalizeNativeFunctionPtr finalizeNativeFunctionPtr = [](void *context) { - // 没有析构方法 - delete (FunctionInfo *)context; - }; - // TODO(ChasonTang): 添加 .prototype 属性 - auto functionCallResult = hermes::vm::FinalizableNativeFunction::createWithoutPrototype( - env->getRuntime(), functionInfo, nativeFunctionPtr, finalizeNativeFunctionPtr, symbolId, 0); - if (functionCallResult == hermes::vm::ExecutionStatus::EXCEPTION) - { - delete functionInfo; - - return NAPIExceptionPendingException; - } - *result = - (NAPIValue)hermes::vm::Handle(gcScope.getParentScope(), functionCallResult.getValue()) - .unsafeGetPinnedHermesValue(); - - return NAPIExceptionOK; +NAPICommonStatus napi_typeof(NAPIEnv /*env*/, NAPIValue value, + NAPIValueType *result) { + CHECK_ARG(value, Common) + CHECK_ARG(result, Common) + + ::hermes::vm::HermesValue hermesValue = + *(const ::hermes::vm::PinnedHermesValue *)value; + if (hermesValue.isUndefined()) { + *result = NAPIUndefined; + } else if (hermesValue.isNull()) { + *result = NAPINull; + } else if (hermesValue.isBool()) { + *result = NAPIBoolean; + } else if (hermesValue.isNumber()) { + *result = NAPINumber; + } else if (hermesValue.isString()) { + *result = NAPIString; + } else if (hermesValue.isObject()) { + bool isFunction = ::hermes::vm::vmisa<::hermes::vm::Callable>(hermesValue); + if (isFunction) { + *result = NAPIFunction; + } else { + *result = ::hermes::vm::vmisa<::hermes::vm::HostObject>(hermesValue) + ? NAPIExternal + : NAPIObject; + } + } else { + assert(false); + + return NAPICommonInvalidArg; + } + + return NAPICommonOK; } -NAPICommonStatus napi_typeof(NAPIEnv /*env*/, NAPIValue value, NAPIValueType *result) -{ - CHECK_ARG(value, Common) - CHECK_ARG(result, Common) +NAPIErrorStatus napi_get_value_double(NAPIEnv /*env*/, NAPIValue value, + double *result) { + CHECK_ARG(value, Error) + CHECK_ARG(result, Error) - hermes::vm::HermesValue hermesValue = *(const hermes::vm::PinnedHermesValue *)value; - if (hermesValue.isUndefined()) - { - *result = NAPIUndefined; - } - else if (hermesValue.isNull()) - { - *result = NAPINull; - } - else if (hermesValue.isBool()) - { - *result = NAPIBoolean; - } - else if (hermesValue.isNumber()) - { - *result = NAPINumber; - } - else if (hermesValue.isString()) - { - *result = NAPIString; - } - else if (hermesValue.isObject()) - { - bool isFunction = hermes::vm::vmisa(hermesValue); - if (isFunction) - { - *result = NAPIFunction; - } - else - { - *result = hermes::vm::vmisa(hermesValue) ? NAPIExternal : NAPIObject; - } - } - else - { - assert(false); + RETURN_STATUS_IF_FALSE( + (*(const ::hermes::vm::PinnedHermesValue *)value).isNumber(), + NAPIErrorNumberExpected) - return NAPICommonInvalidArg; - } + *result = (*(const ::hermes::vm::PinnedHermesValue *)value).getNumber(); - return NAPICommonOK; + return NAPIErrorOK; } -NAPIErrorStatus napi_get_value_double(NAPIEnv /*env*/, NAPIValue value, double *result) -{ - CHECK_ARG(value, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_get_value_bool(NAPIEnv /*env*/, NAPIValue value, + bool *result) { + CHECK_ARG(value, Error) + CHECK_ARG(result, Error) - hermes::vm::HermesValue hermesValue = *(const hermes::vm::PinnedHermesValue *)value; - if (hermesValue.isDouble()) - { - *result = hermesValue.getDouble(); - } - else - { - return NAPIErrorNumberExpected; - } + RETURN_STATUS_IF_FALSE( + ((const ::hermes::vm::PinnedHermesValue *)value)->isBool(), + NAPIErrorBooleanExpected) + *result = ((const ::hermes::vm::PinnedHermesValue *)value)->getBool(); - return NAPIErrorOK; + return NAPIErrorOK; } -NAPIErrorStatus napi_get_value_bool(NAPIEnv /*env*/, NAPIValue value, bool *result) -{ - CHECK_ARG(value, Error) - CHECK_ARG(result, Error) +NAPIExceptionStatus napi_coerce_to_bool(NAPIEnv env, NAPIValue value, + NAPIValue *result) { + CHECK_ARG(env, Exception) + CHECK_ARG(value, Exception) + CHECK_ARG(result, Exception) - RETURN_STATUS_IF_FALSE(((const hermes::vm::PinnedHermesValue *)value)->isBool(), NAPIErrorBooleanExpected) - *result = ((const hermes::vm::PinnedHermesValue *)value)->getBool(); + *result = (NAPIValue)env->getRuntime() + .makeHandle(::hermes::vm::HermesValue::encodeBoolValue( + ::hermes::vm::toBoolean( + *(const ::hermes::vm::PinnedHermesValue *)value))) + .unsafeGetPinnedHermesValue(); - return NAPIErrorOK; + return NAPIExceptionOK; } -NAPIExceptionStatus napi_coerce_to_bool(NAPIEnv env, NAPIValue value, NAPIValue *result) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(value, Exception) - CHECK_ARG(result, Exception) - - *result = (NAPIValue)env->getRuntime() - ->makeHandle(::hermes::vm::HermesValue::encodeBoolValue( - hermes::vm::toBoolean(*(const hermes::vm::PinnedHermesValue *)value))) - .unsafeGetPinnedHermesValue(); +NAPIExceptionStatus napi_coerce_to_number(NAPIEnv env, NAPIValue value, + NAPIValue *result) { + NAPI_PREAMBLE(env) + CHECK_ARG(value, Exception) + CHECK_ARG(result, Exception) + + auto callResult = ::hermes::vm::toNumber_RJS( + env->getRuntime(), ::hermes::vm::Handle<::hermes::vm::HermesValue>( + (const ::hermes::vm::PinnedHermesValue *)value)); + CHECK_HERMES(callResult) + *result = (NAPIValue)env->getRuntime() + .makeHandle(callResult.getValue()) + .unsafeGetPinnedHermesValue(); - return NAPIExceptionOK; + return NAPIExceptionOK; } -NAPIExceptionStatus napi_coerce_to_number(NAPIEnv env, NAPIValue value, NAPIValue *result) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(value, Exception) - CHECK_ARG(result, Exception) - - auto callResult = hermes::vm::toNumber_RJS( - env->getRuntime(), env->getRuntime()->makeHandle(*(const hermes::vm::PinnedHermesValue *)value)); - CHECK_HERMES(callResult) - *result = (NAPIValue)env->getRuntime()->makeHandle(callResult.getValue()).unsafeGetPinnedHermesValue(); +NAPIExceptionStatus napi_coerce_to_string(NAPIEnv env, NAPIValue value, + NAPIValue *result) { + NAPI_PREAMBLE(env) + CHECK_ARG(value, Exception) + CHECK_ARG(result, Exception) + + auto callResult = ::hermes::vm::toString_RJS( + env->getRuntime(), ::hermes::vm::Handle<::hermes::vm::HermesValue>( + (const ::hermes::vm::PinnedHermesValue *)value)); + CHECK_HERMES(callResult) + *result = (NAPIValue)env->getRuntime() + .makeHandle(callResult->getHermesValue()) + .unsafeGetPinnedHermesValue(); - return NAPIExceptionOK; + return NAPIExceptionOK; } -NAPIExceptionStatus napi_coerce_to_string(NAPIEnv env, NAPIValue value, NAPIValue *result) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(value, Exception) - CHECK_ARG(result, Exception) - - auto callResult = hermes::vm::toString_RJS( - env->getRuntime(), env->getRuntime()->makeHandle(*(const hermes::vm::PinnedHermesValue *)value)); - CHECK_HERMES(callResult) - *result = (NAPIValue)env->getRuntime()->makeHandle(callResult->getHermesValue()).unsafeGetPinnedHermesValue(); - - return NAPIExceptionOK; +NAPIExceptionStatus napi_set_property(NAPIEnv env, NAPIValue object, + NAPIValue key, NAPIValue value) { + NAPI_PREAMBLE(env) + CHECK_ARG(object, Exception) + CHECK_ARG(key, Exception) + CHECK_ARG(value, Exception) + + ::hermes::vm::GCScope gcScope(env->getRuntime()); + + RETURN_STATUS_IF_FALSE(::hermes::vm::vmisa<::hermes::vm::JSObject>( + *(const ::hermes::vm::PinnedHermesValue *)object), + NAPIExceptionObjectExpected) + auto callResult = ::hermes::vm::valueToSymbolID( + env->getRuntime(), ::hermes::vm::Handle<::hermes::vm::HermesValue>( + (const ::hermes::vm::PinnedHermesValue *)key)); + CHECK_HERMES(callResult) + auto setCallResult = ::hermes::vm::JSObject::putNamedOrIndexed( + ::hermes::vm::Handle<::hermes::vm::JSObject>::vmcast( + (const ::hermes::vm::PinnedHermesValue *)object), + env->getRuntime(), callResult.getValue().get(), + ::hermes::vm::Handle<::hermes::vm::HermesValue>( + (const ::hermes::vm::PinnedHermesValue *)value)); + CHECK_HERMES(setCallResult) + RETURN_STATUS_IF_FALSE(setCallResult.getValue(), NAPIExceptionGenericFailure) + + return NAPIExceptionOK; } -NAPIExceptionStatus napi_set_property(NAPIEnv env, NAPIValue object, NAPIValue key, NAPIValue value) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(object, Exception) - CHECK_ARG(key, Exception) - CHECK_ARG(value, Exception) - - hermes::vm::GCScope gcScope(env->getRuntime()); - - auto jsObject = - hermes::vm::dyn_vmcast_or_null(*(const hermes::vm::PinnedHermesValue *)object); - RETURN_STATUS_IF_FALSE(jsObject, NAPIExceptionObjectExpected) - auto callResult = hermes::vm::valueToSymbolID( - env->getRuntime(), env->getRuntime()->makeHandle(*(const hermes::vm::PinnedHermesValue *)key)); - CHECK_HERMES(callResult) - auto setCallResult = hermes::vm::JSObject::putNamedOrIndexed( - env->getRuntime()->makeHandle(jsObject), env->getRuntime(), callResult.getValue().get(), - env->getRuntime()->makeHandle(*(const hermes::vm::PinnedHermesValue *)value)); - CHECK_HERMES(setCallResult) - RETURN_STATUS_IF_FALSE(setCallResult.getValue(), NAPIExceptionGenericFailure) - - return NAPIExceptionOK; +NAPIExceptionStatus napi_has_property(NAPIEnv env, NAPIValue object, + NAPIValue key, bool *result) { + NAPI_PREAMBLE(env) + CHECK_ARG(object, Exception) + CHECK_ARG(key, Exception) + CHECK_ARG(result, Exception) + + ::hermes::vm::GCScope gcScope(env->getRuntime()); + + RETURN_STATUS_IF_FALSE(::hermes::vm::vmisa<::hermes::vm::JSObject>( + *(const ::hermes::vm::PinnedHermesValue *)object), + NAPIExceptionObjectExpected) + auto callResult = ::hermes::vm::valueToSymbolID( + env->getRuntime(), ::hermes::vm::Handle<::hermes::vm::HermesValue>( + (const ::hermes::vm::PinnedHermesValue *)key)); + CHECK_HERMES(callResult) + auto hasCallResult = ::hermes::vm::JSObject::hasNamedOrIndexed( + ::hermes::vm::Handle<::hermes::vm::JSObject>::vmcast( + (const ::hermes::vm::PinnedHermesValue *)object), + env->getRuntime(), callResult.getValue().get()); + CHECK_HERMES(hasCallResult) + *result = hasCallResult.getValue(); + + return NAPIExceptionOK; } -NAPIExceptionStatus napi_has_property(NAPIEnv env, NAPIValue object, NAPIValue key, bool *result) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(object, Exception) - CHECK_ARG(key, Exception) - CHECK_ARG(result, Exception) - - hermes::vm::GCScope gcScope(env->getRuntime()); - - auto jsObject = - hermes::vm::dyn_vmcast_or_null(*(const hermes::vm::PinnedHermesValue *)object); - RETURN_STATUS_IF_FALSE(jsObject, NAPIExceptionObjectExpected) - auto callResult = hermes::vm::valueToSymbolID( - env->getRuntime(), env->getRuntime()->makeHandle(*(const hermes::vm::PinnedHermesValue *)key)); - CHECK_HERMES(callResult) - auto hasCallResult = hermes::vm::JSObject::hasNamedOrIndexed(env->getRuntime()->makeHandle(jsObject), - env->getRuntime(), callResult.getValue().get()); - CHECK_HERMES(hasCallResult) - *result = hasCallResult.getValue(); - - return NAPIExceptionOK; +NAPIExceptionStatus napi_get_property(NAPIEnv env, NAPIValue object, + NAPIValue key, NAPIValue *result) { + NAPI_PREAMBLE(env) + CHECK_ARG(object, Exception) + CHECK_ARG(key, Exception) + CHECK_ARG(result, Exception) + + ::hermes::vm::MutableHandle<::hermes::vm::HermesValue> mutableHandle( + env->getRuntime()); + ::hermes::vm::GCScope gcScope(env->getRuntime()); + + RETURN_STATUS_IF_FALSE(::hermes::vm::vmisa<::hermes::vm::JSObject>( + *(const ::hermes::vm::PinnedHermesValue *)object), + NAPIExceptionObjectExpected) + auto callResult = ::hermes::vm::valueToSymbolID( + env->getRuntime(), ::hermes::vm::Handle<::hermes::vm::HermesValue>( + (const ::hermes::vm::PinnedHermesValue *)key)); + CHECK_HERMES(callResult) + auto getCallResult = ::hermes::vm::JSObject::getNamedOrIndexed( + ::hermes::vm::Handle<::hermes::vm::JSObject>::vmcast( + (const ::hermes::vm::PinnedHermesValue *)object), + env->getRuntime(), callResult.getValue().get()); + CHECK_HERMES(getCallResult) + mutableHandle.set(getCallResult.getValue().get()); + *result = (NAPIValue)mutableHandle.unsafeGetPinnedHermesValue(); + + return NAPIExceptionOK; } -NAPIExceptionStatus napi_get_property(NAPIEnv env, NAPIValue object, NAPIValue key, NAPIValue *result) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(object, Exception) - CHECK_ARG(key, Exception) - CHECK_ARG(result, Exception) - - hermes::vm::GCScope gcScope(env->getRuntime()); - - auto jsObject = - hermes::vm::dyn_vmcast_or_null(*(const hermes::vm::PinnedHermesValue *)object); - RETURN_STATUS_IF_FALSE(jsObject, NAPIExceptionObjectExpected) - auto callResult = hermes::vm::valueToSymbolID( - env->getRuntime(), env->getRuntime()->makeHandle(*(const hermes::vm::PinnedHermesValue *)key)); +NAPIExceptionStatus napi_delete_property(NAPIEnv env, NAPIValue object, + NAPIValue key, bool *result) { + NAPI_PREAMBLE(env) + CHECK_ARG(object, Exception) + CHECK_ARG(key, Exception) + + RETURN_STATUS_IF_FALSE(::hermes::vm::vmisa<::hermes::vm::JSObject>( + *(const ::hermes::vm::PinnedHermesValue *)object), + NAPIExceptionObjectExpected) + + bool isSuccess; + if (((const ::hermes::vm::PinnedHermesValue *)key)->isNumber()) { + isSuccess = ::hermes::vm::JSObject::deleteOwnIndexed( + ::hermes::vm::Handle<::hermes::vm::JSObject>::vmcast( + (const ::hermes::vm::PinnedHermesValue *)object), + env->getRuntime(), + (uint32_t)((const ::hermes::vm::PinnedHermesValue *)key)->getDouble()); + } else { + ::hermes::vm::GCScope gcScope(env->getRuntime()); + + auto callResult = ::hermes::vm::valueToSymbolID( + env->getRuntime(), ::hermes::vm::Handle<::hermes::vm::HermesValue>( + (const ::hermes::vm::PinnedHermesValue *)key)); CHECK_HERMES(callResult) - auto getCallResult = hermes::vm::JSObject::getNamedOrIndexed(env->getRuntime()->makeHandle(jsObject), - env->getRuntime(), callResult.getValue().get()); - CHECK_HERMES(getCallResult) - *result = - (NAPIValue)hermes::vm::Handle(gcScope.getParentScope(), getCallResult.getValue().get()) - .unsafeGetPinnedHermesValue(); - - return NAPIExceptionOK; + auto deleteCallResult = ::hermes::vm::JSObject::deleteNamed( + ::hermes::vm::Handle<::hermes::vm::JSObject>::vmcast( + (const ::hermes::vm::PinnedHermesValue *)object), + env->getRuntime(), callResult.getValue().get()); + CHECK_HERMES(deleteCallResult) + isSuccess = deleteCallResult.getValue(); + } + if (result) { + *result = isSuccess; + } + + return NAPIExceptionOK; } -NAPIExceptionStatus napi_delete_property(NAPIEnv env, NAPIValue object, NAPIValue key, bool *result) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(object, Exception) - CHECK_ARG(key, Exception) +NAPICommonStatus napi_is_array(NAPIEnv /*env*/, NAPIValue value, bool *result) { + CHECK_ARG(value, Common) + CHECK_ARG(result, Common) - hermes::vm::GCScope gcScope(env->getRuntime()); + *result = ::hermes::vm::vmisa<::hermes::vm::JSArray>( + *(const ::hermes::vm::PinnedHermesValue *)value); - auto jsObject = - hermes::vm::dyn_vmcast_or_null(*(const hermes::vm::PinnedHermesValue *)object); - RETURN_STATUS_IF_FALSE(jsObject, NAPIExceptionObjectExpected) - - bool isSuccess; - if (((const hermes::vm::PinnedHermesValue *)key)->isDouble()) - { - isSuccess = - hermes::vm::JSObject::deleteOwnIndexed(env->getRuntime()->makeHandle(jsObject), env->getRuntime(), - (uint32_t)((const hermes::vm::PinnedHermesValue *)key)->getDouble()); - } - else - { - auto callResult = hermes::vm::valueToSymbolID( - env->getRuntime(), env->getRuntime()->makeHandle(*(const hermes::vm::PinnedHermesValue *)key)); - CHECK_HERMES(callResult) - auto deleteCallResult = hermes::vm::JSObject::deleteNamed(env->getRuntime()->makeHandle(jsObject), - env->getRuntime(), callResult.getValue().get()); - CHECK_HERMES(deleteCallResult) - isSuccess = deleteCallResult.getValue(); - } - if (result) - { - *result = isSuccess; - } - - return NAPIExceptionOK; + return NAPICommonOK; } -NAPICommonStatus napi_is_array(NAPIEnv /*env*/, NAPIValue value, bool *result) -{ - CHECK_ARG(value, Common) - CHECK_ARG(result, Common) - - // 虽然有 ArrayImpl,但是主要是为了提供给 Arguments 使用 - *result = hermes::vm::vmisa(*(const hermes::vm::PinnedHermesValue *)value); - - return NAPICommonOK; +NAPIExceptionStatus napi_call_function(NAPIEnv env, NAPIValue thisValue, + NAPIValue func, size_t argc, + const NAPIValue *argv, + NAPIValue *result) { + NAPI_PREAMBLE(env) + CHECK_ARG(func, Exception) + if (argc) { + CHECK_ARG(argv, Exception) + } + + RETURN_STATUS_IF_FALSE(::hermes::vm::vmisa<::hermes::vm::Callable>( + *(const ::hermes::vm::PinnedHermesValue *)func), + NAPIExceptionFunctionExpected) + + ::hermes::vm::MutableHandle<::hermes::vm::HermesValue> mutableHandle( + env->getRuntime()); + ::hermes::vm::GCScope gcScope(env->getRuntime()); + + if (!thisValue) { + thisValue = + (NAPIValue)env->getRuntime().getGlobal().unsafeGetPinnedHermesValue(); + } + + auto callResult = ::hermes::vm::Arguments::create( + env->getRuntime(), argc, + ::hermes::vm::HandleRootOwner::makeNullHandle<::hermes::vm::Callable>(), + true); + CHECK_HERMES(callResult) + for (size_t i = 0; i < argc; ++i) { + ::hermes::vm::ArrayImpl::setElementAt( + callResult.getValue(), env->getRuntime(), i, + ::hermes::vm::Handle<::hermes::vm::HermesValue>( + (const ::hermes::vm::PinnedHermesValue *)argv[i])); + } + auto executeCallResult = ::hermes::vm::Callable::executeCall( + ::hermes::vm::Handle<::hermes::vm::Callable>::vmcast( + (const ::hermes::vm::PinnedHermesValue *)func), + env->getRuntime(), ::hermes::vm::HandleRootOwner::getUndefinedValue(), + ::hermes::vm::Handle<::hermes::vm::HermesValue>( + (const ::hermes::vm::PinnedHermesValue *)thisValue), + callResult.getValue()); + CHECK_HERMES(executeCallResult) + if (result) { + mutableHandle.set(executeCallResult.getValue().get()); + *result = (NAPIValue)mutableHandle.unsafeGetPinnedHermesValue(); + } + + return NAPIExceptionOK; } -NAPIExceptionStatus napi_call_function(NAPIEnv env, NAPIValue thisValue, NAPIValue func, size_t argc, - const NAPIValue *argv, NAPIValue *result) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(func, Exception) - if (argc) - { - CHECK_ARG(argv, Exception) - } - - RETURN_STATUS_IF_FALSE(hermes::vm::vmisa(*(const hermes::vm::PinnedHermesValue *)func), - NAPIExceptionFunctionExpected) - - hermes::vm::GCScope gcScope(env->getRuntime()); - - // this - if (!thisValue) - { - CHECK_NAPI(napi_get_global(env, &thisValue), Error, Exception) - } - - // 开启严格模式后,可以直接传入空句柄 - auto callResult = hermes::vm::Arguments::create( - env->getRuntime(), argc, hermes::vm::HandleRootOwner::makeNullHandle(), true); +NAPIExceptionStatus napi_new_instance(NAPIEnv env, NAPIValue constructor, + size_t argc, const NAPIValue *argv, + NAPIValue *result) { + NAPI_PREAMBLE(env) + CHECK_ARG(constructor, Exception) + if (argc) { + CHECK_ARG(argv, Exception) + } + CHECK_ARG(result, Exception) + + { + auto callResult = ::hermes::vm::isConstructor( + env->getRuntime(), + *(const ::hermes::vm::PinnedHermesValue *)constructor); CHECK_HERMES(callResult) - for (size_t i = 0; i < argc; ++i) - { - hermes::vm::ArrayImpl::setElementAt( - callResult.getValue(), env->getRuntime(), i, - env->getRuntime()->makeHandle(*(const hermes::vm::PinnedHermesValue *)argv[i])); - } - auto function = hermes::vm::dyn_vmcast_or_null(*(const hermes::vm::PinnedHermesValue *)func); - if (!function) - { - assert(false && "func is not a Callable"); - } - auto executeCallResult = hermes::vm::Callable::executeCall( - env->getRuntime()->makeHandle(function), env->getRuntime(), hermes::vm::Runtime::getUndefinedValue(), - env->getRuntime()->makeHandle(*(const hermes::vm::PinnedHermesValue *)thisValue), callResult.getValue()); - CHECK_HERMES(executeCallResult) - if (result) - { - *result = (NAPIValue)hermes::vm::Handle(gcScope.getParentScope(), - executeCallResult.getValue().get()) - .unsafeGetPinnedHermesValue(); - } - - return NAPIExceptionOK; + RETURN_STATUS_IF_FALSE(callResult.getValue(), NAPIExceptionFunctionExpected) + } + + ::hermes::vm::MutableHandle<::hermes::vm::HermesValue> mutableHandle( + env->getRuntime()); + ::hermes::vm::GCScope gcScope(env->getRuntime()); + + auto callResult = ::hermes::vm::Arguments::create( + env->getRuntime(), argc, + ::hermes::vm::HandleRootOwner::makeNullHandle<::hermes::vm::Callable>(), + true); + CHECK_HERMES(callResult) + for (size_t i = 0; i < argc; ++i) { + ::hermes::vm::ArrayImpl::setElementAt( + callResult.getValue(), env->getRuntime(), i, + ::hermes::vm::Handle<::hermes::vm::HermesValue>( + (const ::hermes::vm::PinnedHermesValue *)argv[i])); + } + auto functionHandle = ::hermes::vm::Handle<::hermes::vm::Callable>::vmcast( + (const ::hermes::vm::PinnedHermesValue *)constructor); + auto createThisCallResult = ::hermes::vm::Callable::createThisForConstruct( + functionHandle, env->getRuntime()); + CHECK_HERMES(createThisCallResult) + auto thisHandle = env->getRuntime().makeHandle( + createThisCallResult.getValue().getHermesValue()); + auto executeCallResult = ::hermes::vm::Callable::executeCall( + functionHandle, env->getRuntime(), functionHandle, thisHandle, + callResult.getValue()); + CHECK_HERMES(executeCallResult) + if (executeCallResult.getValue()->isObject()) { + mutableHandle.set(executeCallResult.getValue().get()); + *result = (NAPIValue)mutableHandle.unsafeGetPinnedHermesValue(); + } else { + mutableHandle.set(thisHandle.get()); + *result = (NAPIValue)mutableHandle.unsafeGetPinnedHermesValue(); + } + + return NAPIExceptionOK; } -NAPIExceptionStatus napi_new_instance(NAPIEnv env, NAPIValue constructor, size_t argc, const NAPIValue *argv, - NAPIValue *result) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(constructor, Exception) - if (argc) - { - CHECK_ARG(argv, Exception) - } - CHECK_ARG(result, Exception) - - RETURN_STATUS_IF_FALSE( - hermes::vm::isConstructor(env->getRuntime(), *(const hermes::vm::PinnedHermesValue *)constructor), - NAPIExceptionFunctionExpected) - - hermes::vm::GCScope gcScope(env->getRuntime()); - - // 开启严格模式后,可以直接传入空句柄 - auto callResult = hermes::vm::Arguments::create( - env->getRuntime(), argc, hermes::vm::HandleRootOwner::makeNullHandle(), true); - CHECK_HERMES(callResult) - for (size_t i = 0; i < argc; ++i) - { - hermes::vm::ArrayImpl::setElementAt( - callResult.getValue(), env->getRuntime(), i, - env->getRuntime()->makeHandle(*(const hermes::vm::PinnedHermesValue *)argv[i])); - } - auto function = - hermes::vm::dyn_vmcast_or_null(*(const hermes::vm::PinnedHermesValue *)constructor); - auto functionHandle = env->getRuntime()->makeHandle(function); - auto thisCallResult = hermes::vm::Callable::createThisForConstruct(functionHandle, env->getRuntime()); - auto thisHandle = env->getRuntime()->makeHandle(thisCallResult->getHermesValue()); - CHECK_HERMES(thisCallResult) - auto executeCallResult = hermes::vm::Callable::executeCall(functionHandle, env->getRuntime(), functionHandle, - thisHandle, callResult.getValue()); - CHECK_HERMES(executeCallResult) - if (executeCallResult.getValue()->isObject()) - { - *result = (NAPIValue)hermes::vm::Handle(gcScope.getParentScope(), - executeCallResult.getValue().get()) - .unsafeGetPinnedHermesValue(); - } - else - { - // TODO(ChasonTang): 返回标量的情况添加单测 - *result = (NAPIValue)hermes::vm::Handle(gcScope.getParentScope(), thisHandle.get()) - .unsafeGetPinnedHermesValue(); - } - - return NAPIExceptionOK; -} - -NAPIExceptionStatus napi_instanceof(NAPIEnv env, NAPIValue object, NAPIValue constructor, bool *result) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(object, Exception) - CHECK_ARG(constructor, Exception) - CHECK_ARG(result, Exception) - - hermes::vm::GCScope gcScope(env->getRuntime()); - - auto callResult = hermes::vm::instanceOfOperator_RJS( - env->getRuntime(), env->getRuntime()->makeHandle(*(const hermes::vm::PinnedHermesValue *)object), - env->getRuntime()->makeHandle(*(const hermes::vm::PinnedHermesValue *)constructor)); - CHECK_HERMES(callResult) - *result = callResult.getValue(); - - return NAPIExceptionOK; +NAPIExceptionStatus napi_instanceof(NAPIEnv env, NAPIValue object, + NAPIValue constructor, bool *result) { + NAPI_PREAMBLE(env) + CHECK_ARG(object, Exception) + CHECK_ARG(constructor, Exception) + CHECK_ARG(result, Exception) + + auto callResult = ::hermes::vm::instanceOfOperator_RJS( + env->getRuntime(), + ::hermes::vm::Handle<::hermes::vm::HermesValue>( + (const ::hermes::vm::PinnedHermesValue *)object), + ::hermes::vm::Handle<::hermes::vm::HermesValue>( + (const ::hermes::vm::PinnedHermesValue *)constructor)); + CHECK_HERMES(callResult) + *result = callResult.getValue(); + + return NAPIExceptionOK; } -NAPICommonStatus napi_get_cb_info(NAPIEnv env, NAPICallbackInfo callbackInfo, size_t *argc, NAPIValue *argv, - NAPIValue *thisArg, void **data) -{ - CHECK_ARG(env, Common) - CHECK_ARG(callbackInfo, Common) - - if (argv) - { - CHECK_ARG(argc, Common) - unsigned int i = 0; - size_t min = std::min(callbackInfo->getNativeArgs().getArgCount(), (unsigned int)*argc); - for (; i < min; ++i) - { - argv[i] = (NAPIValue)callbackInfo->getNativeArgs().getArgHandle(i).unsafeGetPinnedHermesValue(); - } - if (i < *argc) - { - NAPIValue undefined = (NAPIValue)hermes::vm::Runtime::getUndefinedValue().unsafeGetPinnedHermesValue(); - for (; i < *argc; ++i) - { - argv[i] = undefined; - } - } - } - if (argc) - { - *argc = callbackInfo->getNativeArgs().getArgCount(); - } - if (thisArg) - { - *thisArg = (NAPIValue)callbackInfo->getNativeArgs().getThisHandle().unsafeGetPinnedHermesValue(); - } - if (data) - { - *data = callbackInfo->getData(); - } - - return NAPICommonOK; +NAPICommonStatus napi_get_cb_info(NAPIEnv env, NAPICallbackInfo callbackInfo, + size_t *argc, NAPIValue *argv, + NAPIValue *thisArg, void **data) { + CHECK_ARG(env, Common) + CHECK_ARG(callbackInfo, Common) + + if (argv) { + CHECK_ARG(argc, Common) + unsigned int i = 0; + size_t min = ::std::min(callbackInfo->getNativeArgs().getArgCount(), + (unsigned int)*argc); + for (; i < min; ++i) { + argv[i] = (NAPIValue)callbackInfo->getNativeArgs() + .getArgHandle(i) + .unsafeGetPinnedHermesValue(); + } + if (i < *argc) { + NAPIValue undefined = + (NAPIValue)::hermes::vm::HandleRootOwner::getUndefinedValue() + .unsafeGetPinnedHermesValue(); + for (; i < *argc; ++i) { + argv[i] = undefined; + } + } + } + if (argc) { + *argc = callbackInfo->getNativeArgs().getArgCount(); + } + if (thisArg) { + *thisArg = (NAPIValue)callbackInfo->getNativeArgs() + .getThisHandle() + .unsafeGetPinnedHermesValue(); + } + if (data) { + *data = callbackInfo->getData(); + } + + return NAPICommonOK; } -NAPICommonStatus napi_get_new_target(NAPIEnv env, NAPICallbackInfo callbackInfo, NAPIValue *result) -{ - CHECK_ARG(env, Common) - CHECK_ARG(callbackInfo, Common) - CHECK_ARG(result, Common) - - if (callbackInfo->getNativeArgs().getNewTarget().isUndefined()) - { - *result = nullptr; - } - else - { - *result = (NAPIValue)callbackInfo->getNativeArgs().getNewTargetHandle().unsafeGetPinnedHermesValue(); - } +NAPICommonStatus napi_get_new_target(NAPIEnv env, NAPICallbackInfo callbackInfo, + NAPIValue *result) { + CHECK_ARG(env, Common) + CHECK_ARG(callbackInfo, Common) + CHECK_ARG(result, Common) + + if (callbackInfo->getNativeArgs().getNewTarget().isUndefined()) { + *result = nullptr; + } else { + *result = (NAPIValue)callbackInfo->getNativeArgs() + .getNewTargetHandle() + .unsafeGetPinnedHermesValue(); + } - return NAPICommonOK; + return NAPICommonOK; } -NAPIExceptionStatus napi_create_external(NAPIEnv env, void *data, NAPIFinalize finalizeCB, void *finalizeHint, - NAPIValue *result) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(result, Exception) - - auto hermesExternalObject = new (std::nothrow)::External(env->getRuntime(), data, finalizeCB, finalizeHint); - RETURN_STATUS_IF_FALSE(hermesExternalObject, NAPIExceptionMemoryError) - - auto callResult = hermes::vm::HostObject::createWithoutPrototype(env->getRuntime(), - std::unique_ptr(hermesExternalObject)); - CHECK_HERMES(callResult) - *result = (NAPIValue)env->getRuntime()->makeHandle(callResult.getValue()).unsafeGetPinnedHermesValue(); +NAPIExceptionStatus napi_create_external(NAPIEnv env, void *data, + NAPIFinalize finalizeCB, + void *finalizeHint, + NAPIValue *result) { + NAPI_PREAMBLE(env) + CHECK_ARG(result, Exception) + + auto hermesExternalObject = new (::std::nothrow)::orangelabs::External( + env->getRuntime(), data, finalizeCB, finalizeHint); + RETURN_STATUS_IF_FALSE(hermesExternalObject, NAPIExceptionMemoryError) + + auto callResult = ::hermes::vm::HostObject::createWithoutPrototype( + env->getRuntime(), + std::unique_ptr<::orangelabs::External>(hermesExternalObject)); + CHECK_HERMES(callResult) + *result = (NAPIValue)env->getRuntime() + .makeHandle(callResult.getValue()) + .unsafeGetPinnedHermesValue(); - return NAPIExceptionOK; + return NAPIExceptionOK; } -NAPIErrorStatus napi_get_value_external(NAPIEnv env, NAPIValue value, void **result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(value, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_get_value_external(NAPIEnv env, NAPIValue value, + void **result) { + CHECK_ARG(env, Error) + CHECK_ARG(value, Error) + CHECK_ARG(result, Error) - auto hostObject = - hermes::vm::dyn_vmcast_or_null(*(const hermes::vm::PinnedHermesValue *)value); - RETURN_STATUS_IF_FALSE(hostObject, NAPIErrorExternalExpected) + RETURN_STATUS_IF_FALSE(::hermes::vm::vmisa<::hermes::vm::HostObject>( + *(const ::hermes::vm::PinnedHermesValue *)value), + NAPIErrorExternalExpected) - auto external = (External *)hostObject->getProxy(); - *result = external ? external->getData() : nullptr; + auto external = reinterpret_cast<::orangelabs::External *>( + ::hermes::vm::vmcast<::hermes::vm::HostObject>( + *(const ::hermes::vm::PinnedHermesValue *)value) + ->getProxy()); + *result = external ? external->getData() : nullptr; - return NAPIErrorOK; + return NAPIErrorOK; } -NAPIExceptionStatus napi_create_reference(NAPIEnv env, NAPIValue value, uint32_t initialRefCount, NAPIRef *result) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(value, Exception) - CHECK_ARG(result, Exception) +NAPIExceptionStatus napi_create_reference(NAPIEnv env, NAPIValue value, + uint32_t initialRefCount, + NAPIRef *result) { + CHECK_ARG(env, Exception) + CHECK_ARG(value, Exception) + CHECK_ARG(result, Exception) - *result = new (std::nothrow) OpaqueNAPIRef(env, *(const hermes::vm::PinnedHermesValue *)value, initialRefCount); - RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) + *result = new (::std::nothrow) struct OpaqueNAPIRef( + env, *(const ::hermes::vm::PinnedHermesValue *)value, initialRefCount); + RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) - return NAPIExceptionOK; + return NAPIExceptionOK; } -NAPIExceptionStatus napi_delete_reference(NAPIEnv env, NAPIRef ref) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(ref, Exception) +NAPIExceptionStatus napi_delete_reference(NAPIEnv env, NAPIRef ref) { + CHECK_ARG(env, Exception) + CHECK_ARG(ref, Exception) - delete ref; + delete ref; - return NAPIExceptionOK; + return NAPIExceptionOK; } -NAPIExceptionStatus napi_reference_ref(NAPIEnv env, NAPIRef ref, uint32_t *result) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(ref, Exception) +NAPIExceptionStatus napi_reference_ref(NAPIEnv env, NAPIRef ref, + uint32_t *result) { + CHECK_ARG(env, Exception) + CHECK_ARG(ref, Exception) - ref->ref(); - if (result) - { - *result = ref->getReferenceCount(); - } + ref->ref(); + if (result) { + *result = ref->getReferenceCount(); + } - return NAPIExceptionOK; + return NAPIExceptionOK; } -NAPIExceptionStatus napi_reference_unref(NAPIEnv env, NAPIRef ref, uint32_t *result) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(ref, Exception) +NAPIExceptionStatus napi_reference_unref(NAPIEnv env, NAPIRef ref, + uint32_t *result) { + CHECK_ARG(env, Exception) + CHECK_ARG(ref, Exception) - RETURN_STATUS_IF_FALSE(ref->getReferenceCount(), NAPIExceptionGenericFailure) - ref->unref(); - if (result) - { - *result = ref->getReferenceCount(); - } + RETURN_STATUS_IF_FALSE(ref->getReferenceCount(), NAPIExceptionGenericFailure) + ref->unref(); + if (result) { + *result = ref->getReferenceCount(); + } - return NAPIExceptionOK; + return NAPIExceptionOK; } -NAPIErrorStatus napi_get_reference_value(NAPIEnv env, NAPIRef ref, NAPIValue *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(ref, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_get_reference_value(NAPIEnv env, NAPIRef ref, + NAPIValue *result) { + CHECK_ARG(env, Error) + CHECK_ARG(ref, Error) + CHECK_ARG(result, Error) - RETURN_STATUS_IF_FALSE(env->getRuntime()->getTopGCScope(), NAPIErrorHandleScopeEmpty) + *result = (NAPIValue)ref->getHermesValue(); - *result = (NAPIValue)ref->getHermesValue(); - - return NAPIErrorOK; + return NAPIErrorOK; } -NAPIErrorStatus napi_open_handle_scope(NAPIEnv env, NAPIHandleScope *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_open_handle_scope(NAPIEnv env, NAPIHandleScope *result) { + CHECK_ARG(env, Error) + CHECK_ARG(result, Error) - *result = (NAPIHandleScope) new (std::nothrow) hermes::vm::GCScope(env->getRuntime()); - RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) + *result = + new (::std::nothrow) struct OpaqueNAPIHandleScope(env->getRuntime()); + RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) + SLIST_INSERT_HEAD(&env->handleScopeList, *result, node); - return NAPIErrorOK; + return NAPIErrorOK; } -NAPICommonStatus napi_close_handle_scope(NAPIEnv env, NAPIHandleScope scope) -{ - CHECK_ARG(env, Common) - CHECK_ARG(scope, Common) +NAPIErrorStatus napi_close_handle_scope(NAPIEnv env, NAPIHandleScope scope) { + CHECK_ARG(env, Error) + CHECK_ARG(scope, Error) - delete (hermes::vm::GCScope *)scope; + RETURN_STATUS_IF_FALSE(SLIST_FIRST(&env->handleScopeList) == scope, + NAPIErrorHandleScopeMismatch) + SLIST_REMOVE_HEAD(&env->handleScopeList, node); + delete scope; - return NAPICommonOK; + return NAPIErrorOK; } -EXTERN_C_START - -struct OpaqueNAPIEscapableHandleScope -{ - OpaqueNAPIEscapableHandleScope() : escapeCalled(false) - { - } - - OpaqueNAPIEscapableHandleScope(const OpaqueNAPIEscapableHandleScope &) = delete; - OpaqueNAPIEscapableHandleScope(OpaqueNAPIEscapableHandleScope &&) = delete; - OpaqueNAPIEscapableHandleScope &operator=(const OpaqueNAPIEscapableHandleScope &) = delete; - OpaqueNAPIEscapableHandleScope &operator=(OpaqueNAPIEscapableHandleScope &&) = delete; - - bool isEscapeCalled() const - { - return escapeCalled; - } - - void setEscapeCalled(bool escapeCalled1) - { - escapeCalled = escapeCalled1; - } +NAPIErrorStatus napi_open_escapable_handle_scope( + NAPIEnv env, NAPIEscapableHandleScope *result) { + CHECK_ARG(env, Error) + CHECK_ARG(result, Error) - hermes::vm::GCScope *gcScope = nullptr; + ::hermes::vm::MutableHandle<::hermes::vm::HermesValue> mutableHandle( + env->getRuntime()); - private: - bool escapeCalled; -}; + *result = new (::std::nothrow) struct OpaqueNAPIEscapableHandleScope( + env->getRuntime(), ::std::move(mutableHandle)); + RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) + SLIST_INSERT_HEAD(&env->handleScopeList, *result, node); -EXTERN_C_END - -NAPIErrorStatus napi_open_escapable_handle_scope(NAPIEnv env, NAPIEscapableHandleScope *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(result, Error) - - RETURN_STATUS_IF_FALSE(env->getRuntime()->getTopGCScope(), NAPIErrorHandleScopeMismatch) - - auto gcScope = new (std::nothrow) hermes::vm::GCScope(env->getRuntime()); - RETURN_STATUS_IF_FALSE(gcScope, NAPIErrorMemoryError) - *result = new (std::nothrow) OpaqueNAPIEscapableHandleScope(); - if (!*result) - { - delete gcScope; - - return NAPIErrorMemoryError; - } - (*result)->gcScope = gcScope; + return NAPIErrorOK; +} - return NAPIErrorOK; +NAPIErrorStatus napi_close_escapable_handle_scope( + NAPIEnv env, NAPIEscapableHandleScope scope) { + return napi_close_handle_scope(env, scope); } -NAPICommonStatus napi_close_escapable_handle_scope(NAPIEnv env, NAPIEscapableHandleScope scope) -{ - CHECK_ARG(env, Common) - CHECK_ARG(scope, Common) +NAPIErrorStatus napi_escape_handle(NAPIEnv env, NAPIEscapableHandleScope scope, + NAPIValue escapee, NAPIValue *result) { + CHECK_ARG(env, Error) + CHECK_ARG(scope, Error) + CHECK_ARG(escapee, Error) + CHECK_ARG(result, Error) - delete scope->gcScope; - delete scope; + auto escapedValue = + scope->escape(*(const ::hermes::vm::PinnedHermesValue *)escapee); + RETURN_STATUS_IF_FALSE(escapedValue, NAPIErrorEscapeCalledTwice) + *result = (NAPIValue)escapedValue; - return NAPICommonOK; + return NAPIErrorOK; } -NAPIErrorStatus napi_escape_handle(NAPIEnv env, NAPIEscapableHandleScope scope, NAPIValue escapee, NAPIValue *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(scope, Error) - CHECK_ARG(escapee, Error) - CHECK_ARG(result, Error) +NAPIExceptionStatus napi_throw(NAPIEnv env, NAPIValue error) { + NAPI_PREAMBLE(env) + CHECK_ARG(error, Exception) - RETURN_STATUS_IF_FALSE(!scope->isEscapeCalled(), NAPIErrorEscapeCalledTwice) - - *result = (NAPIValue)hermes::vm::Handle(scope->gcScope->getParentScope(), - *(const hermes::vm::PinnedHermesValue *)escapee) - .unsafeGetPinnedHermesValue(); - scope->setEscapeCalled(true); + // 直接忽略返回值 + env->getRuntime().setThrownValue( + *(const ::hermes::vm::PinnedHermesValue *)error); - return NAPIErrorOK; + return NAPIExceptionOK; } -NAPIExceptionStatus napi_throw(NAPIEnv env, NAPIValue error) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(error, Exception) +NAPIErrorStatus napi_get_and_clear_last_exception(NAPIEnv env, + NAPIValue *result) { + CHECK_ARG(env, Error) + CHECK_ARG(result, Error) - // 直接忽略返回值 - env->getRuntime()->setThrownValue(*(const hermes::vm::PinnedHermesValue *)error); + if (env->getRuntime().getThrownValue().isEmpty()) { + *result = (NAPIValue)::hermes::vm::HandleRootOwner::getUndefinedValue() + .unsafeGetPinnedHermesValue(); + } else { + *result = (NAPIValue)env->getRuntime() + .makeHandle(env->getRuntime().getThrownValue()) + .unsafeGetPinnedHermesValue(); + env->getRuntime().clearThrownValue(); + } - return NAPIExceptionOK; + return NAPIErrorOK; } -NAPIErrorStatus napi_get_and_clear_last_exception(NAPIEnv env, NAPIValue *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(result, Error) +NAPICommonStatus NAPIClearLastException(NAPIEnv env) { + CHECK_ARG(env, Common) - if (env->getRuntime()->getThrownValue().isEmpty()) - { - *result = (NAPIValue)hermes::vm::Runtime::getUndefinedValue().unsafeGetPinnedHermesValue(); - } - else - { - *result = - (NAPIValue)env->getRuntime()->makeHandle(env->getRuntime()->getThrownValue()).unsafeGetPinnedHermesValue(); - env->getRuntime()->clearThrownValue(); - } + env->getRuntime().clearThrownValue(); - return NAPIErrorOK; + return NAPICommonOK; } -NAPICommonStatus NAPIClearLastException(NAPIEnv env) -{ - CHECK_ARG(env, Common) +NAPIExceptionStatus NAPIRunScript(NAPIEnv env, const char *script, + const char *sourceUrl, NAPIValue *result) { + NAPI_PREAMBLE(env) - env->getRuntime()->clearThrownValue(); + ::hermes::hbc::CompileFlags compileFlags = {}; + compileFlags.lazy = true; + compileFlags.debug = true; + auto callResult = env->getRuntime().run(script, sourceUrl, compileFlags); + CHECK_HERMES(callResult) + if (result) { + *result = (NAPIValue)env->getRuntime() + .makeHandle(callResult.getValue()) + .unsafeGetPinnedHermesValue(); + } - return NAPICommonOK; + return NAPIExceptionOK; } -NAPIExceptionStatus NAPIRunScript(NAPIEnv env, const char *script, const char *sourceUrl, NAPIValue *result) -{ - NAPI_PREAMBLE(env) - - hermes::hbc::CompileFlags compileFlags = {}; - compileFlags.lazy = true; - compileFlags.debug = true; - auto callResult = env->getRuntime()->run(script, sourceUrl, compileFlags); +NAPIExceptionStatus NAPIDefineClass(NAPIEnv env, const char *utf8name, + NAPICallback constructor, void *data, + NAPIValue *result) { + NAPI_PREAMBLE(env) + CHECK_ARG(constructor, Exception) + CHECK_ARG(result, Exception) + + ::hermes::vm::MutableHandle<::hermes::vm::HermesValue> mutableHandle( + env->getRuntime()); + ::hermes::vm::GCScope gcScope(env->getRuntime()); + + auto functionInfo = + new (::std::nothrow)::orangelabs::FunctionInfo(env, constructor, data); + RETURN_STATUS_IF_FALSE(functionInfo, NAPIExceptionMemoryError) + NAPIValue externalValue; + auto finalizeCallback = [](void *finalizeData, void * /*finalizeHint*/) { + delete (::orangelabs::FunctionInfo *)finalizeData; + }; + auto createExternalStatus = napi_create_external( + env, functionInfo, finalizeCallback, nullptr, &externalValue); + if (createExternalStatus != NAPIExceptionOK) { + delete functionInfo; + + return createExternalStatus; + } + + ::hermes::vm::NativeFunctionPtr nativeFunctionPtr = + [](void *context, ::hermes::vm::Runtime &runtime, + ::hermes::vm::NativeArgs args) + -> ::hermes::vm::CallResult<::hermes::vm::HermesValue> { + ::hermes::vm::MutableHandle<::hermes::vm::HermesValue> inlineMutableHandle( + runtime); + ::hermes::vm::GCScope inlineGCScope(runtime); + + auto innerFunctionInfo = (::orangelabs::FunctionInfo *)context; + if (!innerFunctionInfo->getCallback() || !innerFunctionInfo->getEnv()) { + assert(false); + + return args.getThisArg(); + } + struct OpaqueNAPICallbackInfo callbackInfo(args, + innerFunctionInfo->getData()); + NAPIValue returnValue = innerFunctionInfo->getCallback()( + innerFunctionInfo->getEnv(), &callbackInfo); + RETURN_STATUS_IF_FALSE( + innerFunctionInfo->getEnv()->getRuntime().getThrownValue().isEmpty(), + ::hermes::vm::ExecutionStatus::EXCEPTION) + if (!returnValue || + !((const ::hermes::vm::PinnedHermesValue *)returnValue)->isObject()) { + return args.getThisArg(); + } + inlineMutableHandle.set( + *(const ::hermes::vm::PinnedHermesValue *)returnValue); + + return inlineMutableHandle.get(); + }; + auto nativeConstructor = ::hermes::vm::NativeConstructor::create( + env->getRuntime(), + ::hermes::vm::Handle<::hermes::vm::JSObject>::vmcast( + &env->getRuntime().functionPrototype), + functionInfo, nativeFunctionPtr, 0, + ::hermes::vm::NativeConstructor::creatorFunction<::hermes::vm::JSObject>, + ::hermes::vm::CellKind::JSObjectKind); + + ::hermes::vm::StringPrimitive *stringPrimitive; + { + auto callResult = ::hermes::vm::StringPrimitive::createEfficient( + env->getRuntime(), + ::llvh::makeArrayRef( + reinterpret_cast(utf8name), + utf8name ? strlen(utf8name) : 0)); CHECK_HERMES(callResult) - if (result) - { - *result = (NAPIValue)env->getRuntime()->makeHandle(callResult.getValue()).unsafeGetPinnedHermesValue(); - } - - return NAPIExceptionOK; + stringPrimitive = ::hermes::vm::vmcast<::hermes::vm::StringPrimitive>( + callResult.getValue()); + } + auto callResult = ::hermes::vm::stringToSymbolID( + env->getRuntime(), ::hermes::vm::createPseudoHandle(stringPrimitive)); + CHECK_HERMES(callResult) + auto symbolId = callResult.getValue().get(); + + auto rawObject = ::hermes::vm::JSObject::create(env->getRuntime()); + + auto defineCallResult = ::hermes::vm::Callable::defineNameLengthAndPrototype( + env->getRuntime().makeHandle(nativeConstructor.get()), env->getRuntime(), + symbolId, 0, env->getRuntime().makeHandle(rawObject.get()), + ::hermes::vm::Callable::WritablePrototype::No, true); + CHECK_HERMES(defineCallResult) + mutableHandle.set(nativeConstructor.getHermesValue()); + *result = (NAPIValue)mutableHandle.unsafeGetPinnedHermesValue(); + NAPIValue privateKeyString; + CHECK_NAPI(napi_create_string_utf8(env, "__constructor__", &privateKeyString), + Exception, Exception) + CHECK_NAPI(napi_set_property(env, *result, privateKeyString, externalValue), + Exception, Exception) + + return NAPIExceptionOK; } -NAPIExceptionStatus NAPIDefineClass(NAPIEnv env, const char *utf8name, NAPICallback constructor, void *data, - NAPIValue *result) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(constructor, Exception) - CHECK_ARG(result, Exception) - - hermes::vm::GCScope gcScope(env->getRuntime()); - - auto functionInfo = new (std::nothrow) FunctionInfo(env, constructor, data); - RETURN_STATUS_IF_FALSE(functionInfo, NAPIExceptionMemoryError) - NAPIValue externalValue; - auto finalizeCallback = [](void *finalizeData, void * /*finalizeHint*/) { delete (FunctionInfo *)finalizeData; }; - auto createExternalStatus = napi_create_external(env, functionInfo, finalizeCallback, nullptr, &externalValue); - if (createExternalStatus != NAPIExceptionOK) - { - delete functionInfo; - - return createExternalStatus; - } +NAPIErrorStatus NAPICreateRuntime(NAPIRuntime *) { return NAPIErrorOK; } - hermes::vm::NativeFunctionPtr nativeFunctionPtr = - [](void *context, hermes::vm::Runtime *runtime, - hermes::vm::NativeArgs args) -> hermes::vm::CallResult { - hermes::vm::GCScope inlineGCScope(runtime); - auto innerFunctionInfo = (FunctionInfo *)context; - if (!innerFunctionInfo->getCallback() || !innerFunctionInfo->getEnv()) - { - assert(false); - - return args.getThisArg(); - } - struct OpaqueNAPICallbackInfo callbackInfo(args, innerFunctionInfo->getData()); - NAPIValue returnValue = innerFunctionInfo->getCallback()(innerFunctionInfo->getEnv(), &callbackInfo); - RETURN_STATUS_IF_FALSE(innerFunctionInfo->getEnv()->getRuntime()->getThrownValue().isEmpty(), - hermes::vm::ExecutionStatus::EXCEPTION) - if (!returnValue || !((const hermes::vm::PinnedHermesValue *)returnValue)->isObject()) - { - return args.getThisArg(); - } - - return {*(const hermes::vm::PinnedHermesValue *)returnValue}; - }; - auto nativeConstructor = hermes::vm::NativeConstructor::create( - env->getRuntime(), hermes::vm::Handle::vmcast(&env->getRuntime()->functionPrototype), - functionInfo, nativeFunctionPtr, 0, hermes::vm::NativeConstructor::creatorFunction, - hermes::vm::CellKind::ObjectKind); - - NAPIValue stringValue; - CHECK_NAPI(napi_create_string_utf8(env, utf8name, &stringValue), Exception, Exception) - auto stringPrimitive = hermes::vm::dyn_vmcast_or_null( - *(const hermes::vm::PinnedHermesValue *)stringValue); - RETURN_STATUS_IF_FALSE(stringPrimitive, NAPIExceptionMemoryError) - auto callResult = hermes::vm::stringToSymbolID(env->getRuntime(), hermes::vm::createPseudoHandle(stringPrimitive)); - CHECK_HERMES(callResult) - auto symbolId = callResult.getValue().get(); - auto rawObject = hermes::vm::JSObject::create(env->getRuntime()); - auto defineCallResult = hermes::vm::Callable::defineNameLengthAndPrototype( - env->getRuntime()->makeHandle(nativeConstructor.get()), env->getRuntime(), symbolId, 0, - env->getRuntime()->makeHandle(rawObject.get()), hermes::vm::Callable::WritablePrototype::No, false); - CHECK_HERMES(defineCallResult) - *result = (NAPIValue)hermes::vm::Handle(gcScope.getParentScope(), - nativeConstructor.getHermesValue()) - .unsafeGetPinnedHermesValue(); - NAPIValue privateKeyString; - CHECK_NAPI(napi_create_string_utf8(env, "__constructor__", &privateKeyString), Exception, Exception) - CHECK_NAPI(napi_set_property(env, *result, privateKeyString, externalValue), Exception, Exception) +NAPICommonStatus NAPIFreeRuntime(NAPIRuntime) { return NAPICommonOK; } - return NAPIExceptionOK; -} +NAPIErrorStatus NAPICreateEnv(NAPIEnv *env, NAPIRuntime) { + CHECK_ARG(env, Error) -NAPIErrorStatus NAPICreateRuntime(NAPIRuntime *runtime) -{ - return NAPIErrorOK; -} + *env = new (::std::nothrow) OpaqueNAPIEnv(::hermes::vm::RuntimeConfig()); + RETURN_STATUS_IF_FALSE(*env, NAPIErrorMemoryError) -NAPICommonStatus NAPIFreeRuntime(NAPIRuntime runtime) -{ - return NAPICommonOK; + return NAPIErrorOK; } -NAPIErrorStatus NAPICreateEnv(NAPIEnv *env, NAPIRuntime runtime) -{ - CHECK_ARG(env, Error) - - auto gcConfigBuilder = hermes::vm::GCConfig::Builder() - .withName("N-API") - // .withAllocInYoung(false) - // .withRevertToYGAtTTI(true) - .withMaxHeapSize(1024 << 20); - auto runtimeConfig = hermes::vm::RuntimeConfig::Builder() - .withGCConfig(gcConfigBuilder.build()) - // .withRegisterStack(nullptr) - .withMaxNumRegisters(kMaxNumRegisters) - .build(); - *env = new (std::nothrow) OpaqueNAPIEnv(runtimeConfig); - RETURN_STATUS_IF_FALSE(*env, NAPIErrorMemoryError) - - return NAPIErrorOK; -} - -NAPICommonStatus NAPIEnableDebugger(NAPIEnv env, const char *debuggerTitle, bool waitForDebugger) -{ - CHECK_ARG(env, Common) +NAPICommonStatus NAPIEnableDebugger(NAPIEnv env, const char *debuggerTitle, + bool waitForDebugger) { + CHECK_ARG(env, Common) - env->enableDebugger(debuggerTitle, waitForDebugger); + env->enableDebugger(debuggerTitle, waitForDebugger); - return NAPICommonOK; + return NAPICommonOK; } -NAPICommonStatus NAPIDisableDebugger(NAPIEnv env) -{ - CHECK_ARG(env, Common) +NAPICommonStatus NAPIDisableDebugger(NAPIEnv env) { + CHECK_ARG(env, Common) - env->disableDebugger(); + env->disableDebugger(); - return NAPICommonOK; + return NAPICommonOK; } -NAPICommonStatus NAPISetMessageQueueThread(NAPIEnv env, MessageQueueThreadWrapper jsQueueWrapper) -{ +NAPICommonStatus NAPISetMessageQueueThread( + NAPIEnv env, MessageQueueThreadWrapper jsQueueWrapper) { #ifdef HERMES_ENABLE_DEBUGGER - CHECK_ARG(env, Common); - env->setMessageQueueThread(jsQueueWrapper->thread_); + CHECK_ARG(env, Common); + env->setMessageQueueThread(jsQueueWrapper->thread_); #endif - return NAPICommonOK; + return NAPICommonOK; } -NAPICommonStatus NAPIFreeEnv(NAPIEnv env) -{ - CHECK_ARG(env, Common) +NAPICommonStatus NAPIFreeEnv(NAPIEnv env) { + CHECK_ARG(env, Common) - delete env; + delete env; - return NAPICommonOK; + return NAPICommonOK; } -NAPIErrorStatus NAPIGetValueStringUTF8(NAPIEnv env, NAPIValue value, const char **result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(value, Error) - CHECK_ARG(result, Error) - - RETURN_STATUS_IF_FALSE( - hermes::vm::vmisa(*(const hermes::vm::PinnedHermesValue *)value), - NAPIErrorStringExpected) - - auto stringPrimitive = - hermes::vm::dyn_vmcast_or_null(*(const hermes::vm::PinnedHermesValue *)value); - if (stringPrimitive->isASCII()) - { - auto asciiStringRef = stringPrimitive->getStringRef(); - char *buffer = static_cast(malloc(sizeof(char) * (asciiStringRef.size() + 1))); - RETURN_STATUS_IF_FALSE(buffer, NAPIErrorMemoryError) - std::memmove(buffer, asciiStringRef.data(), asciiStringRef.size()); - buffer[asciiStringRef.size()] = '\0'; - *result = buffer; - } - else - { - auto utf16StringRef = stringPrimitive->getStringRef(); - auto length = utf16StringRef.size() * 3 + 1; - char *buffer = static_cast(malloc(sizeof(char) * length)); - RETURN_STATUS_IF_FALSE(buffer, NAPIErrorMemoryError) auto sourceStart = utf16StringRef.begin(); - char *targetStart = buffer; - auto conversionResult = llvh::ConvertUTF16toUTF8( - reinterpret_cast(&sourceStart), - reinterpret_cast(utf16StringRef.end()), reinterpret_cast(&targetStart), - reinterpret_cast(buffer + length - 1), llvh::strictConversion); - if (conversionResult == llvh::ConversionResult::targetExhausted) - { - assert(false); - free(buffer); - - return NAPIErrorMemoryError; - } - else if (conversionResult != llvh::ConversionResult::conversionOK) - { - free(buffer); - - return NAPIErrorMemoryError; - } - *targetStart = '\0'; - *result = buffer; - } - - return NAPIErrorOK; +NAPIErrorStatus NAPIGetValueStringUTF8(NAPIEnv env, NAPIValue value, + const char **result) { + CHECK_ARG(env, Error) + CHECK_ARG(value, Error) + CHECK_ARG(result, Error) + + RETURN_STATUS_IF_FALSE(::hermes::vm::vmisa<::hermes::vm::StringPrimitive>( + *(const ::hermes::vm::PinnedHermesValue *)value), + NAPIErrorStringExpected) + + auto stringPrimitive = ::hermes::vm::vmcast<::hermes::vm::StringPrimitive>( + *(const ::hermes::vm::PinnedHermesValue *)value); + if (stringPrimitive->isASCII()) { + auto asciiStringRef = stringPrimitive->getStringRef(); + char *buffer = + static_cast(malloc(sizeof(char) * (asciiStringRef.size() + 1))); + RETURN_STATUS_IF_FALSE(buffer, NAPIErrorMemoryError) + ::std::memmove(buffer, asciiStringRef.data(), asciiStringRef.size()); + buffer[asciiStringRef.size()] = '\0'; + *result = buffer; + } else { + auto utf16StringRef = stringPrimitive->getStringRef(); + auto length = utf16StringRef.size() * 3 + 1; + char *buffer = static_cast(malloc(sizeof(char) * length)); + RETURN_STATUS_IF_FALSE(buffer, NAPIErrorMemoryError) + auto sourceStart = utf16StringRef.begin(); + char *targetStart = buffer; + auto conversionResult = ::llvh::ConvertUTF16toUTF8( + reinterpret_cast(&sourceStart), + reinterpret_cast(utf16StringRef.end()), + reinterpret_cast<::llvh::UTF8 **>(&targetStart), + reinterpret_cast<::llvh::UTF8 *>(buffer + length - 1), + ::llvh::strictConversion); + if (conversionResult == ::llvh::ConversionResult::targetExhausted) { + assert(false); + free(buffer); + + return NAPIErrorMemoryError; + } else if (conversionResult != ::llvh::ConversionResult::conversionOK) { + free(buffer); + + return NAPIErrorMemoryError; + } + *targetStart = '\0'; + *result = buffer; + } + + return NAPIErrorOK; } -NAPICommonStatus NAPIFreeUTF8String(NAPIEnv env, const char *cString) -{ - CHECK_ARG(env, Common) - CHECK_ARG(cString, Common) +NAPICommonStatus NAPIFreeUTF8String(NAPIEnv env, const char *cString) { + CHECK_ARG(env, Common) + CHECK_ARG(cString, Common) - free((void *)cString); + free((void *)cString); - return NAPICommonOK; + return NAPICommonOK; } -NAPI_EXPORT NAPIExceptionStatus NAPICompileToByteBuffer(NAPIEnv, const char *, const char *, const uint8_t **, size_t *) -{ - return NAPIExceptionOK; +NAPI_EXPORT NAPIExceptionStatus NAPICompileToByteBuffer(NAPIEnv, const char *, + const char *, + const uint8_t **, + size_t *) { + return NAPIExceptionOK; } -NAPI_EXPORT NAPICommonStatus NAPIFreeByteBuffer(NAPIEnv, const uint8_t *) -{ - return NAPICommonOK; +NAPI_EXPORT NAPICommonStatus NAPIFreeByteBuffer(NAPIEnv, const uint8_t *) { + return NAPICommonOK; } -NAPI_EXPORT NAPIExceptionStatus NAPIRunByteBuffer(NAPIEnv, const uint8_t *byteBuffer, size_t, NAPIValue *) -{ - return NAPIExceptionOK; +NAPI_EXPORT NAPIExceptionStatus NAPIRunByteBuffer(NAPIEnv, const uint8_t *, + size_t, NAPIValue *) { + return NAPIExceptionOK; } diff --git a/src/js_native_api_jsc.c b/src/js_native_api_jsc.c index fded781..328d319 100644 --- a/src/js_native_api_jsc.c +++ b/src/js_native_api_jsc.c @@ -3,30 +3,27 @@ #include // setLastErrorCode 会处理 env == NULL 问题 -#define RETURN_STATUS_IF_FALSE(condition, status) \ - if (!(condition)) \ - { \ - return status; \ - } - -#define CHECK_ARG(arg, status) \ - if (!arg) \ - { \ - return NAPI##status##InvalidArg; \ - } - -#define CHECK_NAPI(expr, exprStatus, returnStatus) \ - { \ - NAPI##exprStatus##Status status = expr; \ - if (status != NAPI##exprStatus##OK) \ - { \ - return (NAPI##returnStatus##Status)status; \ - } \ - } - -#define CHECK_JSC(env) \ - CHECK_ARG(env, Exception) \ - RETURN_STATUS_IF_FALSE(!((env)->lastException), NAPIExceptionPendingException) +#define RETURN_STATUS_IF_FALSE(condition, status) \ + if (!(condition)) { \ + return status; \ + } + +#define CHECK_ARG(arg, status) \ + if (!arg) { \ + return NAPI##status##InvalidArg; \ + } + +#define CHECK_NAPI(expr, exprStatus, returnStatus) \ + { \ + NAPI##exprStatus##Status status = expr; \ + if (status != NAPI##exprStatus##OK) { \ + return (NAPI##returnStatus##Status)status; \ + } \ + } + +#define CHECK_JSC(env) \ + CHECK_ARG(env, Exception) \ + RETURN_STATUS_IF_FALSE(!((env)->lastException), NAPIExceptionPendingException) #include #include @@ -35,109 +32,101 @@ #include #include -struct OpaqueNAPIRef -{ - LIST_ENTRY(OpaqueNAPIRef) node; // size_t - JSValueRef value; // size_t - uint8_t count; // 8 +struct OpaqueNAPIRef { + LIST_ENTRY(OpaqueNAPIRef) node; // size_t + JSValueRef value; // size_t + uint8_t count; // 8 }; -struct ReferenceInfo -{ - LIST_ENTRY(ReferenceInfo) node; - LIST_HEAD(, OpaqueNAPIRef) referenceList; - bool isEnvFreed; +struct ReferenceInfo { + LIST_ENTRY(ReferenceInfo) node; + LIST_HEAD(, OpaqueNAPIRef) referenceList; + bool isEnvFreed; }; // undefined 和 null 实际上也可以当做 exception // 抛出,所以异常检查只需要检查是否为 C NULL -struct OpaqueNAPIEnv -{ - JSGlobalContextRef context; // size_t - JSValueRef lastException; // size_t - LIST_HEAD(, ReferenceInfo) referenceList; - LIST_HEAD(, OpaqueNAPIRef) strongRefList; - LIST_HEAD(, OpaqueNAPIRef) valueList; +struct OpaqueNAPIEnv { + JSGlobalContextRef context; // size_t + JSValueRef lastException; // size_t + LIST_HEAD(, ReferenceInfo) referenceList; + LIST_HEAD(, OpaqueNAPIRef) strongRefList; + LIST_HEAD(, OpaqueNAPIRef) valueList; }; // NAPIMemoryError -NAPICommonStatus napi_get_undefined(NAPIEnv env, NAPIValue *result) -{ - CHECK_ARG(env, Common) - CHECK_ARG(result, Common) +NAPICommonStatus napi_get_undefined(NAPIEnv env, NAPIValue *result) { + CHECK_ARG(env, Common) + CHECK_ARG(result, Common) - *result = (NAPIValue)JSValueMakeUndefined(env->context); + *result = (NAPIValue)JSValueMakeUndefined(env->context); - return NAPICommonOK; + return NAPICommonOK; } // NAPIMemoryError -NAPICommonStatus napi_get_null(NAPIEnv env, NAPIValue *result) -{ - CHECK_ARG(env, Common) - CHECK_ARG(result, Common) +NAPICommonStatus napi_get_null(NAPIEnv env, NAPIValue *result) { + CHECK_ARG(env, Common) + CHECK_ARG(result, Common) - *result = (NAPIValue)JSValueMakeNull(env->context); + *result = (NAPIValue)JSValueMakeNull(env->context); - return NAPICommonOK; + return NAPICommonOK; } // NAPIMemoryError -NAPIErrorStatus napi_get_global(NAPIEnv env, NAPIValue *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_get_global(NAPIEnv env, NAPIValue *result) { + CHECK_ARG(env, Error) + CHECK_ARG(result, Error) - *result = (NAPIValue)JSContextGetGlobalObject(env->context); - RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError); + *result = (NAPIValue)JSContextGetGlobalObject(env->context); + RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError); - return NAPIErrorOK; + return NAPIErrorOK; } // NAPIMemoryError -NAPIErrorStatus napi_get_boolean(NAPIEnv env, bool value, NAPIValue *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_get_boolean(NAPIEnv env, bool value, NAPIValue *result) { + CHECK_ARG(env, Error) + CHECK_ARG(result, Error) - *result = (NAPIValue)JSValueMakeBoolean(env->context, value); - RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) + *result = (NAPIValue)JSValueMakeBoolean(env->context, value); + RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) - return NAPIErrorOK; + return NAPIErrorOK; } // NAPIMemoryError -NAPIErrorStatus napi_create_double(NAPIEnv env, double value, NAPIValue *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_create_double(NAPIEnv env, double value, + NAPIValue *result) { + CHECK_ARG(env, Error) + CHECK_ARG(result, Error) - *result = (NAPIValue)JSValueMakeNumber(env->context, value); - RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) + *result = (NAPIValue)JSValueMakeNumber(env->context, value); + RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) - return NAPIErrorOK; + return NAPIErrorOK; } // JavaScriptCore 只能接受 \0 结尾的字符串 // 传入 str NULL 则为 "" // V8 引擎传入 NULL 直接崩溃 // NAPIMemoryError -NAPIExceptionStatus napi_create_string_utf8(NAPIEnv env, const char *str, NAPIValue *result) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(result, Exception) - - // 传入 NULL,触发 OpaqueJSString() - JSStringRef stringRef = JSStringCreateWithUTF8CString(str); - // stringRef == NULL,会调用 String() - *result = (NAPIValue)JSValueMakeString(env->context, stringRef); - if (stringRef) - { - JSStringRelease(stringRef); - } - RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) +NAPIExceptionStatus napi_create_string_utf8(NAPIEnv env, const char *str, + NAPIValue *result) { + CHECK_ARG(env, Exception) + CHECK_ARG(result, Exception) + + // 传入 NULL,触发 OpaqueJSString() + JSStringRef stringRef = JSStringCreateWithUTF8CString(str); + // stringRef == NULL,会调用 String() + *result = (NAPIValue)JSValueMakeString(env->context, stringRef); + if (stringRef) { + JSStringRelease(stringRef); + } + RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) - return NAPIExceptionOK; + return NAPIExceptionOK; } // 1. external -> 不透明指针 + finalizer + 调用一个回调 @@ -146,1351 +135,1300 @@ NAPIExceptionStatus napi_create_string_utf8(NAPIEnv env, const char *str, NAPIVa // 4. Reference -> 引用计数 + setWeak/clearWeak -> __reference__ // Function -struct OpaqueNAPICallbackInfo -{ - JSObjectRef newTarget; // size_t - JSObjectRef thisArg; // size_t - const JSValueRef *argv; // size_t - void *data; // size_t - size_t argc; // size_t +struct OpaqueNAPICallbackInfo { + JSObjectRef newTarget; // size_t + JSObjectRef thisArg; // size_t + const JSValueRef *argv; // size_t + void *data; // size_t + size_t argc; // size_t }; -typedef struct -{ - NAPIEnv env; // size_t - void *data; // size_t +typedef struct { + NAPIEnv env; // size_t + void *data; // size_t } BaseInfo; -typedef struct -{ - void *data; // size_t - // BaseInfo baseInfo; - NAPIFinalize finalizeCallback; // size_t - void *finalizeHint; // size_t +typedef struct { + void *data; // size_t + // BaseInfo baseInfo; + NAPIFinalize finalizeCallback; // size_t + void *finalizeHint; // size_t } ExternalInfo; -typedef struct -{ - BaseInfo baseInfo; - NAPICallback callback; // size_t +typedef struct { + BaseInfo baseInfo; + NAPICallback callback; // size_t } FunctionInfo; static const char *const FUNCTION_STRING = "__function__"; // 所有参数都会存在,返回值可以为 NULL -static JSValueRef callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, - const JSValueRef arguments[], JSValueRef *exception) -{ - // JSObjectSetPrototype 确实可以传入非对象 JSValue,但是会被替换为 JS - // Null,并且可以正常取出来 - JSStringRef keyStringRef = JSStringCreateWithUTF8CString(FUNCTION_STRING); - if (!keyStringRef) - { - return NULL; - } - JSValueRef valueRef = JSObjectGetProperty(ctx, function, keyStringRef, exception); - if (*exception || !valueRef) - { - return NULL; - } - if (!JSValueIsObject(ctx, valueRef)) - { - // 正常不应当出现 - assert(false); - - // 返回 NULL 会被转换为 undefined - return NULL; - } - JSObjectRef prototypeObjectRef = JSValueToObject(ctx, valueRef, exception); - if (*exception || !prototypeObjectRef) - { - // 正常不应当出现 - assert(false); - - return NULL; - } - FunctionInfo *functionInfo = JSObjectGetPrivate(prototypeObjectRef); - if (!functionInfo || !functionInfo->baseInfo.env || !functionInfo->callback) - { - // 正常不应当出现 - assert(false); - - return NULL; - } - - // JavaScriptCore 参数都不是 NULL - struct OpaqueNAPICallbackInfo callbackInfo; - callbackInfo.newTarget = NULL; - callbackInfo.thisArg = thisObject; - callbackInfo.argc = argumentCount; - callbackInfo.argv = arguments; - callbackInfo.data = functionInfo->baseInfo.data; - - JSValueRef returnValue = (JSValueRef)functionInfo->callback(functionInfo->baseInfo.env, &callbackInfo); - if (functionInfo->baseInfo.env->lastException) - { - *exception = functionInfo->baseInfo.env->lastException; - functionInfo->baseInfo.env->lastException = NULL; - - return NULL; - } - - return returnValue; +static JSValueRef callAsFunction(JSContextRef ctx, JSObjectRef function, + JSObjectRef thisObject, size_t argumentCount, + const JSValueRef arguments[], + JSValueRef *exception) { + // JSObjectSetPrototype 确实可以传入非对象 JSValue,但是会被替换为 JS + // Null,并且可以正常取出来 + JSStringRef keyStringRef = JSStringCreateWithUTF8CString(FUNCTION_STRING); + if (!keyStringRef) { + return NULL; + } + JSValueRef valueRef = + JSObjectGetProperty(ctx, function, keyStringRef, exception); + if (*exception || !valueRef) { + return NULL; + } + if (!JSValueIsObject(ctx, valueRef)) { + // 正常不应当出现 + assert(false); + + // 返回 NULL 会被转换为 undefined + return NULL; + } + JSObjectRef prototypeObjectRef = JSValueToObject(ctx, valueRef, exception); + if (*exception || !prototypeObjectRef) { + // 正常不应当出现 + assert(false); + + return NULL; + } + FunctionInfo *functionInfo = JSObjectGetPrivate(prototypeObjectRef); + if (!functionInfo || !functionInfo->baseInfo.env || !functionInfo->callback) { + // 正常不应当出现 + assert(false); + + return NULL; + } + + // JavaScriptCore 参数都不是 NULL + struct OpaqueNAPICallbackInfo callbackInfo; + callbackInfo.newTarget = NULL; + callbackInfo.thisArg = thisObject; + callbackInfo.argc = argumentCount; + callbackInfo.argv = arguments; + callbackInfo.data = functionInfo->baseInfo.data; + + JSValueRef returnValue = (JSValueRef)functionInfo->callback( + functionInfo->baseInfo.env, &callbackInfo); + if (functionInfo->baseInfo.env->lastException) { + *exception = functionInfo->baseInfo.env->lastException; + functionInfo->baseInfo.env->lastException = NULL; + + return NULL; + } + + return returnValue; } -static void functionFinalize(JSObjectRef object) -{ - free(JSObjectGetPrivate(object)); +static void functionFinalize(JSObjectRef object) { + free(JSObjectGetPrivate(object)); } // NAPIMemoryError -NAPIExceptionStatus napi_create_function(NAPIEnv env, const char *utf8name, NAPICallback cb, void *data, - NAPIValue *result) -{ - CHECK_JSC(env) - CHECK_ARG(cb, Exception) - CHECK_ARG(result, Exception) - - FunctionInfo *functionInfo = malloc(sizeof(FunctionInfo)); - RETURN_STATUS_IF_FALSE(functionInfo, NAPIExceptionMemoryError) - functionInfo->baseInfo.env = env; - functionInfo->callback = cb; - functionInfo->baseInfo.data = data; - - JSClassDefinition classDefinition = kJSClassDefinitionEmpty; - // 使用 Object.prototype 作为 instance.[[prototype]] - classDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; - // 最重要的是提供 finalize - classDefinition.finalize = functionFinalize; - JSClassRef classRef = JSClassCreate(&classDefinition); - if (!classRef) - { - free(functionInfo); - - return NAPIExceptionMemoryError; - } - JSObjectRef prototype = JSObjectMake(env->context, classRef, functionInfo); - JSClassRelease(classRef); - if (!prototype) - { - free(functionInfo); - - return NAPIExceptionMemoryError; - } - - // utf8name 会被当做函数的 .name 属性 - // V8 传入 NULL 会直接变成 "" - JSStringRef stringRef = JSStringCreateWithUTF8CString(utf8name); - // JSObjectMakeFunctionWithCallback 传入函数名为 NULL 则为 anonymous - JSObjectRef functionObjectRef = JSObjectMakeFunctionWithCallback(env->context, stringRef, callAsFunction); - // JSStringRelease 不能传入 NULL - if (stringRef) - { - JSStringRelease(stringRef); - } - RETURN_STATUS_IF_FALSE(functionObjectRef, NAPIExceptionMemoryError) - - *result = (NAPIValue)functionObjectRef; - stringRef = JSStringCreateWithUTF8CString(FUNCTION_STRING); - RETURN_STATUS_IF_FALSE(stringRef, NAPIExceptionMemoryError) - JSObjectSetProperty(env->context, functionObjectRef, stringRef, prototype, - kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete, - &env->lastException); +NAPIExceptionStatus napi_create_function(NAPIEnv env, const char *utf8name, + NAPICallback cb, void *data, + NAPIValue *result) { + CHECK_JSC(env) + CHECK_ARG(cb, Exception) + CHECK_ARG(result, Exception) + + FunctionInfo *functionInfo = malloc(sizeof(FunctionInfo)); + RETURN_STATUS_IF_FALSE(functionInfo, NAPIExceptionMemoryError) + functionInfo->baseInfo.env = env; + functionInfo->callback = cb; + functionInfo->baseInfo.data = data; + + JSClassDefinition classDefinition = kJSClassDefinitionEmpty; + // 使用 Object.prototype 作为 instance.[[prototype]] + classDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; + // 最重要的是提供 finalize + classDefinition.finalize = functionFinalize; + JSClassRef classRef = JSClassCreate(&classDefinition); + if (!classRef) { + free(functionInfo); + + return NAPIExceptionMemoryError; + } + JSObjectRef prototype = JSObjectMake(env->context, classRef, functionInfo); + JSClassRelease(classRef); + if (!prototype) { + free(functionInfo); + + return NAPIExceptionMemoryError; + } + + // utf8name 会被当做函数的 .name 属性 + // V8 传入 NULL 会直接变成 "" + JSStringRef stringRef = JSStringCreateWithUTF8CString(utf8name); + // JSObjectMakeFunctionWithCallback 传入函数名为 NULL 则为 anonymous + JSObjectRef functionObjectRef = + JSObjectMakeFunctionWithCallback(env->context, stringRef, callAsFunction); + // JSStringRelease 不能传入 NULL + if (stringRef) { JSStringRelease(stringRef); - CHECK_JSC(env) - - return NAPIExceptionOK; + } + RETURN_STATUS_IF_FALSE(functionObjectRef, NAPIExceptionMemoryError) + + *result = (NAPIValue)functionObjectRef; + stringRef = JSStringCreateWithUTF8CString(FUNCTION_STRING); + RETURN_STATUS_IF_FALSE(stringRef, NAPIExceptionMemoryError) + JSObjectSetProperty(env->context, functionObjectRef, stringRef, prototype, + kJSPropertyAttributeReadOnly | + kJSPropertyAttributeDontEnum | + kJSPropertyAttributeDontDelete, + &env->lastException); + JSStringRelease(stringRef); + CHECK_JSC(env) + + return NAPIExceptionOK; } // NAPIPendingException/NAPIMemoryError -NAPICommonStatus napi_typeof(NAPIEnv env, NAPIValue value, NAPIValueType *result) -{ - CHECK_ARG(env, Common) - CHECK_ARG(value, Common) - CHECK_ARG(result, Common) - - // JSC does not support BigInt - JSType valueType = JSValueGetType(env->context, (JSValueRef)value); - switch (valueType) - { +NAPICommonStatus napi_typeof(NAPIEnv env, NAPIValue value, + NAPIValueType *result) { + CHECK_ARG(env, Common) + CHECK_ARG(value, Common) + CHECK_ARG(result, Common) + + // JSC does not support BigInt + JSType valueType = JSValueGetType(env->context, (JSValueRef)value); + switch (valueType) { case kJSTypeUndefined: - *result = NAPIUndefined; - break; + *result = NAPIUndefined; + break; case kJSTypeNull: - *result = NAPINull; - break; + *result = NAPINull; + break; case kJSTypeBoolean: - *result = NAPIBoolean; - break; + *result = NAPIBoolean; + break; case kJSTypeNumber: - *result = NAPINumber; - break; + *result = NAPINumber; + break; case kJSTypeString: - *result = NAPIString; - break; + *result = NAPIString; + break; case kJSTypeObject: { - JSValueRef exception = NULL; - JSObjectRef object = JSValueToObject(env->context, (JSValueRef)value, &exception); - RETURN_STATUS_IF_FALSE(!exception && object, NAPICommonInvalidArg) - if (JSObjectIsFunction(env->context, object)) - { - *result = NAPIFunction; + JSValueRef exception = NULL; + JSObjectRef object = + JSValueToObject(env->context, (JSValueRef)value, &exception); + RETURN_STATUS_IF_FALSE(!exception && object, NAPICommonInvalidArg) + if (JSObjectIsFunction(env->context, object)) { + *result = NAPIFunction; + } else { + if (JSObjectGetPrivate(object)) { + *result = NAPIExternal; + } else { + *result = NAPIObject; } - else - { - if (JSObjectGetPrivate(object)) - { - *result = NAPIExternal; - } - else - { - *result = NAPIObject; - } - } - } - break; + } + } break; default: - // Should not get here unless V8 has added some new kind of value. - assert(false); + // Should not get here unless V8 has added some new kind of value. + assert(false); - return NAPICommonInvalidArg; - } + return NAPICommonInvalidArg; + } - return NAPICommonOK; + return NAPICommonOK; } // NAPINumberExpected/NAPIPendingException -NAPIErrorStatus napi_get_value_double(NAPIEnv env, NAPIValue value, double *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(value, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_get_value_double(NAPIEnv env, NAPIValue value, + double *result) { + CHECK_ARG(env, Error) + CHECK_ARG(value, Error) + CHECK_ARG(result, Error) - RETURN_STATUS_IF_FALSE(JSValueIsNumber(env->context, (JSValueRef)value), NAPIErrorNumberExpected) + RETURN_STATUS_IF_FALSE(JSValueIsNumber(env->context, (JSValueRef)value), + NAPIErrorNumberExpected) - JSValueRef exception = NULL; - *result = JSValueToNumber(env->context, (JSValueRef)value, &exception); - RETURN_STATUS_IF_FALSE(!exception, NAPIErrorNumberExpected) + JSValueRef exception = NULL; + *result = JSValueToNumber(env->context, (JSValueRef)value, &exception); + RETURN_STATUS_IF_FALSE(!exception, NAPIErrorNumberExpected) - return NAPIErrorOK; + return NAPIErrorOK; } // NAPIBooleanExpected -NAPIErrorStatus napi_get_value_bool(NAPIEnv env, NAPIValue value, bool *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(value, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_get_value_bool(NAPIEnv env, NAPIValue value, + bool *result) { + CHECK_ARG(env, Error) + CHECK_ARG(value, Error) + CHECK_ARG(result, Error) - RETURN_STATUS_IF_FALSE(JSValueIsBoolean(env->context, (JSValueRef)value), NAPIErrorBooleanExpected) - *result = JSValueToBoolean(env->context, (JSValueRef)value); + RETURN_STATUS_IF_FALSE(JSValueIsBoolean(env->context, (JSValueRef)value), + NAPIErrorBooleanExpected) + *result = JSValueToBoolean(env->context, (JSValueRef)value); - return NAPIErrorOK; + return NAPIErrorOK; } // NAPIMemoryError -NAPIExceptionStatus napi_coerce_to_bool(NAPIEnv env, NAPIValue value, NAPIValue *result) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(value, Exception) - CHECK_ARG(result, Exception) +NAPIExceptionStatus napi_coerce_to_bool(NAPIEnv env, NAPIValue value, + NAPIValue *result) { + CHECK_ARG(env, Exception) + CHECK_ARG(value, Exception) + CHECK_ARG(result, Exception) - *result = (NAPIValue)JSValueMakeBoolean(env->context, JSValueToBoolean(env->context, (JSValueRef)value)); - RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) + *result = (NAPIValue)JSValueMakeBoolean( + env->context, JSValueToBoolean(env->context, (JSValueRef)value)); + RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) - return NAPIExceptionOK; + return NAPIExceptionOK; } // NAPIMemoryError -NAPIExceptionStatus napi_coerce_to_number(NAPIEnv env, NAPIValue value, NAPIValue *result) -{ - CHECK_JSC(env) - CHECK_ARG(value, Exception) - CHECK_ARG(result, Exception) - - double doubleValue = JSValueToNumber(env->context, (JSValueRef)value, &env->lastException); - CHECK_JSC(env) - *result = (NAPIValue)JSValueMakeNumber(env->context, doubleValue); - RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) - - return NAPIExceptionOK; +NAPIExceptionStatus napi_coerce_to_number(NAPIEnv env, NAPIValue value, + NAPIValue *result) { + CHECK_JSC(env) + CHECK_ARG(value, Exception) + CHECK_ARG(result, Exception) + + double doubleValue = + JSValueToNumber(env->context, (JSValueRef)value, &env->lastException); + CHECK_JSC(env) + *result = (NAPIValue)JSValueMakeNumber(env->context, doubleValue); + RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) + + return NAPIExceptionOK; } // NAPIMemoryError -NAPIExceptionStatus napi_coerce_to_string(NAPIEnv env, NAPIValue value, NAPIValue *result) -{ - CHECK_JSC(env) - CHECK_ARG(value, Exception) - CHECK_ARG(result, Exception) +NAPIExceptionStatus napi_coerce_to_string(NAPIEnv env, NAPIValue value, + NAPIValue *result) { + CHECK_JSC(env) + CHECK_ARG(value, Exception) + CHECK_ARG(result, Exception) + + JSStringRef stringRef = + JSValueToStringCopy(env->context, (JSValueRef)value, &env->lastException); + CHECK_JSC(env) + RETURN_STATUS_IF_FALSE(stringRef, NAPIExceptionMemoryError) + *result = (NAPIValue)JSValueMakeString(env->context, stringRef); + JSStringRelease(stringRef); + RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) + + return NAPIExceptionOK; +} - JSStringRef stringRef = JSValueToStringCopy(env->context, (JSValueRef)value, &env->lastException); +NAPIExceptionStatus napi_set_property(NAPIEnv env, NAPIValue object, + NAPIValue key, NAPIValue value) { + CHECK_JSC(env) + CHECK_ARG(object, Exception) + CHECK_ARG(key, Exception) + CHECK_ARG(value, Exception) + + RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)object), + NAPIExceptionObjectExpected) + JSObjectRef objectRef = + JSValueToObject(env->context, (JSValueRef)object, &env->lastException); + CHECK_JSC(env) + RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) + + if (JSValueIsString(env->context, (JSValueRef)key)) { + JSStringRef stringRef = + JSValueToStringCopy(env->context, (JSValueRef)key, &env->lastException); CHECK_JSC(env) RETURN_STATUS_IF_FALSE(stringRef, NAPIExceptionMemoryError) - *result = (NAPIValue)JSValueMakeString(env->context, stringRef); + JSObjectSetProperty(env->context, objectRef, stringRef, (JSValueRef)value, + kJSPropertyAttributeNone, &env->lastException); JSStringRelease(stringRef); - RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) - - return NAPIExceptionOK; + } else if (JSValueIsNumber(env->context, (JSValueRef)key)) { + double doubleValue; + CHECK_NAPI(napi_get_value_double(env, key, &doubleValue), Error, Exception) + JSObjectSetPropertyAtIndex(env->context, objectRef, + (unsigned int)doubleValue, (JSValueRef)value, + &env->lastException); + } else { + return NAPIExceptionNameExpected; + } + CHECK_JSC(env) + + return NAPIExceptionOK; } -NAPIExceptionStatus napi_set_property(NAPIEnv env, NAPIValue object, NAPIValue key, NAPIValue value) -{ - CHECK_JSC(env) - CHECK_ARG(object, Exception) - CHECK_ARG(key, Exception) - CHECK_ARG(value, Exception) - - RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)object), NAPIExceptionObjectExpected) - JSObjectRef objectRef = JSValueToObject(env->context, (JSValueRef)object, &env->lastException); - CHECK_JSC(env) - RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) - - if (JSValueIsString(env->context, (JSValueRef)key)) - { - JSStringRef stringRef = JSValueToStringCopy(env->context, (JSValueRef)key, &env->lastException); - CHECK_JSC(env) - RETURN_STATUS_IF_FALSE(stringRef, NAPIExceptionMemoryError) - JSObjectSetProperty(env->context, objectRef, stringRef, (JSValueRef)value, kJSPropertyAttributeNone, - &env->lastException); - JSStringRelease(stringRef); - } - else if (JSValueIsNumber(env->context, (JSValueRef)key)) - { - double doubleValue; - CHECK_NAPI(napi_get_value_double(env, key, &doubleValue), Error, Exception) - JSObjectSetPropertyAtIndex(env->context, objectRef, (unsigned int)doubleValue, (JSValueRef)value, - &env->lastException); - } - else - { - return NAPIExceptionNameExpected; - } - CHECK_JSC(env) - - return NAPIExceptionOK; -} - -NAPIExceptionStatus napi_has_property(NAPIEnv env, NAPIValue object, NAPIValue key, bool *result) -{ - CHECK_JSC(env) - CHECK_ARG(object, Exception) - CHECK_ARG(key, Exception) - CHECK_ARG(result, Exception) - - RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)object), NAPIExceptionObjectExpected) - JSObjectRef objectRef = JSValueToObject(env->context, (JSValueRef)object, &env->lastException); - CHECK_JSC(env) - RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) - - if (JSValueIsString(env->context, (JSValueRef)key)) - { - JSStringRef stringRef = JSValueToStringCopy(env->context, (JSValueRef)key, &env->lastException); - RETURN_STATUS_IF_FALSE(stringRef, NAPIExceptionMemoryError) - *result = JSObjectHasProperty(env->context, objectRef, stringRef); - JSStringRelease(stringRef); - } - else if (JSValueIsNumber(env->context, (JSValueRef)key)) - { - double doubleValue; - CHECK_NAPI(napi_get_value_double(env, key, &doubleValue), Error, Exception) - *result = JSObjectGetPropertyAtIndex(env->context, objectRef, (unsigned int)doubleValue, &env->lastException); - CHECK_JSC(env) - } - else - { - return NAPIExceptionNameExpected; - } - - return NAPIExceptionOK; -} - -NAPIExceptionStatus napi_get_property(NAPIEnv env, NAPIValue object, NAPIValue key, NAPIValue *result) -{ - CHECK_JSC(env) - CHECK_ARG(object, Exception) - CHECK_ARG(key, Exception) - CHECK_ARG(result, Exception) - - RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)object), NAPIExceptionObjectExpected) - JSObjectRef objectRef = JSValueToObject(env->context, (JSValueRef)object, &env->lastException); +NAPIExceptionStatus napi_has_property(NAPIEnv env, NAPIValue object, + NAPIValue key, bool *result) { + CHECK_JSC(env) + CHECK_ARG(object, Exception) + CHECK_ARG(key, Exception) + CHECK_ARG(result, Exception) + + RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)object), + NAPIExceptionObjectExpected) + JSObjectRef objectRef = + JSValueToObject(env->context, (JSValueRef)object, &env->lastException); + CHECK_JSC(env) + RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) + + if (JSValueIsString(env->context, (JSValueRef)key)) { + JSStringRef stringRef = + JSValueToStringCopy(env->context, (JSValueRef)key, &env->lastException); + RETURN_STATUS_IF_FALSE(stringRef, NAPIExceptionMemoryError) + *result = JSObjectHasProperty(env->context, objectRef, stringRef); + JSStringRelease(stringRef); + } else if (JSValueIsNumber(env->context, (JSValueRef)key)) { + double doubleValue; + CHECK_NAPI(napi_get_value_double(env, key, &doubleValue), Error, Exception) + *result = JSObjectGetPropertyAtIndex(env->context, objectRef, + (unsigned int)doubleValue, + &env->lastException); CHECK_JSC(env) - RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) - - if (JSValueIsString(env->context, (JSValueRef)key)) - { - JSStringRef stringRef = JSValueToStringCopy(env->context, (JSValueRef)key, &env->lastException); - RETURN_STATUS_IF_FALSE(stringRef, NAPIExceptionMemoryError) - *result = (NAPIValue)JSObjectGetProperty(env->context, objectRef, stringRef, &env->lastException); - JSStringRelease(stringRef); - } - else if (JSValueIsNumber(env->context, (JSValueRef)key)) - { - double doubleValue; - CHECK_NAPI(napi_get_value_double(env, key, &doubleValue), Error, Exception) - *result = (NAPIValue)JSObjectGetPropertyAtIndex(env->context, objectRef, (unsigned int)doubleValue, - &env->lastException); - } - else - { - return NAPIExceptionNameExpected; - } + } else { + return NAPIExceptionNameExpected; + } - return NAPIExceptionOK; + return NAPIExceptionOK; } -// key 必须为字符串 -NAPIExceptionStatus napi_delete_property(NAPIEnv env, NAPIValue object, NAPIValue key, bool *result) -{ - CHECK_JSC(env) - CHECK_ARG(object, Exception) - CHECK_ARG(key, Exception) - - RETURN_STATUS_IF_FALSE(JSValueIsString(env->context, (JSValueRef)key), NAPIExceptionStringExpected) - RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)object), NAPIExceptionObjectExpected) - - JSObjectRef objectRef = JSValueToObject(env->context, (JSValueRef)object, &env->lastException); - CHECK_JSC(env) - RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) - - JSStringRef stringRef = JSValueToStringCopy(env->context, (JSValueRef)key, &env->lastException); - CHECK_JSC(env) +NAPIExceptionStatus napi_get_property(NAPIEnv env, NAPIValue object, + NAPIValue key, NAPIValue *result) { + CHECK_JSC(env) + CHECK_ARG(object, Exception) + CHECK_ARG(key, Exception) + CHECK_ARG(result, Exception) + + RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)object), + NAPIExceptionObjectExpected) + JSObjectRef objectRef = + JSValueToObject(env->context, (JSValueRef)object, &env->lastException); + CHECK_JSC(env) + RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) + + if (JSValueIsString(env->context, (JSValueRef)key)) { + JSStringRef stringRef = + JSValueToStringCopy(env->context, (JSValueRef)key, &env->lastException); RETURN_STATUS_IF_FALSE(stringRef, NAPIExceptionMemoryError) - - bool deleteSuccess = JSObjectDeleteProperty(env->context, objectRef, stringRef, &env->lastException); + *result = (NAPIValue)JSObjectGetProperty(env->context, objectRef, stringRef, + &env->lastException); JSStringRelease(stringRef); - CHECK_JSC(env) - if (result) - { - *result = deleteSuccess; - } - - return NAPIExceptionOK; + } else if (JSValueIsNumber(env->context, (JSValueRef)key)) { + double doubleValue; + CHECK_NAPI(napi_get_value_double(env, key, &doubleValue), Error, Exception) + *result = (NAPIValue)JSObjectGetPropertyAtIndex(env->context, objectRef, + (unsigned int)doubleValue, + &env->lastException); + } else { + return NAPIExceptionNameExpected; + } + + return NAPIExceptionOK; } -NAPICommonStatus napi_is_array(NAPIEnv env, NAPIValue value, bool *result) -{ - CHECK_ARG(env, Common) - CHECK_ARG(value, Common) - CHECK_ARG(result, Common) - - *result = JSValueIsArray(env->context, (JSValueRef)value); - - return NAPICommonOK; +// key 必须为字符串 +NAPIExceptionStatus napi_delete_property(NAPIEnv env, NAPIValue object, + NAPIValue key, bool *result) { + CHECK_JSC(env) + CHECK_ARG(object, Exception) + CHECK_ARG(key, Exception) + + RETURN_STATUS_IF_FALSE(JSValueIsString(env->context, (JSValueRef)key), + NAPIExceptionStringExpected) + RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)object), + NAPIExceptionObjectExpected) + + JSObjectRef objectRef = + JSValueToObject(env->context, (JSValueRef)object, &env->lastException); + CHECK_JSC(env) + RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) + + JSStringRef stringRef = + JSValueToStringCopy(env->context, (JSValueRef)key, &env->lastException); + CHECK_JSC(env) + RETURN_STATUS_IF_FALSE(stringRef, NAPIExceptionMemoryError) + + bool deleteSuccess = JSObjectDeleteProperty(env->context, objectRef, + stringRef, &env->lastException); + JSStringRelease(stringRef); + CHECK_JSC(env) + if (result) { + *result = deleteSuccess; + } + + return NAPIExceptionOK; } -NAPIExceptionStatus napi_call_function(NAPIEnv env, NAPIValue thisValue, NAPIValue func, size_t argc, - const NAPIValue *argv, NAPIValue *result) -{ - CHECK_JSC(env) - CHECK_ARG(func, Exception) - if (argc > 0) - { - CHECK_ARG(argv, Exception) - } - - RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)func), NAPIExceptionObjectExpected) - - JSObjectRef objectRef = JSValueToObject(env->context, (JSValueRef)func, &env->lastException); - RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) - RETURN_STATUS_IF_FALSE(JSObjectIsFunction(env->context, objectRef), NAPIExceptionFunctionExpected) - - JSObjectRef thisObjectRef = NULL; - if (!thisValue) - { - thisObjectRef = JSContextGetGlobalObject(env->context); - } - else - { - RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)thisValue), NAPIExceptionObjectExpected) - thisObjectRef = JSValueToObject(env->context, (JSValueRef)thisValue, &env->lastException); - CHECK_JSC(env) - } - JSValueRef returnValue = NULL; - if (!argc) - { - returnValue = JSObjectCallAsFunction(env->context, objectRef, thisObjectRef, 0, NULL, &env->lastException); - } - else if (argc <= 8) - { - JSValueRef argumentArray[argc]; - for (size_t i = 0; i < argc; ++i) - { - argumentArray[i] = (JSValueRef)argv[i]; - } - returnValue = - JSObjectCallAsFunction(env->context, objectRef, thisObjectRef, argc, argumentArray, &env->lastException); - } - else - { - JSValueRef *argumentArray = malloc(sizeof(JSValueRef) * argc); - RETURN_STATUS_IF_FALSE(argumentArray, NAPIExceptionMemoryError) - for (size_t i = 0; i < argc; ++i) - { - argumentArray[i] = (JSValueRef)argv[i]; - } - returnValue = - JSObjectCallAsFunction(env->context, objectRef, thisObjectRef, argc, argumentArray, &env->lastException); - free(argumentArray); - } - CHECK_JSC(env) +NAPICommonStatus napi_is_array(NAPIEnv env, NAPIValue value, bool *result) { + CHECK_ARG(env, Common) + CHECK_ARG(value, Common) + CHECK_ARG(result, Common) - if (result) - { - RETURN_STATUS_IF_FALSE(returnValue, NAPIExceptionMemoryError) - *result = (NAPIValue)returnValue; - } + *result = JSValueIsArray(env->context, (JSValueRef)value); - return NAPIExceptionOK; + return NAPICommonOK; } -NAPIExceptionStatus napi_new_instance(NAPIEnv env, NAPIValue constructor, size_t argc, const NAPIValue *argv, - NAPIValue *result) -{ +NAPIExceptionStatus napi_call_function(NAPIEnv env, NAPIValue thisValue, + NAPIValue func, size_t argc, + const NAPIValue *argv, + NAPIValue *result) { + CHECK_JSC(env) + CHECK_ARG(func, Exception) + if (argc > 0) { + CHECK_ARG(argv, Exception) + } + + RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)func), + NAPIExceptionObjectExpected) + + JSObjectRef objectRef = + JSValueToObject(env->context, (JSValueRef)func, &env->lastException); + RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) + RETURN_STATUS_IF_FALSE(JSObjectIsFunction(env->context, objectRef), + NAPIExceptionFunctionExpected) + + JSObjectRef thisObjectRef = NULL; + if (!thisValue) { + thisObjectRef = JSContextGetGlobalObject(env->context); + } else { + RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)thisValue), + NAPIExceptionObjectExpected) + thisObjectRef = JSValueToObject(env->context, (JSValueRef)thisValue, + &env->lastException); CHECK_JSC(env) - CHECK_ARG(constructor, Exception) - if (argc > 0) - { - CHECK_ARG(argv, Exception) - } - CHECK_ARG(result, Exception) - - RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)constructor), NAPIExceptionObjectExpected) - JSObjectRef objectRef = JSValueToObject(env->context, (JSValueRef)constructor, &env->lastException); - CHECK_JSC(env) - RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) - RETURN_STATUS_IF_FALSE(JSObjectIsConstructor(env->context, objectRef), NAPIExceptionFunctionExpected) - - *result = (NAPIValue)JSObjectCallAsConstructor(env->context, objectRef, argc, (const JSValueRef *)argv, - &env->lastException); - CHECK_JSC(env) - RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) - - return NAPIExceptionOK; + } + JSValueRef returnValue = NULL; + if (!argc) { + returnValue = JSObjectCallAsFunction(env->context, objectRef, thisObjectRef, + 0, NULL, &env->lastException); + } else if (argc <= 8) { + JSValueRef argumentArray[argc]; + for (size_t i = 0; i < argc; ++i) { + argumentArray[i] = (JSValueRef)argv[i]; + } + returnValue = + JSObjectCallAsFunction(env->context, objectRef, thisObjectRef, argc, + argumentArray, &env->lastException); + } else { + JSValueRef *argumentArray = malloc(sizeof(JSValueRef) * argc); + RETURN_STATUS_IF_FALSE(argumentArray, NAPIExceptionMemoryError) + for (size_t i = 0; i < argc; ++i) { + argumentArray[i] = (JSValueRef)argv[i]; + } + returnValue = + JSObjectCallAsFunction(env->context, objectRef, thisObjectRef, argc, + argumentArray, &env->lastException); + free(argumentArray); + } + CHECK_JSC(env) + + if (result) { + RETURN_STATUS_IF_FALSE(returnValue, NAPIExceptionMemoryError) + *result = (NAPIValue)returnValue; + } + + return NAPIExceptionOK; } -NAPIExceptionStatus napi_instanceof(NAPIEnv env, NAPIValue object, NAPIValue constructor, bool *result) -{ - CHECK_JSC(env) - CHECK_ARG(object, Exception) - CHECK_ARG(constructor, Exception) - CHECK_ARG(result, Exception) - - RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)constructor), NAPIExceptionObjectExpected) - JSObjectRef objectRef = JSValueToObject(env->context, (JSValueRef)constructor, &env->lastException); - CHECK_JSC(env) - RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) - RETURN_STATUS_IF_FALSE(JSObjectIsConstructor(env->context, objectRef), NAPIExceptionFunctionExpected) - - *result = JSValueIsInstanceOfConstructor(env->context, (JSValueRef)object, objectRef, &env->lastException); - CHECK_JSC(env) +NAPIExceptionStatus napi_new_instance(NAPIEnv env, NAPIValue constructor, + size_t argc, const NAPIValue *argv, + NAPIValue *result) { + CHECK_JSC(env) + CHECK_ARG(constructor, Exception) + if (argc > 0) { + CHECK_ARG(argv, Exception) + } + CHECK_ARG(result, Exception) + + RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)constructor), + NAPIExceptionObjectExpected) + JSObjectRef objectRef = JSValueToObject(env->context, (JSValueRef)constructor, + &env->lastException); + CHECK_JSC(env) + RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) + RETURN_STATUS_IF_FALSE(JSObjectIsConstructor(env->context, objectRef), + NAPIExceptionFunctionExpected) + + *result = (NAPIValue)JSObjectCallAsConstructor(env->context, objectRef, argc, + (const JSValueRef *)argv, + &env->lastException); + CHECK_JSC(env) + RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) + + return NAPIExceptionOK; +} - return NAPIExceptionOK; +NAPIExceptionStatus napi_instanceof(NAPIEnv env, NAPIValue object, + NAPIValue constructor, bool *result) { + CHECK_JSC(env) + CHECK_ARG(object, Exception) + CHECK_ARG(constructor, Exception) + CHECK_ARG(result, Exception) + + RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)constructor), + NAPIExceptionObjectExpected) + JSObjectRef objectRef = JSValueToObject(env->context, (JSValueRef)constructor, + &env->lastException); + CHECK_JSC(env) + RETURN_STATUS_IF_FALSE(objectRef, NAPIExceptionMemoryError) + RETURN_STATUS_IF_FALSE(JSObjectIsConstructor(env->context, objectRef), + NAPIExceptionFunctionExpected) + + *result = JSValueIsInstanceOfConstructor(env->context, (JSValueRef)object, + objectRef, &env->lastException); + CHECK_JSC(env) + + return NAPIExceptionOK; } -NAPICommonStatus napi_get_cb_info(NAPIEnv env, NAPICallbackInfo callbackInfo, size_t *argc, NAPIValue *argv, - NAPIValue *thisArg, void **data) -{ - CHECK_ARG(env, Common) - CHECK_ARG(callbackInfo, Common) +NAPICommonStatus napi_get_cb_info(NAPIEnv env, NAPICallbackInfo callbackInfo, + size_t *argc, NAPIValue *argv, + NAPIValue *thisArg, void **data) { + CHECK_ARG(env, Common) + CHECK_ARG(callbackInfo, Common) - if (argv) - { - CHECK_ARG(argc, Common) + if (argv) { + CHECK_ARG(argc, Common) - size_t i = 0; - size_t min = *argc > callbackInfo->argc ? callbackInfo->argc : *argc; + size_t i = 0; + size_t min = *argc > callbackInfo->argc ? callbackInfo->argc : *argc; - for (; i < min; i++) - { - argv[i] = (NAPIValue)callbackInfo->argv[i]; - } - - if (i < *argc) - { - for (; i < *argc; i++) - { - argv[i] = (NAPIValue)JSValueMakeUndefined(env->context); - } - } + for (; i < min; i++) { + argv[i] = (NAPIValue)callbackInfo->argv[i]; } - if (argc) - { - *argc = callbackInfo->argc; + if (i < *argc) { + for (; i < *argc; i++) { + argv[i] = (NAPIValue)JSValueMakeUndefined(env->context); + } } + } - if (thisArg) - { - *thisArg = (NAPIValue)callbackInfo->thisArg; - } + if (argc) { + *argc = callbackInfo->argc; + } - if (data) - { - *data = callbackInfo->data; - } + if (thisArg) { + *thisArg = (NAPIValue)callbackInfo->thisArg; + } + + if (data) { + *data = callbackInfo->data; + } - return NAPICommonOK; + return NAPICommonOK; } -NAPICommonStatus napi_get_new_target(NAPIEnv env, NAPICallbackInfo callbackInfo, NAPIValue *result) -{ - CHECK_ARG(env, Common) - CHECK_ARG(callbackInfo, Common) - CHECK_ARG(result, Common) +NAPICommonStatus napi_get_new_target(NAPIEnv env, NAPICallbackInfo callbackInfo, + NAPIValue *result) { + CHECK_ARG(env, Common) + CHECK_ARG(callbackInfo, Common) + CHECK_ARG(result, Common) - *result = (NAPIValue)callbackInfo->newTarget; + *result = (NAPIValue)callbackInfo->newTarget; - return NAPICommonOK; + return NAPICommonOK; } // Constructor -typedef struct -{ - // ExternalInfo - FunctionInfo functionInfo; - // ConstructorInfo - JSClassRef classRef; +typedef struct { + // ExternalInfo + FunctionInfo functionInfo; + // ConstructorInfo + JSClassRef classRef; } ConstructorInfo; -static void constructorFinalize(JSObjectRef object) -{ - ConstructorInfo *info = JSObjectGetPrivate(object); - if (info && info->classRef) - { - // JSClassRelease 不能传递 NULL - JSClassRelease(info->classRef); - } - free(info); +static void constructorFinalize(JSObjectRef object) { + ConstructorInfo *info = JSObjectGetPrivate(object); + if (info && info->classRef) { + // JSClassRelease 不能传递 NULL + JSClassRelease(info->classRef); + } + free(info); } -static void externalFinalize(JSObjectRef object) -{ - ExternalInfo *info = JSObjectGetPrivate(object); - if (info && info->finalizeCallback) - { - info->finalizeCallback(info->data, info->finalizeHint); - } - free(info); +static void externalFinalize(JSObjectRef object) { + ExternalInfo *info = JSObjectGetPrivate(object); + if (info && info->finalizeCallback) { + info->finalizeCallback(info->data, info->finalizeHint); + } + free(info); } static const char *const CONSTRUCTOR_STRING = "__constructor__"; -static JSObjectRef callAsConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, - const JSValueRef arguments[], JSValueRef *exception) -{ - // constructor 为当初定义的 JSObjectRef,而不是子类的构造函数 - JSStringRef keyStringRef = JSStringCreateWithUTF8CString(CONSTRUCTOR_STRING); - JSValueRef prototype = JSObjectGetProperty(ctx, constructor, keyStringRef, exception); - JSStringRelease(keyStringRef); - if (*exception || !prototype) - { - return NULL; - } - if (!JSValueIsObject(ctx, prototype)) - { - // 正常不应当出现 - assert(false); - - return NULL; - } - JSObjectRef prototypeObjectRef = JSValueToObject(ctx, prototype, exception); - if (*exception || !prototypeObjectRef) - { - // 正常不应当出现 - assert(false); - - return NULL; - } - ConstructorInfo *constructorInfo = JSObjectGetPrivate(prototypeObjectRef); - if (!constructorInfo || !constructorInfo->functionInfo.baseInfo.env || !constructorInfo->functionInfo.callback) - { - // 正常不应当出现 - assert(false); - - return NULL; - } - // constructorInfo->classRef 不存在也没有影响 - // 默认 instance.[[prototype]] 为 CallbackObject,JSObjectGetPrivate 不是 - // NULL,所以需要创建 External 插入原型链 - JSObjectRef instance = JSObjectMake(ctx, constructorInfo->classRef, NULL); - if (!instance) - { - // 正常不应当出现 - assert(false); - - return NULL; - } - - struct OpaqueNAPICallbackInfo callbackInfo = {NULL, NULL, NULL, NULL, 0}; - callbackInfo.newTarget = constructor; - callbackInfo.thisArg = instance; - callbackInfo.argc = argumentCount; - callbackInfo.argv = arguments; - callbackInfo.data = constructorInfo->functionInfo.baseInfo.data; - - JSValueRef returnValue = - (JSValueRef)constructorInfo->functionInfo.callback(constructorInfo->functionInfo.baseInfo.env, &callbackInfo); - if (constructorInfo->functionInfo.baseInfo.env->lastException) - { - *exception = constructorInfo->functionInfo.baseInfo.env->lastException; - constructorInfo->functionInfo.baseInfo.env->lastException = NULL; - - return NULL; - } - - if (!returnValue || !JSValueIsObject(ctx, returnValue)) - { - return instance; - } - JSObjectRef objectRef = JSValueToObject(ctx, returnValue, exception); - if (*exception) - { - // 正常不应当出现 - assert(false); - - return NULL; - } - - return objectRef; +static JSObjectRef callAsConstructor(JSContextRef ctx, JSObjectRef constructor, + size_t argumentCount, + const JSValueRef arguments[], + JSValueRef *exception) { + // constructor 为当初定义的 JSObjectRef,而不是子类的构造函数 + JSStringRef keyStringRef = JSStringCreateWithUTF8CString(CONSTRUCTOR_STRING); + JSValueRef prototype = + JSObjectGetProperty(ctx, constructor, keyStringRef, exception); + JSStringRelease(keyStringRef); + if (*exception || !prototype) { + return NULL; + } + if (!JSValueIsObject(ctx, prototype)) { + // 正常不应当出现 + assert(false); + + return NULL; + } + JSObjectRef prototypeObjectRef = JSValueToObject(ctx, prototype, exception); + if (*exception || !prototypeObjectRef) { + // 正常不应当出现 + assert(false); + + return NULL; + } + ConstructorInfo *constructorInfo = JSObjectGetPrivate(prototypeObjectRef); + if (!constructorInfo || !constructorInfo->functionInfo.baseInfo.env || + !constructorInfo->functionInfo.callback) { + // 正常不应当出现 + assert(false); + + return NULL; + } + // constructorInfo->classRef 不存在也没有影响 + // 默认 instance.[[prototype]] 为 CallbackObject,JSObjectGetPrivate 不是 + // NULL,所以需要创建 External 插入原型链 + JSObjectRef instance = JSObjectMake(ctx, constructorInfo->classRef, NULL); + if (!instance) { + // 正常不应当出现 + assert(false); + + return NULL; + } + + struct OpaqueNAPICallbackInfo callbackInfo = {NULL, NULL, NULL, NULL, 0}; + callbackInfo.newTarget = constructor; + callbackInfo.thisArg = instance; + callbackInfo.argc = argumentCount; + callbackInfo.argv = arguments; + callbackInfo.data = constructorInfo->functionInfo.baseInfo.data; + + JSValueRef returnValue = (JSValueRef)constructorInfo->functionInfo.callback( + constructorInfo->functionInfo.baseInfo.env, &callbackInfo); + if (constructorInfo->functionInfo.baseInfo.env->lastException) { + *exception = constructorInfo->functionInfo.baseInfo.env->lastException; + constructorInfo->functionInfo.baseInfo.env->lastException = NULL; + + return NULL; + } + + if (!returnValue || !JSValueIsObject(ctx, returnValue)) { + return instance; + } + JSObjectRef objectRef = JSValueToObject(ctx, returnValue, exception); + if (*exception) { + // 正常不应当出现 + assert(false); + + return NULL; + } + + return objectRef; } // 没有 .name 和 .prototype.constructor -NAPIExceptionStatus NAPIDefineClass(NAPIEnv env, const char *utf8name, NAPICallback constructor, void *data, - NAPIValue *result) -{ - CHECK_JSC(env) - CHECK_ARG(constructor, Exception) - CHECK_ARG(result, Exception) - - ConstructorInfo *constructorInfo = malloc(sizeof(ConstructorInfo)); - RETURN_STATUS_IF_FALSE(constructorInfo, NAPIExceptionMemoryError) - constructorInfo->functionInfo.baseInfo.env = env; - constructorInfo->functionInfo.baseInfo.data = data; - constructorInfo->functionInfo.callback = constructor; - // JavaScriptCore Function 特殊点 - // 1. Function.prototype 不存在 - - JSClassDefinition classDefinition = kJSClassDefinitionEmpty; - // 提供 className 可以让 instance 显示类名 - // 不能使用 kJSClassAttributeNoAutomaticPrototype,因为所有 instance - // 应当共享 Constructor.prototype - classDefinition.className = utf8name; - constructorInfo->classRef = JSClassCreate(&classDefinition); - if (!constructorInfo->classRef) - { - free(constructorInfo); - - return NAPIExceptionMemoryError; - } - classDefinition = kJSClassDefinitionEmpty; - // 使用 Object.prototype 作为 instance.[[prototype]] - classDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; - classDefinition.className = NULL; - // 最重要的是提供 finalize - classDefinition.finalize = constructorFinalize; - JSClassRef classRef = JSClassCreate(&classDefinition); - if (!classRef) - { - JSClassRelease(constructorInfo->classRef); - free(constructorInfo); - - return NAPIExceptionMemoryError; - } - JSObjectRef prototype = JSObjectMake(env->context, classRef, constructorInfo); - JSClassRelease(classRef); - if (!prototype) - { - JSClassRelease(constructorInfo->classRef); - free(constructorInfo); - - return NAPIExceptionMemoryError; - } - JSObjectRef function = JSObjectMakeConstructor(env->context, constructorInfo->classRef, callAsConstructor); - RETURN_STATUS_IF_FALSE(function, NAPIExceptionMemoryError) - JSStringRef stringRef = JSStringCreateWithUTF8CString(CONSTRUCTOR_STRING); - RETURN_STATUS_IF_FALSE(stringRef, NAPIExceptionMemoryError) - JSObjectSetProperty(env->context, function, stringRef, prototype, - kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete, - &env->lastException); - CHECK_JSC(env) - *result = (NAPIValue)function; - - return NAPIExceptionOK; +NAPIExceptionStatus NAPIDefineClass(NAPIEnv env, const char *utf8name, + NAPICallback constructor, void *data, + NAPIValue *result) { + CHECK_JSC(env) + CHECK_ARG(constructor, Exception) + CHECK_ARG(result, Exception) + + ConstructorInfo *constructorInfo = malloc(sizeof(ConstructorInfo)); + RETURN_STATUS_IF_FALSE(constructorInfo, NAPIExceptionMemoryError) + constructorInfo->functionInfo.baseInfo.env = env; + constructorInfo->functionInfo.baseInfo.data = data; + constructorInfo->functionInfo.callback = constructor; + // JavaScriptCore Function 特殊点 + // 1. Function.prototype 不存在 + + JSClassDefinition classDefinition = kJSClassDefinitionEmpty; + // 提供 className 可以让 instance 显示类名 + // 不能使用 kJSClassAttributeNoAutomaticPrototype,因为所有 instance + // 应当共享 Constructor.prototype + classDefinition.className = utf8name; + constructorInfo->classRef = JSClassCreate(&classDefinition); + if (!constructorInfo->classRef) { + free(constructorInfo); + + return NAPIExceptionMemoryError; + } + classDefinition = kJSClassDefinitionEmpty; + // 使用 Object.prototype 作为 instance.[[prototype]] + classDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; + classDefinition.className = NULL; + // 最重要的是提供 finalize + classDefinition.finalize = constructorFinalize; + JSClassRef classRef = JSClassCreate(&classDefinition); + if (!classRef) { + JSClassRelease(constructorInfo->classRef); + free(constructorInfo); + + return NAPIExceptionMemoryError; + } + JSObjectRef prototype = JSObjectMake(env->context, classRef, constructorInfo); + JSClassRelease(classRef); + if (!prototype) { + JSClassRelease(constructorInfo->classRef); + free(constructorInfo); + + return NAPIExceptionMemoryError; + } + JSObjectRef function = JSObjectMakeConstructor( + env->context, constructorInfo->classRef, callAsConstructor); + RETURN_STATUS_IF_FALSE(function, NAPIExceptionMemoryError) + JSStringRef stringRef = JSStringCreateWithUTF8CString(CONSTRUCTOR_STRING); + RETURN_STATUS_IF_FALSE(stringRef, NAPIExceptionMemoryError) + JSObjectSetProperty(env->context, function, stringRef, prototype, + kJSPropertyAttributeReadOnly | + kJSPropertyAttributeDontEnum | + kJSPropertyAttributeDontDelete, + &env->lastException); + CHECK_JSC(env) + *result = (NAPIValue)function; + + return NAPIExceptionOK; } -NAPIExceptionStatus napi_create_external(NAPIEnv env, void *data, NAPIFinalize finalizeCB, void *finalizeHint, - NAPIValue *result) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(result, Exception) - - ExternalInfo *externalInfo = malloc(sizeof(ExternalInfo)); - RETURN_STATUS_IF_FALSE(externalInfo, NAPIExceptionMemoryError) - externalInfo->data = data; - externalInfo->finalizeCallback = finalizeCB; - externalInfo->finalizeHint = finalizeHint; - JSClassDefinition classDefinition = kJSClassDefinitionEmpty; - classDefinition.className = "External"; - classDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; - classDefinition.finalize = externalFinalize; - JSClassRef classRef = JSClassCreate(&classDefinition); - if (!classRef) - { - free(externalInfo); - - return NAPIExceptionMemoryError; - } - JSObjectRef objectRef = JSObjectMake(env->context, classRef, externalInfo); - JSClassRelease(classRef); - if (!objectRef) - { - free(externalInfo); - - return NAPIExceptionMemoryError; - } - *result = (NAPIValue)objectRef; - - return NAPIExceptionOK; +NAPIExceptionStatus napi_create_external(NAPIEnv env, void *data, + NAPIFinalize finalizeCB, + void *finalizeHint, + NAPIValue *result) { + CHECK_ARG(env, Exception) + CHECK_ARG(result, Exception) + + ExternalInfo *externalInfo = malloc(sizeof(ExternalInfo)); + RETURN_STATUS_IF_FALSE(externalInfo, NAPIExceptionMemoryError) + externalInfo->data = data; + externalInfo->finalizeCallback = finalizeCB; + externalInfo->finalizeHint = finalizeHint; + JSClassDefinition classDefinition = kJSClassDefinitionEmpty; + classDefinition.className = "External"; + classDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; + classDefinition.finalize = externalFinalize; + JSClassRef classRef = JSClassCreate(&classDefinition); + if (!classRef) { + free(externalInfo); + + return NAPIExceptionMemoryError; + } + JSObjectRef objectRef = JSObjectMake(env->context, classRef, externalInfo); + JSClassRelease(classRef); + if (!objectRef) { + free(externalInfo); + + return NAPIExceptionMemoryError; + } + *result = (NAPIValue)objectRef; + + return NAPIExceptionOK; } -NAPIErrorStatus napi_get_value_external(NAPIEnv env, NAPIValue value, void **result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(value, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_get_value_external(NAPIEnv env, NAPIValue value, + void **result) { + CHECK_ARG(env, Error) + CHECK_ARG(value, Error) + CHECK_ARG(result, Error) - RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)value), NAPIErrorExternalExpected) - JSValueRef exception = NULL; - JSObjectRef objectRef = JSValueToObject(env->context, (JSValueRef)value, &exception); - RETURN_STATUS_IF_FALSE(!exception && objectRef, NAPIErrorExternalExpected) + RETURN_STATUS_IF_FALSE(JSValueIsObject(env->context, (JSValueRef)value), + NAPIErrorExternalExpected) + JSValueRef exception = NULL; + JSObjectRef objectRef = + JSValueToObject(env->context, (JSValueRef)value, &exception); + RETURN_STATUS_IF_FALSE(!exception && objectRef, NAPIErrorExternalExpected) - ExternalInfo *info = JSObjectGetPrivate(objectRef); - *result = info ? info->data : NULL; + ExternalInfo *info = JSObjectGetPrivate(objectRef); + *result = info ? info->data : NULL; - return NAPIErrorOK; + return NAPIErrorOK; } static const char *const REFERENCE_STRING = "__reference__"; -static void referenceFinalize(void *finalizeData, void *finalizeHint) -{ - if (!finalizeData) - { - assert(false); - - return; - } - struct ReferenceInfo *referenceInfo = finalizeData; - if (!referenceInfo->isEnvFreed) - { - NAPIRef reference; - LIST_FOREACH(reference, &referenceInfo->referenceList, node) - { - assert(!reference->count); - reference->value = JSValueMakeUndefined(((NAPIEnv)finalizeHint)->context); - LIST_REMOVE(reference, node); - LIST_INSERT_HEAD(&((NAPIEnv)finalizeHint)->valueList, reference, node); - } - LIST_REMOVE(referenceInfo, node); - } - free(referenceInfo); +static void referenceFinalize(void *finalizeData, void *finalizeHint) { + if (!finalizeData) { + assert(false); + + return; + } + struct ReferenceInfo *referenceInfo = finalizeData; + if (!referenceInfo->isEnvFreed) { + NAPIRef reference; + LIST_FOREACH(reference, &referenceInfo->referenceList, node) { + assert(!reference->count); + reference->value = JSValueMakeUndefined(((NAPIEnv)finalizeHint)->context); + LIST_REMOVE(reference, node); + LIST_INSERT_HEAD(&((NAPIEnv)finalizeHint)->valueList, reference, node); + } + LIST_REMOVE(referenceInfo, node); + } + free(referenceInfo); } -static NAPIExceptionStatus setWeak(NAPIEnv env, NAPIValue value, NAPIRef ref) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(value, Exception) - CHECK_ARG(ref, Exception) - - NAPIValue stringValue; - CHECK_NAPI(napi_create_string_utf8(env, REFERENCE_STRING, &stringValue), Exception, Exception) - NAPIValue referenceValue; - CHECK_NAPI(napi_get_property(env, value, stringValue, &referenceValue), Exception, Exception) - NAPIValueType valueType; - CHECK_NAPI(napi_typeof(env, referenceValue, &valueType), Common, Exception) - RETURN_STATUS_IF_FALSE(valueType == NAPIUndefined || valueType == NAPIExternal, NAPIExceptionGenericFailure) - struct ReferenceInfo *referenceInfo; - if (valueType == NAPIUndefined) - { - referenceInfo = malloc(sizeof(struct ReferenceInfo)); - referenceInfo->isEnvFreed = false; - RETURN_STATUS_IF_FALSE(referenceInfo, NAPIExceptionMemoryError) - LIST_INIT(&referenceInfo->referenceList); - { - NAPIExceptionStatus status = - napi_create_external(env, referenceInfo, referenceFinalize, env, &referenceValue); - if (status != NAPIExceptionOK) - { - free(referenceInfo); - - return status; - } - } - CHECK_NAPI(napi_set_property(env, value, stringValue, referenceValue), Exception, Exception) - LIST_INSERT_HEAD(&env->referenceList, referenceInfo, node); +static NAPIExceptionStatus setWeak(NAPIEnv env, NAPIValue value, NAPIRef ref) { + CHECK_ARG(env, Exception) + CHECK_ARG(value, Exception) + CHECK_ARG(ref, Exception) + + NAPIValue stringValue; + CHECK_NAPI(napi_create_string_utf8(env, REFERENCE_STRING, &stringValue), + Exception, Exception) + NAPIValue referenceValue; + CHECK_NAPI(napi_get_property(env, value, stringValue, &referenceValue), + Exception, Exception) + NAPIValueType valueType; + CHECK_NAPI(napi_typeof(env, referenceValue, &valueType), Common, Exception) + RETURN_STATUS_IF_FALSE( + valueType == NAPIUndefined || valueType == NAPIExternal, + NAPIExceptionGenericFailure) + struct ReferenceInfo *referenceInfo; + if (valueType == NAPIUndefined) { + referenceInfo = malloc(sizeof(struct ReferenceInfo)); + referenceInfo->isEnvFreed = false; + RETURN_STATUS_IF_FALSE(referenceInfo, NAPIExceptionMemoryError) + LIST_INIT(&referenceInfo->referenceList); + { + NAPIExceptionStatus status = napi_create_external( + env, referenceInfo, referenceFinalize, env, &referenceValue); + if (status != NAPIExceptionOK) { + free(referenceInfo); + + return status; + } } - else - { - CHECK_NAPI(napi_get_value_external(env, referenceValue, (void **)&referenceInfo), Error, Exception) - if (!referenceInfo) - { - assert(false); + CHECK_NAPI(napi_set_property(env, value, stringValue, referenceValue), + Exception, Exception) + LIST_INSERT_HEAD(&env->referenceList, referenceInfo, node); + } else { + CHECK_NAPI( + napi_get_value_external(env, referenceValue, (void **)&referenceInfo), + Error, Exception) + if (!referenceInfo) { + assert(false); - return NAPIExceptionGenericFailure; - } + return NAPIExceptionGenericFailure; } - LIST_INSERT_HEAD(&referenceInfo->referenceList, ref, node); + } + LIST_INSERT_HEAD(&referenceInfo->referenceList, ref, node); - return NAPIExceptionOK; + return NAPIExceptionOK; } -NAPIExceptionStatus napi_create_reference(NAPIEnv env, NAPIValue value, uint32_t initialRefCount, NAPIRef *result) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(value, Exception) - CHECK_ARG(result, Exception) +NAPIExceptionStatus napi_create_reference(NAPIEnv env, NAPIValue value, + uint32_t initialRefCount, + NAPIRef *result) { + CHECK_ARG(env, Exception) + CHECK_ARG(value, Exception) + CHECK_ARG(result, Exception) - *result = malloc(sizeof(struct OpaqueNAPIRef)); - RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) + *result = malloc(sizeof(struct OpaqueNAPIRef)); + RETURN_STATUS_IF_FALSE(*result, NAPIExceptionMemoryError) - // 标量 && 弱引用 - if (!JSValueIsObject(env->context, (JSValueRef)value) && !initialRefCount) - { - (*result)->count = 0; - (*result)->value = JSValueMakeUndefined(env->context); - LIST_INSERT_HEAD(&env->valueList, *result, node); - - return NAPIExceptionOK; - } - // 对象 || 强引用 - (*result)->value = (JSValueRef)value; - (*result)->count = initialRefCount; - // 强引用 - if (initialRefCount) - { - JSValueProtect(env->context, (JSValueRef)value); - LIST_INSERT_HEAD(&env->strongRefList, *result, node); - - return NAPIExceptionOK; - } - // 对象 && 弱引用 - // setWeak - NAPIExceptionStatus status = setWeak(env, value, *result); - if (status != NAPIExceptionOK) - { - free(*result); - - return status; - } + // 标量 && 弱引用 + if (!JSValueIsObject(env->context, (JSValueRef)value) && !initialRefCount) { + (*result)->count = 0; + (*result)->value = JSValueMakeUndefined(env->context); + LIST_INSERT_HEAD(&env->valueList, *result, node); return NAPIExceptionOK; -} + } + // 对象 || 强引用 + (*result)->value = (JSValueRef)value; + (*result)->count = initialRefCount; + // 强引用 + if (initialRefCount) { + JSValueProtect(env->context, (JSValueRef)value); + LIST_INSERT_HEAD(&env->strongRefList, *result, node); -static NAPIExceptionStatus clearWeak(NAPIEnv env, NAPIRef ref) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(ref, Exception) - - NAPIValue stringValue; - CHECK_NAPI(napi_create_string_utf8(env, REFERENCE_STRING, &stringValue), Exception, Exception) - NAPIValue externalValue; - CHECK_NAPI(napi_get_property(env, (NAPIValue)ref->value, stringValue, &externalValue), Exception, Exception) - struct ReferenceInfo *referenceInfo; - CHECK_NAPI(napi_get_value_external(env, externalValue, (void **)&referenceInfo), Error, Exception) - if (!referenceInfo) - { - assert(false); + return NAPIExceptionOK; + } + // 对象 && 弱引用 + // setWeak + NAPIExceptionStatus status = setWeak(env, value, *result); + if (status != NAPIExceptionOK) { + free(*result); - return NAPIExceptionGenericFailure; - } - if (!LIST_EMPTY(&referenceInfo->referenceList) && LIST_FIRST(&referenceInfo->referenceList) == ref && - !LIST_NEXT(ref, node)) - { - bool deleteResult; - CHECK_NAPI(napi_delete_property(env, (NAPIValue)ref->value, stringValue, &deleteResult), Exception, Exception) - RETURN_STATUS_IF_FALSE(deleteResult, NAPIExceptionGenericFailure) - } - LIST_REMOVE(ref, node); + return status; + } - return NAPIExceptionOK; + return NAPIExceptionOK; } -NAPIExceptionStatus napi_delete_reference(NAPIEnv env, NAPIRef ref) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(ref, Exception) - - // 标量 && 弱引用(被 GC 也会这样) - if (!JSValueIsObject(env->context, ref->value) && !ref->count) - { - LIST_REMOVE(ref, node); - free(ref); +static NAPIExceptionStatus clearWeak(NAPIEnv env, NAPIRef ref) { + CHECK_ARG(env, Exception) + CHECK_ARG(ref, Exception) + + NAPIValue stringValue; + CHECK_NAPI(napi_create_string_utf8(env, REFERENCE_STRING, &stringValue), + Exception, Exception) + NAPIValue externalValue; + CHECK_NAPI(napi_get_property(env, (NAPIValue)ref->value, stringValue, + &externalValue), + Exception, Exception) + struct ReferenceInfo *referenceInfo; + CHECK_NAPI( + napi_get_value_external(env, externalValue, (void **)&referenceInfo), + Error, Exception) + if (!referenceInfo) { + assert(false); + + return NAPIExceptionGenericFailure; + } + if (!LIST_EMPTY(&referenceInfo->referenceList) && + LIST_FIRST(&referenceInfo->referenceList) == ref && + !LIST_NEXT(ref, node)) { + bool deleteResult; + CHECK_NAPI(napi_delete_property(env, (NAPIValue)ref->value, stringValue, + &deleteResult), + Exception, Exception) + RETURN_STATUS_IF_FALSE(deleteResult, NAPIExceptionGenericFailure) + } + LIST_REMOVE(ref, node); + + return NAPIExceptionOK; +} - return NAPIExceptionOK; - } - // 对象 || 强引用 - if (ref->count) - { - LIST_REMOVE(ref, node); - JSValueUnprotect(env->context, ref->value); - free(ref); +NAPIExceptionStatus napi_delete_reference(NAPIEnv env, NAPIRef ref) { + CHECK_ARG(env, Exception) + CHECK_ARG(ref, Exception) - return NAPIExceptionOK; - } - // 对象 && 弱引用 - CHECK_NAPI(clearWeak(env, ref), Exception, Exception) + // 标量 && 弱引用(被 GC 也会这样) + if (!JSValueIsObject(env->context, ref->value) && !ref->count) { + LIST_REMOVE(ref, node); free(ref); return NAPIExceptionOK; -} - -NAPIExceptionStatus napi_reference_ref(NAPIEnv env, NAPIRef ref, uint32_t *result) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(ref, Exception) - - if (!ref->count) - { - if (JSValueIsObject(env->context, ref->value)) - { - CHECK_NAPI(clearWeak(env, ref), Exception, Exception) - } - else - { - LIST_REMOVE(ref, node); - } - LIST_INSERT_HEAD(&env->strongRefList, ref, node); - JSValueProtect(env->context, ref->value); - } - uint8_t count = ++ref->count; - if (result) - { - *result = count; - } + } + // 对象 || 强引用 + if (ref->count) { + LIST_REMOVE(ref, node); + JSValueUnprotect(env->context, ref->value); + free(ref); return NAPIExceptionOK; + } + // 对象 && 弱引用 + CHECK_NAPI(clearWeak(env, ref), Exception, Exception) + free(ref); + + return NAPIExceptionOK; } -NAPIExceptionStatus napi_reference_unref(NAPIEnv env, NAPIRef ref, uint32_t *result) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(ref, Exception) +NAPIExceptionStatus napi_reference_ref(NAPIEnv env, NAPIRef ref, + uint32_t *result) { + CHECK_ARG(env, Exception) + CHECK_ARG(ref, Exception) + + if (!ref->count) { + if (JSValueIsObject(env->context, ref->value)) { + CHECK_NAPI(clearWeak(env, ref), Exception, Exception) + } else { + LIST_REMOVE(ref, node); + } + LIST_INSERT_HEAD(&env->strongRefList, ref, node); + JSValueProtect(env->context, ref->value); + } + uint8_t count = ++ref->count; + if (result) { + *result = count; + } + + return NAPIExceptionOK; +} - RETURN_STATUS_IF_FALSE(ref->count, NAPIExceptionGenericFailure) +NAPIExceptionStatus napi_reference_unref(NAPIEnv env, NAPIRef ref, + uint32_t *result) { + CHECK_ARG(env, Exception) + CHECK_ARG(ref, Exception) - if (ref->count == 1) - { - LIST_REMOVE(ref, node); - if (JSValueIsObject(env->context, ref->value)) - { - CHECK_NAPI(setWeak(env, (NAPIValue)ref->value, ref), Exception, Exception) - JSValueUnprotect(env->context, ref->value); - } - else - { - LIST_INSERT_HEAD(&env->valueList, ref, node); - JSValueUnprotect(env->context, ref->value); - ref->value = JSValueMakeUndefined(env->context); - } - } - uint8_t count = --ref->count; - if (result) - { - *result = count; - } + RETURN_STATUS_IF_FALSE(ref->count, NAPIExceptionGenericFailure) - return NAPIExceptionOK; + if (ref->count == 1) { + LIST_REMOVE(ref, node); + if (JSValueIsObject(env->context, ref->value)) { + CHECK_NAPI(setWeak(env, (NAPIValue)ref->value, ref), Exception, Exception) + JSValueUnprotect(env->context, ref->value); + } else { + LIST_INSERT_HEAD(&env->valueList, ref, node); + JSValueUnprotect(env->context, ref->value); + ref->value = JSValueMakeUndefined(env->context); + } + } + uint8_t count = --ref->count; + if (result) { + *result = count; + } + + return NAPIExceptionOK; } -NAPIErrorStatus napi_get_reference_value(NAPIEnv env, NAPIRef ref, NAPIValue *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(ref, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_get_reference_value(NAPIEnv env, NAPIRef ref, + NAPIValue *result) { + CHECK_ARG(env, Error) + CHECK_ARG(ref, Error) + CHECK_ARG(result, Error) - if (!ref->count && JSValueIsUndefined(env->context, ref->value)) - { - *result = NULL; - } - else - { - *result = (NAPIValue)ref->value; - } + if (!ref->count && JSValueIsUndefined(env->context, ref->value)) { + *result = NULL; + } else { + *result = (NAPIValue)ref->value; + } - return NAPIErrorOK; + return NAPIErrorOK; } -NAPIErrorStatus napi_open_handle_scope(NAPIEnv env, NAPIHandleScope *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_open_handle_scope(NAPIEnv env, NAPIHandleScope *result) { + CHECK_ARG(env, Error) + CHECK_ARG(result, Error) - *result = (NAPIHandleScope)1; + *result = (NAPIHandleScope)1; - return NAPIErrorOK; + return NAPIErrorOK; } -NAPICommonStatus napi_close_handle_scope(__attribute__((unused)) NAPIEnv env, - __attribute__((unused)) NAPIHandleScope scope) -{ - return NAPICommonOK; +NAPIErrorStatus napi_close_handle_scope(__attribute__((unused)) NAPIEnv env, + __attribute__((unused)) + NAPIHandleScope scope) { + return NAPIErrorOK; } -struct OpaqueNAPIEscapableHandleScope -{ - bool escapeCalled; +struct OpaqueNAPIEscapableHandleScope { + bool escapeCalled; }; -NAPIErrorStatus napi_open_escapable_handle_scope(NAPIEnv env, NAPIEscapableHandleScope *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_open_escapable_handle_scope( + NAPIEnv env, NAPIEscapableHandleScope *result) { + CHECK_ARG(env, Error) + CHECK_ARG(result, Error) - *result = malloc(sizeof(struct OpaqueNAPIEscapableHandleScope)); - RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) - (*result)->escapeCalled = false; + *result = malloc(sizeof(struct OpaqueNAPIEscapableHandleScope)); + RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) + (*result)->escapeCalled = false; - return NAPIErrorOK; + return NAPIErrorOK; } -NAPICommonStatus napi_close_escapable_handle_scope(__attribute__((unused)) NAPIEnv env, NAPIEscapableHandleScope scope) -{ - CHECK_ARG(scope, Common) +NAPIErrorStatus napi_close_escapable_handle_scope( + __attribute__((unused)) NAPIEnv env, NAPIEscapableHandleScope scope) { + CHECK_ARG(scope, Error) - free(scope); + free(scope); - return NAPICommonOK; + return NAPIErrorOK; } -NAPIErrorStatus napi_escape_handle(NAPIEnv env, NAPIEscapableHandleScope scope, NAPIValue escapee, NAPIValue *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(scope, Error) - CHECK_ARG(escapee, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_escape_handle(NAPIEnv env, NAPIEscapableHandleScope scope, + NAPIValue escapee, NAPIValue *result) { + CHECK_ARG(env, Error) + CHECK_ARG(scope, Error) + CHECK_ARG(escapee, Error) + CHECK_ARG(result, Error) - RETURN_STATUS_IF_FALSE(!scope->escapeCalled, NAPIErrorEscapeCalledTwice) - scope->escapeCalled = true; - *result = escapee; + RETURN_STATUS_IF_FALSE(!scope->escapeCalled, NAPIErrorEscapeCalledTwice) + scope->escapeCalled = true; + *result = escapee; - return NAPIErrorOK; + return NAPIErrorOK; } -NAPIExceptionStatus napi_throw(NAPIEnv env, NAPIValue error) -{ - CHECK_ARG(env, Exception) - CHECK_ARG(error, Exception) +NAPIExceptionStatus napi_throw(NAPIEnv env, NAPIValue error) { + CHECK_ARG(env, Exception) + CHECK_ARG(error, Exception) - env->lastException = (JSValueRef)error; + env->lastException = (JSValueRef)error; - return NAPIExceptionOK; + return NAPIExceptionOK; } -NAPIErrorStatus napi_get_and_clear_last_exception(NAPIEnv env, NAPIValue *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(result, Error) +NAPIErrorStatus napi_get_and_clear_last_exception(NAPIEnv env, + NAPIValue *result) { + CHECK_ARG(env, Error) + CHECK_ARG(result, Error) - if (!env->lastException) - { - return (NAPIErrorStatus)napi_get_undefined(env, result); - } - else - { - *result = (NAPIValue)env->lastException; - env->lastException = NULL; - } + if (!env->lastException) { + return (NAPIErrorStatus)napi_get_undefined(env, result); + } else { + *result = (NAPIValue)env->lastException; + env->lastException = NULL; + } - return NAPIErrorOK; + return NAPIErrorOK; } -NAPICommonStatus NAPIClearLastException(NAPIEnv env) -{ - CHECK_ARG(env, Common) +NAPICommonStatus NAPIClearLastException(NAPIEnv env) { + CHECK_ARG(env, Common) - env->lastException = NULL; + env->lastException = NULL; - return NAPICommonOK; + return NAPICommonOK; } -NAPIExceptionStatus NAPIRunScript(NAPIEnv env, const char *utf8Script, const char *utf8SourceUrl, NAPIValue *result) -{ - CHECK_JSC(env) - - JSStringRef scriptStringRef = JSStringCreateWithUTF8CString(utf8Script); - JSStringRef sourceUrl = NULL; - if (utf8SourceUrl) - { - sourceUrl = JSStringCreateWithUTF8CString(utf8SourceUrl); - } - // JSEvaluateScript 要求 scriptStringRef 必定存在 - JSValueRef valueRef = JSEvaluateScript(env->context, scriptStringRef, NULL, sourceUrl, 1, &env->lastException); - JSStringRelease(scriptStringRef); - if (utf8SourceUrl) - { - JSStringRelease(sourceUrl); - } - CHECK_JSC(env) - if (result) - { - *result = (NAPIValue)valueRef; - } - - return NAPIExceptionOK; +NAPIExceptionStatus NAPIRunScript(NAPIEnv env, const char *utf8Script, + const char *utf8SourceUrl, + NAPIValue *result) { + CHECK_JSC(env) + + JSStringRef scriptStringRef = JSStringCreateWithUTF8CString(utf8Script); + JSStringRef sourceUrl = NULL; + if (utf8SourceUrl) { + sourceUrl = JSStringCreateWithUTF8CString(utf8SourceUrl); + } + // JSEvaluateScript 要求 scriptStringRef 必定存在 + JSValueRef valueRef = JSEvaluateScript(env->context, scriptStringRef, NULL, + sourceUrl, 1, &env->lastException); + JSStringRelease(scriptStringRef); + if (utf8SourceUrl) { + JSStringRelease(sourceUrl); + } + CHECK_JSC(env) + if (result) { + *result = (NAPIValue)valueRef; + } + + return NAPIExceptionOK; } // static JSContextGroupRef virtualMachine = NULL; // static uint8_t contextCount = 0; -NAPICommonStatus NAPIEnableDebugger(__attribute__((unused)) NAPIEnv env, - __attribute__((unused)) const char *debuggerTitle, - __attribute__((unused)) bool waitForDebugger) -{ - return NAPICommonOK; +NAPICommonStatus NAPIEnableDebugger( + __attribute__((unused)) NAPIEnv env, + __attribute__((unused)) const char *debuggerTitle, + __attribute__((unused)) bool waitForDebugger) { + return NAPICommonOK; } -NAPICommonStatus NAPIDisableDebugger(__attribute__((unused)) NAPIEnv env) -{ - return NAPICommonOK; +NAPICommonStatus NAPIDisableDebugger(__attribute__((unused)) NAPIEnv env) { + return NAPICommonOK; } -NAPICommonStatus NAPISetMessageQueueThread(__attribute__((unused)) NAPIEnv env, - __attribute__((unused)) MessageQueueThreadWrapper jsQueueWrapper) -{ - return NAPICommonOK; +NAPICommonStatus NAPISetMessageQueueThread( + __attribute__((unused)) NAPIEnv env, + __attribute__((unused)) MessageQueueThreadWrapper jsQueueWrapper) { + return NAPICommonOK; } -NAPIErrorStatus NAPICreateRuntime(NAPIRuntime *runtime) -{ - CHECK_ARG(runtime, Error) +NAPIErrorStatus NAPICreateRuntime(NAPIRuntime *runtime) { + CHECK_ARG(runtime, Error) - *runtime = (NAPIRuntime)JSContextGroupCreate(); - RETURN_STATUS_IF_FALSE(*runtime, NAPIErrorMemoryError); + *runtime = (NAPIRuntime)JSContextGroupCreate(); + RETURN_STATUS_IF_FALSE(*runtime, NAPIErrorMemoryError); - return NAPIErrorOK; + return NAPIErrorOK; } -NAPICommonStatus NAPIFreeRuntime(NAPIRuntime runtime) -{ - CHECK_ARG(runtime, Common) +NAPICommonStatus NAPIFreeRuntime(NAPIRuntime runtime) { + CHECK_ARG(runtime, Common) - JSContextGroupRelease((JSContextGroupRef)runtime); + JSContextGroupRelease((JSContextGroupRef)runtime); - return NAPICommonOK; + return NAPICommonOK; } -NAPIErrorStatus NAPICreateEnv(NAPIEnv *env, NAPIRuntime runtime) -{ - CHECK_ARG(env, Error) +NAPIErrorStatus NAPICreateEnv(NAPIEnv *env, NAPIRuntime runtime) { + CHECK_ARG(env, Error) - *env = malloc(sizeof(struct OpaqueNAPIEnv)); - RETURN_STATUS_IF_FALSE(*env, NAPIErrorMemoryError) + *env = malloc(sizeof(struct OpaqueNAPIEnv)); + RETURN_STATUS_IF_FALSE(*env, NAPIErrorMemoryError) - (*env)->context = JSGlobalContextCreateInGroup((JSContextGroupRef)runtime, NULL); - if (!(*env)->context) - { - free(*env); + (*env)->context = + JSGlobalContextCreateInGroup((JSContextGroupRef)runtime, NULL); + if (!(*env)->context) { + free(*env); - return NAPIErrorMemoryError; - } - (*env)->lastException = NULL; - LIST_INIT(&(*env)->strongRefList); - LIST_INIT(&(*env)->valueList); - LIST_INIT(&(*env)->referenceList); + return NAPIErrorMemoryError; + } + (*env)->lastException = NULL; + LIST_INIT(&(*env)->strongRefList); + LIST_INIT(&(*env)->valueList); + LIST_INIT(&(*env)->referenceList); - return NAPIErrorOK; + return NAPIErrorOK; } -NAPICommonStatus NAPIFreeEnv(NAPIEnv env) -{ - CHECK_ARG(env, Common) +NAPICommonStatus NAPIFreeEnv(NAPIEnv env) { + CHECK_ARG(env, Common) - NAPIRef ref, temp; - LIST_FOREACH_SAFE(ref, &env->strongRefList, node, temp) - { - LIST_REMOVE(ref, node); - JSValueUnprotect(env->context, ref->value); - free(ref); - } - struct ReferenceInfo *referenceInfo, *tempReferenceInfo; - LIST_FOREACH_SAFE(referenceInfo, &env->referenceList, node, tempReferenceInfo) - { - LIST_FOREACH_SAFE(ref, &referenceInfo->referenceList, node, temp) - { - LIST_REMOVE(ref, node); - free(ref); - } - LIST_REMOVE(referenceInfo, node); - referenceInfo->isEnvFreed = true; - } - LIST_FOREACH_SAFE(ref, &env->valueList, node, temp) - { - LIST_REMOVE(ref, node); - free(ref); - } - JSGlobalContextRelease(env->context); - free(env); + NAPIRef ref, temp; + LIST_FOREACH_SAFE(ref, &env->strongRefList, node, temp) { + LIST_REMOVE(ref, node); + JSValueUnprotect(env->context, ref->value); + free(ref); + } + struct ReferenceInfo *referenceInfo, *tempReferenceInfo; + LIST_FOREACH_SAFE(referenceInfo, &env->referenceList, node, + tempReferenceInfo) { + LIST_FOREACH_SAFE(ref, &referenceInfo->referenceList, node, temp) { + LIST_REMOVE(ref, node); + free(ref); + } + LIST_REMOVE(referenceInfo, node); + referenceInfo->isEnvFreed = true; + } + LIST_FOREACH_SAFE(ref, &env->valueList, node, temp) { + LIST_REMOVE(ref, node); + free(ref); + } + JSGlobalContextRelease(env->context); + free(env); - return NAPICommonOK; + return NAPICommonOK; } -NAPIErrorStatus NAPIGetValueStringUTF8(NAPIEnv env, NAPIValue value, const char **result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(value, Error) - CHECK_ARG(result, Error) - - RETURN_STATUS_IF_FALSE(JSValueIsString(env->context, (JSValueRef)value), NAPIErrorStringExpected) - JSValueRef exception = NULL; - JSStringRef stringRef = JSValueToStringCopy(env->context, (JSValueRef)value, &exception); - RETURN_STATUS_IF_FALSE(!exception && stringRef, NAPIErrorStringExpected) - // 不为 0 - size_t length = JSStringGetMaximumUTF8CStringSize(stringRef); - char *string = malloc(sizeof(char) * length); - RETURN_STATUS_IF_FALSE(string, NAPIErrorMemoryError) - if (!JSStringGetUTF8CString(stringRef, string, length)) - { - free(string); - - return NAPIErrorGenericFailure; - } - *result = string; - - return NAPIErrorOK; +NAPIErrorStatus NAPIGetValueStringUTF8(NAPIEnv env, NAPIValue value, + const char **result) { + CHECK_ARG(env, Error) + CHECK_ARG(value, Error) + CHECK_ARG(result, Error) + + RETURN_STATUS_IF_FALSE(JSValueIsString(env->context, (JSValueRef)value), + NAPIErrorStringExpected) + JSValueRef exception = NULL; + JSStringRef stringRef = + JSValueToStringCopy(env->context, (JSValueRef)value, &exception); + RETURN_STATUS_IF_FALSE(!exception && stringRef, NAPIErrorStringExpected) + // 不为 0 + size_t length = JSStringGetMaximumUTF8CStringSize(stringRef); + char *string = malloc(sizeof(char) * length); + RETURN_STATUS_IF_FALSE(string, NAPIErrorMemoryError) + if (!JSStringGetUTF8CString(stringRef, string, length)) { + free(string); + + return NAPIErrorGenericFailure; + } + *result = string; + + return NAPIErrorOK; } -NAPICommonStatus NAPIFreeUTF8String(NAPIEnv env, const char *cString) -{ - CHECK_ARG(env, Common) - CHECK_ARG(cString, Common) +NAPICommonStatus NAPIFreeUTF8String(NAPIEnv env, const char *cString) { + CHECK_ARG(env, Common) + CHECK_ARG(cString, Common) - free((void *)cString); + free((void *)cString); - return NAPICommonOK; + return NAPICommonOK; } -NAPI_EXPORT NAPIExceptionStatus NAPICompileToByteBuffer(__attribute__((unused)) NAPIEnv env, - __attribute__((unused)) const char *script, - __attribute__((unused)) const char *sourceUrl, - __attribute__((unused)) const uint8_t **byteBuffer, - __attribute__((unused)) size_t *bufferSize) -{ - return NAPIExceptionOK; +NAPI_EXPORT NAPIExceptionStatus +NAPICompileToByteBuffer(__attribute__((unused)) NAPIEnv env, + __attribute__((unused)) const char *script, + __attribute__((unused)) const char *sourceUrl, + __attribute__((unused)) const uint8_t **byteBuffer, + __attribute__((unused)) size_t *bufferSize) { + return NAPIExceptionOK; } -NAPI_EXPORT NAPICommonStatus NAPIFreeByteBuffer(__attribute__((unused)) NAPIEnv env, - __attribute__((unused)) const uint8_t *byteBuffer) -{ - return NAPICommonOK; +NAPI_EXPORT NAPICommonStatus NAPIFreeByteBuffer(__attribute__((unused)) + NAPIEnv env, + __attribute__((unused)) + const uint8_t *byteBuffer) { + return NAPICommonOK; } -NAPI_EXPORT NAPIExceptionStatus NAPIRunByteBuffer(__attribute__((unused)) NAPIEnv env, - __attribute__((unused)) const uint8_t *byteBuffer, - __attribute__((unused)) size_t bufferSize, - __attribute__((unused)) NAPIValue *result) -{ - return NAPIExceptionOK; +NAPI_EXPORT NAPIExceptionStatus +NAPIRunByteBuffer(__attribute__((unused)) NAPIEnv env, + __attribute__((unused)) const uint8_t *byteBuffer, + __attribute__((unused)) size_t bufferSize, + __attribute__((unused)) NAPIValue *result) { + return NAPIExceptionOK; } diff --git a/src/js_native_api_qjs.c b/src/js_native_api_qjs.c index 1b8245a..a4924e4 100644 --- a/src/js_native_api_qjs.c +++ b/src/js_native_api_qjs.c @@ -71,7 +71,7 @@ struct Handle struct OpaqueNAPIHandleScope { - LIST_ENTRY(OpaqueNAPIHandleScope) node; // size_t + SLIST_ENTRY(OpaqueNAPIHandleScope) node; // size_t SLIST_HEAD(, Handle) handleList; // size_t }; @@ -101,7 +101,7 @@ struct OpaqueNAPIEnv JSValue referenceSymbolValue; // size_t * 2 NAPIRuntime runtime; // size_t JSContext *context; // size_t - LIST_HEAD(, OpaqueNAPIHandleScope) handleScopeList; // size_t + SLIST_HEAD(, OpaqueNAPIHandleScope) handleScopeList; // size_t LIST_HEAD(, WeakReference) weakReferenceList; // size_t LIST_HEAD(, OpaqueNAPIRef) strongRefList; // size_t LIST_HEAD(, OpaqueNAPIRef) valueList; // size_t @@ -124,11 +124,11 @@ static NAPIErrorStatus addValueToHandleScope(NAPIEnv env, JSValue value, struct CHECK_ARG(env, Error) CHECK_ARG(result, Error) - RETURN_STATUS_IF_FALSE(!LIST_EMPTY(&env->handleScopeList), NAPIErrorHandleScopeEmpty) + RETURN_STATUS_IF_FALSE(!SLIST_EMPTY(&env->handleScopeList), NAPIErrorHandleScopeEmpty) *result = malloc(sizeof(struct Handle)); RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) (*result)->value = value; - NAPIHandleScope handleScope = LIST_FIRST(&env->handleScopeList); + NAPIHandleScope handleScope = SLIST_FIRST(&env->handleScopeList); SLIST_INSERT_HEAD(&handleScope->handleList, *result, node); return NAPIErrorOK; @@ -347,8 +347,8 @@ static JSValue callAsFunction(JSContext *ctx, JSValueConst thisVal, int argc, JS // 除非 handleScope == NULL,但是这种情况不影响后续代码的执行 if (handleScope) { - NAPICommonStatus commonStatus = napi_close_handle_scope(functionInfo->baseInfo.env, handleScope); - if (__builtin_expect(commonStatus != NAPICommonOK, false)) + NAPIErrorStatus errorStatus = napi_close_handle_scope(functionInfo->baseInfo.env, handleScope); + if (__builtin_expect(errorStatus != NAPIErrorOK, false)) { JS_FreeValue(ctx, returnValue); assert(false && NAPI_CLOSE_HANDLE_SCOPE_ERROR); @@ -1303,36 +1303,35 @@ NAPIErrorStatus napi_open_handle_scope(NAPIEnv env, NAPIHandleScope *result) RETURN_STATUS_IF_FALSE(handleScope, NAPIErrorMemoryError) *result = handleScope; SLIST_INIT(&(*result)->handleList); - LIST_INSERT_HEAD(&env->handleScopeList, *result, node); + SLIST_INSERT_HEAD(&env->handleScopeList, *result, node); return NAPIErrorOK; } -NAPICommonStatus napi_close_handle_scope(NAPIEnv env, NAPIHandleScope scope) +NAPIErrorStatus napi_close_handle_scope(NAPIEnv env, NAPIHandleScope scope) { - CHECK_ARG(env, Common) - CHECK_ARG(scope, Common) + CHECK_ARG(env, Error) + CHECK_ARG(scope, Error) - // 先入后出 stack 规则 - assert(LIST_FIRST(&env->handleScopeList) == scope && - "napi_close_handle_scope() or napi_close_escapable_handle_scope() should follow FILO rule."); + RETURN_STATUS_IF_FALSE(SLIST_FIRST(&env->handleScopeList) == scope, + NAPIErrorHandleScopeMismatch) struct Handle *handle, *tempHandle; SLIST_FOREACH_SAFE(handle, &scope->handleList, node, tempHandle) { JS_FreeValue(env->context, handle->value); free(handle); } - // 这里和前面的 assert 要求 env->handleScopeList 必须是 LIST 双向链表 - LIST_REMOVE(scope, node); + SLIST_REMOVE_HEAD(&env->handleScopeList, node); free(scope); - return NAPICommonOK; + return NAPIErrorOK; } struct OpaqueNAPIEscapableHandleScope { struct OpaqueNAPIHandleScope handleScope; + struct Handle *handlePointer; // size_t bool escapeCalled; }; @@ -1343,19 +1342,31 @@ NAPIErrorStatus napi_open_escapable_handle_scope(NAPIEnv env, NAPIEscapableHandl CHECK_ARG(env, Error) CHECK_ARG(result, Error) - // 万一前面的 handleScope 被 close 了,会导致当前 EscapableHandleScope 变成最上层 - // handleScope,这里的判断就没有意义了 - // RETURN_STATUS_IF_FALSE(LIST_FIRST(&env->handleScopeList), NAPIHandleScopeMismatch); + RETURN_STATUS_IF_FALSE(SLIST_FIRST(&env->handleScopeList), NAPIErrorHandleScopeEmpty); + + struct Handle *handlePointer = malloc(sizeof(struct Handle)); + RETURN_STATUS_IF_FALSE(handlePointer, NAPIErrorMemoryError) + handlePointer->value = undefinedValue; + *result = malloc(sizeof(struct OpaqueNAPIEscapableHandleScope)); - RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) + if (!*result) { + free(handlePointer); + + return NAPIErrorMemoryError; + } + + NAPIHandleScope handleScope = SLIST_FIRST(&env->handleScopeList); + SLIST_INSERT_HEAD(&handleScope->handleList, handlePointer, node); + (*result)->escapeCalled = false; + (*result)->handlePointer = handlePointer; SLIST_INIT(&(*result)->handleScope.handleList); - LIST_INSERT_HEAD(&env->handleScopeList, &(*result)->handleScope, node); + SLIST_INSERT_HEAD(&env->handleScopeList, &(*result)->handleScope, node); return NAPIErrorOK; } -NAPICommonStatus napi_close_escapable_handle_scope(NAPIEnv env, NAPIEscapableHandleScope scope) +NAPIErrorStatus napi_close_escapable_handle_scope(NAPIEnv env, NAPIEscapableHandleScope scope) { return napi_close_handle_scope(env, (NAPIHandleScope)scope); } @@ -1371,14 +1382,9 @@ NAPIErrorStatus napi_escape_handle(NAPIEnv env, NAPIEscapableHandleScope scope, RETURN_STATUS_IF_FALSE(!scope->escapeCalled, NAPIErrorEscapeCalledTwice) - NAPIHandleScope handleScope = LIST_NEXT(&scope->handleScope, node); - RETURN_STATUS_IF_FALSE(handleScope, NAPIErrorHandleScopeEmpty) - struct Handle *handle = malloc(sizeof(struct Handle)); - RETURN_STATUS_IF_FALSE(handle, NAPIErrorMemoryError) scope->escapeCalled = true; - handle->value = JS_DupValue(env->context, *((JSValue *)escapee)); - SLIST_INSERT_HEAD(&handleScope->handleList, handle, node); - *result = (NAPIValue)&handle->value; + scope->handlePointer->value = JS_DupValue(env->context, *((JSValue *)escapee)); + *result = (NAPIValue)&scope->handlePointer->value; return NAPIErrorOK; } @@ -1606,9 +1612,9 @@ static JSValue callAsConstructor(JSContext *ctx, JSValueConst newTarget, int arg } if (handleScope) { - NAPICommonStatus commonStatus = + NAPIErrorStatus errorStatus = napi_close_handle_scope(constructorInfo->functionInfo.baseInfo.env, handleScope); - if (__builtin_expect(commonStatus != NAPICommonOK, false)) + if (__builtin_expect(errorStatus != NAPIErrorOK, false)) { JS_FreeValue(ctx, thisValue); assert(false && NAPI_CLOSE_HANDLE_SCOPE_ERROR); @@ -1812,7 +1818,7 @@ NAPIErrorStatus NAPICreateEnv(NAPIEnv *env, NAPIRuntime runtime) } (*env)->context = context; (*env)->isThrowNull = false; - LIST_INIT(&(*env)->handleScopeList); + SLIST_INIT(&(*env)->handleScopeList); LIST_INIT(&(*env)->weakReferenceList); LIST_INIT(&(*env)->valueList); LIST_INIT(&(*env)->strongRefList); @@ -1825,7 +1831,7 @@ NAPICommonStatus NAPIFreeEnv(NAPIEnv env) CHECK_ARG(env, Common) NAPIHandleScope handleScope, tempHandleScope; - LIST_FOREACH_SAFE(handleScope, &env->handleScopeList, node, tempHandleScope) + SLIST_FOREACH_SAFE(handleScope, &env->handleScopeList, node, tempHandleScope) { struct Handle *handle, *tempHandle; SLIST_FOREACH_SAFE(handle, &handleScope->handleList, node, tempHandle) @@ -1833,8 +1839,7 @@ NAPICommonStatus NAPIFreeEnv(NAPIEnv env) JS_FreeValue(env->context, handle->value); free(handle); } - // 这里和前面的 assert 要求 env->handleScopeList 必须是 LIST 双向链表 - LIST_REMOVE(handleScope, node); + SLIST_REMOVE_HEAD(&env->handleScopeList, node); free(handleScope); } NAPIRef ref, temp; @@ -2035,4 +2040,4 @@ exceptionHandlerWithProcess : { } return NAPIExceptionPendingException; -} \ No newline at end of file +} diff --git a/third_party/boost-for-react-native b/third_party/boost-for-react-native deleted file mode 160000 index cf63e08..0000000 --- a/third_party/boost-for-react-native +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cf63e08366739c6f4e0321ee17db9d46ee3a402b diff --git a/third_party/fbjni b/third_party/fbjni new file mode 160000 index 0000000..7e1e1fe --- /dev/null +++ b/third_party/fbjni @@ -0,0 +1 @@ +Subproject commit 7e1e1fe3858c63c251c637ae41a20de425dde96f diff --git a/third_party/fmt b/third_party/fmt new file mode 160000 index 0000000..19bd751 --- /dev/null +++ b/third_party/fmt @@ -0,0 +1 @@ +Subproject commit 19bd751020a1f3c3363b2eb67a039852f139a8d3 diff --git a/third_party/folly b/third_party/folly index dec61fc..4baba28 160000 --- a/third_party/folly +++ b/third_party/folly @@ -1 +1 @@ -Subproject commit dec61fcb0aff39cfe2ee0a9a1df38a38c2942285 +Subproject commit 4baba28200d7446c870e96f3cdbeb492f54625d0 diff --git a/third_party/glog b/third_party/glog new file mode 160000 index 0000000..a6a166d --- /dev/null +++ b/third_party/glog @@ -0,0 +1 @@ +Subproject commit a6a166db069520dbbd653c97c2e5b12e08a8bb26 diff --git a/third_party/glog_patch.diff b/third_party/glog_patch.diff new file mode 100644 index 0000000..b94c03c --- /dev/null +++ b/third_party/glog_patch.diff @@ -0,0 +1,14 @@ +diff --git a/src/logging.cc b/src/logging.cc +index 0b5e6ee..8b1710e 100644 +--- a/src/logging.cc ++++ b/src/logging.cc +@@ -1120,7 +1120,9 @@ void LogFileObject::Write(bool force_flush, + if (file_length_ >= logging::kPageSize) { + // don't evict the most recent page + uint32 len = file_length_ & ~(logging::kPageSize - 1); ++#if !defined(__ANDROID__) || !defined(__ANDROID_API__) || __ANDROID_API__ >= 21 + posix_fadvise(fileno(file_), 0, len, POSIX_FADV_DONTNEED); ++#endif + } + } + #endif diff --git a/third_party/googletest b/third_party/googletest index e2239ee..58d77fa 160000 --- a/third_party/googletest +++ b/third_party/googletest @@ -1 +1 @@ -Subproject commit e2239ee6043f73722e7aa812a459f54a28552929 +Subproject commit 58d77fa8070e8cec2dc1ed015d66b454c8d78850 diff --git a/third_party/hermes b/third_party/hermes index 0bac657..2a6b111 160000 --- a/third_party/hermes +++ b/third_party/hermes @@ -1 +1 @@ -Subproject commit 0bac657c61ac47a3a9537d982921f5f6c9630d41 +Subproject commit 2a6b111ab289b55d7b78b5fdf105f466ba270fd7 diff --git a/third_party/hermes_patch.diff b/third_party/hermes_patch.diff index 3012fef..250556d 100644 --- a/third_party/hermes_patch.diff +++ b/third_party/hermes_patch.diff @@ -1,28 +1,23 @@ diff --git a/API/hermes/hermes.cpp b/API/hermes/hermes.cpp -index 76a5214e..ac800c2c 100644 +index f0fe3eb97..9faa5d98f 100644 --- a/API/hermes/hermes.cpp +++ b/API/hermes/hermes.cpp -@@ -1096,6 +1096,15 @@ inline const HermesRuntimeImpl *impl(const HermesRuntime *rt) { +@@ -1080,6 +1080,10 @@ inline const HermesRuntimeImpl *impl(const HermesRuntime *rt) { } // namespace -+::hermes::vm::Runtime *HermesRuntime::getHermesRuntimeFromJSI( -+ const facebook::hermes::HermesRuntime *runtime) { -+ if (!runtime) { -+ return nullptr; -+ } -+ -+ return &(impl(runtime)->runtime_); ++::hermes::vm::Runtime &HermesRuntime::getHermesRuntimeFromJSI(const ::facebook::hermes::HermesRuntime &runtime) { ++ return (impl(&runtime)->runtime_); +} + bool HermesRuntime::isHermesBytecode(const uint8_t *data, size_t len) { return hbc::BCProviderFromBuffer::isBytecodeStream( llvh::ArrayRef(data, len)); diff --git a/API/hermes/hermes.h b/API/hermes/hermes.h -index 59971257..772e55af 100644 +index 708bda235..8cbf42032 100644 --- a/API/hermes/hermes.h +++ b/API/hermes/hermes.h -@@ -38,6 +38,7 @@ class raw_ostream; +@@ -31,6 +31,7 @@ struct HermesTestHelper; namespace hermes { namespace vm { @@ -30,11 +25,11 @@ index 59971257..772e55af 100644 class GCExecTrace; struct MockedEnvironment; } // namespace vm -@@ -63,6 +64,7 @@ class HermesRuntimeImpl; +@@ -56,6 +57,7 @@ class HermesRuntimeImpl; /// Represents a Hermes JS runtime. class HERMES_EXPORT HermesRuntime : public jsi::Runtime { public: -+ static ::hermes::vm::Runtime *getHermesRuntimeFromJSI(const facebook::hermes::HermesRuntime *runtime); ++ static ::hermes::vm::Runtime &getHermesRuntimeFromJSI(const ::facebook::hermes::HermesRuntime &runtime); static bool isHermesBytecode(const uint8_t *data, size_t len); // Returns the supported bytecode version. static uint32_t getBytecodeVersion(); diff --git a/third_party/include/double-conversion b/third_party/include/double-conversion deleted file mode 120000 index d8b5794..0000000 --- a/third_party/include/double-conversion +++ /dev/null @@ -1 +0,0 @@ -../double-conversion/src \ No newline at end of file diff --git a/third_party/include/folly/double-conversion b/third_party/include/folly/double-conversion new file mode 120000 index 0000000..64820f5 --- /dev/null +++ b/third_party/include/folly/double-conversion @@ -0,0 +1 @@ +../../double-conversion/src \ No newline at end of file diff --git a/third_party/include/glog/config.h b/third_party/include/glog/config.h new file mode 100644 index 0000000..e69de29 diff --git a/third_party/include/glog/log_severity.h b/third_party/include/glog/log_severity.h deleted file mode 100644 index e69de29..0000000 diff --git a/third_party/include/glog/log_severity.h b/third_party/include/glog/log_severity.h new file mode 120000 index 0000000..90d2821 --- /dev/null +++ b/third_party/include/glog/log_severity.h @@ -0,0 +1 @@ +../../glog/src/glog/log_severity.h \ No newline at end of file diff --git a/third_party/include/glog/logging.h b/third_party/include/glog/logging.h index d9746a0..6ea15cb 100644 --- a/third_party/include/glog/logging.h +++ b/third_party/include/glog/logging.h @@ -1,28 +1,1661 @@ -#include - -#define INFO 0 -#define WARNING 0 - -#define LOG(severity) \ - if (0) \ - ::std::cout - -#define CHECK(condition) \ - if (0) \ - ::std::cout -#define CHECK_GE(val1, val2) -#define CHECK_EQ(val1, val2) - -#define DCHECK(condition) -#define DCHECK_EQ(val1, val2) \ - if (0) \ - ::std::cout -#define DCHECK_LE(val1, val2) -#define DCHECK_GT(val1, val2) -#define DCHECK_LT(val1, val2) -#define DCHECK_NE(val1, val2) -#define DCHECK_GE(val1, val2) - -#define LOG_FIRST_N(severity, n) \ - if (0) \ - ::std::cout \ No newline at end of file +// Copyright (c) 1999, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Ray Sidney +// +// This file contains #include information about logging-related stuff. +// Pretty much everybody needs to #include this file so that they can +// log various happenings. +// +#ifndef _LOGGING_H_ +#define _LOGGING_H_ + +#include +#include +#include +#include +#include +#include +#include +#if 1 +# include +#endif +#include + +#if defined(_MSC_VER) +#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \ + __pragma(warning(disable:n)) +#define GLOG_MSVC_POP_WARNING() __pragma(warning(pop)) +#else +#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) +#define GLOG_MSVC_POP_WARNING() +#endif + +// Annoying stuff for windows -- makes sure clients can import these functions +#ifndef GOOGLE_GLOG_DLL_DECL +# if defined(_WIN32) && !defined(__CYGWIN__) +# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport) +# else +# define GOOGLE_GLOG_DLL_DECL +# endif +#endif + +// We care a lot about number of bits things take up. Unfortunately, +// systems define their bit-specific ints in a lot of different ways. +// We use our own way, and have a typedef to get there. +// Note: these commands below may look like "#if 1" or "#if 0", but +// that's because they were constructed that way at ./configure time. +// Look at logging.h.in to see how they're calculated (based on your config). +#if 1 +#include // the normal place uint16_t is defined +#endif +#if 0 +#include // the normal place u_int16_t is defined +#endif +#if 0 +#include // a third place for uint16_t or u_int16_t +#endif + +#if 0 +#include +#endif + +namespace google { + +#if 1 // the C99 format +typedef int32_t int32; +typedef uint32_t uint32; +typedef int64_t int64; +typedef uint64_t uint64; +#elif 0 // the BSD format +typedef int32_t int32; +typedef u_int32_t uint32; +typedef int64_t int64; +typedef u_int64_t uint64; +#elif 0 // the windows (vc7) format +typedef __int32 int32; +typedef unsigned __int32 uint32; +typedef __int64 int64; +typedef unsigned __int64 uint64; +#else +#error Do not know how to define a 32-bit integer quantity on your system +#endif + +} + +// The global value of GOOGLE_STRIP_LOG. All the messages logged to +// LOG(XXX) with severity less than GOOGLE_STRIP_LOG will not be displayed. +// If it can be determined at compile time that the message will not be +// printed, the statement will be compiled out. +// +// Example: to strip out all INFO and WARNING messages, use the value +// of 2 below. To make an exception for WARNING messages from a single +// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including +// base/logging.h +#ifndef GOOGLE_STRIP_LOG +#define GOOGLE_STRIP_LOG 0 +#endif + +// GCC can be told that a certain branch is not likely to be taken (for +// instance, a CHECK failure), and use that information in static analysis. +// Giving it this information can help it optimize for the common case in +// the absence of better information (ie. -fprofile-arcs). +// +#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN +#if 1 +#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0)) +#else +#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x +#endif +#endif + +#ifndef GOOGLE_PREDICT_FALSE +#if 1 +#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0)) +#else +#define GOOGLE_PREDICT_FALSE(x) x +#endif +#endif + +#ifndef GOOGLE_PREDICT_TRUE +#if 1 +#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) +#else +#define GOOGLE_PREDICT_TRUE(x) x +#endif +#endif + + +// Make a bunch of macros for logging. The way to log things is to stream +// things to LOG(). E.g., +// +// LOG(INFO) << "Found " << num_cookies << " cookies"; +// +// You can capture log messages in a string, rather than reporting them +// immediately: +// +// vector errors; +// LOG_STRING(ERROR, &errors) << "Couldn't parse cookie #" << cookie_num; +// +// This pushes back the new error onto 'errors'; if given a NULL pointer, +// it reports the error via LOG(ERROR). +// +// You can also do conditional logging: +// +// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; +// +// You can also do occasional logging (log every n'th occurrence of an +// event): +// +// LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie"; +// +// The above will cause log messages to be output on the 1st, 11th, 21st, ... +// times it is executed. Note that the special google::COUNTER value is used +// to identify which repetition is happening. +// +// You can also do occasional conditional logging (log every n'th +// occurrence of an event, when condition is satisfied): +// +// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER +// << "th big cookie"; +// +// You can log messages the first N times your code executes a line. E.g. +// +// LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie"; +// +// Outputs log messages for the first 20 times it is executed. +// +// Analogous SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available. +// These log to syslog as well as to the normal logs. If you use these at +// all, you need to be aware that syslog can drastically reduce performance, +// especially if it is configured for remote logging! Don't use these +// unless you fully understand this and have a concrete need to use them. +// Even then, try to minimize your use of them. +// +// There are also "debug mode" logging macros like the ones above: +// +// DLOG(INFO) << "Found cookies"; +// +// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; +// +// DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie"; +// +// All "debug mode" logging is compiled away to nothing for non-debug mode +// compiles. +// +// We also have +// +// LOG_ASSERT(assertion); +// DLOG_ASSERT(assertion); +// +// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion; +// +// There are "verbose level" logging macros. They look like +// +// VLOG(1) << "I'm printed when you run the program with --v=1 or more"; +// VLOG(2) << "I'm printed when you run the program with --v=2 or more"; +// +// These always log at the INFO log level (when they log at all). +// The verbose logging can also be turned on module-by-module. For instance, +// --vmodule=mapreduce=2,file=1,gfs*=3 --v=0 +// will cause: +// a. VLOG(2) and lower messages to be printed from mapreduce.{h,cc} +// b. VLOG(1) and lower messages to be printed from file.{h,cc} +// c. VLOG(3) and lower messages to be printed from files prefixed with "gfs" +// d. VLOG(0) and lower messages to be printed from elsewhere +// +// The wildcarding functionality shown by (c) supports both '*' (match +// 0 or more characters) and '?' (match any single character) wildcards. +// +// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as +// +// if (VLOG_IS_ON(2)) { +// // do some logging preparation and logging +// // that can't be accomplished with just VLOG(2) << ...; +// } +// +// There are also VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N "verbose level" +// condition macros for sample cases, when some extra computation and +// preparation for logs is not needed. +// VLOG_IF(1, (size > 1024)) +// << "I'm printed when size is more than 1024 and when you run the " +// "program with --v=1 or more"; +// VLOG_EVERY_N(1, 10) +// << "I'm printed every 10th occurrence, and when you run the program " +// "with --v=1 or more. Present occurence is " << google::COUNTER; +// VLOG_IF_EVERY_N(1, (size > 1024), 10) +// << "I'm printed on every 10th occurence of case when size is more " +// " than 1024, when you run the program with --v=1 or more. "; +// "Present occurence is " << google::COUNTER; +// +// The supported severity levels for macros that allow you to specify one +// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL. +// Note that messages of a given severity are logged not only in the +// logfile for that severity, but also in all logfiles of lower severity. +// E.g., a message of severity FATAL will be logged to the logfiles of +// severity FATAL, ERROR, WARNING, and INFO. +// +// There is also the special severity of DFATAL, which logs FATAL in +// debug mode, ERROR in normal mode. +// +// Very important: logging a message at the FATAL severity level causes +// the program to terminate (after the message is logged). +// +// Unless otherwise specified, logs will be written to the filename +// "...log..", followed +// by the date, time, and pid (you can't prevent the date, time, and pid +// from being in the filename). +// +// The logging code takes two flags: +// --v=# set the verbose level +// --logtostderr log all the messages to stderr instead of to logfiles + +// LOG LINE PREFIX FORMAT +// +// Log lines have this form: +// +// Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg... +// +// where the fields are defined as follows: +// +// L A single character, representing the log level +// (eg 'I' for INFO) +// mm The month (zero padded; ie May is '05') +// dd The day (zero padded) +// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds +// threadid The space-padded thread ID as returned by GetTID() +// (this matches the PID on Linux) +// file The file name +// line The line number +// msg The user-supplied message +// +// Example: +// +// I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog +// I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395 +// +// NOTE: although the microseconds are useful for comparing events on +// a single machine, clocks on different machines may not be well +// synchronized. Hence, use caution when comparing the low bits of +// timestamps from different machines. + +#ifndef DECLARE_VARIABLE +#define MUST_UNDEF_GFLAGS_DECLARE_MACROS +#define DECLARE_VARIABLE(type, shorttype, name, tn) \ + namespace fL##shorttype { \ + extern GOOGLE_GLOG_DLL_DECL type FLAGS_##name; \ + } \ + using fL##shorttype::FLAGS_##name + +// bool specialization +#define DECLARE_bool(name) \ + DECLARE_VARIABLE(bool, B, name, bool) + +// int32 specialization +#define DECLARE_int32(name) \ + DECLARE_VARIABLE(google::int32, I, name, int32) + +// Special case for string, because we have to specify the namespace +// std::string, which doesn't play nicely with our FLAG__namespace hackery. +#define DECLARE_string(name) \ + namespace fLS { \ + extern GOOGLE_GLOG_DLL_DECL std::string& FLAGS_##name; \ + } \ + using fLS::FLAGS_##name +#endif + +// Set whether log messages go to stderr instead of logfiles +DECLARE_bool(logtostderr); + +// Set whether log messages go to stderr in addition to logfiles. +DECLARE_bool(alsologtostderr); + +// Set color messages logged to stderr (if supported by terminal). +DECLARE_bool(colorlogtostderr); + +// Log messages at a level >= this flag are automatically sent to +// stderr in addition to log files. +DECLARE_int32(stderrthreshold); + +// Set whether the log prefix should be prepended to each line of output. +DECLARE_bool(log_prefix); + +// Log messages at a level <= this flag are buffered. +// Log messages at a higher level are flushed immediately. +DECLARE_int32(logbuflevel); + +// Sets the maximum number of seconds which logs may be buffered for. +DECLARE_int32(logbufsecs); + +// Log suppression level: messages logged at a lower level than this +// are suppressed. +DECLARE_int32(minloglevel); + +// If specified, logfiles are written into this directory instead of the +// default logging directory. +DECLARE_string(log_dir); + +// Set the log file mode. +DECLARE_int32(logfile_mode); + +// Sets the path of the directory into which to put additional links +// to the log files. +DECLARE_string(log_link); + +DECLARE_int32(v); // in vlog_is_on.cc + +// Sets the maximum log file size (in MB). +DECLARE_int32(max_log_size); + +// Sets whether to avoid logging to the disk if the disk is full. +DECLARE_bool(stop_logging_if_full_disk); + +#ifdef MUST_UNDEF_GFLAGS_DECLARE_MACROS +#undef MUST_UNDEF_GFLAGS_DECLARE_MACROS +#undef DECLARE_VARIABLE +#undef DECLARE_bool +#undef DECLARE_int32 +#undef DECLARE_string +#endif + +// Log messages below the GOOGLE_STRIP_LOG level will be compiled away for +// security reasons. See LOG(severtiy) below. + +// A few definitions of macros that don't generate much code. Since +// LOG(INFO) and its ilk are used all over our code, it's +// better to have compact code for these operations. + +#if GOOGLE_STRIP_LOG == 0 +#define COMPACT_GOOGLE_LOG_INFO google::LogMessage( \ + __FILE__, __LINE__) +#define LOG_TO_STRING_INFO(message) google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_INFO, message) +#else +#define COMPACT_GOOGLE_LOG_INFO google::NullStream() +#define LOG_TO_STRING_INFO(message) google::NullStream() +#endif + +#if GOOGLE_STRIP_LOG <= 1 +#define COMPACT_GOOGLE_LOG_WARNING google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_WARNING) +#define LOG_TO_STRING_WARNING(message) google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_WARNING, message) +#else +#define COMPACT_GOOGLE_LOG_WARNING google::NullStream() +#define LOG_TO_STRING_WARNING(message) google::NullStream() +#endif + +#if GOOGLE_STRIP_LOG <= 2 +#define COMPACT_GOOGLE_LOG_ERROR google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_ERROR) +#define LOG_TO_STRING_ERROR(message) google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_ERROR, message) +#else +#define COMPACT_GOOGLE_LOG_ERROR google::NullStream() +#define LOG_TO_STRING_ERROR(message) google::NullStream() +#endif + +#if GOOGLE_STRIP_LOG <= 3 +#define COMPACT_GOOGLE_LOG_FATAL google::LogMessageFatal( \ + __FILE__, __LINE__) +#define LOG_TO_STRING_FATAL(message) google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_FATAL, message) +#else +#define COMPACT_GOOGLE_LOG_FATAL google::NullStreamFatal() +#define LOG_TO_STRING_FATAL(message) google::NullStreamFatal() +#endif + +#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) +#define DCHECK_IS_ON() 0 +#else +#define DCHECK_IS_ON() 1 +#endif + +// For DFATAL, we want to use LogMessage (as opposed to +// LogMessageFatal), to be consistent with the original behavior. +#if !DCHECK_IS_ON() +#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR +#elif GOOGLE_STRIP_LOG <= 3 +#define COMPACT_GOOGLE_LOG_DFATAL google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_FATAL) +#else +#define COMPACT_GOOGLE_LOG_DFATAL google::NullStreamFatal() +#endif + +#define GOOGLE_LOG_INFO(counter) google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, &google::LogMessage::SendToLog) +#define SYSLOG_INFO(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, \ + &google::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_WARNING(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \ + &google::LogMessage::SendToLog) +#define SYSLOG_WARNING(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \ + &google::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_ERROR(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \ + &google::LogMessage::SendToLog) +#define SYSLOG_ERROR(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \ + &google::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_FATAL(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \ + &google::LogMessage::SendToLog) +#define SYSLOG_FATAL(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \ + &google::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_DFATAL(counter) \ + google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \ + &google::LogMessage::SendToLog) +#define SYSLOG_DFATAL(counter) \ + google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \ + &google::LogMessage::SendToSyslogAndLog) + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(__CYGWIN32__) +// A very useful logging macro to log windows errors: +#define LOG_SYSRESULT(result) \ + if (FAILED(HRESULT_FROM_WIN32(result))) { \ + LPSTR message = NULL; \ + LPSTR msg = reinterpret_cast(&message); \ + DWORD message_length = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | \ + FORMAT_MESSAGE_FROM_SYSTEM, \ + 0, result, 0, msg, 100, NULL); \ + if (message_length > 0) { \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, 0, \ + &google::LogMessage::SendToLog).stream() \ + << reinterpret_cast(message); \ + LocalFree(message); \ + } \ + } +#endif + +// We use the preprocessor's merging operator, "##", so that, e.g., +// LOG(INFO) becomes the token GOOGLE_LOG_INFO. There's some funny +// subtle difference between ostream member streaming functions (e.g., +// ostream::operator<<(int) and ostream non-member streaming functions +// (e.g., ::operator<<(ostream&, string&): it turns out that it's +// impossible to stream something like a string directly to an unnamed +// ostream. We employ a neat hack by calling the stream() member +// function of LogMessage which seems to avoid the problem. +#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream() +#define SYSLOG(severity) SYSLOG_ ## severity(0).stream() + +namespace google { + +// They need the definitions of integer types. +#include "glog/log_severity.h" +#include "glog/vlog_is_on.h" + +// Initialize google's logging library. You will see the program name +// specified by argv0 in log outputs. +GOOGLE_GLOG_DLL_DECL void InitGoogleLogging(const char* argv0); + +// Shutdown google's logging library. +GOOGLE_GLOG_DLL_DECL void ShutdownGoogleLogging(); + +// Install a function which will be called after LOG(FATAL). +GOOGLE_GLOG_DLL_DECL void InstallFailureFunction(void (*fail_func)()); + +class LogSink; // defined below + +// If a non-NULL sink pointer is given, we push this message to that sink. +// For LOG_TO_SINK we then do normal LOG(severity) logging as well. +// This is useful for capturing messages and passing/storing them +// somewhere more specific than the global log of the process. +// Argument types: +// LogSink* sink; +// LogSeverity severity; +// The cast is to disambiguate NULL arguments. +#define LOG_TO_SINK(sink, severity) \ + google::LogMessage( \ + __FILE__, __LINE__, \ + google::GLOG_ ## severity, \ + static_cast(sink), true).stream() +#define LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity) \ + google::LogMessage( \ + __FILE__, __LINE__, \ + google::GLOG_ ## severity, \ + static_cast(sink), false).stream() + +// If a non-NULL string pointer is given, we write this message to that string. +// We then do normal LOG(severity) logging as well. +// This is useful for capturing messages and storing them somewhere more +// specific than the global log of the process. +// Argument types: +// string* message; +// LogSeverity severity; +// The cast is to disambiguate NULL arguments. +// NOTE: LOG(severity) expands to LogMessage().stream() for the specified +// severity. +#define LOG_TO_STRING(severity, message) \ + LOG_TO_STRING_##severity(static_cast(message)).stream() + +// If a non-NULL pointer is given, we push the message onto the end +// of a vector of strings; otherwise, we report it with LOG(severity). +// This is handy for capturing messages and perhaps passing them back +// to the caller, rather than reporting them immediately. +// Argument types: +// LogSeverity severity; +// vector *outvec; +// The cast is to disambiguate NULL arguments. +#define LOG_STRING(severity, outvec) \ + LOG_TO_STRING_##severity(static_cast*>(outvec)).stream() + +#define LOG_IF(severity, condition) \ + !(condition) ? (void) 0 : google::LogMessageVoidify() & LOG(severity) +#define SYSLOG_IF(severity, condition) \ + !(condition) ? (void) 0 : google::LogMessageVoidify() & SYSLOG(severity) + +#define LOG_ASSERT(condition) \ + LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition +#define SYSLOG_ASSERT(condition) \ + SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition + +// CHECK dies with a fatal error if condition is not true. It is *not* +// controlled by DCHECK_IS_ON(), so the check will be executed regardless of +// compilation mode. Therefore, it is safe to do things like: +// CHECK(fp->Write(x) == 4) +#define CHECK(condition) \ + LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \ + << "Check failed: " #condition " " + +// A container for a string pointer which can be evaluated to a bool - +// true iff the pointer is NULL. +struct CheckOpString { + CheckOpString(std::string* str) : str_(str) { } + // No destructor: if str_ is non-NULL, we're about to LOG(FATAL), + // so there's no point in cleaning up str_. + operator bool() const { + return GOOGLE_PREDICT_BRANCH_NOT_TAKEN(str_ != NULL); + } + std::string* str_; +}; + +// Function is overloaded for integral types to allow static const +// integrals declared in classes and not defined to be used as arguments to +// CHECK* macros. It's not encouraged though. +template +inline const T& GetReferenceableValue(const T& t) { return t; } +inline char GetReferenceableValue(char t) { return t; } +inline unsigned char GetReferenceableValue(unsigned char t) { return t; } +inline signed char GetReferenceableValue(signed char t) { return t; } +inline short GetReferenceableValue(short t) { return t; } +inline unsigned short GetReferenceableValue(unsigned short t) { return t; } +inline int GetReferenceableValue(int t) { return t; } +inline unsigned int GetReferenceableValue(unsigned int t) { return t; } +inline long GetReferenceableValue(long t) { return t; } +inline unsigned long GetReferenceableValue(unsigned long t) { return t; } +inline long long GetReferenceableValue(long long t) { return t; } +inline unsigned long long GetReferenceableValue(unsigned long long t) { + return t; +} + +// This is a dummy class to define the following operator. +struct DummyClassToDefineOperator {}; + +} + +// Define global operator<< to declare using ::operator<<. +// This declaration will allow use to use CHECK macros for user +// defined classes which have operator<< (e.g., stl_logging.h). +inline std::ostream& operator<<( + std::ostream& out, const google::DummyClassToDefineOperator&) { + return out; +} + +namespace google { + +// This formats a value for a failing CHECK_XX statement. Ordinarily, +// it uses the definition for operator<<, with a few special cases below. +template +inline void MakeCheckOpValueString(std::ostream* os, const T& v) { + (*os) << v; +} + +// Overrides for char types provide readable values for unprintable +// characters. +template <> GOOGLE_GLOG_DLL_DECL +void MakeCheckOpValueString(std::ostream* os, const char& v); +template <> GOOGLE_GLOG_DLL_DECL +void MakeCheckOpValueString(std::ostream* os, const signed char& v); +template <> GOOGLE_GLOG_DLL_DECL +void MakeCheckOpValueString(std::ostream* os, const unsigned char& v); + +// Build the error message string. Specify no inlining for code size. +template +std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) + __attribute__ ((noinline)); + +namespace base { +namespace internal { + +// If "s" is less than base_logging::INFO, returns base_logging::INFO. +// If "s" is greater than base_logging::FATAL, returns +// base_logging::ERROR. Otherwise, returns "s". +LogSeverity NormalizeSeverity(LogSeverity s); + +} // namespace internal + +// A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX +// statement. See MakeCheckOpString for sample usage. Other +// approaches were considered: use of a template method (e.g., +// base::BuildCheckOpString(exprtext, base::Print, &v1, +// base::Print, &v2), however this approach has complications +// related to volatile arguments and function-pointer arguments). +class GOOGLE_GLOG_DLL_DECL CheckOpMessageBuilder { + public: + // Inserts "exprtext" and " (" to the stream. + explicit CheckOpMessageBuilder(const char *exprtext); + // Deletes "stream_". + ~CheckOpMessageBuilder(); + // For inserting the first variable. + std::ostream* ForVar1() { return stream_; } + // For inserting the second variable (adds an intermediate " vs. "). + std::ostream* ForVar2(); + // Get the result (inserts the closing ")"). + std::string* NewString(); + + private: + std::ostringstream *stream_; +}; + +} // namespace base + +template +std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) { + base::CheckOpMessageBuilder comb(exprtext); + MakeCheckOpValueString(comb.ForVar1(), v1); + MakeCheckOpValueString(comb.ForVar2(), v2); + return comb.NewString(); +} + +// Helper functions for CHECK_OP macro. +// The (int, int) specialization works around the issue that the compiler +// will not instantiate the template version of the function on values of +// unnamed enum type - see comment below. +#define DEFINE_CHECK_OP_IMPL(name, op) \ + template \ + inline std::string* name##Impl(const T1& v1, const T2& v2, \ + const char* exprtext) { \ + if (GOOGLE_PREDICT_TRUE(v1 op v2)) return NULL; \ + else return MakeCheckOpString(v1, v2, exprtext); \ + } \ + inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \ + return name##Impl(v1, v2, exprtext); \ + } + +// We use the full name Check_EQ, Check_NE, etc. in case the file including +// base/logging.h provides its own #defines for the simpler names EQ, NE, etc. +// This happens if, for example, those are used as token names in a +// yacc grammar. +DEFINE_CHECK_OP_IMPL(Check_EQ, ==) // Compilation error with CHECK_EQ(NULL, x)? +DEFINE_CHECK_OP_IMPL(Check_NE, !=) // Use CHECK(x == NULL) instead. +DEFINE_CHECK_OP_IMPL(Check_LE, <=) +DEFINE_CHECK_OP_IMPL(Check_LT, < ) +DEFINE_CHECK_OP_IMPL(Check_GE, >=) +DEFINE_CHECK_OP_IMPL(Check_GT, > ) +#undef DEFINE_CHECK_OP_IMPL + +// Helper macro for binary operators. +// Don't use this macro directly in your code, use CHECK_EQ et al below. + +#if defined(STATIC_ANALYSIS) +// Only for static analysis tool to know that it is equivalent to assert +#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2)) +#elif DCHECK_IS_ON() +// In debug mode, avoid constructing CheckOpStrings if possible, +// to reduce the overhead of CHECK statments by 2x. +// Real DCHECK-heavy tests have seen 1.5x speedups. + +// The meaning of "string" might be different between now and +// when this macro gets invoked (e.g., if someone is experimenting +// with other string implementations that get defined after this +// file is included). Save the current meaning now and use it +// in the macro. +typedef std::string _Check_string; +#define CHECK_OP_LOG(name, op, val1, val2, log) \ + while (google::_Check_string* _result = \ + google::Check##name##Impl( \ + google::GetReferenceableValue(val1), \ + google::GetReferenceableValue(val2), \ + #val1 " " #op " " #val2)) \ + log(__FILE__, __LINE__, \ + google::CheckOpString(_result)).stream() +#else +// In optimized mode, use CheckOpString to hint to compiler that +// the while condition is unlikely. +#define CHECK_OP_LOG(name, op, val1, val2, log) \ + while (google::CheckOpString _result = \ + google::Check##name##Impl( \ + google::GetReferenceableValue(val1), \ + google::GetReferenceableValue(val2), \ + #val1 " " #op " " #val2)) \ + log(__FILE__, __LINE__, _result).stream() +#endif // STATIC_ANALYSIS, DCHECK_IS_ON() + +#if GOOGLE_STRIP_LOG <= 3 +#define CHECK_OP(name, op, val1, val2) \ + CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal) +#else +#define CHECK_OP(name, op, val1, val2) \ + CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal) +#endif // STRIP_LOG <= 3 + +// Equality/Inequality checks - compare two values, and log a FATAL message +// including the two values when the result is not as expected. The values +// must have operator<<(ostream, ...) defined. +// +// You may append to the error message like so: +// CHECK_NE(1, 2) << ": The world must be ending!"; +// +// We are very careful to ensure that each argument is evaluated exactly +// once, and that anything which is legal to pass as a function argument is +// legal here. In particular, the arguments may be temporary expressions +// which will end up being destroyed at the end of the apparent statement, +// for example: +// CHECK_EQ(string("abc")[1], 'b'); +// +// WARNING: These don't compile correctly if one of the arguments is a pointer +// and the other is NULL. To work around this, simply static_cast NULL to the +// type of the desired pointer. + +#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2) +#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2) +#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2) +#define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2) +#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2) +#define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2) + +// Check that the input is non NULL. This very useful in constructor +// initializer lists. + +#define CHECK_NOTNULL(val) \ + google::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val)) + +// Helper functions for string comparisons. +// To avoid bloat, the definitions are in logging.cc. +#define DECLARE_CHECK_STROP_IMPL(func, expected) \ + GOOGLE_GLOG_DLL_DECL std::string* Check##func##expected##Impl( \ + const char* s1, const char* s2, const char* names); +DECLARE_CHECK_STROP_IMPL(strcmp, true) +DECLARE_CHECK_STROP_IMPL(strcmp, false) +DECLARE_CHECK_STROP_IMPL(strcasecmp, true) +DECLARE_CHECK_STROP_IMPL(strcasecmp, false) +#undef DECLARE_CHECK_STROP_IMPL + +// Helper macro for string comparisons. +// Don't use this macro directly in your code, use CHECK_STREQ et al below. +#define CHECK_STROP(func, op, expected, s1, s2) \ + while (google::CheckOpString _result = \ + google::Check##func##expected##Impl((s1), (s2), \ + #s1 " " #op " " #s2)) \ + LOG(FATAL) << *_result.str_ + + +// String (char*) equality/inequality checks. +// CASE versions are case-insensitive. +// +// Note that "s1" and "s2" may be temporary strings which are destroyed +// by the compiler at the end of the current "full expression" +// (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())). + +#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2) +#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2) +#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(strcasecmp, ==, true, s1, s2) +#define CHECK_STRCASENE(s1, s2) CHECK_STROP(strcasecmp, !=, false, s1, s2) + +#define CHECK_INDEX(I,A) CHECK(I < (sizeof(A)/sizeof(A[0]))) +#define CHECK_BOUND(B,A) CHECK(B <= (sizeof(A)/sizeof(A[0]))) + +#define CHECK_DOUBLE_EQ(val1, val2) \ + do { \ + CHECK_LE((val1), (val2)+0.000000000000001L); \ + CHECK_GE((val1), (val2)-0.000000000000001L); \ + } while (0) + +#define CHECK_NEAR(val1, val2, margin) \ + do { \ + CHECK_LE((val1), (val2)+(margin)); \ + CHECK_GE((val1), (val2)-(margin)); \ + } while (0) + +// perror()..googly style! +// +// PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and +// CHECK equivalents with the addition that they postpend a description +// of the current state of errno to their output lines. + +#define PLOG(severity) GOOGLE_PLOG(severity, 0).stream() + +#define GOOGLE_PLOG(severity, counter) \ + google::ErrnoLogMessage( \ + __FILE__, __LINE__, google::GLOG_ ## severity, counter, \ + &google::LogMessage::SendToLog) + +#define PLOG_IF(severity, condition) \ + !(condition) ? (void) 0 : google::LogMessageVoidify() & PLOG(severity) + +// A CHECK() macro that postpends errno if the condition is false. E.g. +// +// if (poll(fds, nfds, timeout) == -1) { PCHECK(errno == EINTR); ... } +#define PCHECK(condition) \ + PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \ + << "Check failed: " #condition " " + +// A CHECK() macro that lets you assert the success of a function that +// returns -1 and sets errno in case of an error. E.g. +// +// CHECK_ERR(mkdir(path, 0700)); +// +// or +// +// int fd = open(filename, flags); CHECK_ERR(fd) << ": open " << filename; +#define CHECK_ERR(invocation) \ +PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN((invocation) == -1)) \ + << #invocation + +// Use macro expansion to create, for each use of LOG_EVERY_N(), static +// variables with the __LINE__ expansion as part of the variable name. +#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line) +#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base ## line + +#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__) +#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__) + +#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \ + static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \ + ++LOG_OCCURRENCES; \ + if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \ + if (LOG_OCCURRENCES_MOD_N == 1) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ + &what_to_do).stream() + +#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \ + static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \ + ++LOG_OCCURRENCES; \ + if (condition && \ + ((LOG_OCCURRENCES_MOD_N=(LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ + &what_to_do).stream() + +#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \ + static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \ + ++LOG_OCCURRENCES; \ + if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \ + if (LOG_OCCURRENCES_MOD_N == 1) \ + google::ErrnoLogMessage( \ + __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ + &what_to_do).stream() + +#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \ + static int LOG_OCCURRENCES = 0; \ + if (LOG_OCCURRENCES <= n) \ + ++LOG_OCCURRENCES; \ + if (LOG_OCCURRENCES <= n) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ + &what_to_do).stream() + +namespace glog_internal_namespace_ { +template +struct CompileAssert { +}; +struct CrashReason; + +// Returns true if FailureSignalHandler is installed. +bool IsFailureSignalHandlerInstalled(); +} // namespace glog_internal_namespace_ + +#define GOOGLE_GLOG_COMPILE_ASSERT(expr, msg) \ + typedef google::glog_internal_namespace_::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] + +#define LOG_EVERY_N(severity, n) \ + GOOGLE_GLOG_COMPILE_ASSERT(google::GLOG_ ## severity < \ + google::NUM_SEVERITIES, \ + INVALID_REQUESTED_LOG_SEVERITY); \ + SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog) + +#define SYSLOG_EVERY_N(severity, n) \ + SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToSyslogAndLog) + +#define PLOG_EVERY_N(severity, n) \ + SOME_KIND_OF_PLOG_EVERY_N(severity, (n), google::LogMessage::SendToLog) + +#define LOG_FIRST_N(severity, n) \ + SOME_KIND_OF_LOG_FIRST_N(severity, (n), google::LogMessage::SendToLog) + +#define LOG_IF_EVERY_N(severity, condition, n) \ + SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), google::LogMessage::SendToLog) + +// We want the special COUNTER value available for LOG_EVERY_X()'ed messages +enum PRIVATE_Counter {COUNTER}; + +#ifdef GLOG_NO_ABBREVIATED_SEVERITIES +// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets +// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us +// to keep using this syntax, we define this macro to do the same thing +// as COMPACT_GOOGLE_LOG_ERROR. +#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR +#define SYSLOG_0 SYSLOG_ERROR +#define LOG_TO_STRING_0 LOG_TO_STRING_ERROR +// Needed for LOG_IS_ON(ERROR). +const LogSeverity GLOG_0 = GLOG_ERROR; +#else +// Users may include windows.h after logging.h without +// GLOG_NO_ABBREVIATED_SEVERITIES nor WIN32_LEAN_AND_MEAN. +// For this case, we cannot detect if ERROR is defined before users +// actually use ERROR. Let's make an undefined symbol to warn users. +# define GLOG_ERROR_MSG ERROR_macro_is_defined_Define_GLOG_NO_ABBREVIATED_SEVERITIES_before_including_logging_h_See_the_document_for_detail +# define COMPACT_GOOGLE_LOG_0 GLOG_ERROR_MSG +# define SYSLOG_0 GLOG_ERROR_MSG +# define LOG_TO_STRING_0 GLOG_ERROR_MSG +# define GLOG_0 GLOG_ERROR_MSG +#endif + +// Plus some debug-logging macros that get compiled to nothing for production + +#if DCHECK_IS_ON() + +#define DLOG(severity) LOG(severity) +#define DVLOG(verboselevel) VLOG(verboselevel) +#define DLOG_IF(severity, condition) LOG_IF(severity, condition) +#define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n) +#define DLOG_IF_EVERY_N(severity, condition, n) \ + LOG_IF_EVERY_N(severity, condition, n) +#define DLOG_ASSERT(condition) LOG_ASSERT(condition) + +// debug-only checking. executed if DCHECK_IS_ON(). +#define DCHECK(condition) CHECK(condition) +#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2) +#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2) +#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2) +#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2) +#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2) +#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2) +#define DCHECK_NOTNULL(val) CHECK_NOTNULL(val) +#define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2) +#define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2) +#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2) +#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2) + +#else // !DCHECK_IS_ON() + +#define DLOG(severity) \ + true ? (void) 0 : google::LogMessageVoidify() & LOG(severity) + +#define DVLOG(verboselevel) \ + (true || !VLOG_IS_ON(verboselevel)) ?\ + (void) 0 : google::LogMessageVoidify() & LOG(INFO) + +#define DLOG_IF(severity, condition) \ + (true || !(condition)) ? (void) 0 : google::LogMessageVoidify() & LOG(severity) + +#define DLOG_EVERY_N(severity, n) \ + true ? (void) 0 : google::LogMessageVoidify() & LOG(severity) + +#define DLOG_IF_EVERY_N(severity, condition, n) \ + (true || !(condition))? (void) 0 : google::LogMessageVoidify() & LOG(severity) + +#define DLOG_ASSERT(condition) \ + true ? (void) 0 : LOG_ASSERT(condition) + +// MSVC warning C4127: conditional expression is constant +#define DCHECK(condition) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK(condition) + +#define DCHECK_EQ(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_EQ(val1, val2) + +#define DCHECK_NE(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_NE(val1, val2) + +#define DCHECK_LE(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_LE(val1, val2) + +#define DCHECK_LT(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_LT(val1, val2) + +#define DCHECK_GE(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_GE(val1, val2) + +#define DCHECK_GT(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_GT(val1, val2) + +// You may see warnings in release mode if you don't use the return +// value of DCHECK_NOTNULL. Please just use DCHECK for such cases. +#define DCHECK_NOTNULL(val) (val) + +#define DCHECK_STREQ(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_STREQ(str1, str2) + +#define DCHECK_STRCASEEQ(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_STRCASEEQ(str1, str2) + +#define DCHECK_STRNE(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_STRNE(str1, str2) + +#define DCHECK_STRCASENE(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2) + +#endif // DCHECK_IS_ON() + +// Log only in verbose mode. + +#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel)) + +#define VLOG_IF(verboselevel, condition) \ + LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel)) + +#define VLOG_EVERY_N(verboselevel, n) \ + LOG_IF_EVERY_N(INFO, VLOG_IS_ON(verboselevel), n) + +#define VLOG_IF_EVERY_N(verboselevel, condition, n) \ + LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n) + +namespace base_logging { + +// LogMessage::LogStream is a std::ostream backed by this streambuf. +// This class ignores overflow and leaves two bytes at the end of the +// buffer to allow for a '\n' and '\0'. +class GOOGLE_GLOG_DLL_DECL LogStreamBuf : public std::streambuf { + public: + // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\n'. + LogStreamBuf(char *buf, int len) { + setp(buf, buf + len - 2); + } + // This effectively ignores overflow. + virtual int_type overflow(int_type ch) { + return ch; + } + + // Legacy public ostrstream method. + size_t pcount() const { return pptr() - pbase(); } + char* pbase() const { return std::streambuf::pbase(); } +}; + +} // namespace base_logging + +// +// This class more or less represents a particular log message. You +// create an instance of LogMessage and then stream stuff to it. +// When you finish streaming to it, ~LogMessage is called and the +// full message gets streamed to the appropriate destination. +// +// You shouldn't actually use LogMessage's constructor to log things, +// though. You should use the LOG() macro (and variants thereof) +// above. +class GOOGLE_GLOG_DLL_DECL LogMessage { +public: + enum { + // Passing kNoLogPrefix for the line number disables the + // log-message prefix. Useful for using the LogMessage + // infrastructure as a printing utility. See also the --log_prefix + // flag for controlling the log-message prefix on an + // application-wide basis. + kNoLogPrefix = -1 + }; + + // LogStream inherit from non-DLL-exported class (std::ostrstream) + // and VC++ produces a warning for this situation. + // However, MSDN says "C4275 can be ignored in Microsoft Visual C++ + // 2005 if you are deriving from a type in the Standard C++ Library" + // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx + // Let's just ignore the warning. +#ifdef _MSC_VER +# pragma warning(disable: 4275) +#endif + class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostream { +#ifdef _MSC_VER +# pragma warning(default: 4275) +#endif + public: + LogStream(char *buf, int len, int ctr) + : std::ostream(NULL), + streambuf_(buf, len), + ctr_(ctr), + self_(this) { + rdbuf(&streambuf_); + } + + int ctr() const { return ctr_; } + void set_ctr(int ctr) { ctr_ = ctr; } + LogStream* self() const { return self_; } + + // Legacy std::streambuf methods. + size_t pcount() const { return streambuf_.pcount(); } + char* pbase() const { return streambuf_.pbase(); } + char* str() const { return pbase(); } + + private: + LogStream(const LogStream&); + LogStream& operator=(const LogStream&); + base_logging::LogStreamBuf streambuf_; + int ctr_; // Counter hack (for the LOG_EVERY_X() macro) + LogStream *self_; // Consistency check hack + }; + +public: + // icc 8 requires this typedef to avoid an internal compiler error. + typedef void (LogMessage::*SendMethod)(); + + LogMessage(const char* file, int line, LogSeverity severity, int ctr, + SendMethod send_method); + + // Two special constructors that generate reduced amounts of code at + // LOG call sites for common cases. + + // Used for LOG(INFO): Implied are: + // severity = INFO, ctr = 0, send_method = &LogMessage::SendToLog. + // + // Using this constructor instead of the more complex constructor above + // saves 19 bytes per call site. + LogMessage(const char* file, int line); + + // Used for LOG(severity) where severity != INFO. Implied + // are: ctr = 0, send_method = &LogMessage::SendToLog + // + // Using this constructor instead of the more complex constructor above + // saves 17 bytes per call site. + LogMessage(const char* file, int line, LogSeverity severity); + + // Constructor to log this message to a specified sink (if not NULL). + // Implied are: ctr = 0, send_method = &LogMessage::SendToSinkAndLog if + // also_send_to_log is true, send_method = &LogMessage::SendToSink otherwise. + LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink, + bool also_send_to_log); + + // Constructor where we also give a vector pointer + // for storing the messages (if the pointer is not NULL). + // Implied are: ctr = 0, send_method = &LogMessage::SaveOrSendToLog. + LogMessage(const char* file, int line, LogSeverity severity, + std::vector* outvec); + + // Constructor where we also give a string pointer for storing the + // message (if the pointer is not NULL). Implied are: ctr = 0, + // send_method = &LogMessage::WriteToStringAndLog. + LogMessage(const char* file, int line, LogSeverity severity, + std::string* message); + + // A special constructor used for check failures + LogMessage(const char* file, int line, const CheckOpString& result); + + ~LogMessage(); + + // Flush a buffered message to the sink set in the constructor. Always + // called by the destructor, it may also be called from elsewhere if + // needed. Only the first call is actioned; any later ones are ignored. + void Flush(); + + // An arbitrary limit on the length of a single log message. This + // is so that streaming can be done more efficiently. + static const size_t kMaxLogMessageLen; + + // Theses should not be called directly outside of logging.*, + // only passed as SendMethod arguments to other LogMessage methods: + void SendToLog(); // Actually dispatch to the logs + void SendToSyslogAndLog(); // Actually dispatch to syslog and the logs + + // Call abort() or similar to perform LOG(FATAL) crash. + static void __attribute__ ((noreturn)) Fail(); + + std::ostream& stream(); + + int preserved_errno() const; + + // Must be called without the log_mutex held. (L < log_mutex) + static int64 num_messages(int severity); + + struct LogMessageData; + +private: + // Fully internal SendMethod cases: + void SendToSinkAndLog(); // Send to sink if provided and dispatch to the logs + void SendToSink(); // Send to sink if provided, do nothing otherwise. + + // Write to string if provided and dispatch to the logs. + void WriteToStringAndLog(); + + void SaveOrSendToLog(); // Save to stringvec if provided, else to logs + + void Init(const char* file, int line, LogSeverity severity, + void (LogMessage::*send_method)()); + + // Used to fill in crash information during LOG(FATAL) failures. + void RecordCrashReason(glog_internal_namespace_::CrashReason* reason); + + // Counts of messages sent at each priority: + static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex + + // We keep the data in a separate struct so that each instance of + // LogMessage uses less stack space. + LogMessageData* allocated_; + LogMessageData* data_; + + friend class LogDestination; + + LogMessage(const LogMessage&); + void operator=(const LogMessage&); +}; + +// This class happens to be thread-hostile because all instances share +// a single data buffer, but since it can only be created just before +// the process dies, we don't worry so much. +class GOOGLE_GLOG_DLL_DECL LogMessageFatal : public LogMessage { + public: + LogMessageFatal(const char* file, int line); + LogMessageFatal(const char* file, int line, const CheckOpString& result); + __attribute__ ((noreturn)) ~LogMessageFatal(); +}; + +// A non-macro interface to the log facility; (useful +// when the logging level is not a compile-time constant). +inline void LogAtLevel(int const severity, std::string const &msg) { + LogMessage(__FILE__, __LINE__, severity).stream() << msg; +} + +// A macro alternative of LogAtLevel. New code may want to use this +// version since there are two advantages: 1. this version outputs the +// file name and the line number where this macro is put like other +// LOG macros, 2. this macro can be used as C++ stream. +#define LOG_AT_LEVEL(severity) google::LogMessage(__FILE__, __LINE__, severity).stream() + +// Check if it's compiled in C++11 mode. +// +// GXX_EXPERIMENTAL_CXX0X is defined by gcc and clang up to at least +// gcc-4.7 and clang-3.1 (2011-12-13). __cplusplus was defined to 1 +// in gcc before 4.7 (Crosstool 16) and clang before 3.1, but is +// defined according to the language version in effect thereafter. +// Microsoft Visual Studio 14 (2015) sets __cplusplus==199711 despite +// reasonably good C++11 support, so we set LANG_CXX for it and +// newer versions (_MSC_VER >= 1900). +#if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \ + (defined(_MSC_VER) && _MSC_VER >= 1900)) +// Helper for CHECK_NOTNULL(). +// +// In C++11, all cases can be handled by a single function. Since the value +// category of the argument is preserved (also for rvalue references), +// member initializer lists like the one below will compile correctly: +// +// Foo() +// : x_(CHECK_NOTNULL(MethodReturningUniquePtr())) {} +template +T CheckNotNull(const char* file, int line, const char* names, T&& t) { + if (t == nullptr) { + LogMessageFatal(file, line, new std::string(names)); + } + return std::forward(t); +} + +#else + +// A small helper for CHECK_NOTNULL(). +template +T* CheckNotNull(const char *file, int line, const char *names, T* t) { + if (t == NULL) { + LogMessageFatal(file, line, new std::string(names)); + } + return t; +} +#endif + +// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This +// only works if ostream is a LogStream. If the ostream is not a +// LogStream you'll get an assert saying as much at runtime. +GOOGLE_GLOG_DLL_DECL std::ostream& operator<<(std::ostream &os, + const PRIVATE_Counter&); + + +// Derived class for PLOG*() above. +class GOOGLE_GLOG_DLL_DECL ErrnoLogMessage : public LogMessage { + public: + + ErrnoLogMessage(const char* file, int line, LogSeverity severity, int ctr, + void (LogMessage::*send_method)()); + + // Postpends ": strerror(errno) [errno]". + ~ErrnoLogMessage(); + + private: + ErrnoLogMessage(const ErrnoLogMessage&); + void operator=(const ErrnoLogMessage&); +}; + + +// This class is used to explicitly ignore values in the conditional +// logging macros. This avoids compiler warnings like "value computed +// is not used" and "statement has no effect". + +class GOOGLE_GLOG_DLL_DECL LogMessageVoidify { + public: + LogMessageVoidify() { } + // This has to be an operator with a precedence lower than << but + // higher than ?: + void operator&(std::ostream&) { } +}; + + +// Flushes all log files that contains messages that are at least of +// the specified severity level. Thread-safe. +GOOGLE_GLOG_DLL_DECL void FlushLogFiles(LogSeverity min_severity); + +// Flushes all log files that contains messages that are at least of +// the specified severity level. Thread-hostile because it ignores +// locking -- used for catastrophic failures. +GOOGLE_GLOG_DLL_DECL void FlushLogFilesUnsafe(LogSeverity min_severity); + +// +// Set the destination to which a particular severity level of log +// messages is sent. If base_filename is "", it means "don't log this +// severity". Thread-safe. +// +GOOGLE_GLOG_DLL_DECL void SetLogDestination(LogSeverity severity, + const char* base_filename); + +// +// Set the basename of the symlink to the latest log file at a given +// severity. If symlink_basename is empty, do not make a symlink. If +// you don't call this function, the symlink basename is the +// invocation name of the program. Thread-safe. +// +GOOGLE_GLOG_DLL_DECL void SetLogSymlink(LogSeverity severity, + const char* symlink_basename); + +// +// Used to send logs to some other kind of destination +// Users should subclass LogSink and override send to do whatever they want. +// Implementations must be thread-safe because a shared instance will +// be called from whichever thread ran the LOG(XXX) line. +class GOOGLE_GLOG_DLL_DECL LogSink { + public: + virtual ~LogSink(); + + // Sink's logging logic (message_len is such as to exclude '\n' at the end). + // This method can't use LOG() or CHECK() as logging system mutex(s) are held + // during this call. + virtual void send(LogSeverity severity, const char* full_filename, + const char* base_filename, int line, + const struct ::tm* tm_time, + const char* message, size_t message_len) = 0; + + // Redefine this to implement waiting for + // the sink's logging logic to complete. + // It will be called after each send() returns, + // but before that LogMessage exits or crashes. + // By default this function does nothing. + // Using this function one can implement complex logic for send() + // that itself involves logging; and do all this w/o causing deadlocks and + // inconsistent rearrangement of log messages. + // E.g. if a LogSink has thread-specific actions, the send() method + // can simply add the message to a queue and wake up another thread that + // handles real logging while itself making some LOG() calls; + // WaitTillSent() can be implemented to wait for that logic to complete. + // See our unittest for an example. + virtual void WaitTillSent(); + + // Returns the normal text output of the log message. + // Can be useful to implement send(). + static std::string ToString(LogSeverity severity, const char* file, int line, + const struct ::tm* tm_time, + const char* message, size_t message_len); +}; + +// Add or remove a LogSink as a consumer of logging data. Thread-safe. +GOOGLE_GLOG_DLL_DECL void AddLogSink(LogSink *destination); +GOOGLE_GLOG_DLL_DECL void RemoveLogSink(LogSink *destination); + +// +// Specify an "extension" added to the filename specified via +// SetLogDestination. This applies to all severity levels. It's +// often used to append the port we're listening on to the logfile +// name. Thread-safe. +// +GOOGLE_GLOG_DLL_DECL void SetLogFilenameExtension( + const char* filename_extension); + +// +// Make it so that all log messages of at least a particular severity +// are logged to stderr (in addition to logging to the usual log +// file(s)). Thread-safe. +// +GOOGLE_GLOG_DLL_DECL void SetStderrLogging(LogSeverity min_severity); + +// +// Make it so that all log messages go only to stderr. Thread-safe. +// +GOOGLE_GLOG_DLL_DECL void LogToStderr(); + +// +// Make it so that all log messages of at least a particular severity are +// logged via email to a list of addresses (in addition to logging to the +// usual log file(s)). The list of addresses is just a string containing +// the email addresses to send to (separated by spaces, say). Thread-safe. +// +GOOGLE_GLOG_DLL_DECL void SetEmailLogging(LogSeverity min_severity, + const char* addresses); + +// A simple function that sends email. dest is a commma-separated +// list of addressess. Thread-safe. +GOOGLE_GLOG_DLL_DECL bool SendEmail(const char *dest, + const char *subject, const char *body); + +GOOGLE_GLOG_DLL_DECL const std::vector& GetLoggingDirectories(); + +// For tests only: Clear the internal [cached] list of logging directories to +// force a refresh the next time GetLoggingDirectories is called. +// Thread-hostile. +void TestOnly_ClearLoggingDirectoriesList(); + +// Returns a set of existing temporary directories, which will be a +// subset of the directories returned by GetLogginDirectories(). +// Thread-safe. +GOOGLE_GLOG_DLL_DECL void GetExistingTempDirectories( + std::vector* list); + +// Print any fatal message again -- useful to call from signal handler +// so that the last thing in the output is the fatal message. +// Thread-hostile, but a race is unlikely. +GOOGLE_GLOG_DLL_DECL void ReprintFatalMessage(); + +// Truncate a log file that may be the append-only output of multiple +// processes and hence can't simply be renamed/reopened (typically a +// stdout/stderr). If the file "path" is > "limit" bytes, copy the +// last "keep" bytes to offset 0 and truncate the rest. Since we could +// be racing with other writers, this approach has the potential to +// lose very small amounts of data. For security, only follow symlinks +// if the path is /proc/self/fd/* +GOOGLE_GLOG_DLL_DECL void TruncateLogFile(const char *path, + int64 limit, int64 keep); + +// Truncate stdout and stderr if they are over the value specified by +// --max_log_size; keep the final 1MB. This function has the same +// race condition as TruncateLogFile. +GOOGLE_GLOG_DLL_DECL void TruncateStdoutStderr(); + +// Return the string representation of the provided LogSeverity level. +// Thread-safe. +GOOGLE_GLOG_DLL_DECL const char* GetLogSeverityName(LogSeverity severity); + +// --------------------------------------------------------------------- +// Implementation details that are not useful to most clients +// --------------------------------------------------------------------- + +// A Logger is the interface used by logging modules to emit entries +// to a log. A typical implementation will dump formatted data to a +// sequence of files. We also provide interfaces that will forward +// the data to another thread so that the invoker never blocks. +// Implementations should be thread-safe since the logging system +// will write to them from multiple threads. + +namespace base { + +class GOOGLE_GLOG_DLL_DECL Logger { + public: + virtual ~Logger(); + + // Writes "message[0,message_len-1]" corresponding to an event that + // occurred at "timestamp". If "force_flush" is true, the log file + // is flushed immediately. + // + // The input message has already been formatted as deemed + // appropriate by the higher level logging facility. For example, + // textual log messages already contain timestamps, and the + // file:linenumber header. + virtual void Write(bool force_flush, + time_t timestamp, + const char* message, + int message_len) = 0; + + // Flush any buffered messages + virtual void Flush() = 0; + + // Get the current LOG file size. + // The returned value is approximate since some + // logged data may not have been flushed to disk yet. + virtual uint32 LogSize() = 0; +}; + +// Get the logger for the specified severity level. The logger +// remains the property of the logging module and should not be +// deleted by the caller. Thread-safe. +extern GOOGLE_GLOG_DLL_DECL Logger* GetLogger(LogSeverity level); + +// Set the logger for the specified severity level. The logger +// becomes the property of the logging module and should not +// be deleted by the caller. Thread-safe. +extern GOOGLE_GLOG_DLL_DECL void SetLogger(LogSeverity level, Logger* logger); + +} + +// glibc has traditionally implemented two incompatible versions of +// strerror_r(). There is a poorly defined convention for picking the +// version that we want, but it is not clear whether it even works with +// all versions of glibc. +// So, instead, we provide this wrapper that automatically detects the +// version that is in use, and then implements POSIX semantics. +// N.B. In addition to what POSIX says, we also guarantee that "buf" will +// be set to an empty string, if this function failed. This means, in most +// cases, you do not need to check the error code and you can directly +// use the value of "buf". It will never have an undefined value. +// DEPRECATED: Use StrError(int) instead. +GOOGLE_GLOG_DLL_DECL int posix_strerror_r(int err, char *buf, size_t len); + +// A thread-safe replacement for strerror(). Returns a string describing the +// given POSIX error code. +GOOGLE_GLOG_DLL_DECL std::string StrError(int err); + +// A class for which we define operator<<, which does nothing. +class GOOGLE_GLOG_DLL_DECL NullStream : public LogMessage::LogStream { + public: + // Initialize the LogStream so the messages can be written somewhere + // (they'll never be actually displayed). This will be needed if a + // NullStream& is implicitly converted to LogStream&, in which case + // the overloaded NullStream::operator<< will not be invoked. + NullStream() : LogMessage::LogStream(message_buffer_, 1, 0) { } + NullStream(const char* /*file*/, int /*line*/, + const CheckOpString& /*result*/) : + LogMessage::LogStream(message_buffer_, 1, 0) { } + NullStream &stream() { return *this; } + private: + // A very short buffer for messages (which we discard anyway). This + // will be needed if NullStream& converted to LogStream& (e.g. as a + // result of a conditional expression). + char message_buffer_[2]; +}; + +// Do nothing. This operator is inline, allowing the message to be +// compiled away. The message will not be compiled away if we do +// something like (flag ? LOG(INFO) : LOG(ERROR)) << message; when +// SKIP_LOG=WARNING. In those cases, NullStream will be implicitly +// converted to LogStream and the message will be computed and then +// quietly discarded. +template +inline NullStream& operator<<(NullStream &str, const T &) { return str; } + +// Similar to NullStream, but aborts the program (without stack +// trace), like LogMessageFatal. +class GOOGLE_GLOG_DLL_DECL NullStreamFatal : public NullStream { + public: + NullStreamFatal() { } + NullStreamFatal(const char* file, int line, const CheckOpString& result) : + NullStream(file, line, result) { } + __attribute__ ((noreturn)) ~NullStreamFatal() throw () { _exit(1); } +}; + +// Install a signal handler that will dump signal information and a stack +// trace when the program crashes on certain signals. We'll install the +// signal handler for the following signals. +// +// SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, and SIGTERM. +// +// By default, the signal handler will write the failure dump to the +// standard error. You can customize the destination by installing your +// own writer function by InstallFailureWriter() below. +// +// Note on threading: +// +// The function should be called before threads are created, if you want +// to use the failure signal handler for all threads. The stack trace +// will be shown only for the thread that receives the signal. In other +// words, stack traces of other threads won't be shown. +GOOGLE_GLOG_DLL_DECL void InstallFailureSignalHandler(); + +// Installs a function that is used for writing the failure dump. "data" +// is the pointer to the beginning of a message to be written, and "size" +// is the size of the message. You should not expect the data is +// terminated with '\0'. +GOOGLE_GLOG_DLL_DECL void InstallFailureWriter( + void (*writer)(const char* data, int size)); + +} + +#endif // _LOGGING_H_ diff --git a/third_party/include/glog/raw_logging.h b/third_party/include/glog/raw_logging.h new file mode 100644 index 0000000..65278f6 --- /dev/null +++ b/third_party/include/glog/raw_logging.h @@ -0,0 +1,185 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Maxim Lifantsev +// +// Thread-safe logging routines that do not allocate any memory or +// acquire any locks, and can therefore be used by low-level memory +// allocation and synchronization code. + +#ifndef BASE_RAW_LOGGING_H_ +#define BASE_RAW_LOGGING_H_ + +#include + +namespace google { + +#include "glog/log_severity.h" +#include "glog/vlog_is_on.h" + +// Annoying stuff for windows -- makes sure clients can import these functions +#ifndef GOOGLE_GLOG_DLL_DECL +# if defined(_WIN32) && !defined(__CYGWIN__) +# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport) +# else +# define GOOGLE_GLOG_DLL_DECL +# endif +#endif + +// This is similar to LOG(severity) << format... and VLOG(level) << format.., +// but +// * it is to be used ONLY by low-level modules that can't use normal LOG() +// * it is desiged to be a low-level logger that does not allocate any +// memory and does not need any locks, hence: +// * it logs straight and ONLY to STDERR w/o buffering +// * it uses an explicit format and arguments list +// * it will silently chop off really long message strings +// Usage example: +// RAW_LOG(ERROR, "Failed foo with %i: %s", status, error); +// RAW_VLOG(3, "status is %i", status); +// These will print an almost standard log lines like this to stderr only: +// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file +// I0821 211317 file.cc:142] RAW: status is 20 +#define RAW_LOG(severity, ...) \ + do { \ + switch (google::GLOG_ ## severity) { \ + case 0: \ + RAW_LOG_INFO(__VA_ARGS__); \ + break; \ + case 1: \ + RAW_LOG_WARNING(__VA_ARGS__); \ + break; \ + case 2: \ + RAW_LOG_ERROR(__VA_ARGS__); \ + break; \ + case 3: \ + RAW_LOG_FATAL(__VA_ARGS__); \ + break; \ + default: \ + break; \ + } \ + } while (0) + +// The following STRIP_LOG testing is performed in the header file so that it's +// possible to completely compile out the logging code and the log messages. +#if STRIP_LOG == 0 +#define RAW_VLOG(verboselevel, ...) \ + do { \ + if (VLOG_IS_ON(verboselevel)) { \ + RAW_LOG_INFO(__VA_ARGS__); \ + } \ + } while (0) +#else +#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG == 0 + +#if STRIP_LOG == 0 +#define RAW_LOG_INFO(...) google::RawLog__(google::GLOG_INFO, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG == 0 + +#if STRIP_LOG <= 1 +#define RAW_LOG_WARNING(...) google::RawLog__(google::GLOG_WARNING, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG <= 1 + +#if STRIP_LOG <= 2 +#define RAW_LOG_ERROR(...) google::RawLog__(google::GLOG_ERROR, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG <= 2 + +#if STRIP_LOG <= 3 +#define RAW_LOG_FATAL(...) google::RawLog__(google::GLOG_FATAL, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_FATAL(...) \ + do { \ + google::RawLogStub__(0, __VA_ARGS__); \ + exit(1); \ + } while (0) +#endif // STRIP_LOG <= 3 + +// Similar to CHECK(condition) << message, +// but for low-level modules: we use only RAW_LOG that does not allocate memory. +// We do not want to provide args list here to encourage this usage: +// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args); +// so that the args are not computed when not needed. +#define RAW_CHECK(condition, message) \ + do { \ + if (!(condition)) { \ + RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \ + } \ + } while (0) + +// Debug versions of RAW_LOG and RAW_CHECK +#ifndef NDEBUG + +#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__) +#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message) + +#else // NDEBUG + +#define RAW_DLOG(severity, ...) \ + while (false) \ + RAW_LOG(severity, __VA_ARGS__) +#define RAW_DCHECK(condition, message) \ + while (false) \ + RAW_CHECK(condition, message) + +#endif // NDEBUG + +// Stub log function used to work around for unused variable warnings when +// building with STRIP_LOG > 0. +static inline void RawLogStub__(int /* ignored */, ...) { +} + +// Helper function to implement RAW_LOG and RAW_VLOG +// Logs format... at "severity" level, reporting it +// as called from file:line. +// This does not allocate memory or acquire locks. +GOOGLE_GLOG_DLL_DECL void RawLog__(LogSeverity severity, + const char* file, + int line, + const char* format, ...) + __attribute__((__format__ (__printf__, 4, 5))); + +// Hack to propagate time information into this module so that +// this module does not have to directly call localtime_r(), +// which could allocate memory. +GOOGLE_GLOG_DLL_DECL void RawLog__SetLastTime(const struct tm& t, int usecs); + +} + +#endif // BASE_RAW_LOGGING_H_ diff --git a/third_party/include/glog/stl_logging.h b/third_party/include/glog/stl_logging.h new file mode 100644 index 0000000..40a15aa --- /dev/null +++ b/third_party/include/glog/stl_logging.h @@ -0,0 +1,220 @@ +// Copyright (c) 2003, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Stream output operators for STL containers; to be used for logging *only*. +// Inclusion of this file lets you do: +// +// list x; +// LOG(INFO) << "data: " << x; +// vector v1, v2; +// CHECK_EQ(v1, v2); +// +// If you want to use this header file with hash maps or slist, you +// need to define macros before including this file: +// +// - GLOG_STL_LOGGING_FOR_UNORDERED - and +// - GLOG_STL_LOGGING_FOR_TR1_UNORDERED - +// - GLOG_STL_LOGGING_FOR_EXT_HASH - +// - GLOG_STL_LOGGING_FOR_EXT_SLIST - +// + +#ifndef UTIL_GTL_STL_LOGGING_INL_H_ +#define UTIL_GTL_STL_LOGGING_INL_H_ + +#if !1 +# error We do not support stl_logging for this compiler +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef GLOG_STL_LOGGING_FOR_UNORDERED +# include +# include +#endif + +#ifdef GLOG_STL_LOGGING_FOR_TR1_UNORDERED +# include +# include +#endif + +#ifdef GLOG_STL_LOGGING_FOR_EXT_HASH +# include +# include +#endif +#ifdef GLOG_STL_LOGGING_FOR_EXT_SLIST +# include +#endif + +// Forward declare these two, and define them after all the container streams +// operators so that we can recurse from pair -> container -> container -> pair +// properly. +template +std::ostream& operator<<(std::ostream& out, const std::pair& p); + +namespace google { + +template +void PrintSequence(std::ostream& out, Iter begin, Iter end); + +} + +#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \ +template \ +inline std::ostream& operator<<(std::ostream& out, \ + const Sequence& seq) { \ + google::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ +} + +OUTPUT_TWO_ARG_CONTAINER(std::vector) +OUTPUT_TWO_ARG_CONTAINER(std::deque) +OUTPUT_TWO_ARG_CONTAINER(std::list) +#ifdef GLOG_STL_LOGGING_FOR_EXT_SLIST +OUTPUT_TWO_ARG_CONTAINER(__gnu_cxx::slist) +#endif + +#undef OUTPUT_TWO_ARG_CONTAINER + +#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \ +template \ +inline std::ostream& operator<<(std::ostream& out, \ + const Sequence& seq) { \ + google::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ +} + +OUTPUT_THREE_ARG_CONTAINER(std::set) +OUTPUT_THREE_ARG_CONTAINER(std::multiset) + +#undef OUTPUT_THREE_ARG_CONTAINER + +#define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \ +template \ +inline std::ostream& operator<<(std::ostream& out, \ + const Sequence& seq) { \ + google::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ +} + +OUTPUT_FOUR_ARG_CONTAINER(std::map) +OUTPUT_FOUR_ARG_CONTAINER(std::multimap) +#ifdef GLOG_STL_LOGGING_FOR_UNORDERED +OUTPUT_FOUR_ARG_CONTAINER(std::unordered_set) +OUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset) +#endif +#ifdef GLOG_STL_LOGGING_FOR_TR1_UNORDERED +OUTPUT_FOUR_ARG_CONTAINER(std::tr1::unordered_set) +OUTPUT_FOUR_ARG_CONTAINER(std::tr1::unordered_multiset) +#endif +#ifdef GLOG_STL_LOGGING_FOR_EXT_HASH +OUTPUT_FOUR_ARG_CONTAINER(__gnu_cxx::hash_set) +OUTPUT_FOUR_ARG_CONTAINER(__gnu_cxx::hash_multiset) +#endif + +#undef OUTPUT_FOUR_ARG_CONTAINER + +#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \ +template \ +inline std::ostream& operator<<(std::ostream& out, \ + const Sequence& seq) { \ + google::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ +} + +#ifdef GLOG_STL_LOGGING_FOR_UNORDERED +OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map) +OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap) +#endif +#ifdef GLOG_STL_LOGGING_FOR_TR1_UNORDERED +OUTPUT_FIVE_ARG_CONTAINER(std::tr1::unordered_map) +OUTPUT_FIVE_ARG_CONTAINER(std::tr1::unordered_multimap) +#endif +#ifdef GLOG_STL_LOGGING_FOR_EXT_HASH +OUTPUT_FIVE_ARG_CONTAINER(__gnu_cxx::hash_map) +OUTPUT_FIVE_ARG_CONTAINER(__gnu_cxx::hash_multimap) +#endif + +#undef OUTPUT_FIVE_ARG_CONTAINER + +template +inline std::ostream& operator<<(std::ostream& out, + const std::pair& p) { + out << '(' << p.first << ", " << p.second << ')'; + return out; +} + +namespace google { + +template +inline void PrintSequence(std::ostream& out, Iter begin, Iter end) { + // Output at most 100 elements -- appropriate if used for logging. + for (int i = 0; begin != end && i < 100; ++i, ++begin) { + if (i > 0) out << ' '; + out << *begin; + } + if (begin != end) { + out << " ..."; + } +} + +} + +// Note that this is technically undefined behavior! We are adding things into +// the std namespace for a reason though -- we are providing new operations on +// types which are themselves defined with this namespace. Without this, these +// operator overloads cannot be found via ADL. If these definitions are not +// found via ADL, they must be #included before they're used, which requires +// this header to be included before apparently independent other headers. +// +// For example, base/logging.h defines various template functions to implement +// CHECK_EQ(x, y) and stream x and y into the log in the event the check fails. +// It does so via the function template MakeCheckOpValueString: +// template +// void MakeCheckOpValueString(strstream* ss, const T& v) { +// (*ss) << v; +// } +// Because 'glog/logging.h' is included before 'glog/stl_logging.h', +// subsequent CHECK_EQ(v1, v2) for vector<...> typed variable v1 and v2 can only +// find these operator definitions via ADL. +// +// Even this solution has problems -- it may pull unintended operators into the +// namespace as well, allowing them to also be found via ADL, and creating code +// that only works with a particular order of includes. Long term, we need to +// move all of the *definitions* into namespace std, bet we need to ensure no +// one references them first. This lets us take that step. We cannot define them +// in both because that would create ambiguous overloads when both are found. +namespace std { using ::operator<<; } + +#endif // UTIL_GTL_STL_LOGGING_INL_H_ diff --git a/third_party/include/glog/vlog_is_on.h b/third_party/include/glog/vlog_is_on.h new file mode 100644 index 0000000..02b0b86 --- /dev/null +++ b/third_party/include/glog/vlog_is_on.h @@ -0,0 +1,129 @@ +// Copyright (c) 1999, 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Ray Sidney and many others +// +// Defines the VLOG_IS_ON macro that controls the variable-verbosity +// conditional logging. +// +// It's used by VLOG and VLOG_IF in logging.h +// and by RAW_VLOG in raw_logging.h to trigger the logging. +// +// It can also be used directly e.g. like this: +// if (VLOG_IS_ON(2)) { +// // do some logging preparation and logging +// // that can't be accomplished e.g. via just VLOG(2) << ...; +// } +// +// The truth value that VLOG_IS_ON(level) returns is determined by +// the three verbosity level flags: +// --v= Gives the default maximal active V-logging level; +// 0 is the default. +// Normally positive values are used for V-logging levels. +// --vmodule= Gives the per-module maximal V-logging levels to override +// the value given by --v. +// E.g. "my_module=2,foo*=3" would change the logging level +// for all code in source files "my_module.*" and "foo*.*" +// ("-inl" suffixes are also disregarded for this matching). +// +// SetVLOGLevel helper function is provided to do limited dynamic control over +// V-logging by overriding the per-module settings given via --vmodule flag. +// +// CAVEAT: --vmodule functionality is not available in non gcc compilers. +// + +#ifndef BASE_VLOG_IS_ON_H_ +#define BASE_VLOG_IS_ON_H_ + +#include "glog/log_severity.h" + +// Annoying stuff for windows -- makes sure clients can import these functions +#ifndef GOOGLE_GLOG_DLL_DECL +# if defined(_WIN32) && !defined(__CYGWIN__) +# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport) +# else +# define GOOGLE_GLOG_DLL_DECL +# endif +#endif + +#if defined(__GNUC__) +// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site. +// (Normally) the first time every VLOG_IS_ON(n) site is hit, +// we determine what variable will dynamically control logging at this site: +// it's either FLAGS_v or an appropriate internal variable +// matching the current source file that represents results of +// parsing of --vmodule flag and/or SetVLOGLevel calls. +#define VLOG_IS_ON(verboselevel) \ + __extension__ \ + ({ static google::int32* vlocal__ = &google::kLogSiteUninitialized; \ + google::int32 verbose_level__ = (verboselevel); \ + (*vlocal__ >= verbose_level__) && \ + ((vlocal__ != &google::kLogSiteUninitialized) || \ + (google::InitVLOG3__(&vlocal__, &FLAGS_v, \ + __FILE__, verbose_level__))); }) +#else +// GNU extensions not available, so we do not support --vmodule. +// Dynamic value of FLAGS_v always controls the logging level. +#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel)) +#endif + +// Set VLOG(_IS_ON) level for module_pattern to log_level. +// This lets us dynamically control what is normally set by the --vmodule flag. +// Returns the level that previously applied to module_pattern. +// NOTE: To change the log level for VLOG(_IS_ON) sites +// that have already executed after/during InitGoogleLogging, +// one needs to supply the exact --vmodule pattern that applied to them. +// (If no --vmodule pattern applied to them +// the value of FLAGS_v will continue to control them.) +extern GOOGLE_GLOG_DLL_DECL int SetVLOGLevel(const char* module_pattern, + int log_level); + +// Various declarations needed for VLOG_IS_ON above: ========================= + +// Special value used to indicate that a VLOG_IS_ON site has not been +// initialized. We make this a large value, so the common-case check +// of "*vlocal__ >= verbose_level__" in VLOG_IS_ON definition +// passes in such cases and InitVLOG3__ is then triggered. +extern google::int32 kLogSiteUninitialized; + +// Helper routine which determines the logging info for a particalur VLOG site. +// site_flag is the address of the site-local pointer to the controlling +// verbosity level +// site_default is the default to use for *site_flag +// fname is the current source file name +// verbose_level is the argument to VLOG_IS_ON +// We will return the return value for VLOG_IS_ON +// and if possible set *site_flag appropriately. +extern GOOGLE_GLOG_DLL_DECL bool InitVLOG3__( + google::int32** site_flag, + google::int32* site_default, + const char* fname, + google::int32 verbose_level); + +#endif // BASE_VLOG_IS_ON_H_ diff --git a/third_party/include/hermes/Support/Config.h b/third_party/include/hermes/Support/Config.h deleted file mode 100644 index f788cd4..0000000 --- a/third_party/include/hermes/Support/Config.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -// This file is processed by CMake. -// See https://cmake.org/cmake/help/v3.0/command/configure_file.html. - -#ifndef HERMES_SUPPORT_CONFIG_H -#define HERMES_SUPPORT_CONFIG_H - -/* - * These values are automatically set according to their cmake variables. - */ - -/// Is std::is_trivially_copyable<> implemented. -#define HAVE_IS_TRIVIALLY_COPYABLE - -#endif // HERMES_SUPPORT_CONFIG_H diff --git a/third_party/include/libevent/event2/event-config.h b/third_party/include/libevent/event2/event-config.h new file mode 100644 index 0000000..2741ded --- /dev/null +++ b/third_party/include/libevent/event2/event-config.h @@ -0,0 +1,9 @@ +#include + +#if SIZE_MAX == UINT64_MAX +#define EVENT__SIZEOF_SIZE_T 8 +#elif SIZE_MAX == UINT32_MAX +#define EVENT__SIZEOF_SIZE_T 4 +#else +#error "No way to infer sizeof size_t" +#endif diff --git a/third_party/include/llvh/Config/config.h b/third_party/include/llvh/Config/config.h deleted file mode 100644 index 5ebb8c9..0000000 --- a/third_party/include/llvh/Config/config.h +++ /dev/null @@ -1,347 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -/* Exported configuration */ -#include "llvh/Config/llvm-config.h" - -/* Bug report URL. */ -#define BUG_REPORT_URL "" - -/* Define to 1 to enable backtraces, and to 0 otherwise. */ -#define ENABLE_BACKTRACES 0 - -/* Define to 1 to enable crash overrides, and to 0 otherwise. */ -#define ENABLE_CRASH_OVERRIDES 0 - -/* Define to 1 to enable crash memory dumps, and to 0 otherwise. */ -#define LLVM_ENABLE_CRASH_DUMPS 0 - -/* Define to 1 if you have the `backtrace' function. */ -/* #undef HAVE_BACKTRACE */ - -#define BACKTRACE_HEADER - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_CRASHREPORTERCLIENT_H */ - -/* can use __crashreporter_info__ */ -#define HAVE_CRASHREPORTER_INFO 0 - -/* Define to 1 if you have the declaration of `arc4random', and to 0 if you - don't. */ -#define HAVE_DECL_ARC4RANDOM 1 - -/* Define to 1 if you have the declaration of `FE_ALL_EXCEPT', and to 0 if you - don't. */ -#define HAVE_DECL_FE_ALL_EXCEPT 1 - -/* Define to 1 if you have the declaration of `FE_INEXACT', and to 0 if you - don't. */ -#define HAVE_DECL_FE_INEXACT 1 - -/* Define to 1 if you have the declaration of `strerror_s', and to 0 if you - don't. */ -#define HAVE_DECL_STRERROR_S 0 - -/* Define to 1 if you have the DIA SDK installed, and to 0 if you don't. */ -#define LLVM_ENABLE_DIA_SDK 0 - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define if dlopen() is available on this platform. */ -#define HAVE_DLOPEN 1 - -/* Define if dladdr() is available on this platform. */ -#define HAVE_DLADDR 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_FENV_H 1 - -/* Define if libffi is available on this platform. */ -/* #undef HAVE_FFI_CALL */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_FFI_FFI_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_FFI_H */ - -/* Define to 1 if you have the `futimens' function. */ -/* #undef HAVE_FUTIMENS */ - -/* Define to 1 if you have the `futimes' function. */ -/* #undef HAVE_FUTIMES */ - -/* Define to 1 if you have the `getpagesize' function. */ -#define HAVE_GETPAGESIZE 1 - -/* Define to 1 if you have the `getrlimit' function. */ -#define HAVE_GETRLIMIT 1 - -/* Define to 1 if you have the `getrusage' function. */ -#define HAVE_GETRUSAGE 1 - -/* Define to 1 if you have the `isatty' function. */ -#define HAVE_ISATTY 1 - -/* Define to 1 if you have the `edit' library (-ledit). */ -/* #undef HAVE_LIBEDIT */ - -/* Define to 1 if you have the `pfm' library (-lpfm). */ -/* #undef HAVE_LIBPFM */ - -/* Define to 1 if you have the `psapi' library (-lpsapi). */ -/* #undef HAVE_LIBPSAPI */ - -/* Define to 1 if you have the `pthread' library (-lpthread). */ -/* #undef HAVE_LIBPTHREAD */ - -/* Define to 1 if you have the `pthread_getname_np' function. */ -/* #undef HAVE_PTHREAD_GETNAME_NP */ - -/* Define to 1 if you have the `pthread_setname_np' function. */ -#define HAVE_PTHREAD_SETNAME_NP 1 - -/* Define to 1 if you have the `z' library (-lz). */ -/* #undef HAVE_LIBZ */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LINK_H */ - -/* Define to 1 if you have the `lseek64' function. */ -/* #undef HAVE_LSEEK64 */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MACH_MACH_H */ - -/* Define to 1 if you have the `mallctl' function. */ -/* #undef HAVE_MALLCTL */ - -/* Define to 1 if you have the `mallinfo' function. */ -/* #undef HAVE_MALLINFO */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MALLOC_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MALLOC_MALLOC_H */ - -/* Define to 1 if you have the `malloc_zone_statistics' function. */ -/* #undef HAVE_MALLOC_ZONE_STATISTICS */ - -/* Define to 1 if you have the `posix_fallocate' function. */ -/* #undef HAVE_POSIX_FALLOCATE */ - -/* Define to 1 if you have the `posix_spawn' function. */ -/* #undef HAVE_POSIX_SPAWN */ - -/* Define to 1 if you have the `pread' function. */ -#define HAVE_PREAD 1 - -/* Have pthread_getspecific */ -#define HAVE_PTHREAD_GETSPECIFIC 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_PTHREAD_H 1 - -/* Have pthread_mutex_lock */ -#define HAVE_PTHREAD_MUTEX_LOCK 1 - -/* Have pthread_rwlock_init */ -#define HAVE_PTHREAD_RWLOCK_INIT 1 - -/* Define to 1 if you have the `realpath' function. */ -#define HAVE_REALPATH 1 - -/* Define to 1 if you have the `sbrk' function. */ -#define HAVE_SBRK 1 - -/* Define to 1 if you have the `setenv' function. */ -#define HAVE_SETENV 1 - -/* Define to 1 if you have the `sched_getaffinity' function. */ -/* #undef HAVE_SCHED_GETAFFINITY */ - -/* Define to 1 if you have the `CPU_COUNT' macro. */ -/* #undef HAVE_CPU_COUNT */ - -/* Define to 1 if you have the `setrlimit' function. */ -#define HAVE_SETRLIMIT 1 - -/* Define to 1 if you have the `sigaltstack' function. */ -/* #undef HAVE_SIGALTSTACK */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define to 1 if you have the `strerror' function. */ -#define HAVE_STRERROR 1 - -/* Define to 1 if you have the `strerror_r' function. */ -#define HAVE_STRERROR_R 1 - -/* Define to 1 if you have the `sysconf' function. */ -#define HAVE_SYSCONF 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_MMAN_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_PARAM_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_RESOURCE_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define if the setupterm() function is supported this platform. */ -/* #undef HAVE_TERMINFO */ - -/* Define if the xar_open() function is supported this platform. */ -/* #undef HAVE_LIBXAR */ - -/* Define to 1 if you have the header file. */ -#define HAVE_TERMIOS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_VALGRIND_VALGRIND_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_ZLIB_H 1 - -/* Have host's _alloca */ -/* #undef HAVE__ALLOCA */ - -/* Define to 1 if you have the `_chsize_s' function. */ -/* #undef HAVE__CHSIZE_S */ - -/* Define to 1 if you have the `_Unwind_Backtrace' function. */ -/* #undef HAVE__UNWIND_BACKTRACE */ - -/* Have host's __alloca */ -/* #undef HAVE___ALLOCA */ - -/* Have host's __ashldi3 */ -/* #undef HAVE___ASHLDI3 */ - -/* Have host's __ashrdi3 */ -/* #undef HAVE___ASHRDI3 */ - -/* Have host's __chkstk */ -/* #undef HAVE___CHKSTK */ - -/* Have host's __chkstk_ms */ -/* #undef HAVE___CHKSTK_MS */ - -/* Have host's __cmpdi2 */ -/* #undef HAVE___CMPDI2 */ - -/* Have host's __divdi3 */ -/* #undef HAVE___DIVDI3 */ - -/* Have host's __fixdfdi */ -/* #undef HAVE___FIXDFDI */ - -/* Have host's __fixsfdi */ -/* #undef HAVE___FIXSFDI */ - -/* Have host's __floatdidf */ -/* #undef HAVE___FLOATDIDF */ - -/* Have host's __lshrdi3 */ -/* #undef HAVE___LSHRDI3 */ - -/* Have host's __main */ -/* #undef HAVE___MAIN */ - -/* Have host's __moddi3 */ -/* #undef HAVE___MODDI3 */ - -/* Have host's __udivdi3 */ -/* #undef HAVE___UDIVDI3 */ - -/* Have host's __umoddi3 */ -/* #undef HAVE___UMODDI3 */ - -/* Have host's ___chkstk */ -/* #undef HAVE____CHKSTK */ - -/* Have host's ___chkstk_ms */ -/* #undef HAVE____CHKSTK_MS */ - -/* Linker version detected at compile time. */ -/* #undef HOST_LINK_VERSION */ - -/* Target triple LLVM will generate code for by default */ -/* Doesn't use `cmakedefine` because it is allowed to be empty. */ -#define LLVM_DEFAULT_TARGET_TRIPLE "" - -/* Define if zlib compression is available */ -#define LLVM_ENABLE_ZLIB 0 - -/* Define if overriding target triple is enabled */ -/* #undef LLVM_TARGET_TRIPLE_ENV */ - -/* LLVM version information */ -/* #undef LLVM_VERSION_INFO */ - -/* Whether tools show host and target info when invoked with --version */ -#define LLVM_VERSION_PRINTER_SHOW_HOST_TARGET_INFO 0 - -/* Define if libxml2 is supported on this platform. */ -/* #undef LLVM_LIBXML2_ENABLED */ - -/* Define to the extension used for shared libraries, say, ".so". */ -/* #undef LTDL_SHLIB_EXT */ - -/* Define to the address where bug reports for this package should be sent. */ -/* #undef PACKAGE_BUGREPORT */ - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "LLVH" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "LLVH 8.0.0svn" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "8.0.0svn" - -/* Define to the vendor of this package. */ -/* #undef PACKAGE_VENDOR */ - -/* Define as the return type of signal handlers (`int' or `void'). */ -#define RETSIGTYPE void - -/* Define to a function implementing stricmp */ -/* #undef stricmp */ - -/* Define to a function implementing strdup */ -/* #undef strdup */ - -/* Whether GlobalISel rule coverage is being collected */ -#define LLVM_GISEL_COV_ENABLED 0 - -/* Define to the default GlobalISel coverage file prefix */ -/* #undef LLVM_GISEL_COV_PREFIX */ - -#endif diff --git a/third_party/include/llvh/Config/llvm-config.h b/third_party/include/llvh/Config/llvm-config.h deleted file mode 100644 index 9504b0c..0000000 --- a/third_party/include/llvh/Config/llvm-config.h +++ /dev/null @@ -1,85 +0,0 @@ -/*===------- llvm/Config/llvm-config.h - llvm configuration -------*- C -*-===*/ -/* */ -/* The LLVM Compiler Infrastructure */ -/* */ -/* This file is distributed under the University of Illinois Open Source */ -/* License. See LICENSE.TXT for details. */ -/* */ -/*===----------------------------------------------------------------------===*/ - -/* This file enumerates variables from the LLVM configuration so that they - can be in exported headers and won't override package specific directives. - This is a C header that can be included in the llvm-c headers. */ - -#ifndef LLVM_CONFIG_H -#define LLVM_CONFIG_H - -/* Define if LLVM_ENABLE_DUMP is enabled */ -/* #undef LLVM_ENABLE_DUMP */ - -/* Define if we link Polly to the tools */ -/* #undef LINK_POLLY_INTO_TOOLS */ - -/* Target triple LLVM will generate code for by default */ -/* #undef LLVM_DEFAULT_TARGET_TRIPLE */ - -/* Define if threads enabled */ -#define LLVM_ENABLE_THREADS 1 - -/* Has gcc/MSVC atomic intrinsics */ -#define LLVM_HAS_ATOMICS 1 - -/* Host triple LLVM will be executed on */ -#define LLVM_HOST_TRIPLE "x86_64-apple-darwin20.6.0" - -/* LLVM architecture name for the native architecture, if available */ -/* #undef LLVM_NATIVE_ARCH */ - -/* LLVM name for the native AsmParser init function, if available */ -/* #undef LLVM_NATIVE_ASMPARSER */ - -/* LLVM name for the native AsmPrinter init function, if available */ -/* #undef LLVM_NATIVE_ASMPRINTER */ - -/* LLVM name for the native Disassembler init function, if available */ -/* #undef LLVM_NATIVE_DISASSEMBLER */ - -/* LLVM name for the native Target init function, if available */ -/* #undef LLVM_NATIVE_TARGET */ - -/* LLVM name for the native TargetInfo init function, if available */ -/* #undef LLVM_NATIVE_TARGETINFO */ - -/* LLVM name for the native target MC init function, if available */ -/* #undef LLVM_NATIVE_TARGETMC */ - -/* Define if this is Unixish platform */ -#define LLVM_ON_UNIX 1 - -/* Define if we have the Intel JIT API runtime support library */ -#define LLVM_USE_INTEL_JITEVENTS 0 - -/* Define if we have the oprofile JIT-support library */ -#define LLVM_USE_OPROFILE 0 - -/* Define if we have the perf JIT-support library */ -#define LLVM_USE_PERF 0 - -/* Major version of the LLVM API */ -#define LLVM_VERSION_MAJOR - -/* Minor version of the LLVM API */ -#define LLVM_VERSION_MINOR - -/* Patch version of the LLVM API */ -#define LLVM_VERSION_PATCH - -/* LLVM version string */ -#define LLVM_VERSION_STRING "8.0.0svn" - -/* Whether LLVM records statistics for use with GetStatistics(), - * PrintStatistics() or PrintStatisticsJSON() - */ -#define LLVM_FORCE_ENABLE_STATS 0 - -#endif diff --git a/third_party/include/llvm/llvh/Config/config.h b/third_party/include/llvm/llvh/Config/config.h new file mode 100644 index 0000000..e69de29 diff --git a/third_party/include/llvm/llvh/Config/llvm-config.h b/third_party/include/llvm/llvh/Config/llvm-config.h new file mode 100644 index 0000000..e69de29 diff --git a/third_party/libevent b/third_party/libevent new file mode 160000 index 0000000..5df3037 --- /dev/null +++ b/third_party/libevent @@ -0,0 +1 @@ +Subproject commit 5df3037d10556bfcb675bc73e516978b75fc7bc7 diff --git a/third_party/react-native b/third_party/react-native index e4d576f..a54ba33 160000 --- a/third_party/react-native +++ b/third_party/react-native @@ -1 +1 @@ -Subproject commit e4d576f6556cd3240c46f2e337d3e70495c48e43 +Subproject commit a54ba33305621abb778085fc01ff954b621ce57b diff --git a/toolchain/BUILD.gn b/toolchain/BUILD.gn deleted file mode 100644 index b8c6bea..0000000 --- a/toolchain/BUILD.gn +++ /dev/null @@ -1,147 +0,0 @@ -depfile = "{{output}}.d" -compiler_command = "-c {{source}} -o {{output}} -MMD -MF $depfile {{include_dirs}} {{defines}} {{cflags}}" -if (debug_info) { - compiler_command = string_join(" ", ["-g", compiler_command]) -} -linker_command = "" -if (asan) { - compiler_command = string_join(" ", ["-fsanitize=address", compiler_command]) - linker_command = string_join(" ", [linker_command, "-fsanitize=address"]) -} -if (ubsan) { -# vptr sanitizer 依赖 RTTI,会强制开启所有 RTTI 编译,因此必须关闭 - compiler_command = string_join(" ", ["-fsanitize=undefined", "-fno-sanitize=vptr,function", compiler_command]) - linker_command = string_join(" ", [linker_command, "-fsanitize=undefined"]) -} -stamp_command = "touch {{output}}" - -if (debug) { - compiler_command = string_join(" ", ["-O0", compiler_command]) -} else { -# NDEBUG for assert.h - compiler_command = string_join(" ", ["-Os -DNDEBUG", compiler_command]) - if (lto) { - compiler_command = string_join(" ", ["-flto", compiler_command]) - } -} - -compiler_outputs = [ - "{{source_out_dir}}/{{source_name_part}}.o" -] -linker_outputs = [ - "{{output_dir}}/{{target_output_name}}{{output_extension}}" -] - -# debug -> -O0 -# -> -Os -# lto -> -flto - -# iOS -# debug -> -fembed-bitcode-marker -# -> lto -# -> -fembed-bitcode - -toolchain("android") { - compiler_command = string_join(" ", ["--sysroot $ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/sysroot -funwind-tables -fstack-protector-strong -fPIC", compiler_command]) - if (!lto) { - compiler_command = string_join(" ", ["-fdata-sections -ffunction-sections", compiler_command]) - } - if (cross_compile_target == "armv7") { - compiler_command = string_join(" ", ["-target armv7-none-linux-androideabi18 -mthumb", compiler_command]) - # 涉及链接库搜索路径 - linker_command = string_join(" ", ["-target armv7-none-linux-androideabi18 -mthumb", linker_command]) - } else if (cross_compile_target == "arm64") { - compiler_command = string_join(" ", ["-target aarch64-none-linux-android21", compiler_command]) - linker_command = string_join(" ", ["-target aarch64-none-linux-android21", linker_command]) - } else if (cross_compile_target == "i386") { - compiler_command = string_join(" ", ["-target i686-none-linux-android18 -mstackrealign", compiler_command]) - linker_command = string_join(" ", ["-target i686-none-linux-android18", linker_command]) - } else { - compiler_command = string_join(" ", ["-target x86_64-none-linux-android21", compiler_command]) - linker_command = string_join(" ", ["-target x86_64-none-linux-android21", linker_command]) - } - tool("cc") { - command = string_join(" ", ["$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang", compiler_command, "{{cflags_c}}"]) - outputs = compiler_outputs - } - tool("cxx") { - command = string_join(" ", ["$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++", compiler_command, "{{cflags_cc}}"]) - outputs = compiler_outputs - } - tool("stamp") { - command = stamp_command - } - tool("solink") { - if (debug) { - optimize_level = "-O0" - } else { - optimize_level = "-O3" - } - default_output_extension = ".so" - command = string_join(" ", ["$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang", linker_command, optimize_level, "--sysroot $ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/sysroot -flto -fdata-sections -ffunction-sections -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,--fatal-warnings -Wl,--no-undefined -shared -Wl,-soname,{{target_output_name}}$default_output_extension -o {{output}} {{inputs}} {{libs}} {{ldflags}}"]) - # target 选择 clang 具体工具链,指定 lto 参数 mcpu - # 不能指定 -Os 否则会出错 - default_output_dir = "{{target_out_dir}}" - outputs = linker_outputs - output_prefix = "lib" - } -} - -toolchain("clang") { - if (!lto && bitcode) { - if (debug) { - compiler_command = string_join(" ", ["-fembed-bitcode-marker", compiler_command]) - } else { - compiler_command = string_join(" ", ["-fembed-bitcode", compiler_command]) - } - } - if (code_coverage) { - compiler_command = string_join(" ", ["-fprofile-instr-generate -fcoverage-mapping", compiler_command]) - } - if (build_ios) { - target_option = "-target $cross_compile_target-apple-ios9.0" - if (cross_compile_target == "i386" || cross_compile_target == "x86_64") { - target_option = string_join("-", [target_option, "simulator"]) - compiler_command = string_join(" ", ["-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk", compiler_command]) - } else { - compiler_command = string_join(" ", ["-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk", compiler_command]) - } - compiler_command = string_join(" ", [target_option, compiler_command]) - } - - tool("cc") { - command = string_join(" ", ["clang", compiler_command, "{{cflags_c}}"]) - # depsformat = "gcc" - outputs = compiler_outputs - } - - tool("cxx") { - command = string_join(" ", ["clang++", compiler_command, "{{cflags_cc}}"]) - # 默认 C++98 + libc++ - outputs = compiler_outputs - } - - tool("stamp") { - command = stamp_command - } - - tool("link") { - command = string_join(" ", ["clang", linker_command, "-o {{output}} {{inputs}} {{frameworks}} {{ldflags}}"]) - # 目前只用于单元测试,可以关闭 -fembed-bitcode 并使用 clang++ - # /tmp/lto.o 丢失会导致 dsymutil 无法生成 dSYM - # -Xlinker -object_path_lto -Xlinker {{output_dir}}/{{target_output_name}}_lto.o - if (code_coverage) { - command = string_join(" ", [command, "-fprofile-instr-generate"]) - } - default_output_dir = "{{root_out_dir}}" - outputs = linker_outputs - } - - tool("alink") { - command = "libtool -static -o {{output}} {{inputs}}" - default_output_dir = "{{target_out_dir}}" - outputs = linker_outputs - default_output_extension = ".a" - output_prefix = "lib" - } -}