From 56195b6e3c9ce1cb0977d5d9a69ad0bdb3b930fd Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Thu, 18 Aug 2022 16:19:58 +0800 Subject: [PATCH 01/25] feat: Update google test. 1. Format gn file. 2. Update BUILDCONFIG.gn and toolchain/BUILD.gn. --- .gn | 2 +- BUILDCONFIG.gn | 65 ++++++++----- third_party/googletest | 2 +- toolchain/BUILD.gn | 209 +++++++++++++++++++++-------------------- 4 files changed, 146 insertions(+), 132 deletions(-) diff --git a/.gn b/.gn index 2c50d77..9fe0b42 100644 --- a/.gn +++ b/.gn @@ -1 +1 @@ -buildconfig = "//BUILDCONFIG.gn" \ No newline at end of file +buildconfig = "//BUILDCONFIG.gn" diff --git a/BUILDCONFIG.gn b/BUILDCONFIG.gn index 6e06bb2..2973fff 100644 --- a/BUILDCONFIG.gn +++ b/BUILDCONFIG.gn @@ -1,36 +1,49 @@ +if (target_os == "") { + target_os = host_os +} +if (target_cpu == "") { + target_cpu = host_cpu +} + +assert(target_os == "android" || target_os == "ios" || target_os == "mac", + "Unsupported target os.") +assert(target_cpu == "arm" || target_cpu == "arm64" || target_cpu == "x86" || + target_cpu == "x64", + "Unsupported target cpu.") + declare_args() { - # -g - debug_info = true - # -Os/-O0 - debug = false - # 只有 debug=false 的情况才生效 - lto = true - # iOS 平台不开启 lto 的情况下才生效,和 debug 无关 - bitcode = true + generate_dwarf = true + is_debug = false - # 是否交叉编译 Android 动态库 - build_android = false - # NDK 路径 + if (target_os == "android") { ndk_path = "~/Library/Android/sdk/ndk/21.4.7075529" + } else { + collect_code_coverage = false + } + asan = false + ubsan = false - # 交叉编译 iOS Android 生效 - cross_compile_target = "x86_64" + enable_qjs_big_number = false +} - # 暂时只对 clang 工具链有效 - code_coverage = false - asan = false - ubsan = false +declare_args() { + if (!is_debug) { + lto = true + } +} - # iOS 交叉编译,否则编译 macOS 版本 - build_ios = false - # 和 -apple-ios9.0 拼接,作为 -target 参数 +have_bitcode_flag = + target_os == "ios" && (target_cpu == "arm" || target_cpu == "arm64") && + !is_debug && !lto - # QuickJS 专属 - big_number = false +declare_args() { + if (have_bitcode_flag) { + bitcode = true + } } -if (build_android) { - set_default_toolchain("//toolchain:android") +if (target_os == "android") { + set_default_toolchain("//toolchain:android") } else { - set_default_toolchain("//toolchain:clang") -} \ No newline at end of file + set_default_toolchain("//toolchain:clang") +} 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/toolchain/BUILD.gn b/toolchain/BUILD.gn index b8c6bea..3b20d3f 100644 --- a/toolchain/BUILD.gn +++ b/toolchain/BUILD.gn @@ -1,147 +1,148 @@ -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]) +# -fPIC -funwind-tables 在大部分平台都是默认开启,除了 PowerPC 32 bit 的平台等少数情况 +# -MMD 收集的用户头文件就足够了 +compiler_command = "-c {{source}} -o {{output}} -MMD -MF {{output}}.d {{include_dirs}} {{defines}} {{cflags}}" +if (generate_dwarf) { + compiler_command = "-g $compiler_command" } linker_command = "" if (asan) { - compiler_command = string_join(" ", ["-fsanitize=address", compiler_command]) - linker_command = string_join(" ", [linker_command, "-fsanitize=address"]) + compiler_command = "-fsanitize=address $compiler_command" + linker_command = "-fsanitize=address $linker_command" } 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"]) + compiler_command = "-fsanitize=undefined $compiler_command" + linker_command = "-fsanitize=undefined $linker_command" } -stamp_command = "touch {{output}}" -if (debug) { - compiler_command = string_join(" ", ["-O0", compiler_command]) +if (!is_debug) { + # NDEBUG for assert.h + compiler_command = "-Os -DNDEBUG $compiler_command" + if (lto) { + compiler_command = "-flto $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_command = "-O0 $compiler_command" } -compiler_outputs = [ - "{{source_out_dir}}/{{source_name_part}}.o" -] -linker_outputs = [ - "{{output_dir}}/{{target_output_name}}{{output_extension}}" -] +compiler_outputs = [ "{{source_out_dir}}/{{source_name_part}}.o" ] +linker_outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ] + +if (target_os == "android") { + toolchain("android") { + sysroot_path = "$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/sysroot" + compiler_command = "--sysroot $sysroot_path $compiler_command" -# debug -> -O0 -# -> -Os -# lto -> -flto + # -fdata-sections 和 -ffunction-sections 原则上应当和链接器的 -Wl,–gc-sections 配合使用缩小包体积 + object_generate_option = "-fdata-sections -ffunction-sections" -# iOS -# debug -> -fembed-bitcode-marker -# -> lto -# -> -fembed-bitcode + if (target_cpu == "arm") { + target_option = "-target armv7-none-linux-androideabi18 -thumb" + } else if (target_cpu == "arm64") { + target_option = "-target aarch64-none-linux-android21" + } else if (target_cpu == "x86") { + target_option = "-target i686-none-linux-android18" + } else { + target_option = "-target x86_64-none-linux-android21" + } -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]) + compiler_command = "$target_option $compiler_command" + if (linker_command == "") { + linker_command = target_option + } else { + linker_command = "$target_option $linker_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]) + + if (is_debug || !lto) { + compiler_command = "$object_generate_option $compiler_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]) + linker_command = "$linker_command $object_generate_option" } + tool("cc") { - command = string_join(" ", ["$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang", compiler_command, "{{cflags_c}}"]) - outputs = compiler_outputs + command = "$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang $compiler_command {{cflags_c}}" + depfile = "{{output}}.d" + depsformat = "gcc" + 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 + command = "$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++ $compiler_command {{cflags_cc}}" + depfile = "{{output}}.d" + depsformat = "gcc" + outputs = compiler_outputs } tool("stamp") { - command = stamp_command + command = "touch {{output}}" } 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" + if (!is_debug) { + # NDK 链接器 LTO 插件问题 + optimize_level = "-O3" + } + default_output_extension = ".so" + # target 选择 clang 具体工具链,指定 lto 参数 mcpu + command = "$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang $linker_command $optimize_level --sysroot $sysroot_path -flto -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,--no-undefined -shared -Wl,-soname,{{target_output_name}}$default_output_extension -o {{output}} {{inputs}} {{libs}} {{ldflags}}" + 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]) - } + } +} else { + toolchain("clang") { + if (have_bitcode_flag) { + compiler_command = "-fembed-bitcode $compiler_command" } - if (code_coverage) { - compiler_command = string_join(" ", ["-fprofile-instr-generate -fcoverage-mapping", compiler_command]) + if (collect_code_coverage) { + compiler_command = + "-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]) + if (target_os == "ios") { + if (target_cpu == "x86") { + compiler_command = "-target i386-apple-ios9.0-simulator -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk $compiler_command" + } else if (target_cpu == "x64") { + compiler_command = "-target x86_64-apple-ios9.0-simulator -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk $compiler_command" + } else if (target_cpu == "arm") { + compiler_command = "-target armv7-apple-ios9.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk $compiler_command" + } else { + compiler_command = "-target arm64-apple-ios9.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk $compiler_command" + } } tool("cc") { - command = string_join(" ", ["clang", compiler_command, "{{cflags_c}}"]) - # depsformat = "gcc" - outputs = compiler_outputs + command = "clang $compiler_command {{cflags_c}}" + depfile = "{{output}}.d" + depsformat = "gcc" + outputs = compiler_outputs } tool("cxx") { - command = string_join(" ", ["clang++", compiler_command, "{{cflags_cc}}"]) - # 默认 C++98 + libc++ - outputs = compiler_outputs + command = "clang++ $compiler_command {{cflags_cc}}" + depfile = "{{output}}.d" + depsformat = "gcc" + outputs = compiler_outputs } tool("stamp") { - command = stamp_command + command = "touch {{output}}" } 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 + command = "clang $linker_command -o {{output}} {{inputs}} {{frameworks}} {{ldflags}}" + + # /tmp/lto.o 丢失会导致 dsymutil 无法生成 dSYM + # -Xlinker -object_path_lto -Xlinker {{output_dir}}/{{target_output_name}}_lto.o + if (collect_code_coverage) { + command = "$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" + command = "libtool -static -o {{output}} {{inputs}}" + default_output_dir = "{{target_out_dir}}" + outputs = linker_outputs + default_output_extension = ".a" + output_prefix = "lib" } + } } From 7a092b81139d1ecdf50f4997db50ddcd9121a09d Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Fri, 19 Aug 2022 14:45:49 +0800 Subject: [PATCH 02/25] feat: Update hermes. 1. Cleanup llvm config.h and llvm-config.h. --- third_party/hermes | 2 +- third_party/include/llvh/Config/config.h | 347 ------------------ third_party/include/llvh/Config/llvm-config.h | 85 ----- 3 files changed, 1 insertion(+), 433 deletions(-) diff --git a/third_party/hermes b/third_party/hermes index 0bac657..ee8941b 160000 --- a/third_party/hermes +++ b/third_party/hermes @@ -1 +1 @@ -Subproject commit 0bac657c61ac47a3a9537d982921f5f6c9630d41 +Subproject commit ee8941b8874132b8f83e4486b63ed5c19fc3f111 diff --git a/third_party/include/llvh/Config/config.h b/third_party/include/llvh/Config/config.h index 5ebb8c9..e69de29 100644 --- a/third_party/include/llvh/Config/config.h +++ b/third_party/include/llvh/Config/config.h @@ -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 index 9504b0c..e69de29 100644 --- a/third_party/include/llvh/Config/llvm-config.h +++ b/third_party/include/llvh/Config/llvm-config.h @@ -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 From 27ebab4b8becc015301c24d2a13a25dc49adb05d Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Sat, 20 Aug 2022 15:59:33 +0800 Subject: [PATCH 03/25] feat: Complete basic BUILD.gn file. 1. Remove cmake generated hermes/Support/Config.h file. 2. Update README.md. 3. Format toolchain/BUILD.gn. --- BUILD.gn | 1554 ++++++++----------- README.md | 6 +- third_party/include/hermes/Support/Config.h | 21 - toolchain/BUILD.gn | 1 + 4 files changed, 645 insertions(+), 937 deletions(-) delete mode 100644 third_party/include/hermes/Support/Config.h diff --git a/BUILD.gn b/BUILD.gn index 73034e5..9d81d9c 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1,983 +1,711 @@ -config("minimal_size_build") { - cflags_cc = ["-fno-exceptions", "-fno-rtti"] -} - -config("standard_build") { - configs = [":minimal_size_build"] - cflags_cc = ["-std=c++11"] -} - -config("new_build") { - configs = [":minimal_size_build"] - cflags_cc = ["-std=c++14"] -} - config("strict_build") { - cflags = ["-Wall", "-Wextra", "-Werror", "-Wpedantic"] + 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"] -} - -config("new_rtti_build") { - configs = [":rtti_build"] - cflags_cc = ["-std=c++14"] -} - -config("new_exception_build") { - configs = [":exception_build"] - cflags_cc = ["-std=c++14"] -} - -config("new_exception_rtti_build") { - configs = [":exception_rtti_build"] - cflags_cc = ["-std=c++14"] +config("minimal_size_build") { + cflags_cc = [ + "-fno-exceptions", + "-fno-rtti", + ] } -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("quickjs_build") { + include_dirs = [ "third_party/quickjs" ] + cflags_c = [ "-funsigned-char" ] } -config("common_build") { - include_dirs = ["third_party/include"] +source_set("quickjs_source_set") { + configs = [ ":quickjs_build" ] + defines = [ "CONFIG_VERSION=\"2021-03-27\"" ] + 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("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"] + include_dirs = [ + "third_party/hermes/external/llvh/include", + "third_party/include", + "third_party/hermes/external/llvh/gen/include", + ] + 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=0", + "HAVE_GETPAGESIZE", # Process.inc:82 + "HAVE_FCNTL_H=1", # Process.inc:216 + "HAVE_SIGNAL_H=1", # Process.inc:232 + "RETSIGTYPE=void", + ] +} + +config("cpp_new_build") { + cflags_cc = [ + # 主要因为 NDK 目前暂时不支持 C++20 + "-std=c++17", + "-fvisibility=hidden", + ] } 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"] + configs = [ + ":minimal_size_build", + ":llvm_build", + ":cpp_new_build", + ] + sources = [ + "third_party/hermes/external/llvh/lib/Demangle/ItaniumDemangle.cpp", + "third_party/hermes/external/llvh/lib/Demangle/MicrosoftDemangle.cpp", + "third_party/hermes/external/llvh/lib/Demangle/MicrosoftDemangleNodes.cpp", + ] } 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", - ] -} - -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" - ] -} - -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", - ] -} - -config("fbjni_build") { - include_dirs = [ - "third_party/hermes/first-party/fbjni/cxx" - ] + configs = [ + ":minimal_size_build", + ":llvm_build", + ":cpp_new_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", + ] } -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_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("dtoa") { + 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", + ] } -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" - ] +config("hermes_build") { + 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", + ] + 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_platform") { - configs = [":standard_build", ":hermes_build", ":llvm_build"] - sources = [ - "third_party/hermes/lib/Platform/Logging.cpp" - ] +source_set("hermes_adt") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":cpp_new_build", + ] + sources = [ "third_party/hermes/lib/ADT/CompactArray.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", - ] + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":cpp_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", + ] } -config("jsi_build") { - include_dirs = ["third_party/hermes/API/jsi"] +source_set("hermes_backend") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":cpp_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("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_frontend_defs") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ] + cflags_cc = [ "-fvisibility=hidden" ] + sources = [ "third_party/hermes/lib/FrontEndDefs/Builtins.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", - ] + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":cpp_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_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_hbc_backend") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":cpp_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_adt") { - configs = [":standard_build", ":llvm_build", ":hermes_build"] - sources = [ - "third_party/hermes/lib/ADT/CompactArray.cpp" - ] +source_set("hermes_inst") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":cpp_new_build", + ] + sources = [ + "third_party/hermes/lib/Inst/InstDecode.cpp", + "third_party/hermes/lib/Inst/InstDecode2.cpp", + ] } -config("dtoa_build") { - include_dirs = ["third_party/hermes/external"] +source_set("hermes_internal_bytecode") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":cpp_new_build", + ] + defines = [ "HERMES_CMAKE_BUILD" ] + sources = [ "third_party/hermes/lib/InternalBytecode/InternalBytecode.cpp" ] } -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_optimizer") { + configs = [ + ":minimal_size_build", + ":llvm_build", + ":hermes_build", + ":cpp_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_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" - ] +source_set("hermes_parser") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":cpp_new_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-ts.cpp", + "third_party/hermes/lib/Parser/JSParserImpl.cpp", + "third_party/hermes/lib/Parser/rust-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" - ] +source_set("hermes_platform") { + configs = [ + ":minimal_size_build", + ":llvm_build", + ":hermes_build", + ":cpp_new_build", + ] + sources = [ "third_party/hermes/lib/Platform/Logging.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_platform_unicode") { + configs = [ + ":minimal_size_build", + ":llvm_build", + ":hermes_build", + ":cpp_new_build", + ] + sources = + [ "third_party/hermes/lib/Platform/Unicode/CharacterProperties.cpp" ] + if (target_os != "android") { + sources += + [ "third_party/hermes/lib/Platform/Unicode/PlatformUnicodeCF.cpp" ] + frameworks = [ "CoreFoundation.framework" ] + } } -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_regex") { + configs = [ + ":minimal_size_build", + ":llvm_build", + ":hermes_build", + ":cpp_new_build", + ] + sources = [ + "third_party/hermes/lib/Regex/Executor.cpp", + "third_party/hermes/lib/Regex/RegexParser.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("hermes_source_map") { + configs = [ + ":minimal_size_build", + ":llvm_build", + ":hermes_build", + ":cpp_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_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" - ] +source_set("hermes_support") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":cpp_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/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_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" - ] -} - -config("jsi_hermes_build") { - configs = [":jsi_build"] - include_dirs = ["third_party/hermes/API"] + configs = [ + ":minimal_size_build", + ":hermes_build", + + ":llvm_build", + ":cpp_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/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/DecoratedObject.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/HostModel.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/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/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/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_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("napi_qjs_source_set") { + configs = [ + ":quickjs_build", + ":strict_build", + ] + include_dirs = [ "include" ] + cflags_c = [ + "-fvisibility=hidden", -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" - ] + # TODO(Chason): QuickJS 头文件内联函数 + "-Wno-unused-parameter", + "-Wno-pedantic", + ] + sources = [ "src/js_native_api_qjs.c" ] } -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"] +source_set("napi_common") { + configs = [ ":strict_build" ] + include_dirs = [ "include" ] + cflags_c = [ "-fvisibility=hidden" ] + sources = [ "src/js_native_api_common.c" ] +} + +if (target_os != "android") { + source_set("napi_jsc_source_set") { + 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", + ] } - # 依赖 DoubleConversion glog - include_dirs = ["third_party/folly", "third_party/boost-for-react-native"] -} - -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" - ] -} -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("jsinspector") { - configs = [":new_build"] - # Android 需要 getInspectorInstance 方法,而该方法没有被标记为 JSINSPECTOR_EXPORT,因此需要去除 -fvisibility=hidden - if (!build_android) { - cflags_cc = ["-fvisibility=hidden"] + static_library("qjs") { + complete_static_lib = true + deps = [ + ":napi_common", + ":napi_qjs_source_set", + ":quickjs_source_set", + ] } - sources = [ - "third_party/react-native/ReactCommon/jsinspector/InspectorInterfaces.cpp" - ] -} - -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"] -} - -config("react_native_common_build") { - include_dirs = ["third_party/react-native/ReactCommon"] -} - -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"] + } 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", + ] } - sources = [ - "src/inspector/js_native_api_hermes_inspector.cpp" - ] -} - -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"] + 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" ] + sources = [ + "test/callable.cpp", + "test/conversion.cpp", + "test/general.cpp", + "test/object.cpp", + "test/reference.cpp", + "test/test.cpp", + "test/typeof.cpp", + ] + deps = [ ":gtest" ] } - 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"] + executable("test_jsc") { + testonly = true + ldflags = [ "-lc++" ] + deps = [ + ":napi_common", + ":napi_jsc_source_set", + ":test", + ] } - 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" - ] -} - -config("napi_build") { - include_dirs = [ - "include" - ] -} - -config("quickjs_build") { - include_dirs = [ - "third_party/quickjs" - ] - # TBD(ChasonTang): 是否可以干掉? - cflags_c = ["-funsigned-char"] -} - -source_set("cutils") { - configs = [":quickjs_build"] - sources = [ - "third_party/quickjs/cutils.c", - ] -} - -source_set("unicode") { - configs = [":quickjs_build"] - sources = [ - "third_party/quickjs/libunicode.c" - ] -} - -source_set("regexp") { - configs = [":quickjs_build"] - sources = [ - "third_party/quickjs/libregexp.c" - ] -} -source_set("bf") { - configs = [":quickjs_build"] - sources = [ - "third_party/quickjs/libbf.c" - ] -} - -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" - ] - } - 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"] - } - } - 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", - ] + executable("test_qjs") { + testonly = true + ldflags = [ "-lc++" ] + deps = [ + ":napi_common", + ":napi_qjs_source_set", + ":quickjs_source_set", + ":test", + ] } -} 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", - ] - } - 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" ] - } - } -} \ No newline at end of file + } +} diff --git a/README.md b/README.md index 190d624..8bd2d71 100644 --- a/README.md +++ b/README.md @@ -91,12 +91,12 @@ JavaScript 值,概念和操作通常映射到 ECMA-262 语言规范,API 具 1. 建议使用 BUILDCONFIG.gn 中定义的 LTS NDK 版本 2. Hermes 引擎需要先 `cd third_party/hermes && git apply ../hermes_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.1 版本内置字节码,需要先编译主机 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_macosx/bin/hermesc -O -Wno-undefined-variable -emit-binary -out=InternalBytecode.hbc InternalBytecode.js +> python3 xxd.py InternalBytecode.hbc > InternalBytecode.inc ``` ## 注意事项 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/toolchain/BUILD.gn b/toolchain/BUILD.gn index 3b20d3f..ab6e767 100644 --- a/toolchain/BUILD.gn +++ b/toolchain/BUILD.gn @@ -79,6 +79,7 @@ if (target_os == "android") { optimize_level = "-O3" } default_output_extension = ".so" + # target 选择 clang 具体工具链,指定 lto 参数 mcpu command = "$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang $linker_command $optimize_level --sysroot $sysroot_path -flto -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,--no-undefined -shared -Wl,-soname,{{target_output_name}}$default_output_extension -o {{output}} {{inputs}} {{libs}} {{ldflags}}" default_output_dir = "{{target_out_dir}}" From 5218d0e5d61eab7a2a0c8c426e92f23cd70a3f01 Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Sat, 20 Aug 2022 20:21:57 +0800 Subject: [PATCH 04/25] feat: Update folly to 2021.06.28.00 1. Update react-native to 0.69.4 --- third_party/folly | 2 +- third_party/react-native | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/third_party/folly b/third_party/folly index dec61fc..f434460 160000 --- a/third_party/folly +++ b/third_party/folly @@ -1 +1 @@ -Subproject commit dec61fcb0aff39cfe2ee0a9a1df38a38c2942285 +Subproject commit f434460f8a98e85f3ddb75390ddd1cc330c8f658 diff --git a/third_party/react-native b/third_party/react-native index e4d576f..4bdec97 160000 --- a/third_party/react-native +++ b/third_party/react-native @@ -1 +1 @@ -Subproject commit e4d576f6556cd3240c46f2e337d3e70495c48e43 +Subproject commit 4bdec975c95e8c46c804a8a00c73ebe696a6982b From 331e0f55ea2c9381e855269d8392394c21ded7aa Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Sat, 20 Aug 2022 20:22:47 +0800 Subject: [PATCH 05/25] feat: Complete jsi hermes debugger_api. --- BUILD.gn | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/BUILD.gn b/BUILD.gn index 9d81d9c..d4d370b 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -463,7 +463,6 @@ source_set("hermes_vm_runtime") { configs = [ ":minimal_size_build", ":hermes_build", - ":llvm_build", ":cpp_new_build", ] @@ -590,6 +589,47 @@ source_set("hermes_vm_runtime") { ] } +source_set("jsi") { + configs = [ ":cpp_new_build" ] + cflags_cc = [ + "-fexceptions", + "-fno-rtti", + ] + include_dirs = [ "third_party/react-native/ReactCommon/jsi" ] + sources = [ "third_party/react-native/ReactCommon/jsi/jsi/jsi.cpp" ] +} + +source_set("hermes") { + configs = [ + ":hermes_build", + ":llvm_build", + ":cpp_new_build", + ] + cflags_cc = [ + "-fexceptions", + "-frtti", + ] + include_dirs = [ + "third_party/hermes/API", + "third_party/react-native/ReactCommon/jsi", + ] + sources = [ "third_party/hermes/API/hermes/hermes.cpp" ] +} + +source_set("debugger_api") { + configs = [ + ":minimal_size_build", + ":hermes_build", + ":llvm_build", + ":cpp_new_build", + ] + include_dirs = [ + "third_party/hermes/API", + "third_party/react-native/ReactCommon/jsi", + ] + sources = [ "third_party/hermes/API/hermes/DebuggerAPI.cpp" ] +} + source_set("napi_qjs_source_set") { configs = [ ":quickjs_build", From 1d4d1553edcd46a0c200a99a164eaed71cd88ffc Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Sun, 21 Aug 2022 23:28:20 +0800 Subject: [PATCH 06/25] feat: Remove boost-for-react-native. 1. Complete basic hermes build. 2. Add libevent and event-config.h. 3. Update glog header. --- .gitmodules | 6 +- BUILD.gn | 81 +++++++++++++++++++---- README.md | 3 + third_party/boost-for-react-native | 1 - third_party/include/event2/event-config.h | 9 +++ third_party/include/glog/log_severity.h | 0 third_party/include/glog/logging.h | 16 ++--- third_party/libevent | 1 + 8 files changed, 87 insertions(+), 30 deletions(-) delete mode 160000 third_party/boost-for-react-native create mode 100644 third_party/include/event2/event-config.h delete mode 100644 third_party/include/glog/log_severity.h create mode 160000 third_party/libevent diff --git a/.gitmodules b/.gitmodules index 0bb9496..d328b9c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,6 +16,6 @@ [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 diff --git a/BUILD.gn b/BUILD.gn index d4d370b..d820e00 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -33,10 +33,14 @@ source_set("quickjs_source_set") { } } +config("common_build") { + include_dirs = [ "third_party/include" ] +} + config("llvm_build") { + configs = [ ":common_build" ] include_dirs = [ "third_party/hermes/external/llvh/include", - "third_party/include", "third_party/hermes/external/llvh/gen/include", ] defines = [ @@ -432,6 +436,8 @@ source_set("hermes_support") { ":llvm_build", ":cpp_new_build", ] + + # dtoa/dtoa.h include_dirs = [ "third_party/hermes/external" ] sources = [ "third_party/hermes/lib/Support/Allocator.cpp", @@ -466,6 +472,8 @@ source_set("hermes_vm_runtime") { ":llvm_build", ":cpp_new_build", ] + + # dtoa/dtoa.h include_dirs = [ "third_party/hermes/external" ] sources = [ "third_party/hermes/lib/VM/ArrayStorage.cpp", @@ -589,16 +597,6 @@ source_set("hermes_vm_runtime") { ] } -source_set("jsi") { - configs = [ ":cpp_new_build" ] - cflags_cc = [ - "-fexceptions", - "-fno-rtti", - ] - include_dirs = [ "third_party/react-native/ReactCommon/jsi" ] - sources = [ "third_party/react-native/ReactCommon/jsi/jsi/jsi.cpp" ] -} - source_set("hermes") { configs = [ ":hermes_build", @@ -630,6 +628,63 @@ source_set("debugger_api") { sources = [ "third_party/hermes/API/hermes/DebuggerAPI.cpp" ] } +config("folly_build") { + configs = [ + ":common_build", + ":libevent_build", + ] + defines = [ + "FOLLY_NO_CONFIG", + "FOLLY_MOBILE=1", + "FOLLY_USE_LIBCPP=1", + "FOLLY_HAVE_CLOCK_GETTIME", + ] + include_dirs = [ "third_party/folly" ] +} + +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" ] +} + +source_set("hermes_inspector") { + configs = [ + ":folly_build", + ":cpp_new_build", + ] + include_dirs = [ + "third_party/hermes/API", + "third_party/react-native/ReactCommon/jsi", + "third_party/react-native/ReactCommon", + "third_party/hermes/public", + ] + defines = [ "HERMES_ENABLE_DEBUGGER" ] + cflags_cc = [ + "-fexceptions", + "-frtti", + ] + 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_qjs_source_set") { configs = [ ":quickjs_build", @@ -638,9 +693,7 @@ source_set("napi_qjs_source_set") { include_dirs = [ "include" ] cflags_c = [ "-fvisibility=hidden", - - # TODO(Chason): QuickJS 头文件内联函数 - "-Wno-unused-parameter", + "-Wno-unused-parameter", # TODO(Chason): QuickJS 头文件内联函数 "-Wno-pedantic", ] sources = [ "src/js_native_api_qjs.c" ] diff --git a/README.md b/README.md index 8bd2d71..069f6a5 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ JavaScript 值,概念和操作通常映射到 ECMA-262 语言规范,API 具 4. 所有 JavaScript 值都抽象在一个名为 NAPIValue 的不透明类型后面。 5. 如果出现 NAPIExceptionPendingException 说明出现 JS 异常,可以通过 napi_get_and_clear_last_exception 获取,或通过 NAPIClearLastException 清除 +## 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 目录下。 + ## 代码静态分析 ### JavaScriptCore 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/include/event2/event-config.h b/third_party/include/event2/event-config.h new file mode 100644 index 0000000..2741ded --- /dev/null +++ b/third_party/include/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/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/logging.h b/third_party/include/glog/logging.h index d9746a0..48dafa7 100644 --- a/third_party/include/glog/logging.h +++ b/third_party/include/glog/logging.h @@ -1,28 +1,20 @@ #include -#define INFO 0 -#define WARNING 0 +#define INFO +#define WARNING #define LOG(severity) \ if (0) \ ::std::cout -#define CHECK(condition) \ - if (0) \ - ::std::cout -#define CHECK_GE(val1, val2) +#define CHECK(condition) #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 +#define DCHECK_GE(val1, val2) \ No newline at end of file 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 From b734c1fcfe6ca38b550fcf33fcba6b05032f55cd Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Sun, 21 Aug 2022 23:37:27 +0800 Subject: [PATCH 07/25] chore: Update LICENSE. --- LICENSE | 203 ++------------------------------------------------------ 1 file changed, 5 insertions(+), 198 deletions(-) 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. From 7ebc90f539d7af9daef7ee4a8ba0ed63471060f8 Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Mon, 22 Aug 2022 00:03:19 +0800 Subject: [PATCH 08/25] feat: Add fbjni. 1. Complete hermes_platform_unicode target on Android. 2. Fix Android NDK toolchain error. --- .gitmodules | 3 +++ BUILD.gn | 13 +++++++++++-- third_party/fbjni | 1 + toolchain/BUILD.gn | 6 ++++-- 4 files changed, 19 insertions(+), 4 deletions(-) create mode 160000 third_party/fbjni diff --git a/.gitmodules b/.gitmodules index d328b9c..558d251 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [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 diff --git a/BUILD.gn b/BUILD.gn index d820e00..62f9f32 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -386,17 +386,25 @@ source_set("hermes_platform") { source_set("hermes_platform_unicode") { configs = [ - ":minimal_size_build", ":llvm_build", ":hermes_build", ":cpp_new_build", ] + include_dirs = [ "third_party/fbjni/cxx" ] 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 { + cflags_cc = [ + "-fexceptions", + "-fno-rtti", + ] + sources += + [ "third_party/hermes/lib/Platform/Unicode/PlatformUnicodeJava.cpp" ] } } @@ -706,7 +714,8 @@ source_set("napi_common") { sources = [ "src/js_native_api_common.c" ] } -if (target_os != "android") { +if (target_os == "android") { +} else { source_set("napi_jsc_source_set") { configs = [ ":strict_build" ] include_dirs = [ "include" ] 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/toolchain/BUILD.gn b/toolchain/BUILD.gn index ab6e767..dd88f0a 100644 --- a/toolchain/BUILD.gn +++ b/toolchain/BUILD.gn @@ -36,7 +36,7 @@ if (target_os == "android") { object_generate_option = "-fdata-sections -ffunction-sections" if (target_cpu == "arm") { - target_option = "-target armv7-none-linux-androideabi18 -thumb" + target_option = "-target armv7-none-linux-androideabi18 -mthumb" } else if (target_cpu == "arm64") { target_option = "-target aarch64-none-linux-android21" } else if (target_cpu == "x86") { @@ -74,7 +74,9 @@ if (target_os == "android") { command = "touch {{output}}" } tool("solink") { - if (!is_debug) { + if (is_debug) { + optimize_level = "-O0" + } else { # NDK 链接器 LTO 插件问题 optimize_level = "-O3" } From 6969a1cd317e4bcc6a7d1ae6cc8b9974dac0736c Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Mon, 22 Aug 2022 21:10:02 +0800 Subject: [PATCH 09/25] chore: Update README.md. 1. Add -fPIC. 2. Complete hermes_api. --- BUILD.gn | 184 +++++++++++++++++++++++++++++++++------------ README.md | 5 +- toolchain/BUILD.gn | 2 +- 3 files changed, 138 insertions(+), 53 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index 62f9f32..12f2676 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -19,9 +19,10 @@ config("quickjs_build") { cflags_c = [ "-funsigned-char" ] } -source_set("quickjs_source_set") { +source_set("quickjs") { configs = [ ":quickjs_build" ] - defines = [ "CONFIG_VERSION=\"2021-03-27\"" ] + cflags_c = [ "-fvisibility=hidden" ] + defines = [ "CONFIG_VERSION=\"\"" ] sources = [ "third_party/quickjs/cutils.c", "third_party/quickjs/libregexp.c", @@ -57,17 +58,34 @@ config("llvm_build") { "HAVE_FCNTL_H=1", # Process.inc:216 "HAVE_SIGNAL_H=1", # Process.inc:232 "RETSIGTYPE=void", + "HAVE_SYS_PARAM_H", # Unix.h:39 ] } config("cpp_new_build") { cflags_cc = [ - # 主要因为 NDK 目前暂时不支持 C++20 "-std=c++17", "-fvisibility=hidden", ] } +source_set("dtoa") { + 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", + ] +} + source_set("llvm_demangle") { configs = [ ":minimal_size_build", @@ -145,23 +163,6 @@ source_set("llvm_support") { ] } -source_set("dtoa") { - 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("hermes_build") { include_dirs = [ "third_party/hermes/include", @@ -362,6 +363,7 @@ source_set("hermes_parser") { ":llvm_build", ":cpp_new_build", ] + include_dirs = [ "third_party/hermes/external" ] sources = [ "third_party/hermes/lib/Parser/JSLexer.cpp", "third_party/hermes/lib/Parser/JSONParser.cpp", @@ -390,7 +392,6 @@ source_set("hermes_platform_unicode") { ":hermes_build", ":cpp_new_build", ] - include_dirs = [ "third_party/fbjni/cxx" ] sources = [ "third_party/hermes/lib/Platform/Unicode/CharacterProperties.cpp" ] if (target_os != "android") { @@ -399,6 +400,7 @@ source_set("hermes_platform_unicode") { [ "third_party/hermes/lib/Platform/Unicode/PlatformUnicodeCF.cpp" ] frameworks = [ "CoreFoundation.framework" ] } else { + include_dirs = [ "third_party/fbjni/cxx" ] cflags_cc = [ "-fexceptions", "-fno-rtti", @@ -444,8 +446,6 @@ source_set("hermes_support") { ":llvm_build", ":cpp_new_build", ] - - # dtoa/dtoa.h include_dirs = [ "third_party/hermes/external" ] sources = [ "third_party/hermes/lib/Support/Allocator.cpp", @@ -480,8 +480,6 @@ source_set("hermes_vm_runtime") { ":llvm_build", ":cpp_new_build", ] - - # dtoa/dtoa.h include_dirs = [ "third_party/hermes/external" ] sources = [ "third_party/hermes/lib/VM/ArrayStorage.cpp", @@ -493,7 +491,6 @@ source_set("hermes_vm_runtime") { "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/DecoratedObject.cpp", "third_party/hermes/lib/VM/DictPropertyMap.cpp", "third_party/hermes/lib/VM/Domain.cpp", "third_party/hermes/lib/VM/DummyObject.cpp", @@ -502,7 +499,6 @@ source_set("hermes_vm_runtime") { "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/HostModel.cpp", "third_party/hermes/lib/VM/IdentifierTable.cpp", "third_party/hermes/lib/VM/Interpreter-slowpaths.cpp", "third_party/hermes/lib/VM/Interpreter.cpp", @@ -605,7 +601,33 @@ source_set("hermes_vm_runtime") { ] } -source_set("hermes") { +source_set("hermes_vm_runtime_rtti") { + configs = [ + ":hermes_build", + ":llvm_build", + ":cpp_new_build", + ] + cflags_cc = [ + "-fno-exceptions", + "-frtti", + ] + sources = [ + "third_party/hermes/lib/VM/DecoratedObject.cpp", + "third_party/hermes/lib/VM/HostModel.cpp", + ] +} + +source_set("jsi") { + configs = [ ":cpp_new_build" ] + cflags_cc = [ + "-fexceptions", + "-frtti", + ] + include_dirs = [ "third_party/react-native/ReactCommon/jsi" ] + sources = [ "third_party/react-native/ReactCommon/jsi/jsi/jsi.cpp" ] +} + +source_set("hermes_api") { configs = [ ":hermes_build", ":llvm_build", @@ -622,7 +644,7 @@ source_set("hermes") { sources = [ "third_party/hermes/API/hermes/hermes.cpp" ] } -source_set("debugger_api") { +source_set("hermes_debugger_api") { configs = [ ":minimal_size_build", ":hermes_build", @@ -636,6 +658,16 @@ source_set("debugger_api") { sources = [ "third_party/hermes/API/hermes/DebuggerAPI.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" ] +} + config("folly_build") { configs = [ ":common_build", @@ -650,16 +682,6 @@ config("folly_build") { include_dirs = [ "third_party/folly" ] } -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" ] -} - source_set("hermes_inspector") { configs = [ ":folly_build", @@ -671,6 +693,9 @@ source_set("hermes_inspector") { "third_party/react-native/ReactCommon", "third_party/hermes/public", ] + if (target_os == "android") { + include_dirs += [ "third_party/fbjni/cxx" ] + } defines = [ "HERMES_ENABLE_DEBUGGER" ] cflags_cc = [ "-fexceptions", @@ -693,7 +718,7 @@ source_set("hermes_inspector") { ] } -source_set("napi_qjs_source_set") { +source_set("napi_qjs") { configs = [ ":quickjs_build", ":strict_build", @@ -701,7 +726,7 @@ source_set("napi_qjs_source_set") { include_dirs = [ "include" ] cflags_c = [ "-fvisibility=hidden", - "-Wno-unused-parameter", # TODO(Chason): QuickJS 头文件内联函数 + "-Wno-unused-parameter", "-Wno-pedantic", ] sources = [ "src/js_native_api_qjs.c" ] @@ -715,8 +740,66 @@ source_set("napi_common") { } if (target_os == "android") { + source_set("fbjni") { + cflags_cc = [ + "-fexceptions", + "-frtti", + "-fvisibility=hidden", + ] + include_dirs = [ "third_party/fbjni/cxx" ] + sources = [ + #"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", + ] + } + shared_library("hermes") { + ldflags = [ + "-lc++", + "-llog", + "-lm", + ] + deps = [ + ":dtoa", + ":fbjni", + ":hermes_adt", + ":hermes_api", + ":hermes_ast", + ":hermes_backend", + ":hermes_debugger_api", + ":hermes_frontend", + ":hermes_frontend_defs", + ":hermes_hbc_backend", + ":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", + ":llvm_support", + ] + } } else { - source_set("napi_jsc_source_set") { + source_set("napi_jsc") { configs = [ ":strict_build" ] include_dirs = [ "include" ] cflags_c = [ "-fvisibility=hidden" ] @@ -728,7 +811,7 @@ if (target_os == "android") { complete_static_lib = true deps = [ ":napi_common", - ":napi_jsc_source_set", + ":napi_jsc", ] } @@ -736,8 +819,8 @@ if (target_os == "android") { complete_static_lib = true deps = [ ":napi_common", - ":napi_qjs_source_set", - ":quickjs_source_set", + ":napi_qjs", + ":quickjs", ] } } else { @@ -776,7 +859,10 @@ if (target_os == "android") { "-fvisibility=hidden", "-std=c++20", ] - configs = [ ":minimal_size_build" ] + configs = [ + ":minimal_size_build", + ":strict_build", + ] sources = [ "test/callable.cpp", "test/conversion.cpp", @@ -794,7 +880,7 @@ if (target_os == "android") { ldflags = [ "-lc++" ] deps = [ ":napi_common", - ":napi_jsc_source_set", + ":napi_jsc", ":test", ] } @@ -804,8 +890,8 @@ if (target_os == "android") { ldflags = [ "-lc++" ] deps = [ ":napi_common", - ":napi_qjs_source_set", - ":quickjs_source_set", + ":napi_qjs", + ":quickjs", ":test", ] } diff --git a/README.md b/README.md index 069f6a5..43af69a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ -## 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 异常 diff --git a/toolchain/BUILD.gn b/toolchain/BUILD.gn index dd88f0a..031b861 100644 --- a/toolchain/BUILD.gn +++ b/toolchain/BUILD.gn @@ -1,6 +1,6 @@ # -fPIC -funwind-tables 在大部分平台都是默认开启,除了 PowerPC 32 bit 的平台等少数情况 # -MMD 收集的用户头文件就足够了 -compiler_command = "-c {{source}} -o {{output}} -MMD -MF {{output}}.d {{include_dirs}} {{defines}} {{cflags}}" +compiler_command = "-c {{source}} -o {{output}} -fPIC -MMD -MF {{output}}.d {{include_dirs}} {{defines}} {{cflags}}" if (generate_dwarf) { compiler_command = "-g $compiler_command" } From d870596f8d74611aeec1c3c9c4dd9f3eb197e04c Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Tue, 23 Aug 2022 17:22:22 +0800 Subject: [PATCH 10/25] feat: Use lto to minimize release build. 1. Use libs instead of ldflags. 2. Add explicit -funwind-tables 3. Make Android api from 18 to 16. --- BUILD.gn | 21 ++++++++-------- toolchain/BUILD.gn | 60 ++++++++++++++++++++-------------------------- 2 files changed, 36 insertions(+), 45 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index 12f2676..3a16c6f 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -748,10 +748,9 @@ if (target_os == "android") { ] include_dirs = [ "third_party/fbjni/cxx" ] sources = [ - #"third_party/fbjni/cxx/fbjni/ByteBuffer.cpp", + "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/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", @@ -761,16 +760,15 @@ if (target_os == "android") { "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_breakpad.cpp", "third_party/fbjni/cxx/lyra/lyra_exceptions.cpp", ] } shared_library("hermes") { - ldflags = [ - "-lc++", - "-llog", - "-lm", + libs = [ + "c++", + "log", + "m", ] deps = [ ":dtoa", @@ -783,6 +781,7 @@ if (target_os == "android") { ":hermes_frontend", ":hermes_frontend_defs", ":hermes_hbc_backend", + ":hermes_inspector", ":hermes_inst", ":hermes_internal_bytecode", ":hermes_optimizer", @@ -877,7 +876,7 @@ if (target_os == "android") { executable("test_jsc") { testonly = true - ldflags = [ "-lc++" ] + libs = [ "c++" ] deps = [ ":napi_common", ":napi_jsc", @@ -887,7 +886,7 @@ if (target_os == "android") { executable("test_qjs") { testonly = true - ldflags = [ "-lc++" ] + libs = [ "c++" ] deps = [ ":napi_common", ":napi_qjs", diff --git a/toolchain/BUILD.gn b/toolchain/BUILD.gn index 031b861..c011764 100644 --- a/toolchain/BUILD.gn +++ b/toolchain/BUILD.gn @@ -1,6 +1,6 @@ -# -fPIC -funwind-tables 在大部分平台都是默认开启,除了 PowerPC 32 bit 的平台等少数情况 # -MMD 收集的用户头文件就足够了 -compiler_command = "-c {{source}} -o {{output}} -fPIC -MMD -MF {{output}}.d {{include_dirs}} {{defines}} {{cflags}}" +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" } @@ -15,28 +15,21 @@ if (ubsan) { } if (!is_debug) { - # NDEBUG for assert.h compiler_command = "-Os -DNDEBUG $compiler_command" if (lto) { compiler_command = "-flto $compiler_command" + linker_command = "-flto $linker_command" } } else { compiler_command = "-O0 $compiler_command" } -compiler_outputs = [ "{{source_out_dir}}/{{source_name_part}}.o" ] -linker_outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ] - if (target_os == "android") { toolchain("android") { - sysroot_path = "$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/sysroot" - compiler_command = "--sysroot $sysroot_path $compiler_command" - - # -fdata-sections 和 -ffunction-sections 原则上应当和链接器的 -Wl,–gc-sections 配合使用缩小包体积 - object_generate_option = "-fdata-sections -ffunction-sections" + compiler_command = "--sysroot $ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/sysroot $compiler_command" if (target_cpu == "arm") { - target_option = "-target armv7-none-linux-androideabi18 -mthumb" + target_option = "-target armv7-none-linux-androideabi16 -mthumb" } else if (target_cpu == "arm64") { target_option = "-target aarch64-none-linux-android21" } else if (target_cpu == "x86") { @@ -52,28 +45,23 @@ if (target_os == "android") { linker_command = "$target_option $linker_command" } - if (is_debug || !lto) { - compiler_command = "$object_generate_option $compiler_command" - } else { - linker_command = "$linker_command $object_generate_option" - } - tool("cc") { command = "$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang $compiler_command {{cflags_c}}" - depfile = "{{output}}.d" + depfile = depfile_string depsformat = "gcc" - outputs = compiler_outputs + 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 = "{{output}}.d" + depfile = depfile_string depsformat = "gcc" - outputs = compiler_outputs + 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 { @@ -82,10 +70,9 @@ if (target_os == "android") { } default_output_extension = ".so" - # target 选择 clang 具体工具链,指定 lto 参数 mcpu - command = "$ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang $linker_command $optimize_level --sysroot $sysroot_path -flto -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,--no-undefined -shared -Wl,-soname,{{target_output_name}}$default_output_extension -o {{output}} {{inputs}} {{libs}} {{ldflags}}" + 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 = linker_outputs + outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ] output_prefix = "lib" } } @@ -112,16 +99,16 @@ if (target_os == "android") { tool("cc") { command = "clang $compiler_command {{cflags_c}}" - depfile = "{{output}}.d" + depfile = depfile_string depsformat = "gcc" - outputs = compiler_outputs + outputs = [ "{{source_out_dir}}/{{source_name_part}}.o" ] } tool("cxx") { command = "clang++ $compiler_command {{cflags_cc}}" - depfile = "{{output}}.d" + depfile = depfile_string depsformat = "gcc" - outputs = compiler_outputs + outputs = [ "{{source_out_dir}}/{{source_name_part}}.o" ] } tool("stamp") { @@ -129,21 +116,26 @@ if (target_os == "android") { } tool("link") { - command = "clang $linker_command -o {{output}} {{inputs}} {{frameworks}} {{ldflags}}" + lib_switch = "-l" + framework_switch = "-framework " - # /tmp/lto.o 丢失会导致 dsymutil 无法生成 dSYM - # -Xlinker -object_path_lto -Xlinker {{output_dir}}/{{target_output_name}}_lto.o + # 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 (collect_code_coverage) { command = "$command -fprofile-instr-generate" } default_output_dir = "{{root_out_dir}}" - outputs = linker_outputs + outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ] } tool("alink") { command = "libtool -static -o {{output}} {{inputs}}" default_output_dir = "{{target_out_dir}}" - outputs = linker_outputs + outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ] default_output_extension = ".a" output_prefix = "lib" } From 2b456ddd19241f22bfc8dcd071c8e3bcbbb215a5 Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Tue, 23 Aug 2022 17:23:39 +0800 Subject: [PATCH 11/25] fix: Fix typo. --- toolchain/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain/BUILD.gn b/toolchain/BUILD.gn index c011764..f9720e0 100644 --- a/toolchain/BUILD.gn +++ b/toolchain/BUILD.gn @@ -117,7 +117,7 @@ if (target_os == "android") { tool("link") { lib_switch = "-l" - framework_switch = "-framework " + 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. From dc35fa2d7e19d7d59334912b2a4b2fa9ffb60430 Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Tue, 23 Aug 2022 22:13:39 +0800 Subject: [PATCH 12/25] feat: Add jsi_dynamic jsinspector double_conversion fmt folly. 1. Modify .gitignore file. --- .gitignore | 74 +-------------- .gitmodules | 3 + BUILD.gn | 143 +++++++++++++++++++++++++++-- third_party/fmt | 1 + third_party/include/glog/logging.h | 14 ++- 5 files changed, 149 insertions(+), 86 deletions(-) create mode 160000 third_party/fmt diff --git a/.gitignore b/.gitignore index de7a6e9..6e4b0b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,75 +1,5 @@ -# macOS.gitignore -# General .DS_Store -.AppleDouble -.LSOverride - -# 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 /out/ -/.vscode/ -/.idea/ -/clion/ -/static_analyze_report/ -/x86_64/ -/i386/ -/armv7/ -/arm64/ -/napi/ -/napi_ios.tar.gz -/napi_hermes_android.tar.gz -/napi_qjs_android.tar.gz + +/arm/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 558d251..9b1a683 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [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 diff --git a/BUILD.gn b/BUILD.gn index 3a16c6f..8bfb2a3 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -39,7 +39,6 @@ config("common_build") { } config("llvm_build") { - configs = [ ":common_build" ] include_dirs = [ "third_party/hermes/external/llvh/include", "third_party/hermes/external/llvh/gen/include", @@ -90,6 +89,7 @@ source_set("llvm_demangle") { configs = [ ":minimal_size_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] sources = [ @@ -103,6 +103,7 @@ source_set("llvm_support") { configs = [ ":minimal_size_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] sources = [ @@ -193,6 +194,7 @@ source_set("hermes_adt") { ":minimal_size_build", ":hermes_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] sources = [ "third_party/hermes/lib/ADT/CompactArray.cpp" ] @@ -203,6 +205,7 @@ source_set("hermes_ast") { ":minimal_size_build", ":hermes_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] sources = [ @@ -220,6 +223,7 @@ source_set("hermes_backend") { ":minimal_size_build", ":hermes_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] sources = [ @@ -244,6 +248,7 @@ source_set("hermes_frontend") { ":minimal_size_build", ":hermes_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] sources = [ @@ -270,6 +275,7 @@ source_set("hermes_hbc_backend") { ":minimal_size_build", ":hermes_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] sources = [ @@ -305,6 +311,7 @@ source_set("hermes_inst") { ":minimal_size_build", ":hermes_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] sources = [ @@ -318,6 +325,7 @@ source_set("hermes_internal_bytecode") { ":minimal_size_build", ":hermes_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] defines = [ "HERMES_CMAKE_BUILD" ] @@ -328,6 +336,7 @@ source_set("hermes_optimizer") { configs = [ ":minimal_size_build", ":llvm_build", + ":common_build", ":hermes_build", ":cpp_new_build", ] @@ -361,6 +370,7 @@ source_set("hermes_parser") { ":minimal_size_build", ":hermes_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] include_dirs = [ "third_party/hermes/external" ] @@ -380,6 +390,7 @@ source_set("hermes_platform") { configs = [ ":minimal_size_build", ":llvm_build", + ":common_build", ":hermes_build", ":cpp_new_build", ] @@ -389,6 +400,7 @@ source_set("hermes_platform") { source_set("hermes_platform_unicode") { configs = [ ":llvm_build", + ":common_build", ":hermes_build", ":cpp_new_build", ] @@ -414,6 +426,7 @@ source_set("hermes_regex") { configs = [ ":minimal_size_build", ":llvm_build", + ":common_build", ":hermes_build", ":cpp_new_build", ] @@ -427,6 +440,7 @@ source_set("hermes_source_map") { configs = [ ":minimal_size_build", ":llvm_build", + ":common_build", ":hermes_build", ":cpp_new_build", ] @@ -444,6 +458,7 @@ source_set("hermes_support") { ":minimal_size_build", ":hermes_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] include_dirs = [ "third_party/hermes/external" ] @@ -478,6 +493,7 @@ source_set("hermes_vm_runtime") { ":minimal_size_build", ":hermes_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] include_dirs = [ "third_party/hermes/external" ] @@ -605,6 +621,7 @@ source_set("hermes_vm_runtime_rtti") { configs = [ ":hermes_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] cflags_cc = [ @@ -627,10 +644,25 @@ source_set("jsi") { sources = [ "third_party/react-native/ReactCommon/jsi/jsi/jsi.cpp" ] } +source_set("jsi_dynamic") { + configs = [ + ":cpp_new_build", + ":folly_build", + ":common_build", + ] + include_dirs = [ "third_party/react-native/ReactCommon/jsi" ] + cflags_cc = [ + "-fexceptions", + "-fno-rtti", + ] + sources = [ "third_party/react-native/ReactCommon/jsi/jsi/JSIDynamic.cpp" ] +} + source_set("hermes_api") { configs = [ ":hermes_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] cflags_cc = [ @@ -644,13 +676,27 @@ source_set("hermes_api") { sources = [ "third_party/hermes/API/hermes/hermes.cpp" ] } -source_set("hermes_debugger_api") { +source_set("jsinspector") { configs = [ ":minimal_size_build", + ":cpp_new_build", + ] + sources = [ + "third_party/react-native/ReactCommon/jsinspector/InspectorInterfaces.cpp", + ] +} + +source_set("hermes_debugger_api") { + configs = [ ":hermes_build", ":llvm_build", + ":common_build", ":cpp_new_build", ] + cflags_cc = [ + "-fno-exceptions", + "-frtti", + ] include_dirs = [ "third_party/hermes/API", "third_party/react-native/ReactCommon/jsi", @@ -669,10 +715,6 @@ config("libevent_build") { } config("folly_build") { - configs = [ - ":common_build", - ":libevent_build", - ] defines = [ "FOLLY_NO_CONFIG", "FOLLY_MOBILE=1", @@ -682,9 +724,93 @@ config("folly_build") { include_dirs = [ "third_party/folly" ] } +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("fmt") { + cflags_cc = [ + "-fvisibility=hidden", + "-frtti", + "-fno-exceptions", + ] + include_dirs = [ "third_party/fmt/include" ] + sources = [ + "third_party/fmt/src/format.cc", + "third_party/fmt/src/os.cc", + ] +} + +source_set("folly") { + configs = [ + ":folly_build", + ":common_build", + ] + cflags_cc = [ + "-fexceptions", + "-frtti", + "-fvisibility=hidden", + ] + include_dirs = [ "third_party/fmt/include" ] + 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") { configs = [ ":folly_build", + ":common_build", + ":libevent_build", ":cpp_new_build", ] include_dirs = [ @@ -771,8 +897,11 @@ if (target_os == "android") { "m", ] deps = [ + ":double_conversion", ":dtoa", ":fbjni", + ":fmt", + ":folly", ":hermes_adt", ":hermes_api", ":hermes_ast", @@ -794,6 +923,8 @@ if (target_os == "android") { ":hermes_vm_runtime", ":hermes_vm_runtime_rtti", ":jsi", + ":jsi_dynamic", + ":jsinspector", ":llvm_support", ] } 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/include/glog/logging.h b/third_party/include/glog/logging.h index 48dafa7..ecde968 100644 --- a/third_party/include/glog/logging.h +++ b/third_party/include/glog/logging.h @@ -3,18 +3,16 @@ #define INFO #define WARNING -#define LOG(severity) \ - if (0) \ - ::std::cout +#define LOG(severity) ::std::cout -#define CHECK(condition) +#define CHECK(condition) ::std::cout #define CHECK_EQ(val1, val2) +#define CHECK_GE(val1, val2) #define DCHECK(condition) -#define DCHECK_EQ(val1, val2) \ - if (0) \ - ::std::cout +#define DCHECK_EQ(val1, val2) ::std::cout #define DCHECK_GT(val1, val2) #define DCHECK_LT(val1, val2) #define DCHECK_NE(val1, val2) -#define DCHECK_GE(val1, val2) \ No newline at end of file +#define DCHECK_GE(val1, val2) +#define DCHECK_LE(val1, val2) \ No newline at end of file From 82f06d99d435f1f532ae3e337ad0f1a7e6dc6824 Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Tue, 23 Aug 2022 22:14:18 +0800 Subject: [PATCH 13/25] feat: Modify .gitignore to exclude boost. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6e4b0b7..e4e26fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store +/third_party/include/boost/ /out/ From bc7d1e98771318394a1451883eb4973b11d1257b Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Thu, 25 Aug 2022 20:23:08 +0800 Subject: [PATCH 14/25] feat: Add bitcode as bitcode if condition. --- toolchain/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain/BUILD.gn b/toolchain/BUILD.gn index f9720e0..7b8dd22 100644 --- a/toolchain/BUILD.gn +++ b/toolchain/BUILD.gn @@ -78,7 +78,7 @@ if (target_os == "android") { } } else { toolchain("clang") { - if (have_bitcode_flag) { + if (have_bitcode_flag && bitcode) { compiler_command = "-fembed-bitcode $compiler_command" } if (collect_code_coverage) { From 867ce9a1148584d725a222a7948d302582930b7a Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Sun, 4 Sep 2022 00:04:30 +0800 Subject: [PATCH 15/25] feat(Hermes): Split up and update code. 1. Remove bitcode logic from build system. --- .clang-format | 2 +- .gitignore | 7 +- BUILD.gn | 35 ++++++ BUILDCONFIG.gn | 16 +-- README.md | 43 ++------ include/hermes/External.h | 42 +++++++ include/hermes/HermesExecutorRuntimeAdapter.h | 59 ++++++++++ include/hermes/OpaqueNAPIEnv.h | 65 +++++++++++ include/hermes/OpaqueNAPIRef.h | 53 +++++++++ src/hermes/External.cpp | 33 ++++++ src/hermes/HermesExecutorRuntimeAdapter.cpp | 33 ++++++ src/hermes/OpaqueNAPIEnv.cpp | 83 ++++++++++++++ src/hermes/OpaqueNAPIRef.cpp | 103 ++++++++++++++++++ toolchain/BUILD.gn | 17 +-- 14 files changed, 531 insertions(+), 60 deletions(-) create mode 100644 include/hermes/External.h create mode 100644 include/hermes/HermesExecutorRuntimeAdapter.h create mode 100644 include/hermes/OpaqueNAPIEnv.h create mode 100644 include/hermes/OpaqueNAPIRef.h create mode 100644 src/hermes/External.cpp create mode 100644 src/hermes/HermesExecutorRuntimeAdapter.cpp create mode 100644 src/hermes/OpaqueNAPIEnv.cpp create mode 100644 src/hermes/OpaqueNAPIRef.cpp diff --git a/.clang-format b/.clang-format index 3e5f49c..468ceea 100644 --- a/.clang-format +++ b/.clang-format @@ -1 +1 @@ -BasedOnStyle: Microsoft \ No newline at end of file +BasedOnStyle: LLVM \ No newline at end of file diff --git a/.gitignore b/.gitignore index e4e26fe..908d2f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,11 @@ .DS_Store /third_party/include/boost/ +/clion/ +/build/ +/.vscode/ +/.cache/ +/.idea/ /out/ -/arm/ \ No newline at end of file +/arm/ diff --git a/BUILD.gn b/BUILD.gn index 8bfb2a3..e523006 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -844,6 +844,40 @@ source_set("hermes_inspector") { ] } +source_set("napi_hermes") { + configs = [ + ":minimal_size_build", + ":strict_build", + ":hermes_build", + ":llvm_build", + ":common_build", + ":cpp_new_build", + ] + include_dirs = [ + "include", + "third_party/hermes/API", + "third_party/react-native/ReactCommon/jsi", + "third_party/react-native/ReactCommon", + ] + cflags_cc = [ + #"-fno-exceptions", + #"-frtti", + "-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/js_native_api_hermes.cpp", + "src/hermes/External.cpp", + "src/hermes/HermesExecutorRuntimeAdapter.cpp", + "src/hermes/OpaqueNAPIEnv.cpp", + "src/hermes/OpaqueNAPIRef.cpp", + ] +} + source_set("napi_qjs") { configs = [ ":quickjs_build", @@ -926,6 +960,7 @@ if (target_os == "android") { ":jsi_dynamic", ":jsinspector", ":llvm_support", + ":napi_hermes", ] } } else { diff --git a/BUILDCONFIG.gn b/BUILDCONFIG.gn index 2973fff..cea40f0 100644 --- a/BUILDCONFIG.gn +++ b/BUILDCONFIG.gn @@ -7,9 +7,13 @@ if (target_cpu == "") { assert(target_os == "android" || target_os == "ios" || target_os == "mac", "Unsupported target os.") -assert(target_cpu == "arm" || target_cpu == "arm64" || target_cpu == "x86" || +if (target_os == "ios" || target_os == "mac") { + assert(target_cpu == "arm64" || target_cpu == "x64", "Unsupported target cpu.") +} else { + assert(target_cpu == "arm" || target_cpu == "arm64" || target_cpu == "x86" || target_cpu == "x64", "Unsupported target cpu.") +} declare_args() { generate_dwarf = true @@ -32,16 +36,6 @@ declare_args() { } } -have_bitcode_flag = - target_os == "ios" && (target_cpu == "arm" || target_cpu == "arm64") && - !is_debug && !lto - -declare_args() { - if (have_bitcode_flag) { - bitcode = true - } -} - if (target_os == "android") { set_default_toolchain("//toolchain:android") } else { diff --git a/README.md b/README.md index 43af69a..4db09ac 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ ## 介绍 - Node-API(以前称为 N-API)是一个用于和 JavaScript 引擎交互并独立于 JavaScript 运行时的 API 接口层,旨在将 C 原生代码和 JavaScript 引擎隔离开来。API 通常用于创建和操作 JavaScript 值,概念和操作通常映射到 ECMA-262 语言规范,API 具有以下特点: 1. 所有节点API调用都返回类型为 NAPI{Common|Error|Exception}Status 的状态代码。此状态指示 API 调用是成功还是失败。 @@ -11,49 +10,28 @@ Node-API(以前称为 N-API)是一个用于和 JavaScript 引擎交互并独 ## 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 目录下。 -## 代码静态分析 - -### JavaScriptCore - -1. `clang --analyze src/js_native_api_jsc.c --analyzer-output html -o ./static_analyze_report -I./include` - -### QuickJS - -1. `clang --analyze src/js_native_api_qjs.c --analyzer-output html -o ./static_analyze_report -I./include -I./third_party/quickjs` +## 编辑器 +1. Clion +2. VSCode + clangd -### Hermes +## VSCode 配置工程 +1. gn gen build --args="is_debug=true" --export-compile-commands -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` +## Clion +1. `gn gen clion --args="is_debug=true" --ide=json --json-ide-script=../gn_to_cmake.py --script-executable=python3` ## 单元测试 - -1. `gn gen out --args="debug=true asan=true ubsan=true"`(Release 模式下 assert 失效,会隐藏很多问题,特殊情况下启用 asan + ubsan) +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` @@ -85,15 +63,13 @@ Node-API(以前称为 N-API)是一个用于和 JavaScript 引擎交互并独 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` #### 交叉编译注意 - 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` 3. Android 版本 libhermes.so 包括 fbjni 库,内含 OnLoad.cpp,需要使用 System.load("hermes") 显式加载,不能依赖 Linux 内核的动态库隐式加载 -4. Hermes 引擎 0.8.1 版本内置字节码,需要先编译主机 hermesc,指令 `./utils/build/build-mac-framework.sh`,后输入如下命令 +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 @@ -102,5 +78,4 @@ Node-API(以前称为 N-API)是一个用于和 JavaScript 引擎交互并独 ``` ## 注意事项 - 1. 只能在单一线程执行,不跨多线程执行,JavaScriptCore 通过锁机制保证同步,但是其他引擎很可能没有该保证 diff --git a/include/hermes/External.h b/include/hermes/External.h new file mode 100644 index 0000000..6d33029 --- /dev/null +++ b/include/hermes/External.h @@ -0,0 +1,42 @@ +#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/HermesExecutorRuntimeAdapter.h b/include/hermes/HermesExecutorRuntimeAdapter.h new file mode 100644 index 0000000..33b451e --- /dev/null +++ b/include/hermes/HermesExecutorRuntimeAdapter.h @@ -0,0 +1,59 @@ +#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/OpaqueNAPIEnv.h b/include/hermes/OpaqueNAPIEnv.h new file mode 100644 index 0000000..ae2357c --- /dev/null +++ b/include/hermes/OpaqueNAPIEnv.h @@ -0,0 +1,65 @@ +#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; + +#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/OpaqueNAPIRef.h b/include/hermes/OpaqueNAPIRef.h new file mode 100644 index 0000000..ef463d9 --- /dev/null +++ b/include/hermes/OpaqueNAPIRef.h @@ -0,0 +1,53 @@ +#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/hermes/External.cpp b/src/hermes/External.cpp new file mode 100644 index 0000000..509f226 --- /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/HermesExecutorRuntimeAdapter.cpp b/src/hermes/HermesExecutorRuntimeAdapter.cpp new file mode 100644 index 0000000..a3a3935 --- /dev/null +++ b/src/hermes/HermesExecutorRuntimeAdapter.cpp @@ -0,0 +1,33 @@ +#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/OpaqueNAPIEnv.cpp b/src/hermes/OpaqueNAPIEnv.cpp new file mode 100644 index 0000000..a44ef97 --- /dev/null +++ b/src/hermes/OpaqueNAPIEnv.cpp @@ -0,0 +1,83 @@ +#include +#include + +#ifdef HERMES_ENABLE_DEBUGGER +#include +#include +#include +#endif + +#include +#include + +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 版本没有执行,需要手动执行清空 + // RuntimeHermesValueFields.def 文件定义了 PinnedHermesValue thrownValue_ = + // {} + // => undefined + LIST_INIT(&this->valueList); + LIST_INIT(&this->weakRefList); + LIST_INIT(&this->strongRefList); + + 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(); + + 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"; + ::facebook::hermes::inspector::chrome::enableDebugging(::std::move(adapter), + debuggerTitleString); +} + +void OpaqueNAPIEnv::disableDebugger() const { + ::facebook::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/OpaqueNAPIRef.cpp b/src/hermes/OpaqueNAPIRef.cpp new file mode 100644 index 0000000..ead8778 --- /dev/null +++ b/src/hermes/OpaqueNAPIRef.cpp @@ -0,0 +1,103 @@ +#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; + break; + case 1: + return &::std::get<::hermes::vm::PinnedHermesValue>(this->storage); + break; + case 3: { + 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(); + } + } break; + + default: + return nullptr; + + break; + } +} diff --git a/toolchain/BUILD.gn b/toolchain/BUILD.gn index 7b8dd22..475ad74 100644 --- a/toolchain/BUILD.gn +++ b/toolchain/BUILD.gn @@ -1,4 +1,3 @@ -# -MMD 收集的用户头文件就足够了 depfile_string = "{{output}}.d" compiler_command = "-c {{source}} -o {{output}} -fPIC -funwind-tables -MMD -MF $depfile_string {{include_dirs}} {{defines}} {{cflags}}" if (generate_dwarf) { @@ -65,7 +64,6 @@ if (target_os == "android") { if (is_debug) { optimize_level = "-O0" } else { - # NDK 链接器 LTO 插件问题 optimize_level = "-O3" } default_output_extension = ".so" @@ -78,22 +76,15 @@ if (target_os == "android") { } } else { toolchain("clang") { - if (have_bitcode_flag && bitcode) { - compiler_command = "-fembed-bitcode $compiler_command" - } if (collect_code_coverage) { compiler_command = "-fprofile-instr-generate -fcoverage-mapping $compiler_command" } if (target_os == "ios") { - if (target_cpu == "x86") { - compiler_command = "-target i386-apple-ios9.0-simulator -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk $compiler_command" - } else if (target_cpu == "x64") { - compiler_command = "-target x86_64-apple-ios9.0-simulator -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk $compiler_command" - } else if (target_cpu == "arm") { - compiler_command = "-target armv7-apple-ios9.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk $compiler_command" + if (target_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-ios9.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk $compiler_command" + compiler_command = "-target arm64-apple-ios11.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk $compiler_command" } } @@ -117,7 +108,7 @@ if (target_os == "android") { tool("link") { lib_switch = "-l" - framework_switch = "-framework" + 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. From 5ce146b7e7d8670d593248298801ab6974ad3777 Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Sun, 4 Sep 2022 17:45:23 +0800 Subject: [PATCH 16/25] feat(Hermes): Complete hermes FunctionInfo class. --- BUILD.gn | 1 + include/hermes/FunctionInfo.h | 26 ++++++++++++++++++++++++++ src/hermes/FunctionInfo.cpp | 17 +++++++++++++++++ src/hermes/OpaqueNAPIEnv.cpp | 2 +- 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 include/hermes/FunctionInfo.h create mode 100644 src/hermes/FunctionInfo.cpp diff --git a/BUILD.gn b/BUILD.gn index e523006..e3d0fb9 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -875,6 +875,7 @@ source_set("napi_hermes") { "src/hermes/HermesExecutorRuntimeAdapter.cpp", "src/hermes/OpaqueNAPIEnv.cpp", "src/hermes/OpaqueNAPIRef.cpp", + "src/hermes/FunctionInfo.cpp", ] } diff --git a/include/hermes/FunctionInfo.h b/include/hermes/FunctionInfo.h new file mode 100644 index 0000000..11c279e --- /dev/null +++ b/include/hermes/FunctionInfo.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace orangelabs { +class FunctionInfo final { +public: + explicit FunctionInfo(NAPIEnv env, NAPICallback callback, void *data); + [[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/src/hermes/FunctionInfo.cpp b/src/hermes/FunctionInfo.cpp new file mode 100644 index 0000000..443c6be --- /dev/null +++ b/src/hermes/FunctionInfo.cpp @@ -0,0 +1,17 @@ +#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/OpaqueNAPIEnv.cpp b/src/hermes/OpaqueNAPIEnv.cpp index a44ef97..16cb57d 100644 --- a/src/hermes/OpaqueNAPIEnv.cpp +++ b/src/hermes/OpaqueNAPIEnv.cpp @@ -18,7 +18,7 @@ OpaqueNAPIEnv::OpaqueNAPIEnv(const ::hermes::vm::RuntimeConfig &runtimeConfig) this->hermesRuntime)) { // 0.8.x 版本开始会执行 runInternalBytecode -> runBytecode -> // clearThrownValue,0.7.2 版本没有执行,需要手动执行清空 - // RuntimeHermesValueFields.def 文件定义了 PinnedHermesValue thrownValue_ = + // Runtime.h 文件定义了 PinnedHermesValue thrownValue_ = // {} // => undefined LIST_INIT(&this->valueList); From 2fc31777501aa53e763a4cbfba4970502de4e18a Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Wed, 7 Sep 2022 23:39:44 +0800 Subject: [PATCH 17/25] feat(Hermes): Complete hermes engine upgrade. --- .clang-format | 2 +- BUILD.gn | 39 +- include/hermes/External.h | 13 +- include/hermes/FunctionInfo.h | 8 +- include/hermes/HermesExecutorRuntimeAdapter.h | 19 +- include/hermes/OpaqueNAPICallbackInfo.h | 29 + include/hermes/OpaqueNAPIEnv.h | 12 +- .../hermes/OpaqueNAPIEscapableHandleScope.h | 37 + include/hermes/OpaqueNAPIHandleScope.h | 29 + include/hermes/OpaqueNAPIRef.h | 13 +- include/napi/js_native_api.h | 4 +- src/hermes/External.cpp | 18 +- src/hermes/FunctionInfo.cpp | 12 +- src/hermes/HermesExecutorRuntimeAdapter.cpp | 3 +- src/hermes/OpaqueNAPICallbackInfo.cpp | 11 + src/hermes/OpaqueNAPIEnv.cpp | 20 + src/hermes/OpaqueNAPIEscapableHandleScope.cpp | 28 + src/hermes/OpaqueNAPIHandleScope.cpp | 6 + src/hermes/OpaqueNAPIRef.cpp | 49 +- src/js_native_api_hermes.cpp | 2290 +++++++---------- third_party/folly | 2 +- third_party/hermes | 2 +- third_party/hermes_patch.diff | 21 +- third_party/react-native | 2 +- 24 files changed, 1151 insertions(+), 1518 deletions(-) create mode 100644 include/hermes/OpaqueNAPICallbackInfo.h create mode 100644 include/hermes/OpaqueNAPIEscapableHandleScope.h create mode 100644 include/hermes/OpaqueNAPIHandleScope.h create mode 100644 src/hermes/OpaqueNAPICallbackInfo.cpp create mode 100644 src/hermes/OpaqueNAPIEscapableHandleScope.cpp create mode 100644 src/hermes/OpaqueNAPIHandleScope.cpp diff --git a/.clang-format b/.clang-format index 468ceea..2593ef5 100644 --- a/.clang-format +++ b/.clang-format @@ -1 +1 @@ -BasedOnStyle: LLVM \ No newline at end of file +BasedOnStyle: Google \ No newline at end of file diff --git a/BUILD.gn b/BUILD.gn index e3d0fb9..246904e 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -57,8 +57,12 @@ config("llvm_build") { "HAVE_FCNTL_H=1", # Process.inc:216 "HAVE_SIGNAL_H=1", # Process.inc:232 "RETSIGTYPE=void", - "HAVE_SYS_PARAM_H", # Unix.h:39 ] + if (target_os == "android") { + defines += [ + "HAVE_SYS_PARAM_H", # Path.inc:178 + ] + } } config("cpp_new_build") { @@ -85,20 +89,6 @@ source_set("dtoa") { ] } -source_set("llvm_demangle") { - configs = [ - ":minimal_size_build", - ":llvm_build", - ":common_build", - ":cpp_new_build", - ] - sources = [ - "third_party/hermes/external/llvh/lib/Demangle/ItaniumDemangle.cpp", - "third_party/hermes/external/llvh/lib/Demangle/MicrosoftDemangle.cpp", - "third_party/hermes/external/llvh/lib/Demangle/MicrosoftDemangleNodes.cpp", - ] -} - source_set("llvm_support") { configs = [ ":minimal_size_build", @@ -106,6 +96,7 @@ source_set("llvm_support") { ":common_build", ":cpp_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", @@ -177,6 +168,7 @@ config("hermes_build") { "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" ] @@ -375,6 +367,7 @@ source_set("hermes_parser") { ] 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", @@ -466,6 +459,7 @@ source_set("hermes_support") { "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", @@ -500,6 +494,7 @@ source_set("hermes_vm_runtime") { 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", @@ -530,6 +525,7 @@ source_set("hermes_vm_runtime") { "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", @@ -566,6 +562,7 @@ source_set("hermes_vm_runtime") { "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", @@ -579,8 +576,10 @@ source_set("hermes_vm_runtime") { "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", @@ -594,7 +593,6 @@ source_set("hermes_vm_runtime") { "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/SingleObject.cpp", @@ -860,8 +858,6 @@ source_set("napi_hermes") { "third_party/react-native/ReactCommon", ] cflags_cc = [ - #"-fno-exceptions", - #"-frtti", "-Wno-unused-parameter", "-Wno-gnu-anonymous-struct", "-Wno-gnu-zero-variadic-macro-arguments", @@ -870,12 +866,15 @@ source_set("napi_hermes") { "-Wno-nested-anon-types", ] sources = [ - #"src/js_native_api_hermes.cpp", "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/FunctionInfo.cpp", + "src/js_native_api_hermes.cpp", ] } diff --git a/include/hermes/External.h b/include/hermes/External.h index 6d33029..1580029 100644 --- a/include/hermes/External.h +++ b/include/hermes/External.h @@ -1,14 +1,11 @@ #pragma once #include - #include namespace orangelabs { - class External final : public ::hermes::vm::HostObjectProxy { - -public: + public: explicit External(::hermes::vm::Runtime &runtime, void *data, NAPIFinalize finalizeCallback, void *finalizeHint); @@ -16,8 +13,8 @@ class External final : public ::hermes::vm::HostObjectProxy { ~External() override; - ::hermes::vm::CallResult<::hermes::vm::HermesValue> - get(::hermes::vm::SymbolID symbolId) 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; @@ -33,10 +30,10 @@ class External final : public ::hermes::vm::HostObjectProxy { External &operator=(External &&) = delete; -private: + private: ::hermes::vm::Runtime &runtime; void *const data; const NAPIFinalize finalizeCallback; void *const finalizeHint; }; -} // namespace orangelabs +} // namespace orangelabs diff --git a/include/hermes/FunctionInfo.h b/include/hermes/FunctionInfo.h index 11c279e..2f13695 100644 --- a/include/hermes/FunctionInfo.h +++ b/include/hermes/FunctionInfo.h @@ -4,8 +4,10 @@ namespace orangelabs { class FunctionInfo final { -public: + public: explicit FunctionInfo(NAPIEnv env, NAPICallback callback, void *data); + ~FunctionInfo() = default; + [[nodiscard]] NAPIEnv getEnv() const; [[nodiscard]] NAPICallback getCallback() const; [[nodiscard]] void *getData() const; @@ -18,9 +20,9 @@ class FunctionInfo final { FunctionInfo &operator=(FunctionInfo &&) = delete; -private: + private: NAPIEnv env; NAPICallback callback; void *data; }; -} // namespace orangelabs \ No newline at end of file +} // namespace orangelabs \ No newline at end of file diff --git a/include/hermes/HermesExecutorRuntimeAdapter.h b/include/hermes/HermesExecutorRuntimeAdapter.h index 33b451e..83dee02 100644 --- a/include/hermes/HermesExecutorRuntimeAdapter.h +++ b/include/hermes/HermesExecutorRuntimeAdapter.h @@ -14,8 +14,8 @@ namespace debugger { class Debugger; } class HermesRuntime; -} // namespace hermes -} // namespace facebook +} // namespace hermes +} // namespace facebook #include @@ -23,8 +23,7 @@ namespace orangelabs { class HermesExecutorRuntimeAdapter final : public ::facebook::hermes::inspector::RuntimeAdapter { - -public: + public: explicit HermesExecutorRuntimeAdapter( ::std::shared_ptr<::facebook::jsi::Runtime> runtime, ::facebook::hermes::HermesRuntime &hermesRuntime, @@ -37,11 +36,11 @@ class HermesExecutorRuntimeAdapter final HermesExecutorRuntimeAdapter(HermesExecutorRuntimeAdapter &&) = delete; - HermesExecutorRuntimeAdapter & - operator=(const HermesExecutorRuntimeAdapter &) = delete; + HermesExecutorRuntimeAdapter &operator=( + const HermesExecutorRuntimeAdapter &) = delete; - HermesExecutorRuntimeAdapter & - operator=(HermesExecutorRuntimeAdapter &&) = delete; + HermesExecutorRuntimeAdapter &operator=(HermesExecutorRuntimeAdapter &&) = + delete; ::facebook::jsi::Runtime &getRuntime() override; @@ -49,11 +48,11 @@ class HermesExecutorRuntimeAdapter final void tickleJs() override; -private: + private: const ::std::shared_ptr<::facebook::jsi::Runtime> runtime; ::facebook::hermes::HermesRuntime &hermesRuntime; const ::std::shared_ptr<::facebook::react::MessageQueueThread> messageQueueThread; }; -} // namespace orangelabs +} // 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 index ae2357c..38cfb2d 100644 --- a/include/hermes/OpaqueNAPIEnv.h +++ b/include/hermes/OpaqueNAPIEnv.h @@ -1,12 +1,13 @@ #pragma once -#include #include +#include + namespace hermes::vm { class RuntimeConfig; class Runtime; -} // namespace hermes::vm +} // namespace hermes::vm namespace facebook::react { class MessageQueueThread; @@ -21,8 +22,7 @@ EXTERN_C_START #include struct OpaqueNAPIEnv final { - -public: + public: explicit OpaqueNAPIEnv(const ::hermes::vm::RuntimeConfig &runtimeConfig); ~OpaqueNAPIEnv(); @@ -43,6 +43,8 @@ struct OpaqueNAPIEnv final { LIST_HEAD(, OpaqueNAPIRef) strongRefList; + SLIST_HEAD(, OpaqueNAPIHandleScope) handleScopeList; + #ifdef HERMES_ENABLE_DEBUGGER void enableDebugger(const char *debuggerTitle, bool waitForDebugger) const; @@ -54,7 +56,7 @@ struct OpaqueNAPIEnv final { #endif -private: + private: ::std::shared_ptr<::facebook::react::MessageQueueThread> messageQueueThread; const ::std::shared_ptr<::facebook::hermes::HermesRuntime> hermesRuntimeSharedPointer; 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 index ef463d9..e5444ee 100644 --- a/include/hermes/OpaqueNAPIRef.h +++ b/include/hermes/OpaqueNAPIRef.h @@ -1,22 +1,21 @@ #pragma once -#include -#include - #include #include +#include + +#include namespace hermes::vm { class JSObject; -} // namespace hermes::vm +} // namespace hermes::vm EXTERN_C_START #include struct OpaqueNAPIRef final { - -public: + public: explicit OpaqueNAPIRef( NAPIEnv env, const ::hermes::vm::PinnedHermesValue &pinnedHermesValue, uint8_t referenceCount); @@ -45,7 +44,7 @@ struct OpaqueNAPIRef final { LIST_ENTRY(OpaqueNAPIRef) node; -private: + private: const NAPIEnv env; uint8_t referenceCount; }; diff --git a/include/napi/js_native_api.h b/include/napi/js_native_api.h index 8c6a7a2..fd5e339 100644 --- a/include/napi/js_native_api.h +++ b/include/napi/js_native_api.h @@ -92,11 +92,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); diff --git a/src/hermes/External.cpp b/src/hermes/External.cpp index 509f226..cb855a9 100644 --- a/src/hermes/External.cpp +++ b/src/hermes/External.cpp @@ -1,29 +1,29 @@ -#include - #include +#include orangelabs::External::External(::hermes::vm::Runtime &runtime, void *data, const NAPIFinalize finalizeCallback, void *finalizeHint) - : runtime(runtime), data(data), finalizeCallback(finalizeCallback), + : runtime(runtime), + data(data), + finalizeCallback(finalizeCallback), finalizeHint(finalizeHint) {} void *orangelabs::External::getData() const { return this->data; } -::orangelabs::External::~External() { +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) { +::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) { +::hermes::vm::CallResult orangelabs::External::set( + ::hermes::vm::SymbolID symbolId, ::hermes::vm::HermesValue value) { return false; } diff --git a/src/hermes/FunctionInfo.cpp b/src/hermes/FunctionInfo.cpp index 443c6be..24b7426 100644 --- a/src/hermes/FunctionInfo.cpp +++ b/src/hermes/FunctionInfo.cpp @@ -4,14 +4,8 @@ orangelabs::FunctionInfo::FunctionInfo(NAPIEnv env, NAPICallback callback, void *data) : env(env), callback(callback), data(data) {} -NAPIEnv orangelabs::FunctionInfo::getEnv() const { - return env; -} +NAPIEnv orangelabs::FunctionInfo::getEnv() const { return env; } -NAPICallback orangelabs::FunctionInfo::getCallback() const { - return callback; -} +NAPICallback orangelabs::FunctionInfo::getCallback() const { return callback; } -void *orangelabs::FunctionInfo::getData() const { - return data; -} \ No newline at end of file +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 index a3a3935..348afd9 100644 --- a/src/hermes/HermesExecutorRuntimeAdapter.cpp +++ b/src/hermes/HermesExecutorRuntimeAdapter.cpp @@ -10,7 +10,8 @@ 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), + : runtime(::std::move(runtime)), + hermesRuntime(hermesRuntime), messageQueueThread(::std::move(messageQueueThread)) {} ::facebook::jsi::Runtime & 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 index 16cb57d..a1d7966 100644 --- a/src/hermes/OpaqueNAPIEnv.cpp +++ b/src/hermes/OpaqueNAPIEnv.cpp @@ -8,8 +8,21 @@ #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)), @@ -24,6 +37,7 @@ OpaqueNAPIEnv::OpaqueNAPIEnv(const ::hermes::vm::RuntimeConfig &runtimeConfig) 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) { @@ -48,6 +62,12 @@ OpaqueNAPIEnv::OpaqueNAPIEnv(const ::hermes::vm::RuntimeConfig &runtimeConfig) 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; } diff --git a/src/hermes/OpaqueNAPIEscapableHandleScope.cpp b/src/hermes/OpaqueNAPIEscapableHandleScope.cpp new file mode 100644 index 0000000..625af9b --- /dev/null +++ b/src/hermes/OpaqueNAPIEscapableHandleScope.cpp @@ -0,0 +1,28 @@ +#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) { + assert(false); + + 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 index ead8778..8693dc2 100644 --- a/src/hermes/OpaqueNAPIRef.cpp +++ b/src/hermes/OpaqueNAPIRef.cpp @@ -1,9 +1,9 @@ -#include -#include - #include #include +#include +#include #include + #include OpaqueNAPIRef::OpaqueNAPIRef( @@ -74,30 +74,31 @@ uint8_t OpaqueNAPIRef::getReferenceCount() const { const ::hermes::vm::PinnedHermesValue *OpaqueNAPIRef::getHermesValue() const { switch (this->storage.index()) { - case 0: - return nullptr; - break; - case 1: - return &::std::get<::hermes::vm::PinnedHermesValue>(this->storage); - break; - case 3: { - 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) { + case 0: return nullptr; - } else { - auto handle = - this->env->getRuntime().makeHandle<::hermes::vm::JSObject>(jsObject); + 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(); + return handle.unsafeGetPinnedHermesValue(); + } } - } break; - default: - return nullptr; - - break; + default: + return nullptr; } } diff --git a/src/js_native_api_hermes.cpp b/src/js_native_api_hermes.cpp index 03a03d1..0f596ce 100644 --- a/src/js_native_api_hermes.cpp +++ b/src/js_native_api_hermes.cpp @@ -1,1572 +1,1056 @@ #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 #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; +NAPICommonStatus napi_get_null(NAPIEnv /*env*/, NAPIValue *result) { + CHECK_ARG(result, Common) - FunctionInfo(FunctionInfo &&) = delete; - - FunctionInfo &operator=(const FunctionInfo &) = delete; - - FunctionInfo &operator=(FunctionInfo &&) = delete; - - private: - NAPIEnv env; - NAPICallback callback; - void *data; -}; -} // namespace - -EXTERN_C_START - -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) - - 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) +NAPICommonStatus napi_is_array(NAPIEnv /*env*/, NAPIValue value, bool *result) { + CHECK_ARG(value, Common) + CHECK_ARG(result, Common) - 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; - } + *result = ::hermes::vm::vmisa<::hermes::vm::JSArray>( + *(const ::hermes::vm::PinnedHermesValue *)value); - 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) + + 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; } -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; +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_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_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; - } - - hermes::vm::GCScope *gcScope = nullptr; - - private: - bool escapeCalled; -}; +NAPIErrorStatus napi_open_escapable_handle_scope( + NAPIEnv env, NAPIEscapableHandleScope *result) { + CHECK_ARG(env, Error) + CHECK_ARG(result, Error) -EXTERN_C_END + ::hermes::vm::MutableHandle<::hermes::vm::HermesValue> mutableHandle( + env->getRuntime()); -NAPIErrorStatus napi_open_escapable_handle_scope(NAPIEnv env, NAPIEscapableHandleScope *result) -{ - CHECK_ARG(env, Error) - CHECK_ARG(result, Error) + *result = new (::std::nothrow) struct OpaqueNAPIEscapableHandleScope( + env->getRuntime(), ::std::move(mutableHandle)); + RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) + SLIST_INSERT_HEAD(&env->handleScopeList, *result, node); - 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; } -NAPICommonStatus napi_close_escapable_handle_scope(NAPIEnv env, NAPIEscapableHandleScope scope) -{ - CHECK_ARG(env, Common) - CHECK_ARG(scope, Common) - - delete scope->gcScope; - delete scope; - - return NAPICommonOK; +NAPIErrorStatus napi_close_escapable_handle_scope( + NAPIEnv env, NAPIEscapableHandleScope scope) { + return napi_close_handle_scope(env, scope); } -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->isEscapeCalled(), NAPIErrorEscapeCalledTwice) - - *result = (NAPIValue)hermes::vm::Handle(scope->gcScope->getParentScope(), - *(const hermes::vm::PinnedHermesValue *)escapee) - .unsafeGetPinnedHermesValue(); - scope->setEscapeCalled(true); + auto escapedValue = + scope->escape(*(const ::hermes::vm::PinnedHermesValue *)escapee); + RETURN_STATUS_IF_FALSE(!escapedValue, NAPIErrorEscapeCalledTwice) + *result = (NAPIValue)escapedValue; - return NAPIErrorOK; + return NAPIErrorOK; } -NAPIExceptionStatus napi_throw(NAPIEnv env, NAPIValue error) -{ - NAPI_PREAMBLE(env) - CHECK_ARG(error, Exception) +NAPIExceptionStatus napi_throw(NAPIEnv env, NAPIValue error) { + NAPI_PREAMBLE(env) + CHECK_ARG(error, Exception) - // 直接忽略返回值 - env->getRuntime()->setThrownValue(*(const hermes::vm::PinnedHermesValue *)error); + // 直接忽略返回值 + env->getRuntime().setThrownValue( + *(const ::hermes::vm::PinnedHermesValue *)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->getRuntime()->getThrownValue().isEmpty()) - { - *result = (NAPIValue)hermes::vm::Runtime::getUndefinedValue().unsafeGetPinnedHermesValue(); - } - else - { - *result = - (NAPIValue)env->getRuntime()->makeHandle(env->getRuntime()->getThrownValue()).unsafeGetPinnedHermesValue(); - env->getRuntime()->clearThrownValue(); - } - - return NAPIErrorOK; -} - -NAPICommonStatus NAPIClearLastException(NAPIEnv env) -{ - CHECK_ARG(env, Common) - - env->getRuntime()->clearThrownValue(); + 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 NAPICommonOK; + return NAPIErrorOK; } -NAPIExceptionStatus NAPIRunScript(NAPIEnv env, const char *script, const char *sourceUrl, NAPIValue *result) -{ - NAPI_PREAMBLE(env) +NAPICommonStatus NAPIClearLastException(NAPIEnv env) { + CHECK_ARG(env, Common) - 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(); - } + env->getRuntime().clearThrownValue(); - return NAPIExceptionOK; + return NAPICommonOK; } -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; - } +NAPIExceptionStatus NAPIRunScript(NAPIEnv env, const char *script, + const char *sourceUrl, NAPIValue *result) { + NAPI_PREAMBLE(env) - 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()) + ::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(); - 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; -} + } -NAPIErrorStatus NAPICreateRuntime(NAPIRuntime *runtime) -{ - return NAPIErrorOK; + return NAPIExceptionOK; } -NAPICommonStatus NAPIFreeRuntime(NAPIRuntime runtime) -{ - return NAPICommonOK; -} - -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; +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) + 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; } -NAPICommonStatus NAPIEnableDebugger(NAPIEnv env, const char *debuggerTitle, bool waitForDebugger) -{ - CHECK_ARG(env, Common) +NAPIErrorStatus NAPICreateRuntime(NAPIRuntime *) { return NAPIErrorOK; } - env->enableDebugger(debuggerTitle, waitForDebugger); +NAPICommonStatus NAPIFreeRuntime(NAPIRuntime) { return NAPICommonOK; } - return NAPICommonOK; -} - -NAPICommonStatus NAPIDisableDebugger(NAPIEnv env) -{ - CHECK_ARG(env, Common) +NAPIErrorStatus NAPICreateEnv(NAPIEnv *env, NAPIRuntime) { + CHECK_ARG(env, Error) - env->disableDebugger(); + *env = new (::std::nothrow) OpaqueNAPIEnv(::hermes::vm::RuntimeConfig()); + RETURN_STATUS_IF_FALSE(*env, NAPIErrorMemoryError) - return NAPICommonOK; + return NAPIErrorOK; } -NAPICommonStatus NAPISetMessageQueueThread(NAPIEnv env, MessageQueueThreadWrapper jsQueueWrapper) -{ -#ifdef HERMES_ENABLE_DEBUGGER - CHECK_ARG(env, Common); - env->setMessageQueueThread(jsQueueWrapper->thread_); -#endif - return NAPICommonOK; +// NAPICommonStatus NAPIEnableDebugger(NAPIEnv env, const char *debuggerTitle, +// bool waitForDebugger) { +// CHECK_ARG(env, Common) +// +// env->enableDebugger(debuggerTitle, waitForDebugger); +// +// return NAPICommonOK; +// } +// +// NAPICommonStatus NAPIDisableDebugger(NAPIEnv env) { +// CHECK_ARG(env, Common) +// +// env->disableDebugger(); +// +// return NAPICommonOK; +// } + +// NAPICommonStatus NAPISetMessageQueueThread( +// NAPIEnv env, MessageQueueThreadWrapper jsQueueWrapper) { +// #ifdef HERMES_ENABLE_DEBUGGER +// CHECK_ARG(env, Common); +// env->setMessageQueueThread(jsQueueWrapper->thread_); +// #endif +// return NAPICommonOK; +// } + +NAPICommonStatus NAPIFreeEnv(NAPIEnv env) { + CHECK_ARG(env, Common) + + delete env; + + return NAPICommonOK; } -NAPICommonStatus NAPIFreeEnv(NAPIEnv env) -{ - CHECK_ARG(env, Common) - - delete env; - - 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/third_party/folly b/third_party/folly index f434460..4baba28 160000 --- a/third_party/folly +++ b/third_party/folly @@ -1 +1 @@ -Subproject commit f434460f8a98e85f3ddb75390ddd1cc330c8f658 +Subproject commit 4baba28200d7446c870e96f3cdbeb492f54625d0 diff --git a/third_party/hermes b/third_party/hermes index ee8941b..716d48b 160000 --- a/third_party/hermes +++ b/third_party/hermes @@ -1 +1 @@ -Subproject commit ee8941b8874132b8f83e4486b63ed5c19fc3f111 +Subproject commit 716d48baf36b0b326ab82f53207b8682c87fc017 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/react-native b/third_party/react-native index 4bdec97..7fc33cc 160000 --- a/third_party/react-native +++ b/third_party/react-native @@ -1 +1 @@ -Subproject commit 4bdec975c95e8c46c804a8a00c73ebe696a6982b +Subproject commit 7fc33cc15afe063cf0bf458757b727b4a608c686 From 24f6ef17af2d4438ffcf9fc0b408af1b29f63883 Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Mon, 3 Oct 2022 15:51:14 +0800 Subject: [PATCH 18/25] chore: Temp commit. --- .gitignore | 5 +-- .gitmodules | 6 +-- .gn | 2 +- BUILD.gn | 39 +++++++++++++++++++ BUILDCONFIG.gn | 43 --------------------- build/config/BUILDCONFIG.gn | 51 +++++++++++++++++++++++++ {toolchain => build/toolchain}/BUILD.gn | 12 +++--- third_party/fmt | 1 - third_party/hermes | 2 +- third_party/include/glog/logging.h | 18 --------- third_party/log | 1 + third_party/react-native | 2 +- 12 files changed, 104 insertions(+), 78 deletions(-) delete mode 100644 BUILDCONFIG.gn create mode 100644 build/config/BUILDCONFIG.gn rename {toolchain => build/toolchain}/BUILD.gn (94%) delete mode 160000 third_party/fmt delete mode 100644 third_party/include/glog/logging.h create mode 160000 third_party/log diff --git a/.gitignore b/.gitignore index 908d2f1..2309303 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,7 @@ /third_party/include/boost/ /clion/ -/build/ -/.vscode/ -/.cache/ /.idea/ -/out/ +/out/ /arm/ diff --git a/.gitmodules b/.gitmodules index 9b1a683..0e5bc5f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,6 +22,6 @@ [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/log"] + path = third_party/log + url = git@github.com:acorninfra/log.git diff --git a/.gn b/.gn index 9fe0b42..c6fefba 100644 --- a/.gn +++ b/.gn @@ -1 +1 @@ -buildconfig = "//BUILDCONFIG.gn" +buildconfig = "//build/config/BUILDCONFIG.gn" diff --git a/BUILD.gn b/BUILD.gn index 246904e..6af9fd4 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -72,6 +72,37 @@ config("cpp_new_build") { ] } +source_set("glog") { + configs = [":minimal_size_build", ":cpp_new_build"] + include_dirs = [ + "third_party/include/glog", + "third_party/include", + "third_party/glog/src", + ] + defines = [ + "_START_GOOGLE_NAMESPACE_=namespace google {", + "_END_GOOGLE_NAMESPACE_=}", + "NO_THREADS", + "GOOGLE_NAMESPACE=google", + "HAVE_SYS_TIME_H", + "HAVE_SYS_SYSCALL_H", + "DISABLE_RTTI", + "HAVE_SYS_UTSNAME_H", + "HAVE_PREAD", + "HAVE_DLADDR", + "HAVE_FCNTL", + ] + 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("dtoa") { configs = [ ":minimal_size_build" ] cflags = [ "-fvisibility=hidden" ] @@ -924,6 +955,14 @@ if (target_os == "android") { "third_party/fbjni/cxx/lyra/lyra_exceptions.cpp", ] } + shared_library("mars") { + libs = [ + "c++", + ] + deps = [ + ":xlog", + ] + } shared_library("hermes") { libs = [ "c++", diff --git a/BUILDCONFIG.gn b/BUILDCONFIG.gn deleted file mode 100644 index cea40f0..0000000 --- a/BUILDCONFIG.gn +++ /dev/null @@ -1,43 +0,0 @@ -if (target_os == "") { - target_os = host_os -} -if (target_cpu == "") { - target_cpu = host_cpu -} - -assert(target_os == "android" || target_os == "ios" || target_os == "mac", - "Unsupported target os.") -if (target_os == "ios" || target_os == "mac") { - assert(target_cpu == "arm64" || target_cpu == "x64", "Unsupported target cpu.") -} else { - assert(target_cpu == "arm" || target_cpu == "arm64" || target_cpu == "x86" || - target_cpu == "x64", - "Unsupported target cpu.") -} - -declare_args() { - generate_dwarf = true - is_debug = false - - if (target_os == "android") { - ndk_path = "~/Library/Android/sdk/ndk/21.4.7075529" - } else { - collect_code_coverage = false - } - asan = false - ubsan = false - - enable_qjs_big_number = false -} - -declare_args() { - if (!is_debug) { - lto = true - } -} - -if (target_os == "android") { - set_default_toolchain("//toolchain:android") -} else { - set_default_toolchain("//toolchain:clang") -} 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/toolchain/BUILD.gn b/build/toolchain/BUILD.gn similarity index 94% rename from toolchain/BUILD.gn rename to build/toolchain/BUILD.gn index 475ad74..1a26511 100644 --- a/toolchain/BUILD.gn +++ b/build/toolchain/BUILD.gn @@ -27,11 +27,11 @@ if (target_os == "android") { toolchain("android") { compiler_command = "--sysroot $ndk_path/toolchains/llvm/prebuilt/darwin-x86_64/sysroot $compiler_command" - if (target_cpu == "arm") { + if (current_cpu == "arm") { target_option = "-target armv7-none-linux-androideabi16 -mthumb" - } else if (target_cpu == "arm64") { + } else if (current_cpu == "arm64") { target_option = "-target aarch64-none-linux-android21" - } else if (target_cpu == "x86") { + } else if (current_cpu == "x86") { target_option = "-target i686-none-linux-android18" } else { target_option = "-target x86_64-none-linux-android21" @@ -76,12 +76,12 @@ if (target_os == "android") { } } else { toolchain("clang") { - if (collect_code_coverage) { + if (target_os == "mac" && collect_code_coverage) { compiler_command = "-fprofile-instr-generate -fcoverage-mapping $compiler_command" } if (target_os == "ios") { - if (target_cpu == "x64") { + 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" @@ -116,7 +116,7 @@ if (target_os == "android") { if (!is_debug && lto) { command = "$command -Xlinker -object_path_lto -Xlinker {{output_dir}}/{{target_output_name}}_lto.o" } - if (collect_code_coverage) { + if (target_os == "mac" && collect_code_coverage) { command = "$command -fprofile-instr-generate" } default_output_dir = "{{root_out_dir}}" diff --git a/third_party/fmt b/third_party/fmt deleted file mode 160000 index 19bd751..0000000 --- a/third_party/fmt +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 19bd751020a1f3c3363b2eb67a039852f139a8d3 diff --git a/third_party/hermes b/third_party/hermes index 716d48b..2a6b111 160000 --- a/third_party/hermes +++ b/third_party/hermes @@ -1 +1 @@ -Subproject commit 716d48baf36b0b326ab82f53207b8682c87fc017 +Subproject commit 2a6b111ab289b55d7b78b5fdf105f466ba270fd7 diff --git a/third_party/include/glog/logging.h b/third_party/include/glog/logging.h deleted file mode 100644 index ecde968..0000000 --- a/third_party/include/glog/logging.h +++ /dev/null @@ -1,18 +0,0 @@ -#include - -#define INFO -#define WARNING - -#define LOG(severity) ::std::cout - -#define CHECK(condition) ::std::cout -#define CHECK_EQ(val1, val2) -#define CHECK_GE(val1, val2) - -#define DCHECK(condition) -#define DCHECK_EQ(val1, val2) ::std::cout -#define DCHECK_GT(val1, val2) -#define DCHECK_LT(val1, val2) -#define DCHECK_NE(val1, val2) -#define DCHECK_GE(val1, val2) -#define DCHECK_LE(val1, val2) \ No newline at end of file diff --git a/third_party/log b/third_party/log new file mode 160000 index 0000000..4451aa3 --- /dev/null +++ b/third_party/log @@ -0,0 +1 @@ +Subproject commit 4451aa3d59b2b193ff9a22e5191d5aeac1672286 diff --git a/third_party/react-native b/third_party/react-native index 7fc33cc..a54ba33 160000 --- a/third_party/react-native +++ b/third_party/react-native @@ -1 +1 @@ -Subproject commit 7fc33cc15afe063cf0bf458757b727b4a608c686 +Subproject commit a54ba33305621abb778085fc01ff954b621ce57b From 35ca579e74a2694e966169ccc9393405b73b108f Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Tue, 4 Oct 2022 17:11:26 +0800 Subject: [PATCH 19/25] chore: Temp commit. --- .gitignore | 2 +- .gitmodules | 9 +- BUILD.gn | 349 ++-- README.md | 4 +- third_party/fmt | 1 + third_party/glog | 1 + third_party/glog_patch.diff | 14 + third_party/include/double-conversion | 1 - third_party/include/folly/double-conversion | 1 + .../include/{llvh/Config => glog}/config.h | 0 third_party/include/glog/log_severity.h | 1 + third_party/include/glog/logging.h | 1661 +++++++++++++++++ third_party/include/glog/raw_logging.h | 185 ++ third_party/include/glog/stl_logging.h | 220 +++ third_party/include/glog/vlog_is_on.h | 129 ++ .../{ => libevent}/event2/event-config.h | 0 .../llvh/Config/config.h} | 0 .../include/llvm/llvh/Config/llvm-config.h | 0 third_party/log | 1 - 19 files changed, 2394 insertions(+), 185 deletions(-) create mode 160000 third_party/fmt create mode 160000 third_party/glog create mode 100644 third_party/glog_patch.diff delete mode 120000 third_party/include/double-conversion create mode 120000 third_party/include/folly/double-conversion rename third_party/include/{llvh/Config => glog}/config.h (100%) create mode 120000 third_party/include/glog/log_severity.h create mode 100644 third_party/include/glog/logging.h create mode 100644 third_party/include/glog/raw_logging.h create mode 100644 third_party/include/glog/stl_logging.h create mode 100644 third_party/include/glog/vlog_is_on.h rename third_party/include/{ => libevent}/event2/event-config.h (100%) rename third_party/include/{llvh/Config/llvm-config.h => llvm/llvh/Config/config.h} (100%) create mode 100644 third_party/include/llvm/llvh/Config/llvm-config.h delete mode 160000 third_party/log diff --git a/.gitignore b/.gitignore index 2309303..088e615 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .DS_Store -/third_party/include/boost/ +/third_party/include/folly/boost/ /clion/ /.idea/ diff --git a/.gitmodules b/.gitmodules index 0e5bc5f..23eda91 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,6 +22,9 @@ [submodule "third_party/fbjni"] path = third_party/fbjni url = git@github.com:facebookincubator/fbjni.git -[submodule "third_party/log"] - path = third_party/log - url = git@github.com:acorninfra/log.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/BUILD.gn b/BUILD.gn index 6af9fd4..9a66273 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1,3 +1,17 @@ +config("minimal_size_build") { + cflags_cc = [ + "-fno-exceptions", + "-fno-rtti", + ] +} + +config("new_build") { + cflags_cc = [ + "-std=c++17", + "-fvisibility=hidden", + ] +} + config("strict_build") { cflags = [ "-Wall", @@ -7,13 +21,6 @@ config("strict_build") { ] } -config("minimal_size_build") { - cflags_cc = [ - "-fno-exceptions", - "-fno-rtti", - ] -} - config("quickjs_build") { include_dirs = [ "third_party/quickjs" ] cflags_c = [ "-funsigned-char" ] @@ -34,14 +41,42 @@ source_set("quickjs") { } } -config("common_build") { - include_dirs = [ "third_party/include" ] +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" ] + 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") { include_dirs = [ "third_party/hermes/external/llvh/include", "third_party/hermes/external/llvh/gen/include", + "third_party/include/llvm", ] defines = [ "LLVM_ON_UNIX", @@ -52,71 +87,12 @@ config("llvm_build") { "PACKAGE_VERSION=\"\"", "HAVE_SYS_MMAN_H", # Memory.inc:51 "HAVE_SYS_STAT_H=1", # Path.inc:286 - "LLVM_ENABLE_CRASH_DUMPS=0", + "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", - ] - if (target_os == "android") { - defines += [ - "HAVE_SYS_PARAM_H", # Path.inc:178 - ] - } -} - -config("cpp_new_build") { - cflags_cc = [ - "-std=c++17", - "-fvisibility=hidden", - ] -} - -source_set("glog") { - configs = [":minimal_size_build", ":cpp_new_build"] - include_dirs = [ - "third_party/include/glog", - "third_party/include", - "third_party/glog/src", - ] - defines = [ - "_START_GOOGLE_NAMESPACE_=namespace google {", - "_END_GOOGLE_NAMESPACE_=}", - "NO_THREADS", - "GOOGLE_NAMESPACE=google", - "HAVE_SYS_TIME_H", - "HAVE_SYS_SYSCALL_H", - "DISABLE_RTTI", - "HAVE_SYS_UTSNAME_H", - "HAVE_PREAD", - "HAVE_DLADDR", - "HAVE_FCNTL", - ] - 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("dtoa") { - 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", + "HAVE_SYS_PARAM_H", # Path.inc:178 ] } @@ -124,8 +100,7 @@ source_set("llvm_support") { configs = [ ":minimal_size_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] cflags_c = [ "-fvisibility=hidden" ] sources = [ @@ -217,8 +192,7 @@ source_set("hermes_adt") { ":minimal_size_build", ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] sources = [ "third_party/hermes/lib/ADT/CompactArray.cpp" ] } @@ -228,8 +202,7 @@ source_set("hermes_ast") { ":minimal_size_build", ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] sources = [ "third_party/hermes/lib/AST/ASTBuilder.cpp", @@ -246,8 +219,7 @@ source_set("hermes_backend") { ":minimal_size_build", ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] sources = [ "third_party/hermes/lib/BCGen/BCOpt.cpp", @@ -271,8 +243,7 @@ source_set("hermes_frontend") { ":minimal_size_build", ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] sources = [ "third_party/hermes/lib/IR/CFG.cpp", @@ -298,8 +269,7 @@ source_set("hermes_hbc_backend") { ":minimal_size_build", ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] sources = [ "third_party/hermes/lib/BCGen/HBC/BackendContext.cpp", @@ -334,8 +304,7 @@ source_set("hermes_inst") { ":minimal_size_build", ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] sources = [ "third_party/hermes/lib/Inst/InstDecode.cpp", @@ -348,8 +317,7 @@ source_set("hermes_internal_bytecode") { ":minimal_size_build", ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] defines = [ "HERMES_CMAKE_BUILD" ] sources = [ "third_party/hermes/lib/InternalBytecode/InternalBytecode.cpp" ] @@ -359,9 +327,8 @@ source_set("hermes_optimizer") { configs = [ ":minimal_size_build", ":llvm_build", - ":common_build", ":hermes_build", - ":cpp_new_build", + ":new_build", ] sources = [ "third_party/hermes/lib/IR/Analysis.cpp", @@ -393,8 +360,7 @@ source_set("hermes_parser") { ":minimal_size_build", ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] include_dirs = [ "third_party/hermes/external" ] sources = [ @@ -414,9 +380,8 @@ source_set("hermes_platform") { configs = [ ":minimal_size_build", ":llvm_build", - ":common_build", ":hermes_build", - ":cpp_new_build", + ":new_build", ] sources = [ "third_party/hermes/lib/Platform/Logging.cpp" ] } @@ -424,9 +389,8 @@ source_set("hermes_platform") { source_set("hermes_platform_unicode") { configs = [ ":llvm_build", - ":common_build", ":hermes_build", - ":cpp_new_build", + ":new_build", ] sources = [ "third_party/hermes/lib/Platform/Unicode/CharacterProperties.cpp" ] @@ -450,9 +414,8 @@ source_set("hermes_regex") { configs = [ ":minimal_size_build", ":llvm_build", - ":common_build", ":hermes_build", - ":cpp_new_build", + ":new_build", ] sources = [ "third_party/hermes/lib/Regex/Executor.cpp", @@ -464,9 +427,8 @@ source_set("hermes_source_map") { configs = [ ":minimal_size_build", ":llvm_build", - ":common_build", ":hermes_build", - ":cpp_new_build", + ":new_build", ] sources = [ "third_party/hermes/lib/SourceMap/SourceMap.cpp", @@ -482,8 +444,7 @@ source_set("hermes_support") { ":minimal_size_build", ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] include_dirs = [ "third_party/hermes/external" ] sources = [ @@ -518,8 +479,7 @@ source_set("hermes_vm_runtime") { ":minimal_size_build", ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] include_dirs = [ "third_party/hermes/external" ] sources = [ @@ -650,8 +610,7 @@ source_set("hermes_vm_runtime_rtti") { configs = [ ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] cflags_cc = [ "-fno-exceptions", @@ -664,7 +623,7 @@ source_set("hermes_vm_runtime_rtti") { } source_set("jsi") { - configs = [ ":cpp_new_build" ] + configs = [ ":new_build" ] cflags_cc = [ "-fexceptions", "-frtti", @@ -673,11 +632,24 @@ source_set("jsi") { sources = [ "third_party/react-native/ReactCommon/jsi/jsi/jsi.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("jsi_dynamic") { configs = [ - ":cpp_new_build", ":folly_build", - ":common_build", + ":glog_build", + ":new_build", ] include_dirs = [ "third_party/react-native/ReactCommon/jsi" ] cflags_cc = [ @@ -691,8 +663,7 @@ source_set("hermes_api") { configs = [ ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] cflags_cc = [ "-fexceptions", @@ -705,26 +676,15 @@ source_set("hermes_api") { sources = [ "third_party/hermes/API/hermes/hermes.cpp" ] } -source_set("jsinspector") { - configs = [ - ":minimal_size_build", - ":cpp_new_build", - ] - sources = [ - "third_party/react-native/ReactCommon/jsinspector/InspectorInterfaces.cpp", - ] -} - source_set("hermes_debugger_api") { configs = [ ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] cflags_cc = [ "-fno-exceptions", - "-frtti", + "-frtti", # hermes_inspector -> Inspector.cpp 依赖 ] include_dirs = [ "third_party/hermes/API", @@ -733,24 +693,14 @@ source_set("hermes_debugger_api") { sources = [ "third_party/hermes/API/hermes/DebuggerAPI.cpp" ] } -config("libevent_build") { - defines = [ - "EVENT__HAVE_UINT64_T", - "EVENT__HAVE_UINT32_T", - "EVENT__HAVE_UINT16_T", - "EVENT__NUMERIC_VERSION=0x02010c00", +source_set("jsinspector") { + configs = [ + ":minimal_size_build", + ":new_build", ] - include_dirs = [ "third_party/libevent/include" ] -} - -config("folly_build") { - defines = [ - "FOLLY_NO_CONFIG", - "FOLLY_MOBILE=1", - "FOLLY_USE_LIBCPP=1", - "FOLLY_HAVE_CLOCK_GETTIME", + sources = [ + "third_party/react-native/ReactCommon/jsinspector/InspectorInterfaces.cpp", ] - include_dirs = [ "third_party/folly" ] } source_set("double_conversion") { @@ -768,30 +718,79 @@ source_set("double_conversion") { ] } -source_set("fmt") { - cflags_cc = [ - "-fvisibility=hidden", - "-frtti", - "-fno-exceptions", +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("glog_source") { + configs = [ + ":minimal_size_build", + ":glog_build", ] - include_dirs = [ "third_party/fmt/include" ] sources = [ - "third_party/fmt/src/format.cc", - "third_party/fmt/src/os.cc", + "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", + ] +} + +config("fmt_build") { + include_dirs = [ "third_party/fmt/include" ] + defines = [ + "FMT_EXPORT", + "FMT_SHARED", + ] +} + +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"] } source_set("folly") { configs = [ ":folly_build", - ":common_build", + ":fmt_build", + ":glog_build", + ":new_build", ] cflags_cc = [ "-fexceptions", "-frtti", - "-fvisibility=hidden", ] - include_dirs = [ "third_party/fmt/include" ] sources = [ "third_party/folly/folly/Conv.cpp", "third_party/folly/folly/Demangle.cpp", @@ -835,12 +834,25 @@ source_set("folly") { } } +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") { configs = [ ":folly_build", - ":common_build", + ":glog_build", ":libevent_build", - ":cpp_new_build", + ":new_build", ] include_dirs = [ "third_party/hermes/API", @@ -851,11 +863,16 @@ source_set("hermes_inspector") { if (target_os == "android") { include_dirs += [ "third_party/fbjni/cxx" ] } - defines = [ "HERMES_ENABLE_DEBUGGER" ] + + # 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", @@ -879,8 +896,7 @@ source_set("napi_hermes") { ":strict_build", ":hermes_build", ":llvm_build", - ":common_build", - ":cpp_new_build", + ":new_build", ] include_dirs = [ "include", @@ -909,20 +925,6 @@ source_set("napi_hermes") { ] } -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("napi_common") { configs = [ ":strict_build" ] include_dirs = [ "include" ] @@ -955,14 +957,6 @@ if (target_os == "android") { "third_party/fbjni/cxx/lyra/lyra_exceptions.cpp", ] } - shared_library("mars") { - libs = [ - "c++", - ] - deps = [ - ":xlog", - ] - } shared_library("hermes") { libs = [ "c++", @@ -973,7 +967,6 @@ if (target_os == "android") { ":double_conversion", ":dtoa", ":fbjni", - ":fmt", ":folly", ":hermes_adt", ":hermes_api", @@ -1000,6 +993,8 @@ if (target_os == "android") { ":jsinspector", ":llvm_support", ":napi_hermes", + ":fmt_source", + ":glog_source", ] } } else { diff --git a/README.md b/README.md index 4db09ac..107730d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Node-API(以前称为 N-API)是一个用于和 JavaScript 引擎交互并独 5. 如果出现 NAPIExceptionPendingException 说明出现 JS 异常,可以通过 napi_get_and_clear_last_exception 获取,或通过 NAPIClearLastException 清除 ## 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 依赖了 Boost,而 Boost 本身为模块化仓库管理源代码,而代码量非常大,因此需要先提前下载,地址为 `https://boostorg.jfrog.io/artifactory/main/release/1.76.0/source/boost_1_76_0.tar.gz` 然后解压后将 boost 文件夹移动到 third_party/include/folly 目录下。 ## 编辑器 1. Clion @@ -73,7 +73,7 @@ Node-API(以前称为 N-API)是一个用于和 JavaScript 引擎交互并独 ``` > cd lib/InternalBytecode > cat 00-header.js 01-Promise.js 02-AsyncFn.js 99-footer.js > InternalBytecode.js -> ../../build_macosx/bin/hermesc -O -Wno-undefined-variable -emit-binary -out=InternalBytecode.hbc InternalBytecode.js +> ../../build_host_hermesc/bin/hermesc -O -Wno-undefined-variable -emit-binary -out=InternalBytecode.hbc InternalBytecode.js > python3 xxd.py InternalBytecode.hbc > InternalBytecode.inc ``` 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/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/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/llvh/Config/config.h b/third_party/include/glog/config.h similarity index 100% rename from third_party/include/llvh/Config/config.h rename to third_party/include/glog/config.h 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 new file mode 100644 index 0000000..6ea15cb --- /dev/null +++ b/third_party/include/glog/logging.h @@ -0,0 +1,1661 @@ +// 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/event2/event-config.h b/third_party/include/libevent/event2/event-config.h similarity index 100% rename from third_party/include/event2/event-config.h rename to third_party/include/libevent/event2/event-config.h diff --git a/third_party/include/llvh/Config/llvm-config.h b/third_party/include/llvm/llvh/Config/config.h similarity index 100% rename from third_party/include/llvh/Config/llvm-config.h rename to third_party/include/llvm/llvh/Config/config.h 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/log b/third_party/log deleted file mode 160000 index 4451aa3..0000000 --- a/third_party/log +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4451aa3d59b2b193ff9a22e5191d5aeac1672286 From 4c8dd3d73000065763f99a4a9f77b01ab81f00c2 Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Tue, 4 Oct 2022 21:26:05 +0800 Subject: [PATCH 20/25] chore: Temp commit. --- .gitignore | 3 + BUILD.gn | 105 +++++++++++++++++- README.md | 2 +- build/toolchain/BUILD.gn | 2 +- src/hermes/OpaqueNAPIEscapableHandleScope.cpp | 4 +- src/js_native_api_hermes.cpp | 3 +- src/js_native_api_jsc.c | 10 +- src/js_native_api_qjs.c | 77 +++++++------ 8 files changed, 153 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index 088e615..ae302e4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ /out/ /arm/ +/arm64/ +/x86/ +/x64/ diff --git a/BUILD.gn b/BUILD.gn index 9a66273..c4c6970 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -616,6 +616,9 @@ source_set("hermes_vm_runtime_rtti") { "-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", @@ -626,7 +629,7 @@ source_set("jsi") { configs = [ ":new_build" ] cflags_cc = [ "-fexceptions", - "-frtti", + "-frtti", # hermes_api 需要 rtti ] include_dirs = [ "third_party/react-native/ReactCommon/jsi" ] sources = [ "third_party/react-native/ReactCommon/jsi/jsi/jsi.cpp" ] @@ -667,8 +670,11 @@ source_set("hermes_api") { ] cflags_cc = [ "-fexceptions", - "-frtti", + "-frtti", # std::function -> target 要求 rtti ] + if (ubsan) { + cflags_cc += [ "-fno-sanitize=vptr" ] + } include_dirs = [ "third_party/hermes/API", "third_party/react-native/ReactCommon/jsi", @@ -775,9 +781,9 @@ source_set("fmt_source") { ] cflags_cc = [ "-fno-exceptions", - "-frtti", # Folly 引用 fmt,Folly 强制开启 rtti + "-frtti", # Folly 引用 fmt,Folly 强制开启 rtti ] - sources = ["third_party/fmt/src/format.cc"] + sources = [ "third_party/fmt/src/format.cc" ] } source_set("folly") { @@ -957,6 +963,14 @@ if (target_os == "android") { "third_party/fbjni/cxx/lyra/lyra_exceptions.cpp", ] } + shared_library("qjs") { + libs = [ "m" ] + deps = [ + ":napi_common", + ":napi_qjs", + ":quickjs", + ] + } shared_library("hermes") { libs = [ "c++", @@ -967,7 +981,9 @@ if (target_os == "android") { ":double_conversion", ":dtoa", ":fbjni", + ":fmt_source", ":folly", + ":glog_source", ":hermes_adt", ":hermes_api", ":hermes_ast", @@ -993,8 +1009,6 @@ if (target_os == "android") { ":jsinspector", ":llvm_support", ":napi_hermes", - ":fmt_source", - ":glog_source", ] } } else { @@ -1022,6 +1036,43 @@ if (target_os == "android") { ":quickjs", ] } + + 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", + ] + } } else { source_set("gtest") { testonly = true @@ -1094,5 +1145,47 @@ if (target_os == "android") { ":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/README.md b/README.md index 107730d..42b809b 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Node-API(以前称为 N-API)是一个用于和 JavaScript 引擎交互并独 #### 注意 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.x 版本内置字节码,需要先编译主机 hermesc,指令 `./utils/build/build-mac-framework.sh`,后输入如下命令 ``` diff --git a/build/toolchain/BUILD.gn b/build/toolchain/BUILD.gn index 1a26511..1043351 100644 --- a/build/toolchain/BUILD.gn +++ b/build/toolchain/BUILD.gn @@ -28,7 +28,7 @@ if (target_os == "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-androideabi16 -mthumb" + 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") { diff --git a/src/hermes/OpaqueNAPIEscapableHandleScope.cpp b/src/hermes/OpaqueNAPIEscapableHandleScope.cpp index 625af9b..153e5c9 100644 --- a/src/hermes/OpaqueNAPIEscapableHandleScope.cpp +++ b/src/hermes/OpaqueNAPIEscapableHandleScope.cpp @@ -16,9 +16,7 @@ bool OpaqueNAPIEscapableHandleScope::isEscapeCalled() const { const ::hermes::vm::PinnedHermesValue *OpaqueNAPIEscapableHandleScope::escape( const ::hermes::vm::HermesValue &hermesValue) { - if (!this->escapeCalled) { - assert(false); - + if (this->escapeCalled) { return nullptr; } this->mutableHandle.set(hermesValue); diff --git a/src/js_native_api_hermes.cpp b/src/js_native_api_hermes.cpp index 0f596ce..2b49147 100644 --- a/src/js_native_api_hermes.cpp +++ b/src/js_native_api_hermes.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -774,7 +775,7 @@ NAPIErrorStatus napi_escape_handle(NAPIEnv env, NAPIEscapableHandleScope scope, auto escapedValue = scope->escape(*(const ::hermes::vm::PinnedHermesValue *)escapee); - RETURN_STATUS_IF_FALSE(!escapedValue, NAPIErrorEscapeCalledTwice) + RETURN_STATUS_IF_FALSE(escapedValue, NAPIErrorEscapeCalledTwice) *result = (NAPIValue)escapedValue; return NAPIErrorOK; diff --git a/src/js_native_api_jsc.c b/src/js_native_api_jsc.c index fded781..140b58f 100644 --- a/src/js_native_api_jsc.c +++ b/src/js_native_api_jsc.c @@ -1232,10 +1232,10 @@ NAPIErrorStatus napi_open_handle_scope(NAPIEnv env, NAPIHandleScope *result) return NAPIErrorOK; } -NAPICommonStatus napi_close_handle_scope(__attribute__((unused)) NAPIEnv env, +NAPIErrorStatus napi_close_handle_scope(__attribute__((unused)) NAPIEnv env, __attribute__((unused)) NAPIHandleScope scope) { - return NAPICommonOK; + return NAPIErrorOK; } struct OpaqueNAPIEscapableHandleScope @@ -1255,13 +1255,13 @@ NAPIErrorStatus napi_open_escapable_handle_scope(NAPIEnv env, NAPIEscapableHandl return NAPIErrorOK; } -NAPICommonStatus napi_close_escapable_handle_scope(__attribute__((unused)) NAPIEnv env, NAPIEscapableHandleScope scope) +NAPIErrorStatus napi_close_escapable_handle_scope(__attribute__((unused)) NAPIEnv env, NAPIEscapableHandleScope scope) { - CHECK_ARG(scope, Common) + CHECK_ARG(scope, Error) free(scope); - return NAPICommonOK; + return NAPIErrorOK; } NAPIErrorStatus napi_escape_handle(NAPIEnv env, NAPIEscapableHandleScope scope, NAPIValue escapee, NAPIValue *result) diff --git a/src/js_native_api_qjs.c b/src/js_native_api_qjs.c index 1b8245a..4479048 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); - *result = malloc(sizeof(struct OpaqueNAPIEscapableHandleScope)); + RETURN_STATUS_IF_FALSE(SLIST_FIRST(&env->handleScopeList), NAPIErrorHandleScopeEmpty); + + struct Handle *handlePointer = malloc(sizeof(struct Handle)); RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) + handlePointer->value = undefinedValue; + + *result = malloc(sizeof(struct OpaqueNAPIEscapableHandleScope)); + 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 +} From ca304216c998e41f0ec9a18fda42b8cf77623131 Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Tue, 4 Oct 2022 21:31:39 +0800 Subject: [PATCH 21/25] feat: Using #pragma once instead of macro. --- include/napi/js_native_api.h | 5 +---- include/napi/js_native_api_types.h | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/include/napi/js_native_api.h b/include/napi/js_native_api.h index fd5e339..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 @@ -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..afc9d26 100644 --- a/include/napi/js_native_api_types.h +++ b/include/napi/js_native_api_types.h @@ -1,5 +1,4 @@ -#ifndef SRC_JS_NATIVE_API_TYPES_H_ -#define SRC_JS_NATIVE_API_TYPES_H_ +#pragma once #ifdef __cplusplus #define EXTERN_C_START \ @@ -84,5 +83,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_ From 8ef1cf1eeb45666e5b95ffb983f0c2d800737b4a Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Thu, 6 Oct 2022 21:49:26 +0800 Subject: [PATCH 22/25] feat: Remove clion support. 1. Update README.md. 2. Format code. --- .gitignore | 4 +- README.md | 46 +- gn_to_cmake.py | 610 ------- include/napi/js_native_api_types.h | 63 +- src/js_native_api_hermes.cpp | 2 +- src/js_native_api_jsc.c | 2358 ++++++++++++++-------------- src/js_native_api_qjs.c | 2 +- 7 files changed, 1202 insertions(+), 1883 deletions(-) delete mode 100644 gn_to_cmake.py diff --git a/.gitignore b/.gitignore index ae302e4..6e422b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ .DS_Store /third_party/include/folly/boost/ -/clion/ -/.idea/ +/.vscode/ +/.cache/ /out/ /arm/ diff --git a/README.md b/README.md index 42b809b..fa1e03d 100644 --- a/README.md +++ b/README.md @@ -5,24 +5,21 @@ Node-API(以前称为 N-API)是一个用于和 JavaScript 引擎交互并独 2. NAPICommonStatus 类型的接口一般情况下不需要检查返回值,NAPIErrorStatus 接口可能抛出内存分配失败错误,NAPIExceptionStatus 代表可能抛出 JavaScript 异常 3. API 的返回值通过 out 参数传递。 4. 所有 JavaScript 值都抽象在一个名为 NAPIValue 的不透明类型后面。 -5. 如果出现 NAPIExceptionPendingException 说明出现 JS 异常,可以通过 napi_get_and_clear_last_exception 获取,或通过 NAPIClearLastException 清除 +5. 如果出现 NAPIExceptionPendingException 说明出现 JS 异常,可以通过 napi_get_and_clear_last_exception 获取或清除。A +6. 内存管理分为栈式和引用计数式两种,大部分情况下栈式自动管理就足够。 ## 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 目录下。 +由于 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 目录下。 ## 编辑器 -1. Clion -2. VSCode + clangd +1. VSCode + clangd ## VSCode 配置工程 -1. gn gen build --args="is_debug=true" --export-compile-commands - -## Clion -1. `gn gen clion --args="is_debug=true" --ide=json --json-ide-script=../gn_to_cmake.py --script-executable=python3` +1. gn 添加 --export-compile-commands 即可导出,可能需要设置 VSCode clangd 插件配置,以及单独导入子工程。 ## 单元测试 1. `gn gen out --args="is_debug=true asan=true ubsan=true"`(Release 模式下 assert 失效,会隐藏很多问题,特殊情况下启用 asan + ubsan) -2. `ninja -C out test_{qjs|jsc|hermes}` +2. `ninja -C out test_{qjs,jsc,hermes}` 3. `./out/test_{qjs|jsc|hermes}` ### QuickJS 单元测试修改源代码部分 @@ -38,29 +35,28 @@ Node-API(以前称为 N-API)是一个用于和 JavaScript 引擎交互并独 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` 临时修改 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/napi/js_native_api_types.h b/include/napi/js_native_api_types.h index afc9d26..c2f586c 100644 --- a/include/napi/js_native_api_types.h +++ b/include/napi/js_native_api_types.h @@ -1,9 +1,7 @@ #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 @@ -22,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 diff --git a/src/js_native_api_hermes.cpp b/src/js_native_api_hermes.cpp index 2b49147..7073f67 100644 --- a/src/js_native_api_hermes.cpp +++ b/src/js_native_api_hermes.cpp @@ -13,8 +13,8 @@ #include #include #include -#include #include +#include #include diff --git a/src/js_native_api_jsc.c b/src/js_native_api_jsc.c index 140b58f..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; } NAPIErrorStatus napi_close_handle_scope(__attribute__((unused)) NAPIEnv env, - __attribute__((unused)) NAPIHandleScope scope) -{ - return NAPIErrorOK; + __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; } -NAPIErrorStatus napi_close_escapable_handle_scope(__attribute__((unused)) NAPIEnv env, NAPIEscapableHandleScope scope) -{ - CHECK_ARG(scope, Error) +NAPIErrorStatus napi_close_escapable_handle_scope( + __attribute__((unused)) NAPIEnv env, NAPIEscapableHandleScope scope) { + CHECK_ARG(scope, Error) - free(scope); + free(scope); - return NAPIErrorOK; + 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 4479048..a4924e4 100644 --- a/src/js_native_api_qjs.c +++ b/src/js_native_api_qjs.c @@ -1345,7 +1345,7 @@ NAPIErrorStatus napi_open_escapable_handle_scope(NAPIEnv env, NAPIEscapableHandl RETURN_STATUS_IF_FALSE(SLIST_FIRST(&env->handleScopeList), NAPIErrorHandleScopeEmpty); struct Handle *handlePointer = malloc(sizeof(struct Handle)); - RETURN_STATUS_IF_FALSE(*result, NAPIErrorMemoryError) + RETURN_STATUS_IF_FALSE(handlePointer, NAPIErrorMemoryError) handlePointer->value = undefinedValue; *result = malloc(sizeof(struct OpaqueNAPIEscapableHandleScope)); From 3482ede9c5be4944d81839e164c132f7ebacc08b Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Sat, 8 Oct 2022 22:13:42 +0800 Subject: [PATCH 23/25] feat(Hermes): Add hermes engine debugger support. --- BUILD.gn | 1 + .../hermes}/js_native_api_hermes_inspector.h | 0 src/hermes/OpaqueNAPIEnv.cpp | 9 ++-- .../js_native_api_hermes_inspector.cpp | 2 +- src/js_native_api_hermes.cpp | 52 ++++++++++--------- 5 files changed, 34 insertions(+), 30 deletions(-) rename {src/inspector => include/hermes}/js_native_api_hermes_inspector.h (100%) rename src/{inspector => hermes}/js_native_api_hermes_inspector.cpp (99%) diff --git a/BUILD.gn b/BUILD.gn index c4c6970..14f6cce 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -927,6 +927,7 @@ source_set("napi_hermes") { "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", ] } 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/src/hermes/OpaqueNAPIEnv.cpp b/src/hermes/OpaqueNAPIEnv.cpp index a1d7966..498bf97 100644 --- a/src/hermes/OpaqueNAPIEnv.cpp +++ b/src/hermes/OpaqueNAPIEnv.cpp @@ -4,7 +4,8 @@ #ifdef HERMES_ENABLE_DEBUGGER #include #include -#include +// #include +#include #endif #include @@ -87,12 +88,12 @@ void OpaqueNAPIEnv::enableDebugger(const char *debuggerTitle, this->messageQueueThread); ::std::string debuggerTitleString = debuggerTitle ? debuggerTitle : "N-API Hermes"; - ::facebook::hermes::inspector::chrome::enableDebugging(::std::move(adapter), - debuggerTitleString); + ::orangelab::hermes::inspector::chrome::enableDebugging( + ::std::move(adapter), debuggerTitleString, waitForDebugger); } void OpaqueNAPIEnv::disableDebugger() const { - ::facebook::hermes::inspector::chrome::disableDebugging(this->hermesRuntime); + ::orangelab::hermes::inspector::chrome::disableDebugging(this->hermesRuntime); } void OpaqueNAPIEnv::setMessageQueueThread( 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 7073f67..1c3f621 100644 --- a/src/js_native_api_hermes.cpp +++ b/src/js_native_api_hermes.cpp @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include @@ -947,31 +949,31 @@ NAPIErrorStatus NAPICreateEnv(NAPIEnv *env, NAPIRuntime) { return NAPIErrorOK; } -// NAPICommonStatus NAPIEnableDebugger(NAPIEnv env, const char *debuggerTitle, -// bool waitForDebugger) { -// CHECK_ARG(env, Common) -// -// env->enableDebugger(debuggerTitle, waitForDebugger); -// -// return NAPICommonOK; -// } -// -// NAPICommonStatus NAPIDisableDebugger(NAPIEnv env) { -// CHECK_ARG(env, Common) -// -// env->disableDebugger(); -// -// return NAPICommonOK; -// } - -// NAPICommonStatus NAPISetMessageQueueThread( -// NAPIEnv env, MessageQueueThreadWrapper jsQueueWrapper) { -// #ifdef HERMES_ENABLE_DEBUGGER -// CHECK_ARG(env, Common); -// env->setMessageQueueThread(jsQueueWrapper->thread_); -// #endif -// return NAPICommonOK; -// } +NAPICommonStatus NAPIEnableDebugger(NAPIEnv env, const char *debuggerTitle, + bool waitForDebugger) { + CHECK_ARG(env, Common) + + env->enableDebugger(debuggerTitle, waitForDebugger); + + return NAPICommonOK; +} + +NAPICommonStatus NAPIDisableDebugger(NAPIEnv env) { + CHECK_ARG(env, Common) + + env->disableDebugger(); + + return NAPICommonOK; +} + +NAPICommonStatus NAPISetMessageQueueThread( + NAPIEnv env, MessageQueueThreadWrapper jsQueueWrapper) { +#ifdef HERMES_ENABLE_DEBUGGER + CHECK_ARG(env, Common); + env->setMessageQueueThread(jsQueueWrapper->thread_); +#endif + return NAPICommonOK; +} NAPICommonStatus NAPIFreeEnv(NAPIEnv env) { CHECK_ARG(env, Common) From 0c5a9ae850334b8f2c4df1f50226f85a792d77e1 Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Sat, 8 Oct 2022 22:41:56 +0800 Subject: [PATCH 24/25] docs: Update README.md. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa1e03d..7271ad1 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Node-API(以前称为 N-API)是一个用于和 JavaScript 引擎交互并独 2. NAPICommonStatus 类型的接口一般情况下不需要检查返回值,NAPIErrorStatus 接口可能抛出内存分配失败错误,NAPIExceptionStatus 代表可能抛出 JavaScript 异常 3. API 的返回值通过 out 参数传递。 4. 所有 JavaScript 值都抽象在一个名为 NAPIValue 的不透明类型后面。 -5. 如果出现 NAPIExceptionPendingException 说明出现 JS 异常,可以通过 napi_get_and_clear_last_exception 获取或清除。A +5. 如果出现 NAPIExceptionPendingException 说明出现 JS 异常,可以通过 napi_get_and_clear_last_exception 获取或清除。 6. 内存管理分为栈式和引用计数式两种,大部分情况下栈式自动管理就足够。 ## Boost From a3b2d996019699b888f636ba549964aab785f40d Mon Sep 17 00:00:00 2001 From: Chason Tang Date: Sun, 16 Oct 2022 22:41:59 +0800 Subject: [PATCH 25/25] chore: Update .gitignore file. --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6e422b0..0e5068c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ /third_party/include/folly/boost/ /.vscode/ -/.cache/ /out/ /arm/