diff --git a/.gitignore b/.gitignore index 2165bc74..a4f0e773 100644 --- a/.gitignore +++ b/.gitignore @@ -55,4 +55,6 @@ v8_build /project-template-ios/.build_env_vars.sh /project-template-ios/__PROJECT_NAME__.xcodeproj/project.xcworkspace/xcshareddata/ /project-template-vision/.build_env_vars.sh -/project-template-vision/__PROJECT_NAME__.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist \ No newline at end of file +/project-template-vision/__PROJECT_NAME__.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist + +.cache/ \ No newline at end of file diff --git a/NativeScript/CMakeLists.txt b/NativeScript/CMakeLists.txt index 3b8d599e..3ce985e5 100644 --- a/NativeScript/CMakeLists.txt +++ b/NativeScript/CMakeLists.txt @@ -2,14 +2,12 @@ cmake_minimum_required(VERSION 3.15) # Metadata -project(NativeScript) +project(NativeScript CXX OBJCXX) set(NAME NativeScript) set(VERSION 0.1.0) set(BUNDLE_IDENTIFIER "org.nativescript.runtime") -enable_language(OBJCXX) - set(CMAKE_CXX_STANDARD 20) set(BUILD_FRAMEWORK TRUE) @@ -21,8 +19,9 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMMON_FLAGS}") # Arguments set(TARGET_PLATFORM "macos" CACHE STRING "Target platform for the Objective-C bridge") -set(TARGET_ENGINE "hermes" CACHE STRING "Target JS engine for the NativeScript runtime") +set(TARGET_ENGINE "v8" CACHE STRING "Target JS engine for the NativeScript runtime") set(METADATA_SIZE 0 CACHE STRING "Size of embedded metadata in bytes") +set(BUILD_CLI_BINARY OFF CACHE BOOL "Build the NativeScript CLI binary") if(TARGET_PLATFORM STREQUAL "ios") set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "13.0") @@ -72,7 +71,7 @@ elseif(TARGET_ENGINE STREQUAL "hermes") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -std=c++20 -DTARGET_ENGINE_HERMES") elseif(TARGET_ENGINE STREQUAL "v8") set(TARGET_ENGINE_V8 TRUE) - add_link_options("-fuse-ld=/opt/homebrew/opt/llvm/bin/ld64.lld") + add_link_options("-fuse-ld=lld") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -stdlib=libc++ -std=c++20 -DTARGET_ENGINE_V8") elseif(TARGET_ENGINE STREQUAL "quickjs") set(TARGET_ENGINE_QUICKJS TRUE) @@ -86,6 +85,7 @@ else() endif() if(ENABLE_JS_RUNTIME) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_JS_RUNTIME") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_JS_RUNTIME") elseif(TARGET_PLATFORM_MACOS) # If building a generic library for macOS, we'll build a dylib instead of a framework @@ -102,7 +102,6 @@ message(STATUS "ENABLE_JS_RUNTIME = ${ENABLE_JS_RUNTIME}") include_directories( ./ ../metadata-generator/include - ada napi/common libffi/${LIBFFI_BUILD}/include ) @@ -128,20 +127,30 @@ set(SOURCE_FILES ffi/Interop.mm ffi/InlineFunctions.mm ffi/ClassBuilder.mm + ffi/NativeScriptException.mm ) if(ENABLE_JS_RUNTIME) set(SOURCE_FILES ${SOURCE_FILES} - runtime/Console.cpp + runtime/modules/console/Console.cpp runtime/Runtime.cpp - runtime/Require.cpp - runtime/Performance.cpp + runtime/modules/worker/Worker.mm + runtime/modules/worker/MessageJSON.cpp + runtime/modules/worker/MessageV8.cpp + runtime/modules/worker/ConcurrentQueue.cpp + runtime/modules/worker/WorkerImpl.mm + runtime/modules/worker/WorkerImpl.mm + runtime/modules/module/ModuleInternal.cpp + runtime/modules/performance/Performance.cpp runtime/Bundle.mm - runtime/Timers.mm - runtime/App.mm + runtime/modules/timers/Timers.mm + runtime/modules/app/App.mm runtime/NativeScript.mm runtime/RuntimeConfig.cpp + runtime/modules/url/ada/ada.cpp + runtime/modules/url/URL.cpp + runtime/modules/url/URLSearchParams.cpp ) if(TARGET_ENGINE_V8) @@ -161,8 +170,9 @@ if(ENABLE_JS_RUNTIME) elseif(TARGET_ENGINE_HERMES) include_directories( napi/hermes - napi/hermes/hermes - napi/hermes/jsi + napi/hermes/include + napi/hermes/include/hermes + napi/hermes/include/jsi ) set(SOURCE_FILES @@ -219,6 +229,13 @@ else() ) endif() +if(BUILD_CLI_BINARY) + set(SOURCE_FILES ${SOURCE_FILES} + cli/main.cpp + cli/segappend.cpp + ) +endif() + # Find SDK find_program(XCODEBUILD_EXECUTABLE xcodebuild) @@ -247,11 +264,15 @@ message(STATUS "SDK = ${CMAKE_OSX_SYSROOT}") # Build targets -add_library( - ${NAME} - SHARED - ${SOURCE_FILES} -) +if(BUILD_CLI_BINARY) + add_executable(${NAME} ${SOURCE_FILES}) +else() + add_library( + ${NAME} + SHARED + ${SOURCE_FILES} + ) +endif() target_sources( ${NAME} diff --git a/NativeScript/NativeScript.h b/NativeScript/NativeScript.h index c09b5cdc..32802134 100644 --- a/NativeScript/NativeScript.h +++ b/NativeScript/NativeScript.h @@ -8,7 +8,7 @@ extern "C" #endif // __cplusplus void - objc_bridge_init(void* env, const char* metadata_path, const void* metadata_ptr); + nativescript_init(void* env, const char* metadata_path, const void* metadata_ptr); #ifdef __OBJC__ diff --git a/NativeScript/cli/main.cpp b/NativeScript/cli/main.cpp new file mode 100644 index 00000000..11876d59 --- /dev/null +++ b/NativeScript/cli/main.cpp @@ -0,0 +1,105 @@ +#ifdef ENABLE_JS_RUNTIME + +#include +#include +#include + +#include "ffi/NativeScriptException.h" +#include "runtime/Bundle.h" +#include "runtime/Runtime.h" +#include "runtime/RuntimeConfig.h" +#include "segappend.h" + +using namespace nativescript; + +void bootFromBytecode(std::string baseDir, const void* data, size_t size) { + RuntimeConfig.BaseDir = baseDir; + + auto runtime = Runtime(); + + runtime.Init(); + + // TODO + // runtime.ExecuteBytecode(data, size); + + runtime.RunLoop(); +} + +void bootFromModuleSpec(std::string baseDir, std::string spec) { + RuntimeConfig.BaseDir = baseDir; + + auto runtime = Runtime(); + + runtime.Init(); + + try { + runtime.RunModule(spec); + } catch (const nativescript::NativeScriptException& e) { + std::cerr << "Uncaught Exception: " << e.Description() << std::endl; + std::exit(1); + } + + runtime.RunLoop(); +} + +int main(int argc, char** argv) { + RuntimeConfig.LogToSystemConsole = true; + +#ifdef __APPLE__ + std::string bytecodePath = getBytecodePathFromBundle(); + if (!bytecodePath.empty()) { + std::string bundlePath = getBundlePath(); + + std::ifstream file(bytecodePath, std::ios::binary); + if (!file.is_open()) { + std::cout << "Failed to open bytecode file" << std::endl; + return 1; + } + + file.seekg(0, std::ios::end); + size_t size = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector data(size); + file.read((char*)data.data(), size); + + file.close(); + + bootFromBytecode(bundlePath, data.data(), size); + + return 0; + } +#endif // __APPLE__ + + const uint8_t* segmentData; + size_t segmentSize; + auto status = segappend_load_segment("__nativescript_start", + (void**)&segmentData, &segmentSize); + + std::string cwd = std::filesystem::current_path().string(); + + if (status == segappend_ok) { + size_t bytecode_size = *(size_t*)segmentData; + segmentData += sizeof(size_t); + + bootFromBytecode(cwd, segmentData, bytecode_size); + } else { + if (argc < 3) { + std::cout << "Usage: " << argv[0] << " run " << std::endl; + return 1; + } + + std::string cmd = argv[1]; + + if (cmd == "run") { + bootFromModuleSpec(cwd, argv[2]); + } else { + std::cout << "Unknown command: " << cmd << std::endl; + return 1; + } + } + + return 0; +} + +#endif // ENABLE_JS_RUNTIME diff --git a/NativeScript/runtime/segappend.cpp b/NativeScript/cli/segappend.cpp similarity index 100% rename from NativeScript/runtime/segappend.cpp rename to NativeScript/cli/segappend.cpp diff --git a/NativeScript/runtime/segappend.h b/NativeScript/cli/segappend.h similarity index 100% rename from NativeScript/runtime/segappend.h rename to NativeScript/cli/segappend.h diff --git a/NativeScript/ffi/AutoreleasePool.h b/NativeScript/ffi/AutoreleasePool.h index 0ac2f8bb..0241932e 100644 --- a/NativeScript/ffi/AutoreleasePool.h +++ b/NativeScript/ffi/AutoreleasePool.h @@ -4,14 +4,14 @@ #include "node_api_util.h" extern "C" { -void *objc_autoreleasePoolPush(void); -void objc_autoreleasePoolPop(void *pool); +void* objc_autoreleasePoolPush(void); +void objc_autoreleasePoolPop(void* pool); } -namespace objc_bridge { +namespace nativescript { NAPI_FUNCTION(autoreleasepool); -} // namespace objc_bridge +} // namespace nativescript -#endif // AUTORELEASEPOOL_H +#endif // AUTORELEASEPOOL_H diff --git a/NativeScript/ffi/AutoreleasePool.mm b/NativeScript/ffi/AutoreleasePool.mm index 9ee8c552..edd187b2 100644 --- a/NativeScript/ffi/AutoreleasePool.mm +++ b/NativeScript/ffi/AutoreleasePool.mm @@ -1,6 +1,6 @@ #include "AutoreleasePool.h" -namespace objc_bridge { +namespace nativescript { napi_value JS_autoreleasepool(napi_env env, napi_callback_info info) { napi_value callback; @@ -15,4 +15,4 @@ napi_value JS_autoreleasepool(napi_env env, napi_callback_info info) { return result; } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/Block.h b/NativeScript/ffi/Block.h index abda0de9..f1ae8b50 100644 --- a/NativeScript/ffi/Block.h +++ b/NativeScript/ffi/Block.h @@ -1,30 +1,32 @@ #ifndef BLOCK_H #define BLOCK_H +#include + #include "Cif.h" #include "Closure.h" #include "node_api_util.h" -#include -namespace objc_bridge { +namespace nativescript { class FunctionPointer { -public: - void *function; + public: + void* function; metagen::MDSectionOffset offset; - Cif *cif; + Cif* cif; - static napi_value wrap(napi_env env, void *function, metagen::MDSectionOffset offset, bool isBlock); - static void finalize(napi_env env, void *finalize_data, void *finalize_hint); + static napi_value wrap(napi_env env, void* function, + metagen::MDSectionOffset offset, bool isBlock); + static void finalize(napi_env env, void* finalize_data, void* finalize_hint); static napi_value jsCallAsCFunction(napi_env env, napi_callback_info cbinfo); static napi_value jsCallAsBlock(napi_env env, napi_callback_info cbinfo); }; -id registerBlock(napi_env env, Closure *closure, napi_value callback); +id registerBlock(napi_env env, Closure* closure, napi_value callback); NAPI_FUNCTION(registerBlock); -} // namespace objc_bridge +} // namespace nativescript #endif /* BLOCK_H */ diff --git a/NativeScript/ffi/Block.mm b/NativeScript/ffi/Block.mm index e3842ae3..322bdc88 100644 --- a/NativeScript/ffi/Block.mm +++ b/NativeScript/ffi/Block.mm @@ -1,9 +1,9 @@ #include "Block.h" #import -#include "js_native_api_types.h" #include "Interop.h" #include "ObjCBridge.h" #include "js_native_api.h" +#include "js_native_api_types.h" #include "node_api_util.h" #include "objc/runtime.h" @@ -24,7 +24,7 @@ void* invoke; Block_descriptor_1* descriptor; // imported variables - objc_bridge::Closure* closure; + nativescript::Closure* closure; }; void block_copy(void* dest, void* src) {} @@ -36,7 +36,7 @@ void block_finalize(napi_env env, void* data, void* hint) { delete block; } -namespace objc_bridge { +namespace nativescript { void* stackBlockISA = nullptr; @@ -63,8 +63,8 @@ id registerBlock(napi_env env, Closure* closure, napi_value callback) { // TODO: fix memory management of objc blocks here // napi_wrap(env, callback, block, block_finalize, nullptr, &ref); // if (ref == nullptr) { - // Deno doesn't handle napi_wrap properly. - ref = make_ref(env, callback, 1); + // Deno doesn't handle napi_wrap properly. + ref = make_ref(env, callback, 1); // } else { // uint32_t refCount; // napi_reference_ref(env, ref, &refCount); @@ -72,6 +72,8 @@ id registerBlock(napi_env env, Closure* closure, napi_value callback) { closure->func = ref; auto bridgeState = ObjCBridgeState::InstanceData(env); + +#ifndef ENABLE_JS_RUNTIME if (napiSupportsThreadsafeFunctions(bridgeState->self_dl)) { napi_value workName; napi_create_string_utf8(env, "Block", NAPI_AUTO_LENGTH, &workName); @@ -79,6 +81,7 @@ id registerBlock(napi_env env, Closure* closure, napi_value callback) { closure, Closure::callBlockFromMainThread, &closure->tsfn); if (closure->tsfn) napi_unref_threadsafe_function(env, closure->tsfn); } +#endif // ENABLE_JS_RUNTIME return (id)block; } @@ -207,4 +210,4 @@ id registerBlock(napi_env env, Closure* closure, napi_value callback) { return cif->returnType->toJS(env, rvalue); } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/CFunction.h b/NativeScript/ffi/CFunction.h index 687be7f5..3c31093c 100644 --- a/NativeScript/ffi/CFunction.h +++ b/NativeScript/ffi/CFunction.h @@ -3,19 +3,19 @@ #include "Cif.h" -namespace objc_bridge { +namespace nativescript { class CFunction { -public: + public: static napi_value jsCall(napi_env env, napi_callback_info cbinfo); - CFunction(void *fnptr) : fnptr(fnptr) {} + CFunction(void* fnptr) : fnptr(fnptr) {} ~CFunction(); - void *fnptr; - Cif *cif = nullptr; + void* fnptr; + Cif* cif = nullptr; }; -} // namespace objc_bridge +} // namespace nativescript #endif /* C_FUNCTION_H */ diff --git a/NativeScript/ffi/CFunction.mm b/NativeScript/ffi/CFunction.mm index 536065bc..36c18899 100644 --- a/NativeScript/ffi/CFunction.mm +++ b/NativeScript/ffi/CFunction.mm @@ -1,8 +1,9 @@ #include "CFunction.h" #include "ClassMember.h" #include "ObjCBridge.h" +#include "ffi/NativeScriptException.h" -namespace objc_bridge { +namespace nativescript { void ObjCBridgeState::registerFunctionGlobals(napi_env env, napi_value global) { MDSectionOffset offset = metadata->functionsOffset; @@ -71,7 +72,15 @@ } } - ffi_call(&cif->cif, FFI_FN(func->fnptr), rvalue, avalues); + @try { + ffi_call(&cif->cif, FFI_FN(func->fnptr), rvalue, avalues); + } @catch (NSException* exception) { + std::string message = exception.description.UTF8String; + NSLog(@"ObjC->JS: Exception in CFunction: %s", message.c_str()); + nativescript::NativeScriptException nativeScriptException(message); + nativeScriptException.ReThrowToJS(env); + return nullptr; + } if (shouldFreeAny) { for (unsigned int i = 0; i < cif->argc; i++) { @@ -90,4 +99,4 @@ } } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/Cif.h b/NativeScript/ffi/Cif.h index b525c344..97673e9a 100644 --- a/NativeScript/ffi/Cif.h +++ b/NativeScript/ffi/Cif.h @@ -1,38 +1,39 @@ #ifndef METHOD_CIF_H #define METHOD_CIF_H +#include + #include "MetadataReader.h" #include "TypeConv.h" #include "ffi.h" #include "objc/message.h" #include "objc/runtime.h" -#include -namespace objc_bridge { +namespace nativescript { class Cif { -public: + public: ffi_cif cif; unsigned int argc; size_t frameLength; size_t rvalueLength; bool isVariadic = false; - void *rvalue; - void **avalues; + void* rvalue; + void** avalues; std::shared_ptr returnType; std::vector> argTypes; - napi_value *argv; + napi_value* argv; bool shouldFreeAny; - bool *shouldFree; + bool* shouldFree; Cif(napi_env env, std::string typeEncoding); - Cif(napi_env env, MDMetadataReader *reader, MDSectionOffset offset, - bool isMethod = false, bool isBlock = false); + Cif(napi_env env, MDMetadataReader* reader, MDSectionOffset offset, + bool isMethod = false, bool isBlock = false); }; -} // namespace objc_bridge +} // namespace nativescript #endif /* METHOD_CIF_H */ diff --git a/NativeScript/ffi/Cif.mm b/NativeScript/ffi/Cif.mm index 85774c5b..b6b1ae84 100644 --- a/NativeScript/ffi/Cif.mm +++ b/NativeScript/ffi/Cif.mm @@ -8,7 +8,7 @@ #include "TypeConv.h" #include "Util.h" -namespace objc_bridge { +namespace nativescript { // Essentially, we cache libffi structures per unique method signature, // this helps us avoid the overhead of creating them on the fly for each @@ -183,4 +183,4 @@ rvalueLength = cif.rtype->size; } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/Class.h b/NativeScript/ffi/Class.h index 99ea65ab..4797d88d 100644 --- a/NativeScript/ffi/Class.h +++ b/NativeScript/ffi/Class.h @@ -1,22 +1,23 @@ #ifndef BRIDGED_CLASS_H #define BRIDGED_CLASS_H +#include +#include + #include "ClassMember.h" #include "MetadataReader.h" #include "node_api_util.h" #include "objc/message.h" #include "objc/runtime.h" -#include -#include using namespace metagen; -namespace objc_bridge { +namespace nativescript { void setupObjCClassDecorator(napi_env env); void initFastEnumeratorIteratorFactory(napi_env env, - ObjCBridgeState *bridgeState); + ObjCBridgeState* bridgeState); NAPI_FUNCTION(registerClass); NAPI_FUNCTION(import); @@ -25,22 +26,22 @@ NAPI_FUNCTION(classGetter); class ObjCBridgeState; class ObjCClass { -public: + public: ObjCClass() {} ObjCClass(napi_env env, MDSectionOffset offset); ~ObjCClass(); - ObjCBridgeState *bridgeState; + ObjCBridgeState* bridgeState; napi_env env; napi_ref constructor; napi_ref prototype; MDSectionOffset metadataOffset; std::string name; Class nativeClass; - ObjCClass *superclass; + ObjCClass* superclass; ObjCClassMemberMap members; }; -} // namespace objc_bridge +} // namespace nativescript #endif /* BRIDGED_CLASS_H */ diff --git a/NativeScript/ffi/Class.mm b/NativeScript/ffi/Class.mm index c84417a5..f1b85a3c 100644 --- a/NativeScript/ffi/Class.mm +++ b/NativeScript/ffi/Class.mm @@ -13,7 +13,7 @@ #import #include -namespace objc_bridge { +namespace nativescript { void ObjCBridgeState::registerClassGlobals(napi_env env, napi_value global) { MDSectionOffset offset = metadata->classesOffset; @@ -99,7 +99,7 @@ return nullptr; } -const char *ObjCClassDecorator = R"( +const char* ObjCClassDecorator = R"( globalThis.ObjCClass = function ObjCClass(...protocols) { return function (target) { if (target.ObjCProtocols) { @@ -546,4 +546,4 @@ napi_value toJS(napi_env env) { napi_delete_reference(env, prototype); } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/ClassBuilder.h b/NativeScript/ffi/ClassBuilder.h index 75a60579..03acacba 100644 --- a/NativeScript/ffi/ClassBuilder.h +++ b/NativeScript/ffi/ClassBuilder.h @@ -9,27 +9,27 @@ @end -namespace objc_bridge { +namespace nativescript { class ObjCProtocol; class ClassBuilder : public ObjCClass { -public: + public: ClassBuilder(napi_env env, napi_value constructor); ~ClassBuilder(); - void addProtocol(ObjCProtocol *protocol); - MethodDescriptor *lookupMethodDescriptor(std::string &name); - void addMethod(std::string &name, MethodDescriptor *desc, napi_value key, + void addProtocol(ObjCProtocol* protocol); + MethodDescriptor* lookupMethodDescriptor(std::string& name); + void addMethod(std::string& name, MethodDescriptor* desc, napi_value key, napi_value func = nullptr); void build(); MethodMap exposedMethods; - std::unordered_set protocols; + std::unordered_set protocols; bool isFinal = false; }; -} // namespace objc_bridge +} // namespace nativescript #endif /* CLASS_BUILDER_H */ diff --git a/NativeScript/ffi/ClassBuilder.mm b/NativeScript/ffi/ClassBuilder.mm index e9f06f32..e7b4087f 100644 --- a/NativeScript/ffi/ClassBuilder.mm +++ b/NativeScript/ffi/ClassBuilder.mm @@ -1,14 +1,14 @@ #include "ClassBuilder.h" +#import +#include +#include "Closure.h" #include "Metadata.h" #include "ObjCBridge.h" #include "Util.h" #include "js_native_api.h" #include "node_api_util.h" -#import -#include -#include "Closure.h" -namespace objc_bridge { +namespace nativescript { ClassBuilder::ClassBuilder(napi_env env, napi_value constructor) { this->env = env; @@ -19,7 +19,7 @@ napi_value superConstructor; napi_get_prototype(env, constructor, &superConstructor); Class superClassNative = nullptr; - napi_unwrap(env, superConstructor, (void **)&superClassNative); + napi_unwrap(env, superConstructor, (void**)&superClassNative); if (superClassNative == nullptr) { // If the class does not inherit from a native class, @@ -51,7 +51,7 @@ napi_remove_wrap(env, constructor, nullptr); - napi_wrap(env, constructor, (void *)nativeClass, nullptr, nullptr, nullptr); + napi_wrap(env, constructor, (void*)nativeClass, nullptr, nullptr, nullptr); napi_value prototype; napi_get_named_property(env, constructor, "prototype", &prototype); @@ -68,19 +68,19 @@ } } -void ClassBuilder::addProtocol(ObjCProtocol *protocol) { +void ClassBuilder::addProtocol(ObjCProtocol* protocol) { if (!protocols.contains(protocol)) { protocols.emplace(protocol); // Not always there is a `Protocol` object for the protocol, so we // need to check if it exists first. - Protocol *proto = objc_getProtocol(protocol->name.c_str()); + Protocol* proto = objc_getProtocol(protocol->name.c_str()); if (proto != nullptr) { class_addProtocol(nativeClass, proto); } } } -MethodDescriptor *ClassBuilder::lookupMethodDescriptor(std::string &name) { +MethodDescriptor* ClassBuilder::lookupMethodDescriptor(std::string& name) { // 1. First we look up if there was a custom definition for the method // in ObjCExposedMethods static of the custom class. auto findExposedMethod = exposedMethods.find(name); @@ -90,11 +90,10 @@ // 2. Then walk through the class hierarchy and see if we can find the // method in the superclass chain. - ObjCClass *currentClass = superclass; + ObjCClass* currentClass = superclass; while (currentClass != nullptr) { auto findMethod = currentClass->members.find(name); - if (findMethod != currentClass->members.end() && - !findMethod->second.classMethod && + if (findMethod != currentClass->members.end() && !findMethod->second.classMethod && !findMethod->second.methodOrGetter.isProperty) { return &findMethod->second.methodOrGetter; } @@ -103,64 +102,57 @@ // 3. And finally, look into all protocols implemented (directly or // indirectly) and try to find the method there. - std::function & - protocols)> - processProtocols = [&](std::unordered_set &protocols) - -> MethodDescriptor * { + std::function & protocols)> processProtocols = + [&](std::unordered_set& protocols) -> MethodDescriptor* { for (auto protocol : protocols) { auto findMethod = protocol->members.find(name); - if (findMethod != protocol->members.end() && - !findMethod->second.classMethod && + if (findMethod != protocol->members.end() && !findMethod->second.classMethod && !findMethod->second.methodOrGetter.isProperty) { return &findMethod->second.methodOrGetter; } - MethodDescriptor *desc = processProtocols(protocol->protocols); - if (desc != nullptr) - return desc; + MethodDescriptor* desc = processProtocols(protocol->protocols); + if (desc != nullptr) return desc; } - return (MethodDescriptor *)nullptr; + return (MethodDescriptor*)nullptr; }; return processProtocols(protocols); } -void ClassBuilder::addMethod(std::string &name, MethodDescriptor *desc, - napi_value key, napi_value func) { +void ClassBuilder::addMethod(std::string& name, MethodDescriptor* desc, napi_value key, + napi_value func) { switch (desc->kind) { - case kMethodDescEncoding: { - const char *encoding = desc->encoding.c_str(); - auto closure = new Closure(encoding, false); - closure->env = env; - if (func != nullptr) - closure->func = make_ref(env, func); - else - closure->propertyName = name; - closure->thisConstructor = constructor; - class_replaceMethod(nativeClass, desc->selector, (IMP)closure->fnptr, - encoding); - break; - } + case kMethodDescEncoding: { + const char* encoding = desc->encoding.c_str(); + auto closure = new Closure(encoding, false); + closure->env = env; + if (func != nullptr) + closure->func = make_ref(env, func); + else + closure->propertyName = name; + closure->thisConstructor = constructor; + class_replaceMethod(nativeClass, desc->selector, (IMP)closure->fnptr, encoding); + break; + } - case kMethodDescSignatureOffset: { - std::string encoding; - auto closure = new Closure(bridgeState->metadata, desc->signatureOffset, - false, &encoding, true, desc->isProperty); - closure->env = env; - if (func != nullptr) - closure->func = make_ref(env, func); - else - closure->propertyName = name; - closure->thisConstructor = constructor; - class_replaceMethod(nativeClass, desc->selector, (IMP)closure->fnptr, - encoding.c_str()); - break; - } + case kMethodDescSignatureOffset: { + std::string encoding; + auto closure = new Closure(bridgeState->metadata, desc->signatureOffset, false, &encoding, + true, desc->isProperty); + closure->env = env; + if (func != nullptr) + closure->func = make_ref(env, func); + else + closure->propertyName = name; + closure->thisConstructor = constructor; + class_replaceMethod(nativeClass, desc->selector, (IMP)closure->fnptr, encoding.c_str()); + break; + } } } void ClassBuilder::build() { - if (isFinal) - return; + if (isFinal) return; isFinal = true; @@ -171,16 +163,13 @@ napi_value exposedMethods, exposedMethodNames; bool hasExposedMethods = false; - napi_has_named_property(env, constructor, "ObjCExposedMethods", - &hasExposedMethods); + napi_has_named_property(env, constructor, "ObjCExposedMethods", &hasExposedMethods); if (hasExposedMethods) { - napi_get_named_property(env, constructor, "ObjCExposedMethods", - &exposedMethods); + napi_get_named_property(env, constructor, "ObjCExposedMethods", &exposedMethods); - napi_get_all_property_names( - env, exposedMethods, napi_key_own_only, napi_key_skip_symbols, - napi_key_numbers_to_strings, &exposedMethodNames); + napi_get_all_property_names(env, exposedMethods, napi_key_own_only, napi_key_skip_symbols, + napi_key_numbers_to_strings, &exposedMethodNames); uint32_t exposedMethodCount = 0; napi_get_array_length(env, exposedMethodNames, &exposedMethodCount); @@ -189,8 +178,7 @@ napi_value exposedMethodName; napi_get_element(env, exposedMethodNames, i, &exposedMethodName); static char exposedMethodNameBuf[512]; - napi_get_value_string_utf8(env, exposedMethodName, exposedMethodNameBuf, - 512, nullptr); + napi_get_value_string_utf8(env, exposedMethodName, exposedMethodNameBuf, 512, nullptr); std::string name = exposedMethodNameBuf; SEL selector = sel_registerName(name.c_str()); std::string encoding; @@ -211,8 +199,7 @@ napi_get_element(env, params, j, ¶m); std::string enctype = getEncodedType(env, param); if (enctype == "v") { - napi_throw_error(env, nullptr, - "Void type not allowed in method params"); + napi_throw_error(env, nullptr, "Void type not allowed in method params"); return; } encoding += enctype; @@ -239,10 +226,9 @@ napi_get_element(env, protocols, i, &protocol); static char protocolNameBuf[512]; napi_get_value_string_utf8(env, protocol, protocolNameBuf, 512, nullptr); - ObjCProtocol *proto = nullptr; - napi_unwrap(env, protocol, (void **)&proto); - if (proto != nullptr) - addProtocol(proto); + ObjCProtocol* proto = nullptr; + napi_unwrap(env, protocol, (void**)&proto); + if (proto != nullptr) addProtocol(proto); i++; } } @@ -252,8 +238,7 @@ napi_value properties; - napi_get_all_property_names(env, prototype, napi_key_own_only, - napi_key_skip_symbols, + napi_get_all_property_names(env, prototype, napi_key_own_only, napi_key_skip_symbols, napi_key_numbers_to_strings, &properties); uint32_t propertyCount = 0; @@ -266,7 +251,7 @@ static char propertyNameBuf[512]; napi_get_value_string_utf8(env, property, propertyNameBuf, 512, nullptr); std::string name = propertyNameBuf; - MethodDescriptor *desc = lookupMethodDescriptor(name); + MethodDescriptor* desc = lookupMethodDescriptor(name); if (desc != nullptr) { addMethod(name, desc, property); } @@ -274,4 +259,4 @@ } } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/ClassMember.h b/NativeScript/ffi/ClassMember.h index 4596070d..68964449 100644 --- a/NativeScript/ffi/ClassMember.h +++ b/NativeScript/ffi/ClassMember.h @@ -1,11 +1,12 @@ #ifndef BRIDGED_METHOD_H #define BRIDGED_METHOD_H +#include + #include "Cif.h" #include "objc/runtime.h" -#include -namespace objc_bridge { +namespace nativescript { class ObjCBridgeState; @@ -15,7 +16,7 @@ enum MethodDescriptorKind : uint8_t { }; class MethodDescriptor { -public: + public: SEL selector; MethodDescriptorKind kind; @@ -27,10 +28,11 @@ class MethodDescriptor { MethodDescriptor() {} MethodDescriptor(SEL selector, MDSectionOffset offset) - : selector(selector), kind(kMethodDescSignatureOffset), + : selector(selector), + kind(kMethodDescSignatureOffset), signatureOffset(offset) {} - MethodDescriptor(SEL selector, char *encoding) + MethodDescriptor(SEL selector, char* encoding) : selector(selector), kind(kMethodDescEncoding), encoding(encoding) {} MethodDescriptor(SEL selector, std::string encoding) @@ -46,8 +48,8 @@ class ObjCClassMember; typedef std::unordered_map ObjCClassMemberMap; class ObjCClassMember { -public: - static void defineMembers(napi_env env, ObjCClassMemberMap &memberMap, + public: + static void defineMembers(napi_env env, ObjCClassMemberMap& memberMap, MDSectionOffset offset, napi_value constructor); static napi_value jsCall(napi_env env, napi_callback_info cbinfo); @@ -55,14 +57,14 @@ class ObjCClassMember { static napi_value jsGetter(napi_env env, napi_callback_info cbinfo); static napi_value jsSetter(napi_env env, napi_callback_info cbinfo); - ObjCClassMember(ObjCBridgeState *bridgeState, SEL selector, + ObjCClassMember(ObjCBridgeState* bridgeState, SEL selector, MDSectionOffset offset, MDMemberFlag flags) : bridgeState(bridgeState), methodOrGetter(MethodDescriptor(selector, offset)), returnOwned((flags & metagen::mdMemberReturnOwned) != 0), classMethod((flags & metagen::mdMemberStatic) != 0) {} - ObjCClassMember(ObjCBridgeState *bridgeState, SEL getterSelector, + ObjCClassMember(ObjCBridgeState* bridgeState, SEL getterSelector, SEL setterSelector, MDSectionOffset getterOffset, MDSectionOffset setterOffset, MDMemberFlag flags) : bridgeState(bridgeState), @@ -74,15 +76,15 @@ class ObjCClassMember { setter.isProperty = true; } - ObjCBridgeState *bridgeState; + ObjCBridgeState* bridgeState; MethodDescriptor methodOrGetter; MethodDescriptor setter; - Cif *cif = nullptr; - Cif *setterCif = nullptr; + Cif* cif = nullptr; + Cif* setterCif = nullptr; bool returnOwned; bool classMethod; }; -} // namespace objc_bridge +} // namespace nativescript #endif /* BRIDGED_METHOD_H */ diff --git a/NativeScript/ffi/ClassMember.mm b/NativeScript/ffi/ClassMember.mm index 4dc7988d..d3f00631 100644 --- a/NativeScript/ffi/ClassMember.mm +++ b/NativeScript/ffi/ClassMember.mm @@ -1,43 +1,41 @@ #include "ClassMember.h" +#import +#include +#include +#include #include "ClassBuilder.h" #include "MetadataReader.h" #include "ObjCBridge.h" #include "TypeConv.h" #include "Util.h" +#include "ffi/NativeScriptException.h" #include "js_native_api.h" #include "js_native_api_types.h" #include "node_api_util.h" -#import -#include -#include -#include -namespace objc_bridge { +namespace nativescript { napi_value JS_NSObject_alloc(napi_env env, napi_callback_info cbinfo) { napi_value jsThis; napi_get_cb_info(env, cbinfo, nullptr, nullptr, &jsThis, nullptr); id self; - napi_unwrap(env, jsThis, (void **)&self); + napi_unwrap(env, jsThis, (void**)&self); bool supercall = class_conformsToProtocol(self, @protocol(ObjCBridgeClassBuilderProtocol)); if (supercall) { - ObjCBridgeState *state = ObjCBridgeState::InstanceData(env); - ClassBuilder *builder = (ClassBuilder *)state->classesByPointer[self]; - if (!builder->isFinal) - builder->build(); + ObjCBridgeState* state = ObjCBridgeState::InstanceData(env); + ClassBuilder* builder = (ClassBuilder*)state->classesByPointer[self]; + if (!builder->isFinal) builder->build(); } id result = [self alloc]; - return ObjCBridgeState::InstanceData(env)->getObject(env, result, jsThis, - kOwnedObject); + return ObjCBridgeState::InstanceData(env)->getObject(env, result, jsThis, kOwnedObject); } -void ObjCClassMember::defineMembers(napi_env env, ObjCClassMemberMap &memberMap, - MDSectionOffset offset, - napi_value constructor) { +void ObjCClassMember::defineMembers(napi_env env, ObjCClassMemberMap& memberMap, + MDSectionOffset offset, napi_value constructor) { auto bridgeState = ObjCBridgeState::InstanceData(env); napi_value prototype; @@ -48,8 +46,7 @@ napi_value JS_NSObject_alloc(napi_env env, napi_callback_info cbinfo) { while (next) { auto flags = bridgeState->metadata->getMemberFlag(offset); - if (flags == mdMemberFlagNull) - break; + if (flags == mdMemberFlagNull) break; next = (flags & mdMemberNext) != 0; offset += sizeof(flags); @@ -63,40 +60,38 @@ napi_value JS_NSObject_alloc(napi_env env, napi_callback_info cbinfo) { if ((flags & mdMemberProperty) != 0) { bool readonly = (flags & mdMemberReadonly) != 0; - const char *name = bridgeState->metadata->getString(offset); - offset += sizeof(MDSectionOffset); // name + const char* name = bridgeState->metadata->getString(offset); + offset += sizeof(MDSectionOffset); // name MDSectionOffset getterSignature, setterSignature; - const char *getterSelector = bridgeState->metadata->getString(offset); + const char* getterSelector = bridgeState->metadata->getString(offset); - offset += sizeof(MDSectionOffset); // getterSelector + offset += sizeof(MDSectionOffset); // getterSelector getterSignature = bridgeState->metadata->getOffset(offset); - offset += sizeof(MDSectionOffset); // getterSignature + offset += sizeof(MDSectionOffset); // getterSignature - const char *setterSelector = nullptr; + const char* setterSelector = nullptr; if (!readonly) { setterSelector = bridgeState->metadata->getString(offset); - offset += sizeof(MDSectionOffset); // setterSelector + offset += sizeof(MDSectionOffset); // setterSelector setterSignature = bridgeState->metadata->getOffset(offset); - offset += sizeof(MDSectionOffset); // setterSignature + offset += sizeof(MDSectionOffset); // setterSignature } if (memberMap.contains(name)) { memberMap.erase(name); } - const auto &kv = memberMap.emplace( - name, ObjCClassMember( - bridgeState, sel_registerName(getterSelector), - !readonly ? sel_registerName(setterSelector) : nullptr, - getterSignature + bridgeState->metadata->signaturesOffset, - !readonly ? setterSignature + - bridgeState->metadata->signaturesOffset - : 0, - flags)); + const auto& kv = memberMap.emplace( + name, + ObjCClassMember(bridgeState, sel_registerName(getterSelector), + !readonly ? sel_registerName(setterSelector) : nullptr, + getterSignature + bridgeState->metadata->signaturesOffset, + !readonly ? setterSignature + bridgeState->metadata->signaturesOffset : 0, + flags)); napi_property_descriptor property = { .utf8name = name, @@ -105,17 +100,16 @@ napi_value JS_NSObject_alloc(napi_env env, napi_callback_info cbinfo) { .getter = jsGetter, .setter = readonly ? nil : jsSetter, .value = nil, - .attributes = - (napi_property_attributes)(napi_configurable | napi_enumerable), + .attributes = (napi_property_attributes)(napi_configurable | napi_enumerable), .data = &kv.first->second, }; napi_define_properties(env, jsObject, 1, &property); } else { auto selector = bridgeState->metadata->getString(offset); - offset += sizeof(MDSectionOffset); // selector + offset += sizeof(MDSectionOffset); // selector auto signature = bridgeState->metadata->getOffset(offset); - offset += sizeof(MDSectionOffset); // signature + offset += sizeof(MDSectionOffset); // signature auto name = jsifySelector(selector); @@ -125,23 +119,19 @@ napi_value JS_NSObject_alloc(napi_env env, napi_callback_info cbinfo) { continue; } - const auto &kv = memberMap.emplace( - name, - ObjCClassMember(bridgeState, sel_registerName(selector), - signature + bridgeState->metadata->signaturesOffset, - flags)); + const auto& kv = memberMap.emplace( + name, ObjCClassMember(bridgeState, sel_registerName(selector), + signature + bridgeState->metadata->signaturesOffset, flags)); napi_property_descriptor property = { .utf8name = name.c_str(), .name = nil, - .method = - (flags & metagen::mdMemberIsInit) != 0 ? jsCallInit : jsCall, + .method = (flags & metagen::mdMemberIsInit) != 0 ? jsCallInit : jsCall, .getter = nil, .setter = nil, .value = nil, .attributes = - (napi_property_attributes)(napi_configurable | napi_writable | - napi_enumerable), + (napi_property_attributes)(napi_configurable | napi_writable | napi_enumerable), .data = &kv.first->second, }; @@ -154,83 +144,100 @@ napi_value JS_NSObject_alloc(napi_env env, napi_callback_info cbinfo) { } } -inline void objcNativeCall(napi_env env, napi_value jsThis, Cif *cif, id self, - void **avalues, void *rvalue) { +inline bool objcNativeCall(napi_env env, napi_value jsThis, Cif* cif, id self, void** avalues, + void* rvalue) { bool classMethod = class_isMetaClass(object_getClass(self)); - bool supercall = - classMethod - ? class_conformsToProtocol(self, - @protocol(ObjCBridgeClassBuilderProtocol)) - : class_conformsToProtocol(object_getClass(self), - @protocol(ObjCBridgeClassBuilderProtocol)); + bool supercall = classMethod + ? class_conformsToProtocol(self, @protocol(ObjCBridgeClassBuilderProtocol)) + : class_conformsToProtocol(object_getClass(self), + @protocol(ObjCBridgeClassBuilderProtocol)); if (supercall && classMethod) { - ObjCBridgeState *state = ObjCBridgeState::InstanceData(env); - ClassBuilder *builder = (ClassBuilder *)state->classesByPointer[self]; - if (!builder->isFinal) - builder->build(); + ObjCBridgeState* state = ObjCBridgeState::InstanceData(env); + ClassBuilder* builder = (ClassBuilder*)state->classesByPointer[self]; + if (!builder->isFinal) builder->build(); } #if defined(__x86_64__) - bool isStret = cif->returnType->type->size > 16 && - cif->returnType->type->type == FFI_TYPE_STRUCT; + bool isStret = cif->returnType->type->size > 16 && cif->returnType->type->type == FFI_TYPE_STRUCT; #endif - if (!supercall) { + @try { + if (!supercall) { #if defined(__x86_64__) - if (isStret) { - ffi_call(&cif->cif, FFI_FN(objc_msgSend_stret), rvalue, avalues); - } else { - ffi_call(&cif->cif, FFI_FN(objc_msgSend), rvalue, avalues); - } + if (isStret) { + ffi_call(&cif->cif, FFI_FN(objc_msgSend_stret), rvalue, avalues); + } else { + ffi_call(&cif->cif, FFI_FN(objc_msgSend), rvalue, avalues); + } #else - ffi_call(&cif->cif, FFI_FN(objc_msgSend), rvalue, avalues); + ffi_call(&cif->cif, FFI_FN(objc_msgSend), rvalue, avalues); #endif - } else { - struct objc_super superobj = {self, - class_getSuperclass(object_getClass(self))}; - auto superobjPtr = &superobj; - avalues[0] = (void *)&superobjPtr; -#if defined(__x86_64__) - if (isStret) { - ffi_call(&cif->cif, FFI_FN(objc_msgSendSuper_stret), rvalue, avalues); } else { - ffi_call(&cif->cif, FFI_FN(objc_msgSendSuper), rvalue, avalues); - } + struct objc_super superobj = {self, class_getSuperclass(object_getClass(self))}; + auto superobjPtr = &superobj; + avalues[0] = (void*)&superobjPtr; +#if defined(__x86_64__) + if (isStret) { + ffi_call(&cif->cif, FFI_FN(objc_msgSendSuper_stret), rvalue, avalues); + } else { + ffi_call(&cif->cif, FFI_FN(objc_msgSendSuper), rvalue, avalues); + } #else - ffi_call(&cif->cif, FFI_FN(objc_msgSendSuper), rvalue, avalues); + ffi_call(&cif->cif, FFI_FN(objc_msgSendSuper), rvalue, avalues); #endif + } + + } @catch (NSException* exception) { + std::string message = exception.description.UTF8String; + nativescript::NativeScriptException nativeScriptException(message); + nativeScriptException.ReThrowToJS(env); + return false; + } + + return true; +} + +inline id assertSelf(napi_env env, napi_value jsThis) { + id self; + napi_unwrap(env, jsThis, (void**)&self); + + if (self == nil) { + napi_throw_error(env, "NativeScriptException", + "There was no native counterpart to the JavaScript object. Native API was " + "called with a likely plain object."); + return nullptr; } + + return self; } -napi_value ObjCClassMember::jsCallInit(napi_env env, - napi_callback_info cbinfo) { +napi_value ObjCClassMember::jsCallInit(napi_env env, napi_callback_info cbinfo) { napi_value jsThis; - ObjCClassMember *method; + ObjCClassMember* method; - napi_get_cb_info(env, cbinfo, nullptr, nullptr, &jsThis, (void **)&method); + napi_get_cb_info(env, cbinfo, nullptr, nullptr, &jsThis, (void**)&method); - id self = nil; - napi_unwrap(env, jsThis, (void **)&self); - if (self == nil) { - napi_throw_error(env, nullptr, "self is nil"); + id self = assertSelf(env, jsThis); + + if (self == nullptr) { return nullptr; } - Cif *cif = method->cif; + Cif* cif = method->cif; if (cif == nullptr) { - cif = method->cif = method->bridgeState->getMethodCif( - env, method->methodOrGetter.signatureOffset); + cif = method->cif = + method->bridgeState->getMethodCif(env, method->methodOrGetter.signatureOffset); } size_t argc = cif->argc; napi_get_cb_info(env, cbinfo, &argc, cif->argv, &jsThis, nullptr); - void *avalues[cif->cif.nargs]; + void* avalues[cif->cif.nargs]; - avalues[0] = (void *)&self; - avalues[1] = (void *)&method->methodOrGetter.selector; + avalues[0] = (void*)&self; + avalues[1] = (void*)&method->methodOrGetter.selector; bool shouldFreeAny = false; bool shouldFree[cif->argc]; @@ -239,18 +246,19 @@ inline void objcNativeCall(napi_env env, napi_value jsThis, Cif *cif, id self, for (unsigned int i = 0; i < cif->argc; i++) { shouldFree[i] = false; avalues[i + 2] = cif->avalues[i]; - cif->argTypes[i]->toNative(env, cif->argv[i], avalues[i + 2], - &shouldFree[i], &shouldFreeAny); + cif->argTypes[i]->toNative(env, cif->argv[i], avalues[i + 2], &shouldFree[i], &shouldFreeAny); } } id rvalue; - objcNativeCall(env, jsThis, cif, self, avalues, &rvalue); + if (!objcNativeCall(env, jsThis, cif, self, avalues, &rvalue)) { + return nullptr; + } for (unsigned int i = 0; i < cif->argc; i++) { if (shouldFree[i]) { - cif->argTypes[i]->free(env, *((void **)avalues[i + 2])); + cif->argTypes[i]->free(env, *((void**)avalues[i + 2])); } } @@ -261,11 +269,9 @@ inline void objcNativeCall(napi_env env, napi_value jsThis, Cif *cif, id self, } napi_value constructor = jsThis; - if (!method->classMethod) - napi_get_named_property(env, jsThis, "constructor", &constructor); + if (!method->classMethod) napi_get_named_property(env, jsThis, "constructor", &constructor); - napi_value result = - method->bridgeState->getObject(env, rvalue, constructor, kUnownedObject); + napi_value result = method->bridgeState->getObject(env, rvalue, constructor, kUnownedObject); if (rvalue != self) { [self retain]; @@ -277,31 +283,30 @@ inline void objcNativeCall(napi_env env, napi_value jsThis, Cif *cif, id self, napi_value ObjCClassMember::jsCall(napi_env env, napi_callback_info cbinfo) { napi_value jsThis; - ObjCClassMember *method; + ObjCClassMember* method; - napi_get_cb_info(env, cbinfo, nullptr, nullptr, &jsThis, (void **)&method); + napi_get_cb_info(env, cbinfo, nullptr, nullptr, &jsThis, (void**)&method); - id self = nil; - napi_unwrap(env, jsThis, (void **)&self); - if (self == nil) { - napi_throw_error(env, nullptr, "self is nil"); + id self = assertSelf(env, jsThis); + + if (self == nullptr) { return nullptr; } - Cif *cif = method->cif; + Cif* cif = method->cif; if (cif == nullptr) { - cif = method->cif = method->bridgeState->getMethodCif( - env, method->methodOrGetter.signatureOffset); + cif = method->cif = + method->bridgeState->getMethodCif(env, method->methodOrGetter.signatureOffset); } size_t argc = cif->argc; napi_get_cb_info(env, cbinfo, &argc, cif->argv, &jsThis, nullptr); - void *avalues[cif->cif.nargs]; - void *rvalue = cif->rvalue; + void* avalues[cif->cif.nargs]; + void* rvalue = cif->rvalue; - avalues[0] = (void *)&self; - avalues[1] = (void *)&method->methodOrGetter.selector; + avalues[0] = (void*)&self; + avalues[1] = (void*)&method->methodOrGetter.selector; bool shouldFreeAny = false; bool shouldFree[cif->argc]; @@ -310,52 +315,55 @@ inline void objcNativeCall(napi_env env, napi_value jsThis, Cif *cif, id self, for (unsigned int i = 0; i < cif->argc; i++) { shouldFree[i] = false; avalues[i + 2] = cif->avalues[i]; - cif->argTypes[i]->toNative(env, cif->argv[i], avalues[i + 2], - &shouldFree[i], &shouldFreeAny); + cif->argTypes[i]->toNative(env, cif->argv[i], avalues[i + 2], &shouldFree[i], &shouldFreeAny); } } - objcNativeCall(env, jsThis, cif, self, avalues, rvalue); + if (!objcNativeCall(env, jsThis, cif, self, avalues, rvalue)) { + return nullptr; + } for (unsigned int i = 0; i < cif->argc; i++) { if (shouldFree[i]) { - cif->argTypes[i]->free(env, *((void **)avalues[i + 2])); + cif->argTypes[i]->free(env, *((void**)avalues[i + 2])); } } if (cif->returnType->kind == mdTypeInstanceObject) { napi_value constructor = jsThis; - if (!method->classMethod) - napi_get_named_property(env, jsThis, "constructor", &constructor); - id obj = *((id *)rvalue); + if (!method->classMethod) napi_get_named_property(env, jsThis, "constructor", &constructor); + id obj = *((id*)rvalue); return method->bridgeState->getObject(env, obj, constructor, - method->returnOwned ? kOwnedObject - : kUnownedObject); + method->returnOwned ? kOwnedObject : kUnownedObject); } - return cif->returnType->toJS(env, rvalue, - method->returnOwned ? kReturnOwned : 0); + return cif->returnType->toJS(env, rvalue, method->returnOwned ? kReturnOwned : 0); } napi_value ObjCClassMember::jsGetter(napi_env env, napi_callback_info cbinfo) { napi_value jsThis; - ObjCClassMember *method; + ObjCClassMember* method; - napi_get_cb_info(env, cbinfo, nullptr, nullptr, &jsThis, (void **)&method); + napi_get_cb_info(env, cbinfo, nullptr, nullptr, &jsThis, (void**)&method); - id self; - napi_unwrap(env, jsThis, (void **)&self); + id self = assertSelf(env, jsThis); - Cif *cif = method->cif; + if (self == nullptr) { + return nullptr; + } + + Cif* cif = method->cif; if (cif == nullptr) { - cif = method->cif = method->bridgeState->getMethodCif( - env, method->methodOrGetter.signatureOffset); + cif = method->cif = + method->bridgeState->getMethodCif(env, method->methodOrGetter.signatureOffset); } - void *avalues[2] = {&self, &method->methodOrGetter.selector}; - void *rvalue = cif->rvalue; + void* avalues[2] = {&self, &method->methodOrGetter.selector}; + void* rvalue = cif->rvalue; - objcNativeCall(env, jsThis, cif, self, avalues, rvalue); + if (!objcNativeCall(env, jsThis, cif, self, avalues, rvalue)) { + return nullptr; + } if (cif->returnType->kind == mdTypeInstanceObject) { napi_value constructor = jsThis; @@ -363,9 +371,8 @@ inline void objcNativeCall(napi_env env, napi_value jsThis, Cif *cif, id self, napi_get_named_property(env, jsThis, "constructor", &constructor); } - return method->bridgeState->getObject(env, *((id *)rvalue), constructor, - method->returnOwned ? kOwnedObject - : kUnownedObject); + return method->bridgeState->getObject(env, *((id*)rvalue), constructor, + method->returnOwned ? kOwnedObject : kUnownedObject); } return cif->returnType->toJS(env, rvalue, 0); @@ -374,32 +381,37 @@ inline void objcNativeCall(napi_env env, napi_value jsThis, Cif *cif, id self, napi_value ObjCClassMember::jsSetter(napi_env env, napi_callback_info cbinfo) { napi_value jsThis, argv; size_t argc = 1; - ObjCClassMember *method; + ObjCClassMember* method; - napi_get_cb_info(env, cbinfo, &argc, &argv, &jsThis, (void **)&method); + napi_get_cb_info(env, cbinfo, &argc, &argv, &jsThis, (void**)&method); - id self; - napi_unwrap(env, jsThis, (void **)&self); + id self = assertSelf(env, jsThis); - Cif *cif = method->setterCif; + if (self == nullptr) { + return nullptr; + } + + Cif* cif = method->setterCif; if (cif == nullptr) { cif = method->setterCif = method->bridgeState->getMethodCif(env, method->setter.signatureOffset); } - void *avalues[3] = {&self, &method->setter.selector, cif->avalues[0]}; - void *rvalue = nullptr; + void* avalues[3] = {&self, &method->setter.selector, cif->avalues[0]}; + void* rvalue = nullptr; bool shouldFree = false; cif->argTypes[0]->toNative(env, argv, avalues[2], &shouldFree, &shouldFree); - objcNativeCall(env, jsThis, cif, self, avalues, rvalue); + if (!objcNativeCall(env, jsThis, cif, self, avalues, rvalue)) { + return nullptr; + } if (shouldFree) { - cif->argTypes[0]->free(env, *((void **)avalues[2])); + cif->argTypes[0]->free(env, *((void**)avalues[2])); } return nullptr; } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/Closure.h b/NativeScript/ffi/Closure.h index 9c91683f..ed32b164 100644 --- a/NativeScript/ffi/Closure.h +++ b/NativeScript/ffi/Closure.h @@ -1,24 +1,25 @@ #ifndef CLOSURE_H #define CLOSURE_H +#include +#include + #include "MetadataReader.h" #include "TypeConv.h" #include "ffi.h" #include "node_api_util.h" #include "objc/runtime.h" -#include -#include -namespace objc_bridge { +namespace nativescript { class Closure { -public: + public: static void callBlockFromMainThread(napi_env env, napi_value js_cb, - void *context, void *data); + void* context, void* data); Closure(std::string typeEncoding, bool isBlock); - Closure(MDMetadataReader *reader, MDSectionOffset offset, - bool isBlock = false, std::string *encoding = nullptr, + Closure(MDMetadataReader* reader, MDSectionOffset offset, + bool isBlock = false, std::string* encoding = nullptr, bool isMethod = false, bool isGetter = false, bool isSetter = false); ~Closure(); @@ -34,13 +35,13 @@ class Closure { std::thread::id jsThreadId = std::this_thread::get_id(); ffi_cif cif; - ffi_closure *closure; - void *fnptr; + ffi_closure* closure; + void* fnptr; std::shared_ptr returnType; std::vector> argTypes; }; -} // namespace objc_bridge +} // namespace nativescript #endif /* CLOSURE_H */ diff --git a/NativeScript/ffi/Closure.mm b/NativeScript/ffi/Closure.mm index 215d51f5..0b544aba 100644 --- a/NativeScript/ffi/Closure.mm +++ b/NativeScript/ffi/Closure.mm @@ -5,8 +5,10 @@ #include "ObjCBridge.h" #include "TypeConv.h" #include "Util.h" +#include "ffi/NativeScriptException.h" #include "js_native_api.h" #include "js_native_api_types.h" +#include "jsr.h" #include "node_api_util.h" #include "objc/message.h" @@ -15,13 +17,15 @@ #include #include -namespace objc_bridge { +namespace nativescript { inline void JSCallbackInner(Closure* closure, napi_value func, napi_value thisArg, napi_value* argv, size_t argc, bool* done, void* ret) { napi_env env = closure->env; - napi_value result; + NapiScope scope(env); + + napi_value result; napi_get_and_clear_last_exception(env, &result); @@ -29,6 +33,9 @@ inline void JSCallbackInner(Closure* closure, napi_value func, napi_value thisAr if (done != NULL) *done = true; + // If the call failed, we need to create an error object and throw it in native + // Likely it will circle back to JS. We have try/catch around all native calls from JS, + // so those are likely to catch it. if (status != napi_ok) { napi_get_and_clear_last_exception(env, &result); napi_valuetype resultType; @@ -36,21 +43,14 @@ inline void JSCallbackInner(Closure* closure, napi_value func, napi_value thisAr if (resultType != napi_object) { napi_value code, msg; - napi_create_string_utf8(env, "Error", NAPI_AUTO_LENGTH, &code); + napi_create_string_utf8(env, "NativeScriptException", NAPI_AUTO_LENGTH, &code); napi_create_string_utf8(env, - "Unable to obtain the error thrown by the JS function " - "call", + "Unable to obtain the error thrown by the JS implemented closure", NAPI_AUTO_LENGTH, &msg); napi_create_error(env, code, msg, &result); } - napi_value errstr; - NAPI_GUARD(napi_get_named_property(env, result, "stack", &errstr)) { return; } - char errbuf[512]; - size_t errlen; - napi_get_value_string_utf8(env, errstr, errbuf, 512, &errlen); - NSLog(@"ObjC->JS call failed: %s", errbuf); - napi_throw(env, result); + NativeScriptException::OnUncaughtError(env, result); } // Even if call was failed and result is just undefined, let's still try to @@ -142,6 +142,7 @@ void JSBlockCallback(ffi_cif* cif, void* ret, void* args[], void* data) { if (currentThreadId == closure->jsThreadId) { Closure::callBlockFromMainThread(env, get_ref_value(env, closure->func), closure, &ctx); } else { +#ifndef ENABLE_JS_RUNTIME if (!closure->tsfn) { assert(false && "Threadsafe functions are not supported"); } @@ -151,6 +152,9 @@ void JSBlockCallback(ffi_cif* cif, void* ret, void* args[], void* data) { napi_call_threadsafe_function(closure->tsfn, &ctx, napi_tsfn_blocking); ctx.cv.wait(lock, [&ctx] { return ctx.done; }); napi_release_threadsafe_function(closure->tsfn, napi_tsfn_release); +#else + assert(false && "Threadsafe functions are not supported"); +#endif // ENABLE_JS_RUNTIME } } @@ -249,10 +253,12 @@ void JSBlockCallback(ffi_cif* cif, void* ret, void* args[], void* data) { if (func != nullptr) { napi_delete_reference(env, func); } +#ifndef ENABLE_JS_RUNTIME if (tsfn != nullptr) { napi_release_threadsafe_function(tsfn, napi_tsfn_abort); } +#endif // ENABLE_JS_RUNTIME ffi_closure_free(closure); } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/Enum.h b/NativeScript/ffi/Enum.h index 701d8f7f..42f983d6 100644 --- a/NativeScript/ffi/Enum.h +++ b/NativeScript/ffi/Enum.h @@ -3,10 +3,10 @@ #include "node_api_util.h" -namespace objc_bridge { +namespace nativescript { NAPI_FUNCTION(enumGetter); -} // namespace objc_bridge +} // namespace nativescript #endif /* ENUM_H */ diff --git a/NativeScript/ffi/Enum.mm b/NativeScript/ffi/Enum.mm index 8aa962c9..bcbc233d 100644 --- a/NativeScript/ffi/Enum.mm +++ b/NativeScript/ffi/Enum.mm @@ -2,7 +2,7 @@ #import #include "ObjCBridge.h" -namespace objc_bridge { +namespace nativescript { void ObjCBridgeState::registerEnumGlobals(napi_env env, napi_value global) { MDSectionOffset offset = metadata->enumsOffset; @@ -81,4 +81,4 @@ return result; } -} // namespace objc_bridge \ No newline at end of file +} // namespace nativescript \ No newline at end of file diff --git a/NativeScript/ffi/InlineFunctions.h b/NativeScript/ffi/InlineFunctions.h index 9250e167..d81664d7 100644 --- a/NativeScript/ffi/InlineFunctions.h +++ b/NativeScript/ffi/InlineFunctions.h @@ -3,10 +3,10 @@ #include "js_native_api.h" -namespace objc_bridge { +namespace nativescript { void registerInlineFunctions(napi_env env); -} // namespace objc_bridge +} // namespace nativescript #endif /* INLINE_FUNCTIONS_H */ diff --git a/NativeScript/ffi/InlineFunctions.mm b/NativeScript/ffi/InlineFunctions.mm index 354ad7be..9c86c40d 100644 --- a/NativeScript/ffi/InlineFunctions.mm +++ b/NativeScript/ffi/InlineFunctions.mm @@ -1,9 +1,9 @@ #include "InlineFunctions.h" #include "js_native_api.h" -namespace objc_bridge { +namespace nativescript { -static const char *inlineFunctionsSource = R"( +static const char* inlineFunctionsSource = R"( globalThis.CGPointMake = globalThis.NSMakePoint = function CGMakePoint(x, y) { return { x, y }; @@ -29,9 +29,8 @@ void registerInlineFunctions(napi_env env) { napi_value script, result; - napi_create_string_utf8(env, inlineFunctionsSource, NAPI_AUTO_LENGTH, - &script); + napi_create_string_utf8(env, inlineFunctionsSource, NAPI_AUTO_LENGTH, &script); napi_run_script(env, script, &result); } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/Interop.h b/NativeScript/ffi/Interop.h index 4a81f4d4..00b618c8 100644 --- a/NativeScript/ffi/Interop.h +++ b/NativeScript/ffi/Interop.h @@ -5,7 +5,7 @@ #include "TypeConv.h" #include "js_native_api.h" -namespace objc_bridge { +namespace nativescript { void registerInterop(napi_env env, napi_value global); @@ -19,12 +19,12 @@ napi_value interop_handleof(napi_env env, napi_callback_info info); napi_value interop_bufferFromData(napi_env env, napi_callback_info info); class Pointer { -public: + public: static napi_value defineJSClass(napi_env env); static bool isInstance(napi_env env, napi_value value); - static napi_value create(napi_env env, void *data); - static Pointer *unwrap(napi_env env, napi_value value); + static napi_value create(napi_env env, void* data); + static Pointer* unwrap(napi_env env, napi_value value); static napi_value constructor(napi_env env, napi_callback_info info); static napi_value add(napi_env env, napi_callback_info info); @@ -32,58 +32,58 @@ class Pointer { static napi_value toNumber(napi_env env, napi_callback_info info); static napi_value customInspect(napi_env env, napi_callback_info info); - static void finalize(napi_env env, void *data, void *hint); + static void finalize(napi_env env, void* data, void* hint); - Pointer(void *data); + Pointer(void* data); ~Pointer(); - void *data; + void* data; bool adopted = false; }; class Reference { -public: + public: static napi_value defineJSClass(napi_env env); static bool isInstance(napi_env env, napi_value value); - static Reference *unwrap(napi_env env, napi_value value); + static Reference* unwrap(napi_env env, napi_value value); static napi_value constructor(napi_env env, napi_callback_info info); static napi_value get_value(napi_env env, napi_callback_info info); static napi_value set_value(napi_env env, napi_callback_info info); static napi_value customInspect(napi_env env, napi_callback_info info); - static void finalize(napi_env env, void *data, void *hint); + static void finalize(napi_env env, void* data, void* hint); Reference() {} ~Reference(); // data = nullptr means the reference is not initialized. - void *data = nullptr; + void* data = nullptr; std::shared_ptr type = nullptr; napi_ref initValue = nullptr; }; class FunctionReference { -public: + public: static napi_value defineJSClass(napi_env env); - static FunctionReference *unwrap(napi_env env, napi_value value); + static FunctionReference* unwrap(napi_env env, napi_value value); static napi_value constructor(napi_env env, napi_callback_info info); - static void finalize(napi_env env, void *data, void *hint); + static void finalize(napi_env env, void* data, void* hint); - FunctionReference(napi_env env, napi_ref ref) : env(env), ref(ref){}; + FunctionReference(napi_env env, napi_ref ref) : env(env), ref(ref) {}; ~FunctionReference(); - void *getFunctionPointer(MDSectionOffset offset); + void* getFunctionPointer(MDSectionOffset offset); napi_env env; napi_ref ref; std::shared_ptr closure = nullptr; }; -} // namespace objc_bridge +} // namespace nativescript #endif /* INTEROP_H */ diff --git a/NativeScript/ffi/Interop.mm b/NativeScript/ffi/Interop.mm index 9824644b..acb0f777 100644 --- a/NativeScript/ffi/Interop.mm +++ b/NativeScript/ffi/Interop.mm @@ -10,7 +10,7 @@ #import #include -namespace objc_bridge { +namespace nativescript { inline napi_value createJSNumber(napi_env env, int32_t ival) { napi_value value; @@ -877,4 +877,4 @@ napi_value interop_bufferFromData(napi_env env, napi_callback_info info) { return closure->fnptr; } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/JSObject.h b/NativeScript/ffi/JSObject.h index 5d512557..c6944d76 100644 --- a/NativeScript/ffi/JSObject.h +++ b/NativeScript/ffi/JSObject.h @@ -4,11 +4,11 @@ #include "js_native_api.h" #include "objc/runtime.h" -namespace objc_bridge { +namespace nativescript { id jsObjectToId(napi_env env, napi_value value); napi_value idToJsObject(napi_env env, id obj); -} // namespace objc_bridge +} // namespace nativescript #endif /* JS_OBJECT_H */ diff --git a/NativeScript/ffi/JSObject.mm b/NativeScript/ffi/JSObject.mm index c91305ef..c54dd247 100644 --- a/NativeScript/ffi/JSObject.mm +++ b/NativeScript/ffi/JSObject.mm @@ -4,7 +4,7 @@ #import -void JSObject_finalize(napi_env, void *data, void *) { +void JSObject_finalize(napi_env, void* data, void*) { id obj = (id)data; [obj release]; } @@ -12,7 +12,7 @@ void JSObject_finalize(napi_env, void *data, void *) { @interface JSObject : NSObject { napi_env env; napi_ref ref; - objc_bridge::ObjCBridgeState *bridgeState; + nativescript::ObjCBridgeState* bridgeState; } - (instancetype)initWithEnv:(napi_env)env value:(napi_value)value; @@ -29,7 +29,7 @@ - (instancetype)initWithEnv:(napi_env)_env value:(napi_value)value { uint32_t result; napi_reference_ref(env, ref, &result); napi_wrap(env, value, self, nullptr, nullptr, nullptr); - bridgeState = objc_bridge::ObjCBridgeState::InstanceData(env); + bridgeState = nativescript::ObjCBridgeState::InstanceData(env); bridgeState->objectRefs[self] = ref; return self; } @@ -55,7 +55,7 @@ @protocol Test @end -namespace objc_bridge { +namespace nativescript { id jsObjectToId(napi_env env, napi_value value) { return [[JSObject alloc] initWithEnv:env value:value]; @@ -66,9 +66,9 @@ napi_value idToJsObject(napi_env env, id obj) { return nullptr; } if ([obj isKindOfClass:[JSObject class]]) { - return [((JSObject *)obj) value]; + return [((JSObject*)obj) value]; } return nil; } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/NativeScriptException.h b/NativeScript/ffi/NativeScriptException.h new file mode 100644 index 00000000..3f973009 --- /dev/null +++ b/NativeScript/ffi/NativeScriptException.h @@ -0,0 +1,52 @@ +#ifndef NativeScriptException_h +#define NativeScriptException_h + +#include + +#include "js_native_api.h" +#include "js_native_api_types.h" + +namespace nativescript { + +class NativeScriptException { + public: + NativeScriptException(const std::string& message); + NativeScriptException(const std::string& message, + const std::string& stackTrace); + NativeScriptException(napi_env env, napi_value error, + const std::string& message, + const std::string& name = "NativeScriptException"); + NativeScriptException(napi_env env, const std::string& message, + const std::string& name = "NativeScriptException"); + + void ReThrowToJS(napi_env env, napi_value* errorOut = nullptr); + + static void OnUncaughtError(napi_env env, napi_value error); + + inline std::string Name() const { + if (name_.empty()) { + return "NativeScriptException"; + } + return name_; + } + + std::string Description() const; + + private: + std::string name_; + std::string message_; + std::string stackTrace_; + std::string fullMessage_; + + static std::string GetErrorStackTrace(napi_env env, napi_value stackTrace); + static std::string GetErrorMessage(napi_env env, napi_value error, + const std::string& prependMessage = ""); + std::string GetFullMessage(napi_env env, napi_value error, + const std::string& jsExceptionMessage); + + static void PrintErrorMessage(const std::string& errorMessage); +}; + +} // namespace nativescript + +#endif /* NativeScriptException_h */ diff --git a/NativeScript/ffi/NativeScriptException.mm b/NativeScript/ffi/NativeScriptException.mm new file mode 100644 index 00000000..82fdc33a --- /dev/null +++ b/NativeScript/ffi/NativeScriptException.mm @@ -0,0 +1,225 @@ +#include "NativeScriptException.h" +#import +#include +#include "js_native_api.h" +#include "js_native_api_types.h" +#include "jsr.h" +#include "native_api_util.h" +#include "runtime/Runtime.h" + +namespace nativescript { + +NativeScriptException::NativeScriptException(const std::string& message) { + this->message_ = message; + this->name_ = "NativeScriptException"; +} + +NativeScriptException::NativeScriptException(const std::string& message, + const std::string& stackTrace) { + this->message_ = message; + this->stackTrace_ = stackTrace; + this->name_ = "NativeScriptException"; +} + +NativeScriptException::NativeScriptException(napi_env env, const std::string& message, + const std::string& name) { + this->message_ = message; + this->stackTrace_ = ""; + this->fullMessage_ = message; + this->name_ = name; +} + +NativeScriptException::NativeScriptException(napi_env env, napi_value error, + const std::string& message, const std::string& name) { + this->message_ = GetErrorMessage(env, error, message); + this->stackTrace_ = GetErrorStackTrace(env, error); + this->fullMessage_ = GetFullMessage(env, error, this->message_); + this->name_ = name; + napi_set_named_property(env, error, "name", napi_util::to_js_string(env, name)); +} + +std::string NativeScriptException::Description() const { + if (this->fullMessage_.empty()) { + return this->message_; + } else { + return this->fullMessage_; + } +} + +void NativeScriptException::OnUncaughtError(napi_env env, napi_value error) { + NapiScope scope(env); + + std::stringstream fullMessageStream; + + if (napi_util::has_property(env, error, "fullMessage")) { + fullMessageStream << napi_util::get_cxx_string( + env, napi_util::get_property(env, error, "fullMessage")); + } else { +#ifdef TARGET_ENGINE_V8 + fullMessageStream << GetErrorStackTrace(env, error); +#else + fullMessageStream << GetErrorMessage(env, error); + fullMessageStream << "\n at \n" << GetErrorStackTrace(env, error); +#endif + } + + // TODO: discardUncaughtJsExceptions + + napi_value global; + napi_get_global(env, &global); + + napi_value handler; + napi_get_named_property(env, global, "__onUncaughtError", &handler); + + if (napi_util::is_of_type(env, handler, napi_function)) { + napi_value args[] = {error}; + napi_value result; + napi_status status = napi_call_function(env, global, handler, 1, args, &result); + + if (status != napi_ok) { + napi_get_and_clear_last_exception(env, &result); + + if (napi_util::is_of_type(env, result, napi_object)) { + fullMessageStream << "\n\nError handler threw an error too:\n"; +#ifdef TARGET_ENGINE_V8 + fullMessageStream << GetErrorStackTrace(env, result); +#else + fullMessageStream << GetErrorMessage(env, result); + fullMessageStream << "\n at \n" << GetErrorStackTrace(env, result); +#endif + } else { + fullMessageStream + << "\n\nError handler threw an error too, but we couldn't get the error object"; + } + } + } + + std::string fullMessage = fullMessageStream.str(); + + NSLog(@"NativeScriptException::OnUncaughtError: %s", fullMessage.c_str()); + + NSException* objcException = [NSException exceptionWithName:@"NativeScriptException" + reason:@(fullMessage.c_str()) + userInfo:@{@"sender" : @"onUncaughtError"}]; + + // dispatch_async(dispatch_get_main_queue(), ^(void) { + @throw objcException; + // }); +} + +void NativeScriptException::ReThrowToJS(napi_env env, napi_value* errorOut) { + napi_value errObj; + + if (!fullMessage_.empty()) { + napi_create_error(env, napi_util::to_js_string(env, name_), + napi_util::to_js_string(env, fullMessage_), &errObj); + } else if (!message_.empty()) { + napi_create_error(env, napi_util::to_js_string(env, name_), + napi_util::to_js_string(env, message_), &errObj); + } else { + napi_create_error(env, napi_util::to_js_string(env, name_), + napi_util::to_js_string(env, "No javascript exception or message provided."), + &errObj); + } + + if (errorOut != nullptr) { + *errorOut = errObj; + } else { + napi_throw(env, errObj); + } +} + +void NativeScriptException::PrintErrorMessage(const std::string& errorMessage) { + std::stringstream ss(errorMessage); + std::string line; + while (std::getline(ss, line, '\n')) { + NSLog(@"%s", line.c_str()); + } +} + +std::string NativeScriptException::GetErrorMessage(napi_env env, napi_value error, + const std::string& prependMessage) { + bool isError; + napi_is_error(env, error, &isError); + + if (!isError) { + napi_value err; + napi_coerce_to_string(env, error, &err); + return napi_util::get_string_value(env, err); + } + + napi_value message; + napi_get_named_property(env, error, "message", &message); + + std::string mes = napi_util::get_string_value(env, message); + + std::stringstream ss; + + if (!prependMessage.empty()) { + ss << prependMessage << std::endl; + } + + std::string errMessage; + bool hasFullErrorMessage = false; + napi_value fullMessage; + napi_get_named_property(env, error, "fullMessage", &fullMessage); + if (napi_util::is_of_type(env, fullMessage, napi_string)) { + hasFullErrorMessage = true; + errMessage = napi_util::get_string_value(env, fullMessage); + ss << errMessage; + } + + if (!mes.empty()) { + if (hasFullErrorMessage) { + ss << std::endl; + } + ss << mes; + } + + return ss.str(); +} + +std::string NativeScriptException::GetErrorStackTrace(napi_env env, napi_value error) { + std::stringstream ss; + + bool isError; + napi_is_error(env, error, &isError); + if (!isError) return ""; + + napi_value stack; + napi_get_named_property(env, error, "stack", &stack); + + std::string stackStr = napi_util::get_string_value(env, stack); + ss << stackStr; + + return ss.str(); +} + +std::string NativeScriptException::GetFullMessage(napi_env env, napi_value error, + const std::string& jsExceptionMessage) { + bool isError; + napi_is_error(env, error, &isError); + if (!isError) { + return jsExceptionMessage; + } + + std::string stackTraceMessage = GetErrorStackTrace(env, error); + + std::stringstream ss; + +#ifdef TARGET_ENGINE_V8 + ss << stackTraceMessage; +#else + ss << jsExceptionMessage; + + ss << std::endl << "StackTrace: " << std::endl << stackTraceMessage; +#endif + + std::string loggedMessage = ss.str(); + + // PrintErrorMessage(loggedMessage); + + return loggedMessage; +} + +} // namespace nativescript diff --git a/NativeScript/ffi/ObjCBridge.h b/NativeScript/ffi/ObjCBridge.h index 33867474..7261450a 100644 --- a/NativeScript/ffi/ObjCBridge.h +++ b/NativeScript/ffi/ObjCBridge.h @@ -1,32 +1,34 @@ -#ifndef OBJC_BRIDGE_H -#define OBJC_BRIDGE_H +#ifndef nativescript_H +#define nativescript_H + +#include +#include +#include + +#include +#include +#include +#include #include "AutoreleasePool.h" #include "CFunction.h" +#include "Cif.h" #include "Class.h" #include "MetadataReader.h" -#include "Cif.h" +#include "NativeScript.h" #include "Protocol.h" #include "Struct.h" #include "TypeConv.h" #include "js_native_api.h" -#include "NativeScript.h" #include "objc/runtime.h" -#include -#include -#include -#include -#include -#include -#include extern "C" napi_value napi_register_module_v1(napi_env env, napi_value exports); using namespace metagen; -namespace objc_bridge { +namespace nativescript { -void finalize_objc_object(napi_env /*env*/, void *data, void *hint); +void finalize_objc_object(napi_env /*env*/, void* data, void* hint); // Determines how retain/release should be called when an Objective-C // object is exposed to JavaScript land. @@ -41,13 +43,14 @@ typedef enum ObjectOwnership { } ObjectOwnership; class ObjCBridgeState { -public: - ObjCBridgeState(napi_env env, const char *metadata_path = nullptr, const void *metadata_ptr = nullptr); + public: + ObjCBridgeState(napi_env env, const char* metadata_path = nullptr, + const void* metadata_ptr = nullptr); ~ObjCBridgeState(); - static inline ObjCBridgeState *InstanceData(napi_env env) { - ObjCBridgeState *bridgeState; - napi_status status = napi_get_instance_data(env, (void **)&bridgeState); + static inline ObjCBridgeState* InstanceData(napi_env env) { + ObjCBridgeState* bridgeState; + napi_status status = napi_get_instance_data(env, (void**)&bridgeState); if (status != napi_ok) { return nullptr; } @@ -62,14 +65,14 @@ class ObjCBridgeState { void registerClassGlobals(napi_env env, napi_value global); void registerProtocolGlobals(napi_env env, napi_value global); - ObjCClass *getClass(napi_env env, MDSectionOffset offset); + ObjCClass* getClass(napi_env env, MDSectionOffset offset); - ObjCProtocol *getProtocol(napi_env env, MDSectionOffset offset); + ObjCProtocol* getProtocol(napi_env env, MDSectionOffset offset); - Cif *getMethodCif(napi_env env, Method method); - Cif *getMethodCif(napi_env env, MDSectionOffset offset); - Cif *getBlockCif(napi_env env, MDSectionOffset offset); - Cif *getCFunctionCif(napi_env env, MDSectionOffset offset); + Cif* getMethodCif(napi_env env, Method method); + Cif* getMethodCif(napi_env env, MDSectionOffset offset); + Cif* getBlockCif(napi_env env, MDSectionOffset offset); + Cif* getCFunctionCif(napi_env env, MDSectionOffset offset); napi_value proxyNativeObject(napi_env env, napi_value object, id nativeObject); @@ -79,13 +82,13 @@ class ObjCBridgeState { napi_value getObject(napi_env env, id object, ObjectOwnership ownership = kUnownedObject, MDSectionOffset classOffset = 0, - std::vector *protocolOffsets = nullptr); + std::vector* protocolOffsets = nullptr); void unregisterObject(id object) noexcept; - CFunction *getCFunction(napi_env env, MDSectionOffset offset); + CFunction* getCFunction(napi_env env, MDSectionOffset offset); - inline StructInfo *getStructInfo(napi_env env, MDSectionOffset offset) { + inline StructInfo* getStructInfo(napi_env env, MDSectionOffset offset) { auto cached = structInfoCache.find(offset); if (cached != structInfoCache.end()) { return cached->second; @@ -97,7 +100,7 @@ class ObjCBridgeState { return structInfo; } - inline StructInfo *getUnionInfo(napi_env env, MDSectionOffset offset) { + inline StructInfo* getUnionInfo(napi_env env, MDSectionOffset offset) { auto cached = structInfoCache.find(offset); if (cached != structInfoCache.end()) { return cached->second; @@ -109,7 +112,7 @@ class ObjCBridgeState { return structInfo; } -public: + public: std::unordered_map objectRefs; napi_ref pointerClass; @@ -118,32 +121,32 @@ class ObjCBridgeState { napi_ref createFastEnumeratorIterator; napi_ref transferOwnershipToNative; - std::unordered_map classes; - std::unordered_map protocols; - std::unordered_map classesByPointer; + std::unordered_map classes; + std::unordered_map protocols; + std::unordered_map classesByPointer; std::unordered_map mdClassesByPointer; - std::unordered_map mdProtocolsByPointer; + std::unordered_map mdProtocolsByPointer; std::unordered_map constructorsByPointer; - std::unordered_map cifs; + std::unordered_map cifs; std::unordered_map mdValueCache; - std::unordered_map cFunctionCache; - std::unordered_map mdFunctionSignatureCache; - std::unordered_map mdMethodSignatureCache; - std::unordered_map mdBlockSignatureCache; + std::unordered_map cFunctionCache; + std::unordered_map mdFunctionSignatureCache; + std::unordered_map mdMethodSignatureCache; + std::unordered_map mdBlockSignatureCache; std::unordered_map structOffsets; std::unordered_map unionOffsets; // std::unordered_map protocolOffsets; - void *self_dl; + void* self_dl; - MDMetadataReader *metadata; + MDMetadataReader* metadata; -private: - std::unordered_map structInfoCache; - void *objc_autoreleasePool; + private: + std::unordered_map structInfoCache; + void* objc_autoreleasePool; }; -} // namespace objc_bridge +} // namespace nativescript -#endif /* OBJC_BRIDGE_H */ +#endif /* nativescript_H */ diff --git a/NativeScript/ffi/ObjCBridge.mm b/NativeScript/ffi/ObjCBridge.mm index 2dea5434..32dc9456 100644 --- a/NativeScript/ffi/ObjCBridge.mm +++ b/NativeScript/ffi/ObjCBridge.mm @@ -32,7 +32,7 @@ const unsigned char __attribute__((section("__objc_metadata,__objc_metadata"))) #endif #endif -namespace objc_bridge { +namespace nativescript { void finalize_bridge_data(napi_env env, void* data, void* hint) { auto bridgeState = (ObjCBridgeState*)data; @@ -71,7 +71,7 @@ void finalize_bridge_data(napi_env env, void* data, void* hint) { if (metadata_path != nullptr) { metadata = loadMetadataFromFile(metadata_path); } else { - metadata = new MDMetadataReader((void*)embedded_metadata, EMBED_METADATA_SIZE); + metadata = new MDMetadataReader((void*)embedded_metadata); } #else unsigned long segmentSize = 0; @@ -120,9 +120,9 @@ void finalize_bridge_data(napi_env env, void* data, void* hint) { return result; } -} // namespace objc_bridge +} // namespace nativescript -using namespace objc_bridge; +using namespace nativescript; NAPI_FUNCTION(getArrayBuffer) { NAPI_CALLBACK_BEGIN(2) @@ -148,7 +148,7 @@ void finalize_bridge_data(napi_env env, void* data, void* hint) { metadata_path = (char*)malloc(len + 1); napi_get_value_string_utf8(env, argv[0], (char*)metadata_path, len + 1, &len); } - objc_bridge_init(env, metadata_path, nullptr); + nativescript_init(env, metadata_path, nullptr); return nullptr; } @@ -158,7 +158,8 @@ void finalize_bridge_data(napi_env env, void* data, void* hint) { return exports; } -NAPI_EXPORT void objc_bridge_init(void* _env, const char* metadata_path, const void* metadata_ptr) { +NAPI_EXPORT void nativescript_init(void* _env, const char* metadata_path, + const void* metadata_ptr) { napi_env env = (napi_env)_env; ObjCBridgeState* bridgeState = new ObjCBridgeState(env, metadata_path, metadata_ptr); diff --git a/NativeScript/ffi/Object.h b/NativeScript/ffi/Object.h index b284e357..c06fcac9 100644 --- a/NativeScript/ffi/Object.h +++ b/NativeScript/ffi/Object.h @@ -3,10 +3,10 @@ #include "ObjCBridge.h" -namespace objc_bridge { +namespace nativescript { -void initProxyFactory(napi_env env, ObjCBridgeState *bridgeState); +void initProxyFactory(napi_env env, ObjCBridgeState* bridgeState); -} // namespace objc_bridge +} // namespace nativescript #endif /* OBJECT_H */ diff --git a/NativeScript/ffi/Object.mm b/NativeScript/ffi/Object.mm index 2a962398..2d56f767 100644 --- a/NativeScript/ffi/Object.mm +++ b/NativeScript/ffi/Object.mm @@ -11,8 +11,8 @@ @interface JSWrapperObjectAssociation : NSObject -@property (nonatomic) napi_env env; -@property (nonatomic) napi_ref ref; +@property(nonatomic) napi_env env; +@property(nonatomic) napi_ref ref; + (void)transferOwnership:(napi_env)env of:(napi_value)value toNative:(id)object; @@ -34,9 +34,11 @@ - (instancetype)initWithEnv:(napi_env)env ref:(napi_ref)ref { } + (void)transferOwnership:(napi_env)env of:(napi_value)value toNative:(id)object { - napi_ref ref = objc_bridge::make_ref(env, value); - JSWrapperObjectAssociation *association = [[JSWrapperObjectAssociation alloc] initWithEnv:env ref:ref]; - objc_setAssociatedObject(object, JSWrapperObjectAssociationKey, association, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + napi_ref ref = nativescript::make_ref(env, value); + JSWrapperObjectAssociation* association = [[JSWrapperObjectAssociation alloc] initWithEnv:env + ref:ref]; + objc_setAssociatedObject(object, JSWrapperObjectAssociationKey, association, + OBJC_ASSOCIATION_RETAIN_NONATOMIC); } + (instancetype)associationFor:(id)object { @@ -56,16 +58,16 @@ napi_value JS_transferOwnershipToNative(napi_env env, napi_callback_info cbinfo) napi_get_cb_info(env, cbinfo, &argc, &arg, nullptr, nullptr); id obj = nil; - napi_unwrap(env, arg, (void **)&obj); - + napi_unwrap(env, arg, (void**)&obj); + [JSWrapperObjectAssociation transferOwnership:env of:arg toNative:obj]; return nullptr; } -namespace objc_bridge { +namespace nativescript { -const char *nativeObjectProxySource = R"( +const char* nativeObjectProxySource = R"( (function (object, isArray, transferOwnershipToNative) { let isTransfered = false; @@ -105,26 +107,25 @@ napi_value JS_transferOwnershipToNative(napi_env env, napi_callback_info cbinfo) }) )"; -void initProxyFactory(napi_env env, ObjCBridgeState *state) { +void initProxyFactory(napi_env env, ObjCBridgeState* state) { napi_value script, result; - napi_create_string_utf8(env, nativeObjectProxySource, NAPI_AUTO_LENGTH, - &script); + napi_create_string_utf8(env, nativeObjectProxySource, NAPI_AUTO_LENGTH, &script); napi_run_script(env, script, &result); state->createNativeProxy = make_ref(env, result); napi_value transferOwnershipToNative; - napi_create_function(env, "transferOwnershipToNative", NAPI_AUTO_LENGTH, JS_transferOwnershipToNative, nullptr, &transferOwnershipToNative); + napi_create_function(env, "transferOwnershipToNative", NAPI_AUTO_LENGTH, + JS_transferOwnershipToNative, nullptr, &transferOwnershipToNative); state->transferOwnershipToNative = make_ref(env, transferOwnershipToNative); } -void finalize_objc_object(napi_env /*env*/, void *data, void *hint) { +void finalize_objc_object(napi_env /*env*/, void* data, void* hint) { id object = static_cast(data); - ObjCBridgeState *bridgeState = static_cast(hint); + ObjCBridgeState* bridgeState = static_cast(hint); bridgeState->unregisterObject(object); } -napi_value ObjCBridgeState::getObject(napi_env env, id obj, - napi_value constructor, +napi_value ObjCBridgeState::getObject(napi_env env, id obj, napi_value constructor, ObjectOwnership ownership) { if (obj == nil) { return nullptr; @@ -142,7 +143,7 @@ void finalize_objc_object(napi_env /*env*/, void *data, void *hint) { unregisterObject(obj); } - JSWrapperObjectAssociation *association = [JSWrapperObjectAssociation associationFor:obj]; + JSWrapperObjectAssociation* association = [JSWrapperObjectAssociation associationFor:obj]; if (association != nil) { napi_value jsObject = get_ref_value(env, association.ref); [obj retain]; @@ -185,7 +186,7 @@ void finalize_objc_object(napi_env /*env*/, void *data, void *hint) { result = proxyNativeObject(env, result, obj); -// #if DEBUG + // #if DEBUG // napi_value global, Error, error, stack; // napi_get_global(env, &global); // napi_get_named_property(env, global, "Error", &Error); @@ -202,14 +203,14 @@ void finalize_objc_object(napi_env /*env*/, void *data, void *hint) { // dbglog([str UTF8String]); // delete[] stackStr; -// #endif + // #endif } return result; } -napi_value findConstructorForObject(napi_env env, ObjCBridgeState *bridgeState, - id object, Class cls = nil) { +napi_value findConstructorForObject(napi_env env, ObjCBridgeState* bridgeState, id object, + Class cls = nil) { if (cls == nil) { cls = object_getClass(object); } @@ -244,31 +245,29 @@ napi_value findConstructorForObject(napi_env env, ObjCBridgeState *bridgeState, { unsigned int count; auto protocols = class_copyProtocolList(cls, &count); - std::unordered_set impls; - - std::function processProtocolList = - [&](Protocol **list, unsigned int count) { - for (unsigned int i = 0; i < count; i++) { - auto protocol = list[i]; - auto find = bridgeState->mdProtocolsByPointer.find(protocol); - if (find != bridgeState->mdProtocolsByPointer.end()) { - impls.insert(bridgeState->getProtocol(env, find->second)); - } - list = protocol_copyProtocolList(protocol, &count); - processProtocolList(list, count); - } - }; + std::unordered_set impls; + + std::function processProtocolList = [&](Protocol** list, + unsigned int count) { + for (unsigned int i = 0; i < count; i++) { + auto protocol = list[i]; + auto find = bridgeState->mdProtocolsByPointer.find(protocol); + if (find != bridgeState->mdProtocolsByPointer.end()) { + impls.insert(bridgeState->getProtocol(env, find->second)); + } + list = protocol_copyProtocolList(protocol, &count); + processProtocolList(list, count); + } + }; processProtocolList(protocols, count); if (!impls.empty()) { napi_value constructor; - napi_define_class(env, class_getName(cls), NAPI_AUTO_LENGTH, - ObjCProtocol::jsConstructor, nullptr, 0, nullptr, - &constructor); + napi_define_class(env, class_getName(cls), NAPI_AUTO_LENGTH, ObjCProtocol::jsConstructor, + nullptr, 0, nullptr, &constructor); for (auto impl : impls) { - ObjCClassMember::defineMembers(env, impl->members, impl->membersOffset, - constructor); + ObjCClassMember::defineMembers(env, impl->members, impl->membersOffset, constructor); } bridgeState->constructorsByPointer[cls] = make_ref(env, constructor); @@ -289,10 +288,9 @@ napi_value findConstructorForObject(napi_env env, ObjCBridgeState *bridgeState, // Here we also ensure that the native object always points to the same // JS object, this makes sure that we only ever finalize it once. // Might want to consider using associated objects instead of a hashtable. -napi_value -ObjCBridgeState::getObject(napi_env env, id obj, ObjectOwnership ownership, - MDSectionOffset classOffset, - std::vector *protocolOffsets) { +napi_value ObjCBridgeState::getObject(napi_env env, id obj, ObjectOwnership ownership, + MDSectionOffset classOffset, + std::vector* protocolOffsets) { NAPI_PREAMBLE if (obj == nullptr) { @@ -324,9 +322,7 @@ napi_value findConstructorForObject(napi_env env, ObjCBridgeState *bridgeState, auto findByPointer = classesByPointer.find(cls); if (findByPointer != classesByPointer.end()) { - return getObject(env, obj, - get_ref_value(env, findByPointer->second->constructor), - ownership); + return getObject(env, obj, get_ref_value(env, findByPointer->second->constructor), ownership); } napi_value constructor = nullptr; @@ -358,13 +354,14 @@ napi_value findConstructorForObject(napi_env env, ObjCBridgeState *bridgeState, } void ObjCBridgeState::unregisterObject(id object) noexcept { -// #if DEBUG - // NSString *string = [NSString stringWithFormat: @"Unregistering object <%s: %p> @ %ld # success: %d, finalized: %d", + // #if DEBUG + // NSString *string = [NSString stringWithFormat: @"Unregistering object <%s: %p> @ %ld # success: + // %d, finalized: %d", // class_getName(object_getClass(object)), object, [object retainCount], // (int)objectRefs.contains(object), (int)finalized]; - + // dbglog([string UTF8String]); -// #endif + // #endif if (objectRefs.contains(object)) { objectRefs.erase(object); @@ -372,4 +369,4 @@ napi_value findConstructorForObject(napi_env env, ObjCBridgeState *bridgeState, } } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/ObjectRef.h b/NativeScript/ffi/ObjectRef.h index ce160fa7..2e74e87d 100644 --- a/NativeScript/ffi/ObjectRef.h +++ b/NativeScript/ffi/ObjectRef.h @@ -3,10 +3,10 @@ #include "js_native_api.h" -namespace objc_bridge { +namespace nativescript { napi_value defineObjectRefClass(napi_env env); -} // namespace objc_bridge +} // namespace nativescript #endif /* OBJECT_REF_H */ \ No newline at end of file diff --git a/NativeScript/ffi/ObjectRef.mm b/NativeScript/ffi/ObjectRef.mm index be5da09e..e265f25f 100644 --- a/NativeScript/ffi/ObjectRef.mm +++ b/NativeScript/ffi/ObjectRef.mm @@ -6,9 +6,9 @@ #import -namespace objc_bridge { +namespace nativescript { -void ObjectRef_finalize(napi_env env, void *data, void *hint) { free(data); } +void ObjectRef_finalize(napi_env env, void* data, void* hint) { free(data); } NAPI_FUNCTION(ObjectRef_constructor) { napi_value jsThis, arg; @@ -22,12 +22,12 @@ napi_typeof(env, arg, &argType); if (argType != napi_undefined && argType != napi_null) { - const char *argenc = "@"; + const char* argenc = "@"; auto conv = TypeConv::Make(env, &argenc); bool shouldFree; conv->toNative(env, arg, data, &shouldFree, &shouldFree); } else { - *(id *)data = nil; + *(id*)data = nil; } return jsThis; @@ -37,16 +37,16 @@ napi_value jsThis; napi_get_cb_info(env, cbinfo, nullptr, nullptr, &jsThis, nullptr); - void *data; + void* data; napi_unwrap(env, jsThis, &data); - id obj = *(id *)data; + id obj = *(id*)data; if (obj == nil) { napi_throw_error(env, nullptr, "ObjectRef.unwrap returned nil"); return nullptr; } - const char *argenc = "@"; + const char* argenc = "@"; auto conv = TypeConv::Make(env, &argenc); return conv->toJS(env, &obj); } @@ -55,11 +55,11 @@ napi_value jsThis; napi_get_cb_info(env, cbinfo, nullptr, nullptr, &jsThis, nullptr); - void *data; + void* data; napi_unwrap(env, jsThis, &data); - id obj = *(id *)data; - const char *argenc = "@"; + id obj = *(id*)data; + const char* argenc = "@"; auto conv = TypeConv::Make(env, &argenc); return conv->toJS(env, &obj); } @@ -69,10 +69,10 @@ size_t argc = 1; napi_get_cb_info(env, cbinfo, &argc, &arg, &jsThis, nullptr); - void *data; + void* data; napi_unwrap(env, jsThis, &data); - const char *argenc = "@"; + const char* argenc = "@"; auto conv = TypeConv::Make(env, &argenc); bool shouldFree; conv->toNative(env, arg, data, &shouldFree, &shouldFree); @@ -84,10 +84,10 @@ napi_value jsThis; napi_get_cb_info(env, cbinfo, nullptr, nullptr, &jsThis, nullptr); - void *data; + void* data; napi_unwrap(env, jsThis, &data); - id obj = *(id *)data; + id obj = *(id*)data; std::string inspect = "ObjectRef("; if (obj == nil) { @@ -135,9 +135,9 @@ napi_value defineObjectRefClass(napi_env env) { .attributes = napi_default, .data = nullptr, }}; - napi_define_class(env, "ObjectRef", NAPI_AUTO_LENGTH, - JS_ObjectRef_constructor, nullptr, 3, properties, &result); + napi_define_class(env, "ObjectRef", NAPI_AUTO_LENGTH, JS_ObjectRef_constructor, nullptr, 3, + properties, &result); return result; } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/Protocol.h b/NativeScript/ffi/Protocol.h index 43a75dd2..e4dc6866 100644 --- a/NativeScript/ffi/Protocol.h +++ b/NativeScript/ffi/Protocol.h @@ -1,20 +1,21 @@ #ifndef PROTOCOL_H #define PROTOCOL_H +#include +#include + #include "ClassMember.h" #include "MetadataReader.h" #include "node_api_util.h" -#include -#include using namespace metagen; -namespace objc_bridge { +namespace nativescript { NAPI_FUNCTION(protocolGetter); class ObjCProtocol { -public: + public: static napi_value jsConstructor(napi_env env, napi_callback_info cbinfo); ObjCProtocol(napi_env env, MDSectionOffset offset); @@ -26,9 +27,9 @@ class ObjCProtocol { napi_ref constructor; MDSectionOffset membersOffset; ObjCClassMemberMap members; - std::unordered_set protocols; + std::unordered_set protocols; }; -} // namespace objc_bridge +} // namespace nativescript #endif /* PROTOCOL_H */ diff --git a/NativeScript/ffi/Protocol.mm b/NativeScript/ffi/Protocol.mm index 359cd4b6..f1a78473 100644 --- a/NativeScript/ffi/Protocol.mm +++ b/NativeScript/ffi/Protocol.mm @@ -9,7 +9,7 @@ #import -namespace objc_bridge { +namespace nativescript { void ObjCBridgeState::registerProtocolGlobals(napi_env env, napi_value global) { MDSectionOffset offset = metadata->protocolsOffset; @@ -153,4 +153,4 @@ ObjCProtocol::~ObjCProtocol() { napi_delete_reference(env, constructor); } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/Struct.h b/NativeScript/ffi/Struct.h index e0bb580a..e91626aa 100644 --- a/NativeScript/ffi/Struct.h +++ b/NativeScript/ffi/Struct.h @@ -1,57 +1,58 @@ #ifndef STRUCT_H #define STRUCT_H +#include + #include "MetadataReader.h" #include "TypeConv.h" #include "js_native_api.h" -#include -namespace objc_bridge { +namespace nativescript { napi_value JS_structGetter(napi_env env, napi_callback_info info); napi_value JS_unionGetter(napi_env env, napi_callback_info info); typedef struct StructFieldInfo { - char *name; + char* name; uint16_t offset; std::shared_ptr type; } StructFieldInfo; typedef struct StructInfo { - char *name; + char* name; uint16_t size; std::vector fields; napi_ref jsClass; } StructInfo; -StructInfo *getStructInfoFromMetadata(napi_env env, MDMetadataReader *metadata, +StructInfo* getStructInfoFromMetadata(napi_env env, MDMetadataReader* metadata, MDSectionOffset offset); -StructInfo *getStructInfoFromUnionMetadata(napi_env env, - MDMetadataReader *metadata, +StructInfo* getStructInfoFromUnionMetadata(napi_env env, + MDMetadataReader* metadata, MDSectionOffset offset); class StructObject { -public: - void *data; - StructInfo *info; + public: + void* data; + StructInfo* info; bool owned; - StructObject(StructInfo *info, void *data = nullptr); - StructObject(napi_env env, StructInfo *info, napi_value object, - void *memory = nullptr); + StructObject(StructInfo* info, void* data = nullptr); + StructObject(napi_env env, StructInfo* info, napi_value object, + void* memory = nullptr); - napi_value get(napi_env env, StructFieldInfo *field); - void set(napi_env env, StructFieldInfo *field, napi_value value); + napi_value get(napi_env env, StructFieldInfo* field); + void set(napi_env env, StructFieldInfo* field, napi_value value); - static StructObject *unwrap(napi_env env, napi_value object); - static napi_value defineJSClass(napi_env env, StructInfo *info); - static napi_value getJSClass(napi_env env, StructInfo *info); - static napi_value fromNative(napi_env env, StructInfo *info, void *data, + static StructObject* unwrap(napi_env env, napi_value object); + static napi_value defineJSClass(napi_env env, StructInfo* info); + static napi_value getJSClass(napi_env env, StructInfo* info); + static napi_value fromNative(napi_env env, StructInfo* info, void* data, bool owned); ~StructObject(); }; -} // namespace objc_bridge +} // namespace nativescript #endif /* STRUCT_H */ diff --git a/NativeScript/ffi/Struct.mm b/NativeScript/ffi/Struct.mm index 9e21ffbf..f74e9ebb 100644 --- a/NativeScript/ffi/Struct.mm +++ b/NativeScript/ffi/Struct.mm @@ -9,7 +9,7 @@ #import -namespace objc_bridge { +namespace nativescript { void ObjCBridgeState::registerStructGlobals(napi_env env, napi_value global) { MDSectionOffset offset = metadata->structsOffset; @@ -388,4 +388,4 @@ void StructObject_finalize(napi_env env, void* data, void* hint) { return result; } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/TypeConv.h b/NativeScript/ffi/TypeConv.h index a67d5b66..2b05613b 100644 --- a/NativeScript/ffi/TypeConv.h +++ b/NativeScript/ffi/TypeConv.h @@ -1,15 +1,16 @@ #ifndef TYPE_CONV_H #define TYPE_CONV_H +#include + #include "MetadataReader.h" #include "ffi.h" #include "js_native_api.h" #include "objc/runtime.h" -#include using namespace metagen; -namespace objc_bridge { +namespace nativescript { typedef enum ConvertToJSFlags : uint32_t { kReturnOwned = 1 << 0, @@ -18,27 +19,27 @@ typedef enum ConvertToJSFlags : uint32_t { } ConvertToJSFlags; class TypeConv { -public: - static std::shared_ptr Make(napi_env env, const char **encoding); - static std::shared_ptr Make(napi_env env, MDMetadataReader *reader, - MDSectionOffset *offset, + public: + static std::shared_ptr Make(napi_env env, const char** encoding); + static std::shared_ptr Make(napi_env env, MDMetadataReader* reader, + MDSectionOffset* offset, uint8_t opaquePointers = 0); - ffi_type *type; + ffi_type* type; MDTypeKind kind = mdTypeChar; - virtual napi_value toJS(napi_env env, void *value, uint32_t flags = 0) { + virtual napi_value toJS(napi_env env, void* value, uint32_t flags = 0) { return nullptr; } - virtual void toNative(napi_env env, napi_value value, void *result, - bool *shouldFree, bool *shouldFreeAny) {} + virtual void toNative(napi_env env, napi_value value, void* result, + bool* shouldFree, bool* shouldFreeAny) {} - virtual void free(napi_env env, void *value) {} + virtual void free(napi_env env, void* value) {} - virtual void encode(std::string *encoding) {} + virtual void encode(std::string* encoding) {} }; -} // namespace objc_bridge +} // namespace nativescript #endif /* TYPE_CONV_H */ diff --git a/NativeScript/ffi/TypeConv.mm b/NativeScript/ffi/TypeConv.mm index a88c678d..ace81c7a 100644 --- a/NativeScript/ffi/TypeConv.mm +++ b/NativeScript/ffi/TypeConv.mm @@ -19,7 +19,7 @@ #include #include -namespace objc_bridge { +namespace nativescript { ffi_type* typeFromStruct(napi_env env, const char** encoding) { ffi_type* type = new ffi_type; @@ -1609,4 +1609,4 @@ void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, } } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/Util.h b/NativeScript/ffi/Util.h index e2ca3d05..cc835e96 100644 --- a/NativeScript/ffi/Util.h +++ b/NativeScript/ffi/Util.h @@ -1,19 +1,20 @@ #ifndef UTIL_H #define UTIL_H +#include + #include "js_native_api.h" #include "objc/message.h" #include "objc/runtime.h" -#include -namespace objc_bridge { +namespace nativescript { std::string implicitSetterSelector(std::string name); std::string jsifySelector(std::string selector); -napi_value jsSymbolFor(napi_env env, const char *string); +napi_value jsSymbolFor(napi_env env, const char* string); std::string getEncodedType(napi_env env, napi_value value); -} // namespace objc_bridge +} // namespace nativescript #endif /* UTIL_H */ diff --git a/NativeScript/ffi/Util.mm b/NativeScript/ffi/Util.mm index 44ae3255..f56a3bea 100644 --- a/NativeScript/ffi/Util.mm +++ b/NativeScript/ffi/Util.mm @@ -5,7 +5,7 @@ using namespace metagen; -namespace objc_bridge { +namespace nativescript { std::string implicitSetterSelector(std::string name) { std::string setter; @@ -32,7 +32,7 @@ return jsifiedSelector; } -napi_value jsSymbolFor(napi_env env, const char *string) { +napi_value jsSymbolFor(napi_env env, const char* string) { napi_value global, Symbol, SymbolFor, symbol, symbolString; napi_get_global(env, &global); napi_get_named_property(env, global, "Symbol", &Symbol); @@ -49,73 +49,73 @@ napi_value jsSymbolFor(napi_env env, const char *string) { napi_typeof(env, value, &type); switch (type) { - case napi_number: { - int32_t number = -1; - napi_get_value_int32(env, value, &number); + case napi_number: { + int32_t number = -1; + napi_get_value_int32(env, value, &number); - switch (number) { - case mdTypeVoid: - return "v"; + switch (number) { + case mdTypeVoid: + return "v"; - case mdTypeBool: - return "B"; + case mdTypeBool: + return "B"; - case mdTypeChar: - return "c"; + case mdTypeChar: + return "c"; - case mdTypeUInt8: - return "C"; + case mdTypeUInt8: + return "C"; - case mdTypeSShort: - return "s"; + case mdTypeSShort: + return "s"; - case mdTypeUShort: - return "S"; + case mdTypeUShort: + return "S"; - case mdTypeSInt: - return "i"; + case mdTypeSInt: + return "i"; - case mdTypeUInt: - return "I"; + case mdTypeUInt: + return "I"; - case mdTypeSInt64: - return "q"; + case mdTypeSInt64: + return "q"; - case mdTypeUInt64: - return "Q"; + case mdTypeUInt64: + return "Q"; - case mdTypeFloat: - return "f"; + case mdTypeFloat: + return "f"; - case mdTypeDouble: - return "d"; + case mdTypeDouble: + return "d"; - case mdTypeString: - return "*"; + case mdTypeString: + return "*"; - case mdTypeAnyObject: - return "@"; + case mdTypeAnyObject: + return "@"; - case mdTypePointer: - return "^v"; + case mdTypePointer: + return "^v"; - case mdTypeSelector: - return ":"; + case mdTypeSelector: + return ":"; - default: - napi_throw_error(env, nullptr, "Invalid type"); - return "v"; + default: + napi_throw_error(env, nullptr, "Invalid type"); + return "v"; + } } - } - case napi_function: - // Must be a native class constructor like NSObject. - return "@"; + case napi_function: + // Must be a native class constructor like NSObject. + return "@"; - default: - napi_throw_error(env, nullptr, "Invalid type"); - return "v"; + default: + napi_throw_error(env, nullptr, "Invalid type"); + return "v"; } } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/Variable.h b/NativeScript/ffi/Variable.h index 023ea771..eceafb91 100644 --- a/NativeScript/ffi/Variable.h +++ b/NativeScript/ffi/Variable.h @@ -3,10 +3,10 @@ #include "node_api_util.h" -namespace objc_bridge { +namespace nativescript { NAPI_FUNCTION(variableGetter); -} // namespace objc_bridge +} // namespace nativescript #endif /* VARIABLE_H */ diff --git a/NativeScript/ffi/Variable.mm b/NativeScript/ffi/Variable.mm index e8ce9d7f..8ed8f6ff 100644 --- a/NativeScript/ffi/Variable.mm +++ b/NativeScript/ffi/Variable.mm @@ -3,7 +3,7 @@ #include "ObjCBridge.h" #include "js_native_api.h" -namespace objc_bridge { +namespace nativescript { void ObjCBridgeState::registerVarGlobals(napi_env env, napi_value global) { auto offset = metadata->constantsOffset; @@ -108,4 +108,4 @@ return result; } -} // namespace objc_bridge +} // namespace nativescript diff --git a/NativeScript/ffi/node_api_util.h b/NativeScript/ffi/node_api_util.h index 13c6aba8..5cc04134 100644 --- a/NativeScript/ffi/node_api_util.h +++ b/NativeScript/ffi/node_api_util.h @@ -1,21 +1,22 @@ #ifndef NODE_API_UTIL_H #define NODE_API_UTIL_H -#include "js_native_api.h" #include -typedef void *napi_threadsafe_function; +#include "js_native_api.h" + +typedef void* napi_threadsafe_function; typedef void (*napi_threadsafe_function_call_js)(napi_env env, napi_value js_cb, - void *context, void *data); + void* context, void* data); extern "C" NAPI_EXTERN napi_status napi_create_threadsafe_function( napi_env env, napi_value func, napi_value async_resource, napi_value async_resource_name, size_t max_queue_size, - size_t initial_thread_count, void *thread_finalize_data, - napi_finalize thread_finalize_cb, void *context, + size_t initial_thread_count, void* thread_finalize_data, + napi_finalize thread_finalize_cb, void* context, napi_threadsafe_function_call_js call_js_cb, - napi_threadsafe_function *result); + napi_threadsafe_function* result); enum napi_threadsafe_function_release_mode { napi_tsfn_release, @@ -34,13 +35,13 @@ enum napi_threadsafe_function_call_mode { }; extern "C" NAPI_EXTERN napi_status -napi_call_threadsafe_function(napi_threadsafe_function func, void *data, +napi_call_threadsafe_function(napi_threadsafe_function func, void* data, napi_threadsafe_function_call_mode is_blocking); extern "C" NAPI_EXTERN napi_status napi_unref_threadsafe_function(napi_env env, napi_threadsafe_function func); -inline bool napiSupportsThreadsafeFunctions(void *dl) { +inline bool napiSupportsThreadsafeFunctions(void* dl) { return dlsym(dl, "napi_create_threadsafe_function") != NULL; } @@ -48,56 +49,56 @@ inline bool napiSupportsThreadsafeFunctions(void *dl) { #define NAPI_PREAMBLE napi_status status; -#define NAPI_CALLBACK_BEGIN(n_args) \ - NAPI_PREAMBLE \ - napi_value argv[n_args]; \ - size_t argc = n_args; \ - napi_value jsThis; \ - void *data; \ - NAPI_GUARD(napi_get_cb_info(env, cbinfo, &argc, argv, &jsThis, &data)) { \ - NAPI_THROW_LAST_ERROR \ - return NULL; \ +#define NAPI_CALLBACK_BEGIN(n_args) \ + NAPI_PREAMBLE \ + napi_value argv[n_args]; \ + size_t argc = n_args; \ + napi_value jsThis; \ + void* data; \ + NAPI_GUARD(napi_get_cb_info(env, cbinfo, &argc, argv, &jsThis, &data)) { \ + NAPI_THROW_LAST_ERROR \ + return NULL; \ } -#define NAPI_ERROR_INFO \ - const napi_extended_error_info *error_info = \ - (napi_extended_error_info *)malloc(sizeof(napi_extended_error_info)); \ +#define NAPI_ERROR_INFO \ + const napi_extended_error_info* error_info = \ + (napi_extended_error_info*)malloc(sizeof(napi_extended_error_info)); \ napi_get_last_error_info(env, &error_info); -#define NAPI_THROW_LAST_ERROR \ - NAPI_ERROR_INFO \ +#define NAPI_THROW_LAST_ERROR \ + NAPI_ERROR_INFO \ napi_throw_error(env, NULL, error_info->error_message); #ifndef DEBUG -#define NAPI_GUARD(expr) \ - status = expr; \ - if (status != napi_ok) { \ - NAPI_ERROR_INFO \ - std::cout << "Node-API returned error: " << status << "\n " << #expr \ - << "\n ^\n " \ - << "at " << __FILE__ << ":" << __LINE__ << std::endl; \ - } \ +#define NAPI_GUARD(expr) \ + status = expr; \ + if (status != napi_ok) { \ + NAPI_ERROR_INFO \ + std::cout << "Node-API returned error: " << status << "\n " << #expr \ + << "\n ^\n " \ + << "at " << __FILE__ << ":" << __LINE__ << std::endl; \ + } \ if (status != napi_ok) #else -#define NAPI_GUARD(expr) \ - status = expr; \ +#define NAPI_GUARD(expr) \ + status = expr; \ if (status != napi_ok) #endif -#define NAPI_MODULE_REGISTER \ +#define NAPI_MODULE_REGISTER \ napi_value napi_register_module_v1(napi_env env, napi_value exports) -#define NAPI_FUNCTION(name) \ +#define NAPI_FUNCTION(name) \ napi_value JS_##name(napi_env env, napi_callback_info cbinfo) -#define NAPI_FUNCTION_DESC(name) \ - { #name, NULL, JS_##name, NULL, NULL, NULL, napi_enumerable, NULL } +#define NAPI_FUNCTION_DESC(name) \ + {#name, NULL, JS_##name, NULL, NULL, NULL, napi_enumerable, NULL} -namespace objc_bridge { +namespace nativescript { inline napi_ref make_ref(napi_env env, napi_value value, uint32_t initialCount = 1) { @@ -133,6 +134,6 @@ inline void napi_inherits(napi_env env, napi_value ctor, napi_call_function(env, global, set_proto, 2, argv, NULL); } -} // namespace objc_bridge +} // namespace nativescript #endif /* NODE_API_UTIL_H */ diff --git a/NativeScript/napi/common/native_api_util.h b/NativeScript/napi/common/native_api_util.h index c89e914d..2986b541 100644 --- a/NativeScript/napi/common/native_api_util.h +++ b/NativeScript/napi/common/native_api_util.h @@ -1,49 +1,103 @@ #ifndef NATIVE_API_UTIL_H_ #define NATIVE_API_UTIL_H_ -#include "js_native_api.h" +#include +#include +#include +#include + +#ifdef TARGET_ENGINE_V8 +namespace std { +template<> +struct char_traits { + using char_type = unsigned short; + using int_type = int; + using off_type = streamoff; + using pos_type = streampos; + using state_type = mbstate_t; + + static void assign(char_type& c1, const char_type& c2) noexcept { c1 = c2; } + static void assign(char_type* s, size_t n, char_type a) noexcept { + for (size_t i = 0; i < n; ++i) s[i] = a; + } + static bool eq(char_type c1, char_type c2) noexcept { return c1 == c2; } + static bool lt(char_type c1, char_type c2) noexcept { return c1 < c2; } + static int compare(const char_type* s1, const char_type* s2, size_t n) { + for (size_t i = 0; i < n; ++i) { + if (lt(s1[i], s2[i])) return -1; + if (lt(s2[i], s1[i])) return 1; + } + return 0; + } + static size_t length(const char_type* s) { + size_t len = 0; + while (!eq(s[len], char_type(0))) ++len; + return len; + } + static const char_type* find(const char_type* s, size_t n, const char_type& a) { + for (size_t i = 0; i < n; ++i) if (eq(s[i], a)) return s + i; + return nullptr; + } + static char_type* move(char_type* s1, const char_type* s2, size_t n) { + if (n == 0) return s1; + return (char_type*)memmove(s1, s2, n * sizeof(char_type)); + } + static char_type* copy(char_type* s1, const char_type* s2, size_t n) { + if (n == 0) return s1; + return (char_type*)memcpy(s1, s2, n * sizeof(char_type)); + } + static char_type to_char_type(int_type c) noexcept { return char_type(c); } + static int_type to_int_type(char_type c) noexcept { return int_type(c); } + static bool eq_int_type(int_type c1, int_type c2) noexcept { return c1 == c2; } + static int_type eof() noexcept { return static_cast(-1); } + static int_type not_eof(int_type c) noexcept { return eq_int_type(c, eof()) ? 0 : c; } +}; +} +#endif // TARGET_ENGINE_V8 + #include + #include +#include "js_native_api.h" +#include "js_native_api_types.h" + #ifndef NAPI_PREAMBLE #define NAPI_PREAMBLE napi_status status; #endif -#define NAPI_CALLBACK_BEGIN(n_args) \ - napi_status status; \ - napi_value argv[n_args]; \ - size_t argc = n_args; \ - napi_value jsThis; \ - void *data; \ - NAPI_GUARD(napi_get_cb_info(env, info, &argc, argv, &jsThis, &data)) \ - { \ - NAPI_THROW_LAST_ERROR \ - return NULL; \ +#define NAPI_CALLBACK_BEGIN(n_args) \ + napi_status status; \ + napi_value argv[n_args]; \ + size_t argc = n_args; \ + napi_value jsThis; \ + void* data; \ + NAPI_GUARD(napi_get_cb_info(env, info, &argc, argv, &jsThis, &data)) { \ + NAPI_THROW_LAST_ERROR \ + return NULL; \ } -#define NAPI_CALLBACK_BEGIN_VARGS() \ - napi_status status; \ - size_t argc; \ - void *data; \ - napi_value jsThis; \ - NAPI_GUARD(napi_get_cb_info(env, info, &argc, nullptr, &jsThis, &data)) \ - { \ - NAPI_THROW_LAST_ERROR \ - return NULL; \ - } \ - std::vector argv(argc); \ - if (argc > 0) \ - { \ - NAPI_GUARD(napi_get_cb_info(env, info, &argc, argv.data(), nullptr, nullptr)) \ - { \ - NAPI_THROW_LAST_ERROR \ - return NULL; \ - } \ +#define NAPI_CALLBACK_BEGIN_VARGS() \ + napi_status status; \ + size_t argc; \ + void* data; \ + napi_value jsThis; \ + NAPI_GUARD(napi_get_cb_info(env, info, &argc, nullptr, &jsThis, &data)) { \ + NAPI_THROW_LAST_ERROR \ + return NULL; \ + } \ + std::vector argv(argc); \ + if (argc > 0) { \ + NAPI_GUARD( \ + napi_get_cb_info(env, info, &argc, argv.data(), nullptr, nullptr)) { \ + NAPI_THROW_LAST_ERROR \ + return NULL; \ + } \ } -#define NAPI_ERROR_INFO \ - const napi_extended_error_info *error_info = \ - (napi_extended_error_info *)malloc(sizeof(napi_extended_error_info)); \ +#define NAPI_ERROR_INFO \ + const napi_extended_error_info* error_info = \ + (napi_extended_error_info*)malloc(sizeof(napi_extended_error_info)); \ napi_get_last_error_info(env, &error_info); #define NAPI_THROW_LAST_ERROR \ @@ -54,8 +108,7 @@ #define NAPI_GUARD(expr) \ status = expr; \ - if (status != napi_ok) \ - { \ + if (status != napi_ok) { \ NAPI_ERROR_INFO \ std::stringstream msg; \ msg << "Node-API returned error: " << status << "\n " << #expr \ @@ -78,310 +131,428 @@ #define NAPI_FUNCTION_DESC(name) \ {#name, NULL, JS_##name, NULL, NULL, NULL, napi_enumerable, NULL} +#define JS_METHOD(name) napi_value name(napi_env env, napi_callback_info cbinfo) + +#define JS_CLASS_INIT(name) void name(napi_env env, napi_value global) + #define PROTOTYPE "prototype" #define OBJECT "Object" #define SET_PROTOTYPE_OF "setPrototypeOf" #define CONSTRUCTOR "constructor" -#define UNDEFINED \ -napi_util::undefined(env); +#define UNDEFINED napi_util::undefined(env); namespace napi_util { - inline napi_value undefined(napi_env env) { - napi_value undefined; - napi_get_undefined(env, &undefined); - return undefined; - } +class PersistentObject { + public: + PersistentObject(napi_env env, napi_value value) + : env_(env), isOwnedRef_(true) { + napi_create_reference(env_, value, 1, &ref_); + } - inline napi_value null(napi_env env) { - napi_value null; - napi_get_null(env, &null); - return null; - } + PersistentObject(napi_env env, napi_ref ref) + : env_(env), ref_(ref), isOwnedRef_(false) { + uint32_t result; + napi_reference_ref(env, ref, &result); + } - inline napi_ref make_ref(napi_env env, napi_value value, - uint32_t initialCount = 1) { - napi_ref ref; - napi_create_reference(env, value, initialCount, &ref); - return ref; + ~PersistentObject() { + if (isOwnedRef_) + napi_delete_reference(env_, ref_); + else { + uint32_t result; + napi_reference_unref(env_, ref_, &result); } + } - inline napi_value get_ref_value(napi_env env, napi_ref ref) { - napi_value value; - napi_get_reference_value(env, ref, &value); - return value; + napi_value GetValue(napi_env env = nullptr) { + if (env == nullptr) { + env = env_; } + napi_value value; + napi_get_reference_value(env, ref_, &value); + return value; + } - inline napi_value get__proto__(napi_env env, napi_value object) { - napi_value proto; - napi_get_named_property(env, object, "__proto__", &proto); - return proto; - } + napi_ref GetRef() const { return ref_; } + + napi_env GetEnv() const { return env_; } + + private: + bool isOwnedRef_ = false; + napi_env env_; + napi_ref ref_; +}; + +inline napi_property_descriptor desc(const char* name, napi_callback method, + void* data = nullptr) { + return { + .utf8name = name, + .name = nullptr, + .method = method, + .getter = nullptr, + .setter = nullptr, + .value = nullptr, + .attributes = napi_configurable, + .data = data, + }; +} - inline void set__proto__(napi_env env, napi_value object, napi_value __proto__) { - napi_set_named_property(env, object, "__proto__", __proto__); - } +inline napi_property_descriptor desc(const char* name, napi_value value) { + return { + .utf8name = name, + .name = nullptr, + .method = nullptr, + .getter = nullptr, + .setter = nullptr, + .value = value, + .attributes = napi_configurable, + .data = nullptr, + }; +} - inline napi_value getPrototypeOf(napi_env env, napi_value object) { - napi_value proto; - napi_get_prototype(env, object, &proto); - return proto; - } +inline std::string get_cxx_string(napi_env env, napi_value str) { + size_t length = 0; + napi_get_value_string_utf8(env, str, nullptr, 0, &length); + char* strbuf = (char*)malloc(length + 1); + napi_get_value_string_utf8(env, str, strbuf, length + 1, &length); + std::string result = strbuf; + free(strbuf); + return result; +} - inline napi_value get_prototype(napi_env env, napi_value object) { - napi_value prototype; - napi_get_named_property(env, object, "prototype", &prototype); - return prototype; - } +inline napi_value to_js_number(napi_env env, double value) { + napi_value js_number; + napi_create_double(env, value, &js_number); + return js_number; +} +inline napi_value to_js_number(napi_env env, int32_t value) { + napi_value js_number; + napi_create_int32(env, value, &js_number); + return js_number; +} - inline void set_prototype(napi_env env, napi_value object, napi_value prototype) { - napi_set_named_property(env, object, "prototype", prototype); - } +inline napi_value to_js_string(napi_env env, const std::string& str) { + napi_value js_string; + napi_create_string_utf8(env, str.c_str(), str.length(), &js_string); + return js_string; +} - inline char *get_string_value(napi_env env, napi_value str, size_t size = 0) { - size_t str_size = size; - if (str_size == 0) { - napi_get_value_string_utf8(env, str, nullptr, 0, &str_size); - } - char *buffer = new char[str_size + 1]; - napi_get_value_string_utf8(env, str, buffer, str_size + 1, nullptr); - return buffer; - } +inline napi_value to_js_string(napi_env env, const char* str) { + napi_value js_string; + napi_create_string_utf8(env, str, strlen(str), &js_string); + return js_string; +} - inline napi_status define_property(napi_env env, napi_value object, const char *propertyName, - napi_value value = nullptr, napi_callback getter = nullptr, - napi_callback setter = nullptr, void *data = nullptr, napi_property_attributes attributes = napi_default_jsproperty) { - napi_property_descriptor desc = { - propertyName, // utf8name - nullptr, // name - nullptr, // method - getter, // getter - setter, // setter - value, // value - attributes, // attributes - data // data - }; - - return napi_define_properties(env, object, 1, &desc); - } +inline napi_value undefined(napi_env env) { + napi_value undefined; + napi_get_undefined(env, &undefined); + return undefined; +} - inline void setPrototypeOf(napi_env env, napi_value object, napi_value prototype) { - napi_value global, global_object, set_proto; +inline napi_value null(napi_env env) { + napi_value null; + napi_get_null(env, &null); + return null; +} - // Get the global object - napi_get_global(env, &global); +inline napi_ref make_ref(napi_env env, napi_value value, + uint32_t initialCount = 1) { + napi_ref ref; + napi_create_reference(env, value, initialCount, &ref); + return ref; +} - // Get the Object global object - napi_get_named_property(env, global, OBJECT, &global_object); +inline napi_value get_ref_value(napi_env env, napi_ref ref) { + napi_value value; + napi_get_reference_value(env, ref, &value); + return value; +} - // Get the setPrototypeOf function from the Object global object - napi_get_named_property(env, global_object, SET_PROTOTYPE_OF, &set_proto); +inline napi_value get__proto__(napi_env env, napi_value object) { + napi_value proto; + napi_get_named_property(env, object, "__proto__", &proto); + return proto; +} - // Prepare the arguments for the setPrototypeOf call - napi_value argv[] { - object, - prototype - }; - // Call setPrototypeOf(object, prototype) - napi_call_function(env, global, set_proto, 2, argv, nullptr); - } +inline void set__proto__(napi_env env, napi_value object, + napi_value __proto__) { + napi_set_named_property(env, object, "__proto__", __proto__); +} +inline napi_value getPrototypeOf(napi_env env, napi_value object) { + napi_value proto; + napi_get_prototype(env, object, &proto); + return proto; +} +inline napi_value get_prototype(napi_env env, napi_value object) { + napi_value prototype; + napi_get_named_property(env, object, "prototype", &prototype); + return prototype; +} - inline bool is_object_explicit(napi_env env, napi_value value) { - napi_valuetype type; - napi_typeof(env, value, &type); - return type == napi_object; - } +inline void set_prototype(napi_env env, napi_value object, + napi_value prototype) { + napi_set_named_property(env, object, "prototype", prototype); +} - inline bool is_object(napi_env env, napi_value value) { - napi_valuetype type; - napi_typeof(env, value, &type); - return type == napi_object || type == napi_function; - } +inline char* get_string_value(napi_env env, napi_value str, size_t size = 0) { + size_t str_size = size; + if (str_size == 0) { + napi_get_value_string_utf8(env, str, nullptr, 0, &str_size); + } + char* buffer = new char[str_size + 1]; + napi_get_value_string_utf8(env, str, buffer, str_size + 1, nullptr); + return buffer; +} - inline bool is_of_type(napi_env env, napi_value value, napi_valuetype expected_type) { - napi_valuetype type; - napi_typeof(env, value, &type); - return type == expected_type; - } +inline bool has_property(napi_env env, napi_value object, + const char* propertyName) { + bool result; + napi_has_named_property(env, object, propertyName, &result); + return result; +} - inline bool is_number_object(napi_env env, napi_value value) { - bool result; - napi_value numberCtor; - napi_value global; - napi_get_global(env, &global); - napi_get_named_property(env, global, "Number", &numberCtor); - napi_instanceof(env, value, numberCtor, &result); - return result; - } +inline napi_value get_property(napi_env env, napi_value object, + const char* propertyName) { + napi_value value; + napi_get_named_property(env, object, propertyName, &value); + return value; +} - inline napi_value valueOf(napi_env env, napi_value value) { - napi_value valueOf, result; - napi_get_named_property(env, value, "valueOf", &valueOf); - napi_call_function(env, value, valueOf, 0, nullptr, &result); - return result; - } +inline napi_status define_property( + napi_env env, napi_value object, const char* propertyName, + napi_value value = nullptr, napi_callback getter = nullptr, + napi_callback setter = nullptr, void* data = nullptr, + napi_property_attributes attributes = napi_default_jsproperty) { + napi_property_descriptor desc = { + propertyName, // utf8name + nullptr, // name + nullptr, // method + getter, // getter + setter, // setter + value, // value + attributes, // attributes + data // data + }; + + return napi_define_properties(env, object, 1, &desc); +} - inline bool is_string_object(napi_env env, napi_value value) { - bool result; - napi_value stringCtor; - napi_value global; - napi_get_global(env, &global); - napi_get_named_property(env, global, "String", &stringCtor); - napi_instanceof(env, value, stringCtor, &result); - return result; - } +inline void setPrototypeOf(napi_env env, napi_value object, + napi_value prototype) { + napi_value global, global_object, set_proto; - inline bool is_boolean_object(napi_env env, napi_value value) { - bool result; - napi_value booleanCtor; - napi_value global; - napi_get_global(env, &global); - napi_get_named_property(env, global, "Boolean", &booleanCtor); - napi_instanceof(env, value, booleanCtor, &result); - return result; - } - + // Get the global object + napi_get_global(env, &global); - inline bool is_array(napi_env env, napi_value value) { - bool result; - napi_is_array(env, value, &result); - return result; - } + // Get the Object global object + napi_get_named_property(env, global, OBJECT, &global_object); - inline bool is_arraybuffer(napi_env env, napi_value value) { - bool result; - napi_is_arraybuffer(env, value, &result); - return result; - } + // Get the setPrototypeOf function from the Object global object + napi_get_named_property(env, global_object, SET_PROTOTYPE_OF, &set_proto); - inline bool is_dataview(napi_env env, napi_value value) { - bool result; - napi_is_dataview(env, value, &result); - return result; - } + // Prepare the arguments for the setPrototypeOf call + napi_value argv[]{object, prototype}; + // Call setPrototypeOf(object, prototype) + napi_call_function(env, global, set_proto, 2, argv, nullptr); +} - inline bool is_typedarray(napi_env env, napi_value value) { - bool result; - napi_is_typedarray(env, value, &result); - return result; - } +inline bool is_object_explicit(napi_env env, napi_value value) { + napi_valuetype type; + napi_typeof(env, value, &type); + return type == napi_object; +} - inline bool is_date(napi_env env, napi_value value) { - bool result; - napi_is_date(env, value, &result); - return result; - } +inline bool is_object(napi_env env, napi_value value) { + napi_valuetype type; + napi_typeof(env, value, &type); + return type == napi_object || type == napi_function; +} +inline bool is_of_type(napi_env env, napi_value value, + napi_valuetype expected_type) { + napi_valuetype type; + napi_typeof(env, value, &type); + return type == expected_type; +} - inline bool is_undefined(napi_env env, napi_value value) { - if (value == nullptr) return true; - napi_valuetype type; - napi_typeof(env, value, &type); - return type == napi_undefined; - } +inline bool is_number_object(napi_env env, napi_value value) { + bool result; + napi_value numberCtor; + napi_value global; + napi_get_global(env, &global); + napi_get_named_property(env, global, "Number", &numberCtor); + napi_instanceof(env, value, numberCtor, &result); + return result; +} - inline bool is_null(napi_env env, napi_value value) { - napi_valuetype type; - napi_typeof(env, value, &type); - return type == napi_null; - } +inline napi_value valueOf(napi_env env, napi_value value) { + napi_value valueOf, result; + napi_get_named_property(env, value, "valueOf", &valueOf); + napi_call_function(env, value, valueOf, 0, nullptr, &result); + return result; +} - inline napi_value get_true(napi_env env) { - napi_value trueValue; - napi_get_boolean(env, true, &trueValue); - return trueValue; - } +inline bool is_string_object(napi_env env, napi_value value) { + bool result; + napi_value stringCtor; + napi_value global; + napi_get_global(env, &global); + napi_get_named_property(env, global, "String", &stringCtor); + napi_instanceof(env, value, stringCtor, &result); + return result; +} - inline napi_value get_false(napi_env env) { - napi_value falseValue; - napi_get_boolean(env, false, &falseValue); - return falseValue; - } +inline bool is_boolean_object(napi_env env, napi_value value) { + bool result; + napi_value booleanCtor; + napi_value global; + napi_get_global(env, &global); + napi_get_named_property(env, global, "Boolean", &booleanCtor); + napi_instanceof(env, value, booleanCtor, &result); + return result; +} - inline bool get_bool(napi_env env, napi_value value) { - bool result; - napi_get_value_bool(env, value, &result); - return result; - } +inline bool is_array(napi_env env, napi_value value) { + bool result; + napi_is_array(env, value, &result); + return result; +} - inline bool is_float(napi_env env, napi_value value) { - napi_value global, number, is_int, result; - napi_get_global(env, &global); - napi_get_named_property(env, global, "Number", &number); - napi_get_named_property(env, number, "isInteger", &is_int); - napi_call_function(env, number, is_int, 1, &value, &result); +inline bool is_arraybuffer(napi_env env, napi_value value) { + bool result; + napi_is_arraybuffer(env, value, &result); + return result; +} - return !napi_util::get_bool(env, result); - } +inline bool is_dataview(napi_env env, napi_value value) { + bool result; + napi_is_dataview(env, value, &result); + return result; +} - // Same as Object.create()` - inline napi_value object_create_from(napi_env env, napi_value object) { - napi_value new_object; - napi_create_object(env, &new_object); - napi_set_named_property(env, new_object, "prototype", object); - return new_object; - } +inline bool is_typedarray(napi_env env, napi_value value) { + bool result; + napi_is_typedarray(env, value, &result); + return result; +} - inline bool strict_equal(napi_env env, napi_value v1, napi_value v2) { - bool equal; - napi_strict_equals(env, v1, v2, &equal); - return equal; - } +inline bool is_date(napi_env env, napi_value value) { + bool result; + napi_is_date(env, value, &result); + return result; +} - inline double get_number(napi_env env, napi_value value) { - double result; - napi_get_value_double(env, value, &result); - return result; - } +inline bool is_undefined(napi_env env, napi_value value) { + if (value == nullptr) return true; + napi_valuetype type; + napi_typeof(env, value, &type); + return type == napi_undefined; +} - inline int32_t get_int32(napi_env env, napi_value value) { - int32_t result; - napi_get_value_int32(env, value, &result); - return result; - } +inline bool is_null(napi_env env, napi_value value) { + napi_valuetype type; + napi_typeof(env, value, &type); + return type == napi_null; +} - template - inline void run_in_handle_scope(napi_env env, Func func, Args &&...args) { - napi_handle_scope scope; - napi_open_handle_scope(env, &scope); +inline napi_value get_true(napi_env env) { + napi_value trueValue; + napi_get_boolean(env, true, &trueValue); + return trueValue; +} - // Call the provided function - func(std::forward(args)...); +inline napi_value get_false(napi_env env) { + napi_value falseValue; + napi_get_boolean(env, false, &falseValue); + return falseValue; +} - napi_close_handle_scope(env, scope); - } +inline bool get_bool(napi_env env, napi_value value) { + bool result; + napi_get_value_bool(env, value, &result); + return result; +} - template - inline napi_value run_in_escapable_handle_scope(napi_env env, Func func, Args &&...args) { - napi_escapable_handle_scope scope; - napi_value result, escaped = nullptr; +inline bool is_float(napi_env env, napi_value value) { + napi_value global, number, is_int, result; + napi_get_global(env, &global); + napi_get_named_property(env, global, "Number", &number); + napi_get_named_property(env, number, "isInteger", &is_int); + napi_call_function(env, number, is_int, 1, &value, &result); - napi_open_escapable_handle_scope(env, &scope); + return !napi_util::get_bool(env, result); +} - // Call the provided function with forwarded arguments and get the result - result = func(std::forward(args)...); +// Same as Object.create()` +inline napi_value object_create_from(napi_env env, napi_value object) { + napi_value new_object; + napi_create_object(env, &new_object); + napi_set_named_property(env, new_object, "prototype", object); + return new_object; +} - if (result != nullptr) { - // Escape the result - napi_escape_handle(env, scope, result, &escaped); - } +inline bool strict_equal(napi_env env, napi_value v1, napi_value v2) { + bool equal; + napi_strict_equals(env, v1, v2, &equal); + return equal; +} - napi_close_escapable_handle_scope(env, scope); +inline double get_number(napi_env env, napi_value value) { + double result; + napi_get_value_double(env, value, &result); + return result; +} - return escaped; - } +inline int32_t get_int32(napi_env env, napi_value value) { + int32_t result; + napi_get_value_int32(env, value, &result); + return result; +} - inline napi_value - napi_set_function(napi_env env, napi_value object, const char *name, napi_callback callback, - void *data = nullptr) { - napi_value fn; - napi_create_function(env, name, strlen(name), callback, data, &fn); - napi_set_named_property(env, object, name, fn); - return fn; - } +template +inline void run_in_handle_scope(napi_env env, Func func, Args&&... args) { + napi_handle_scope scope; + napi_open_handle_scope(env, &scope); + + // Call the provided function + func(std::forward(args)...); + + napi_close_handle_scope(env, scope); +} + +template +inline napi_value run_in_escapable_handle_scope(napi_env env, Func func, + Args&&... args) { + napi_escapable_handle_scope scope; + napi_value result, escaped = nullptr; + + napi_open_escapable_handle_scope(env, &scope); + + // Call the provided function with forwarded arguments and get the result + result = func(std::forward(args)...); + + if (result != nullptr) { + // Escape the result + napi_escape_handle(env, scope, result, &escaped); + } + + napi_close_escapable_handle_scope(env, scope); + + return escaped; +} + +inline napi_value napi_set_function(napi_env env, napi_value object, + const char* name, napi_callback callback, + void* data = nullptr) { + napi_value fn; + napi_create_function(env, name, strlen(name), callback, data, &fn); + napi_set_named_property(env, object, name, fn); + return fn; +} // inline napi_value symbolFor(napi_env env, const char *string) { // napi_value symbol; @@ -389,56 +560,53 @@ namespace napi_util { // return symbol; // } - inline bool is_null_or_undefined(napi_env env, napi_value value) { - return value == nullptr || is_undefined(env, value) || is_null(env, value); - } - - inline napi_value global(napi_env env) { - napi_value global; - napi_get_global(env, &global); - return global; - } - +inline bool is_null_or_undefined(napi_env env, napi_value value) { + return value == nullptr || is_undefined(env, value) || is_null(env, value); +} - inline void log_value(napi_env env, napi_value value) { - napi_value global; - napi_value console; - napi_value log; - napi_get_global(env, &global); - napi_get_named_property(env, global, "console", &console); - napi_get_named_property(env, console, "log", &log); - napi_value argv[] = { - value - }; +inline napi_value global(napi_env env) { + napi_value global; + napi_get_global(env, &global); + return global; +} - napi_call_function(env, console, log, 1, argv, nullptr); - } +inline void log_value(napi_env env, napi_value value) { + napi_value global; + napi_value console; + napi_value log; + napi_get_global(env, &global); + napi_get_named_property(env, global, "console", &console); + napi_get_named_property(env, console, "log", &log); + napi_value argv[] = {value}; - inline void napi_inherits(napi_env env, napi_value ctor, - napi_value super_ctor) { - napi_value global, global_object, set_proto, ctor_proto_prop, - super_ctor_proto_prop; - napi_value argv[2]; + napi_call_function(env, console, log, 1, argv, nullptr); +} - napi_get_global(env, &global); - napi_get_named_property(env, global, OBJECT, &global_object); - napi_get_named_property(env, global_object, SET_PROTOTYPE_OF, &set_proto); - napi_get_named_property(env, ctor, PROTOTYPE, &ctor_proto_prop); - napi_get_named_property(env, super_ctor, PROTOTYPE, &super_ctor_proto_prop); +inline void napi_inherits(napi_env env, napi_value ctor, + napi_value super_ctor) { + napi_value global, global_object, set_proto, ctor_proto_prop, + super_ctor_proto_prop; + napi_value argv[2]; - bool exception; + napi_get_global(env, &global); + napi_get_named_property(env, global, OBJECT, &global_object); + napi_get_named_property(env, global_object, SET_PROTOTYPE_OF, &set_proto); + napi_get_named_property(env, ctor, PROTOTYPE, &ctor_proto_prop); + napi_get_named_property(env, super_ctor, PROTOTYPE, &super_ctor_proto_prop); - napi_is_exception_pending(env, &exception); + bool exception; - argv[0] = ctor_proto_prop; - argv[1] = super_ctor_proto_prop; - napi_call_function(env, global, set_proto, 2, argv, nullptr); + napi_is_exception_pending(env, &exception); - argv[0] = ctor; - argv[1] = super_ctor; - napi_call_function(env, global, set_proto, 2, argv, nullptr); - } + argv[0] = ctor_proto_prop; + argv[1] = super_ctor_proto_prop; + napi_call_function(env, global, set_proto, 2, argv, nullptr); + argv[0] = ctor; + argv[1] = super_ctor; + napi_call_function(env, global, set_proto, 2, argv, nullptr); } +} // namespace napi_util + #endif /* NATIVE_API_UTIL_H_ */ \ No newline at end of file diff --git a/NativeScript/napi/hermes/include/hermes/Public/SamplingProfiler.h b/NativeScript/napi/hermes/include/hermes/Public/SamplingProfiler.h new file mode 100644 index 00000000..4184964e --- /dev/null +++ b/NativeScript/napi/hermes/include/hermes/Public/SamplingProfiler.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_PUBLIC_SAMPLINGPROFILER_H +#define HERMES_PUBLIC_SAMPLINGPROFILER_H + +#include + +#include +#include +#include +#include + +namespace facebook { +namespace hermes { +namespace sampling_profiler { + +/// Represents a single frame inside the captured sample stack. +/// Base struct for different kinds of frames. +struct HERMES_EXPORT ProfileSampleCallStackFrame { + /// Represents type of frame inside of recorded call stack. + enum class Kind { + JSFunction, /// JavaScript function frame. + NativeFunction, /// Native built-in functions, like arrayPrototypeMap. + HostFunction, /// Native functions, defined by Host, a.k.a. Host functions. + Suspend, /// Frame that suspends the execution of the VM: GC or Debugger. + }; + + public: + explicit ProfileSampleCallStackFrame(const Kind kind) : kind_(kind) {} + + /// \return type of the call stack frame. + Kind getKind() const { + return kind_; + } + + private: + Kind kind_; +}; + +/// Extends ProfileSampleCallStackFrame with an information about JavaScript +/// function frame: function name, and possibly scriptId, url, line and column +/// numbers. +struct HERMES_EXPORT ProfileSampleCallStackJSFunctionFrame + : public ProfileSampleCallStackFrame { + explicit ProfileSampleCallStackJSFunctionFrame( + const std::string &functionName, + const std::optional &scriptId = std::nullopt, + const std::optional &url = std::nullopt, + const std::optional &lineNumber = std::nullopt, + const std::optional &columnNumber = std::nullopt) + : ProfileSampleCallStackFrame( + ProfileSampleCallStackFrame::Kind::JSFunction), + functionName_(functionName), + scriptId_(scriptId), + url_(url), + lineNumber_(lineNumber), + columnNumber_(columnNumber) {} + + /// \return name of the function that represents call frame. + const std::string &getFunctionName() const { + return functionName_; + } + + bool hasScriptId() const { + return scriptId_.has_value(); + } + + /// \return id of the corresponding script in the VM. + uint32_t getScriptId() const { + return scriptId_.value(); + } + + bool hasUrl() const { + return url_.has_value(); + } + + /// \return source url of the corresponding script in the VM. + const std::string &getUrl() const { + return url_.value(); + } + + bool hasLineNumber() const { + return lineNumber_.has_value(); + } + + /// \return 1-based line number of the corresponding call frame. + uint32_t getLineNumber() const { + return lineNumber_.value(); + } + + bool hasColumnNumber() const { + return columnNumber_.has_value(); + } + + /// \return 1-based column number of the corresponding call frame. + uint32_t getColumnNumber() const { + return columnNumber_.value(); + } + + private: + std::string functionName_; + std::optional scriptId_; + std::optional url_; + std::optional lineNumber_; + std::optional columnNumber_; +}; + +/// Extends ProfileSampleCallStackFrame with a function name. +struct HERMES_EXPORT ProfileSampleCallStackNativeFunctionFrame + : public ProfileSampleCallStackFrame { + public: + explicit ProfileSampleCallStackNativeFunctionFrame( + const std::string &functionName) + : ProfileSampleCallStackFrame( + ProfileSampleCallStackFrame::Kind::NativeFunction), + functionName_(functionName) {} + + /// \return name of the function that represents call frame. + const std::string &getFunctionName() const { + return functionName_; + } + + private: + std::string functionName_; +}; + +/// Extends ProfileSampleCallStackFrame with a function name. +struct HERMES_EXPORT ProfileSampleCallStackHostFunctionFrame + : public ProfileSampleCallStackFrame { + public: + explicit ProfileSampleCallStackHostFunctionFrame( + const std::string &functionName) + : ProfileSampleCallStackFrame( + ProfileSampleCallStackFrame::Kind::HostFunction), + functionName_(functionName) {} + + /// \return name of the function that represents call frame. + const std::string &getFunctionName() const { + return functionName_; + } + + private: + std::string functionName_; +}; + +/// Extends ProfileSampleCallStackFrame with a suspend frame information. +struct HERMES_EXPORT ProfileSampleCallStackSuspendFrame + : public ProfileSampleCallStackFrame { + /// Subtype of the Suspend frame. + enum class SuspendFrameKind { + GC, /// Frame that suspends the execution of the VM due to GC. + Debugger, /// Frame that suspends the execution of the VM due to debugger. + Multiple, /// Multiple suspensions have occurred. + }; + + public: + explicit ProfileSampleCallStackSuspendFrame( + const SuspendFrameKind suspendFrameKind) + : ProfileSampleCallStackFrame(ProfileSampleCallStackFrame::Kind::Suspend), + suspendFrameKind_(suspendFrameKind) {} + + /// \return subtype of the suspend frame. + SuspendFrameKind getSuspendFrameKind() const { + return suspendFrameKind_; + } + + private: + SuspendFrameKind suspendFrameKind_; +}; + +/// A pair of a timestamp and a snapshot of the call stack at this point in +/// time. +struct HERMES_EXPORT ProfileSample { + public: + ProfileSample( + uint64_t timestamp, + uint64_t threadId, + std::vector callStack) + : timestamp_(timestamp), + threadId_(threadId), + callStack_(std::move(callStack)) {} + + /// \return serialized unix timestamp in microseconds granularity. The + /// moment when this sample was recorded. + uint64_t getTimestamp() const { + return timestamp_; + } + + /// \return thread id where sample was recorded. + uint64_t getThreadId() const { + return threadId_; + } + + /// \return a snapshot of the call stack. The first element of the vector is + /// the lowest frame in the stack. + const std::vector &getCallStack() const { + return callStack_; + } + + private: + /// When the call stack snapshot was taken (μs). + uint64_t timestamp_; + /// Thread id where sample was recorded. + uint64_t threadId_; + /// Snapshot of the call stack. The first element of the vector is + /// the lowest frame in the stack. + std::vector callStack_; +}; + +/// Contains relevant information about the sampled trace from start to finish. +struct HERMES_EXPORT Profile { + public: + explicit Profile(std::vector samples) + : samples_(std::move(samples)) {} + + /// \return list of recorded samples, should be chronologically sorted. + const std::vector &getSamples() const { + return samples_; + } + + private: + /// List of recorded samples, should be chronologically sorted. + std::vector samples_; +}; + +} // namespace sampling_profiler +} // namespace hermes +} // namespace facebook + +#endif diff --git a/NativeScript/napi/hermes/include/hermes/SynthTrace.h b/NativeScript/napi/hermes/include/hermes/SynthTrace.h index f8d174c8..749887b6 100644 --- a/NativeScript/napi/hermes/include/hermes/SynthTrace.h +++ b/NativeScript/napi/hermes/include/hermes/SynthTrace.h @@ -171,6 +171,9 @@ class SynthTrace { } val_; }; + /// Represents the encoding type of a String or PropNameId + enum class StringEncodingType { ASCII, UTF8, UTF16 }; + /// A TimePoint is a time when some event occurred. using TimePoint = std::chrono::steady_clock::time_point; using TimeSinceStart = std::chrono::milliseconds; @@ -180,8 +183,10 @@ class SynthTrace { RECORD(EndExecJS) \ RECORD(Marker) \ RECORD(CreateObject) \ + RECORD(CreateObjectWithPrototype) \ RECORD(CreateString) \ RECORD(CreatePropNameID) \ + RECORD(CreatePropNameIDWithValue) \ RECORD(CreateHostObject) \ RECORD(CreateHostFunction) \ RECORD(QueueMicrotask) \ @@ -208,6 +213,10 @@ class SynthTrace { RECORD(BigIntToString) \ RECORD(SetExternalMemoryPressure) \ RECORD(Utf8) \ + RECORD(Utf16) \ + RECORD(GetStringData) \ + RECORD(GetPrototype) \ + RECORD(SetPrototype) \ RECORD(Global) /// RecordType is a tag used to differentiate which type of record it is. @@ -317,7 +326,7 @@ class SynthTrace { /// The version of the Synth Benchmark constexpr static uint32_t synthVersion() { - return 4; + return 5; } static const char *nameFromReleaseUnused(::hermes::vm::ReleaseUnused ru); @@ -557,8 +566,10 @@ class SynthTrace { /// The string that was passed to Runtime::createStringFromAscii() or /// Runtime::createStringFromUtf8() when the string was created. std::string chars_; - /// Whether the string was created from ASCII (true) or UTF8 (false). - bool ascii_; + /// The string that was passed to Runtime::createStringFromUtf16() + std::u16string chars16_; + /// Whether the String was created from ASCII, UTF-8 or UTF-16 + StringEncodingType encodingType_; // General UTF-8. CreateStringRecord( @@ -569,14 +580,27 @@ class SynthTrace { : Record(time), objID_(objID), chars_(reinterpret_cast(chars), length), - ascii_(false) {} + encodingType_(StringEncodingType::UTF8) {} // Ascii. CreateStringRecord( TimeSinceStart time, ObjectID objID, const char *chars, size_t length) - : Record(time), objID_(objID), chars_(chars, length), ascii_(true) {} + : Record(time), + objID_(objID), + chars_(chars, length), + encodingType_(StringEncodingType::ASCII) {} + // UTF-16. + CreateStringRecord( + TimeSinceStart time, + ObjectID objID, + const char16_t *chars, + size_t length) + : Record(time), + objID_(objID), + chars16_(chars, length), + encodingType_(StringEncodingType::UTF16) {} void toJSONInternal(::hermes::JSONEmitter &json) const override; RecordType getType() const override { @@ -596,19 +620,15 @@ class SynthTrace { /// created by the native code. struct CreatePropNameIDRecord : public Record { static constexpr RecordType type{RecordType::CreatePropNameID}; - /// The ObjectID of the PropNameID that was created by - /// Runtime::createPropNameIDFromXxx() functions. + /// The ObjectID of the PropNameID that was created. const ObjectID propNameID_; /// The string that was passed to Runtime::createPropNameIDFromAscii() or /// Runtime::createPropNameIDFromUtf8(). std::string chars_; - /// The String for Symbol that was passed to - /// Runtime::createPropNameIDFromString() or - /// Runtime::createPropNameIDFromSymbol(). - const TraceValue traceValue_{TraceValue::encodeUndefinedValue()}; - /// Whether the PropNameID was created from ASCII, UTF8, jsi::String - /// (TRACEVALUE) or jsi::Symbol (TRACEVALUE). - enum ValueType { ASCII, UTF8, TRACEVALUE } valueType_; + /// The string that was passed to Runtime::createPropNameIDFromUtf16() + std::u16string chars16_; + /// Whether the PropNameID was created from ASCII, UTF-8, or UTF-16 + StringEncodingType encodingType_; // General UTF-8. CreatePropNameIDRecord( @@ -619,7 +639,7 @@ class SynthTrace { : Record(time), propNameID_(propNameID), chars_(reinterpret_cast(chars), length), - valueType_(UTF8) {} + encodingType_(StringEncodingType::UTF8) {} // Ascii. CreatePropNameIDRecord( TimeSinceStart time, @@ -629,16 +649,49 @@ class SynthTrace { : Record(time), propNameID_(propNameID), chars_(chars, length), - valueType_(ASCII) {} - // jsi::String or jsi::Symbol. + encodingType_(StringEncodingType::ASCII) {} + // UTF16 CreatePropNameIDRecord( TimeSinceStart time, ObjectID propNameID, - TraceValue traceValue) + const char16_t *chars, + size_t length) : Record(time), propNameID_(propNameID), - traceValue_(traceValue), - valueType_(TRACEVALUE) {} + chars16_(chars, length), + encodingType_(StringEncodingType::UTF16) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + RecordType getType() const override { + return type; + } + + std::vector defs() const override { + return {propNameID_}; + } + + std::vector uses() const override { + return {}; + } + }; + + /// A CreatePropNameIDWithValueRecord is an event where a jsi::PropNameID is + /// created by the native code from JSI Value + struct CreatePropNameIDWithValueRecord : public Record { + static constexpr RecordType type{RecordType::CreatePropNameIDWithValue}; + /// The ObjectID of the PropNameID that was created. + const ObjectID propNameID_; + /// The String or Symbol that was passed to + /// Runtime::createPropNameIDFromString() or + /// Runtime::createPropNameIDFromSymbol(). + const TraceValue traceValue_; + + // jsi::String or jsi::Symbol. + CreatePropNameIDWithValueRecord( + TimeSinceStart time, + ObjectID propNameID, + TraceValue traceValue) + : Record(time), propNameID_(propNameID), traceValue_(traceValue) {} void toJSONInternal(::hermes::JSONEmitter &json) const override; RecordType getType() const override { @@ -656,6 +709,31 @@ class SynthTrace { } }; + struct CreateObjectWithPrototypeRecord : public Record { + static constexpr RecordType type{RecordType::CreateObjectWithPrototype}; + const ObjectID objID_; + /// The prototype being assigned + const TraceValue prototype_; + + CreateObjectWithPrototypeRecord( + TimeSinceStart time, + ObjectID objID, + TraceValue prototype) + : Record(time), objID_(objID), prototype_(prototype) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + + RecordType getType() const override { + return type; + } + + std::vector uses() const override { + std::vector uses{objID_}; + pushIfTrackedValue(prototype_, uses); + return uses; + } + }; + struct CreateHostObjectRecord final : public CreateObjectRecord { static constexpr RecordType type{RecordType::CreateHostObject}; using CreateObjectRecord::CreateObjectRecord; @@ -883,6 +961,48 @@ class SynthTrace { } }; + /// A SetPrototypeRecord is an event where native code sets the prototype of a + /// JS Object + struct SetPrototypeRecord : public Record { + static constexpr RecordType type{RecordType::SetPrototype}; + /// The ObjectID of the object that was accessed for its prototype. + const ObjectID objID_; + /// The custom prototype being assigned + const TraceValue value_; + SetPrototypeRecord(TimeSinceStart time, ObjectID objID, TraceValue value) + : Record(time), objID_(objID), value_(value) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + + RecordType getType() const override { + return type; + } + std::vector uses() const override { + std::vector uses{objID_}; + pushIfTrackedValue(value_, uses); + return uses; + } + }; + + /// A GetPrototypeRecord is an event where native code gets the prototype of a + /// JS Object + struct GetPrototypeRecord : public Record { + static constexpr RecordType type{RecordType::GetPrototype}; + /// The ObjectID of the object that was accessed for its prototype. + const ObjectID objID_; + GetPrototypeRecord(TimeSinceStart time, ObjectID objID) + : Record(time), objID_(objID) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + + RecordType getType() const override { + return type; + } + std::vector uses() const override { + return {objID_}; + } + }; + /// A CreateArrayRecord is an event where a new array is created of a specific /// length. struct CreateArrayRecord final : public Record { @@ -1285,6 +1405,63 @@ class SynthTrace { void toJSONInternal(::hermes::JSONEmitter &json) const override; }; + /// A Utf16Record is an event where a PropNameID or String was converted to + /// UTF-16. + struct Utf16Record final : public Record { + static constexpr RecordType type{RecordType::Utf16}; + /// PropNameID, String passed to utf16() as an argument + const TraceValue objID_; + /// Returned string from utf16(). + const std::u16string retVal_; + + explicit Utf16Record( + TimeSinceStart time, + const TraceValue objID, + std::u16string retval) + : Record(time), objID_(objID), retVal_(std::move(retval)) {} + + RecordType getType() const override { + return type; + } + + std::vector uses() const override { + std::vector vec; + pushIfTrackedValue(objID_, vec); + return vec; + } + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + + /// A GetStringData is an event where getStringData or getPropNameIdData was + /// invoked. + struct GetStringDataRecord final : public Record { + static constexpr RecordType type{RecordType::GetStringData}; + /// The String or PropNameID passed into getStringData or getPropNameIdData + const TraceValue objID_; + /// The string content in the String or PropNameID that was passed into the + /// callback + const std::u16string strData_; + + explicit GetStringDataRecord( + TimeSinceStart time, + const TraceValue objID, + std::u16string strData) + : Record(time), objID_(objID), strData_(std::move(strData)) {} + + RecordType getType() const override { + return type; + } + + std::vector uses() const override { + std::vector vec; + pushIfTrackedValue(objID_, vec); + return vec; + } + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + struct GlobalRecord final : public Record { static constexpr RecordType type{RecordType::Global}; const ObjectID objID_; // global's ObjectID returned from Runtime::global(). diff --git a/NativeScript/napi/hermes/include/hermes/TracingRuntime.h b/NativeScript/napi/hermes/include/hermes/TracingRuntime.h index f3d082d5..14fb20eb 100644 --- a/NativeScript/napi/hermes/include/hermes/TracingRuntime.h +++ b/NativeScript/napi/hermes/include/hermes/TracingRuntime.h @@ -47,6 +47,7 @@ class TracingRuntime : public jsi::RuntimeDecorator { jsi::Object global() override; jsi::Object createObject() override; + jsi::Object createObjectWithPrototype(const jsi::Value &prototype) override; jsi::Object createObject(std::shared_ptr ho) override; // Note that the NativeState methods do not need to be traced since they @@ -58,14 +59,32 @@ class TracingRuntime : public jsi::RuntimeDecorator { jsi::String createStringFromAscii(const char *str, size_t length) override; jsi::String createStringFromUtf8(const uint8_t *utf8, size_t length) override; + jsi::String createStringFromUtf16(const char16_t *utf16, size_t length) + override; std::string utf8(const jsi::PropNameID &) override; jsi::PropNameID createPropNameIDFromAscii(const char *str, size_t length) override; jsi::PropNameID createPropNameIDFromUtf8(const uint8_t *utf8, size_t length) override; + jsi::PropNameID createPropNameIDFromUtf16( + const char16_t *utf16, + size_t length) override; std::string utf8(const jsi::String &) override; + std::u16string utf16(const jsi::PropNameID &) override; + std::u16string utf16(const jsi::String &) override; + + void getStringData( + const jsi::String &str, + void *ctx, + void (*cb)(void *ctx, bool ascii, const void *data, size_t num)) override; + + void getPropNameIdData( + const jsi::PropNameID &sym, + void *ctx, + void (*cb)(void *ctx, bool ascii, const void *data, size_t num)) override; + std::string symbolToString(const jsi::Symbol &) override; jsi::PropNameID createPropNameIDFromString(const jsi::String &str) override; @@ -89,6 +108,10 @@ class TracingRuntime : public jsi::RuntimeDecorator { const jsi::PropNameID &name, const jsi::Value &value) override; + void setPrototypeOf(const jsi::Object &object, const jsi::Value &prototype) + override; + jsi::Value getPrototypeOf(const jsi::Object &object) override; + jsi::Array getPropertyNames(const jsi::Object &o) override; jsi::WeakObject createWeakObject(const jsi::Object &o) override; diff --git a/NativeScript/napi/hermes/include/hermes/cdp/CDPAgent.h b/NativeScript/napi/hermes/include/hermes/cdp/CDPAgent.h index e2243259..fc89c3b3 100644 --- a/NativeScript/napi/hermes/include/hermes/cdp/CDPAgent.h +++ b/NativeScript/napi/hermes/include/hermes/cdp/CDPAgent.h @@ -103,8 +103,9 @@ class HERMES_EXPORT CDPAgent { /// tasks enqueued during destruction. ~CDPAgent(); - /// Process a CDP command encoded in \p json. This can be called from - /// arbitrary threads. + /// This function can be called from arbitrary threads. It processes a CDP + /// command encoded in \p json as UTF-8 in accordance with RFC-8259. See: + // https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/public/devtools_protocol/#wire-format_strings-and-binary-values void handleCommand(std::string json); /// Enable the Runtime domain without processing a CDP command or sending a diff --git a/NativeScript/napi/hermes/include/hermes/cdp/DebuggerDomainAgent.h b/NativeScript/napi/hermes/include/hermes/cdp/DebuggerDomainAgent.h index b1336e6b..c54b8983 100644 --- a/NativeScript/napi/hermes/include/hermes/cdp/DebuggerDomainAgent.h +++ b/NativeScript/napi/hermes/include/hermes/cdp/DebuggerDomainAgent.h @@ -24,6 +24,13 @@ namespace cdp { enum class PausedNotificationReason; +/// Last explicit debugger step command issued by the user. +enum class LastUserStepRequest { + StepInto, + StepOver, + StepOut, +}; + namespace m = ::facebook::hermes::cdp::message; /// Details about a single Hermes breakpoint, implied by a CDP breakpoint. @@ -119,7 +126,8 @@ class DebuggerDomainAgent : public DomainAgent { /// Handles Debugger.setBlackboxedRanges request void setBlackboxedRanges(const m::debugger::SetBlackboxedRangesRequest &req); - + /// Handles Debugger.setBlackboxPatterns request + void setBlackboxPatterns(const m::debugger::SetBlackboxPatternsRequest &req); /// Handles Debugger.setPauseOnExceptions void setPauseOnExceptions( const m::debugger::SetPauseOnExceptionsRequest &req); @@ -161,14 +169,90 @@ class DebuggerDomainAgent : public DomainAgent { CDPBreakpointDescription &&description, std::optional hermesBreakpoint = std::nullopt); - std::optional createHermesBreakpont( + std::optional createHermesBreakpoint( debugger::ScriptID scriptID, const CDPBreakpointDescription &description); + void applyBreakpointAndSendNotification( + CDPBreakpointID cdpBreakpointID, + CDPBreakpoint &cdpBreakpoint, + const debugger::SourceLocation &srcLoc); + std::optional applyBreakpoint( - CDPBreakpoint &breakpoint, + CDPBreakpoint &cdpBreakpoint, debugger::ScriptID scriptID); + /// Holds a boolean that determines if scripts without a script url + /// (e.g. anonymous scripts) should be blackboxed. + /// Same as V8: + /// https://source.chromium.org/chromium/chromium/src/+/fef5d519bab86dbd712d76bfca5be90a6e03459c:v8/src/inspector/v8-debugger-agent-impl.cc;l=997-999 + bool blackboxAnonymousScripts_ = false; + /// Optionally, holds a compiled regex pattern that is used to test if + /// script urls should be blackboxed. + /// See isLocationBlackboxed below for more details. Same as V8: + /// https://source.chromium.org/chromium/chromium/src/+/fef5d519bab86dbd712d76bfca5be90a6e03459c:v8/src/inspector/v8-debugger-agent-impl.cc;l=993-996 + /// Matching using the compiled regex should be done with + /// ::hermes::regex::searchWithBytecode. + std::optional> compiledBlackboxPatternRegex_; + + /// A vector of 1-based positions per script id indicating where blackbox + /// state changes using [from inclusive, to exclusive) pairs. + /// [ (start) ... position[0]) range is not blackboxed + /// [position[0] ... position[1]) range is blackboxed + /// [position[1] ... position[2]) range is not blackboxed ... ... + /// [position[n] ... (end) ) range is blackboxed if n is even, not + /// blackboxed if odd. + /// This is used to determine if the debugger is paused on one of these + /// blackboxed ranges, to prevent the user from stopping there in the + /// following scenarios: + /// 1. Step out- repeats stepping out until reaches a non-blackboxed range. + /// 2. Step over- stepping over to a blackboxed range meaning that + /// the next un-blackboxed range would be after all the stepping in the + /// function are done (because blackboxing is per file, meaning per function + /// as well) so we can execute step out as well in this case until we + /// step out of blackboxed ranges. + /// Comparing with v8, we don’t check if the user comes from a blackboxed + /// range, but only if a stepover got you to a blackboxed range. However + /// both results in the same thing which is stepping out until reaching a + /// non-blackboxed range. + /// 3. Step into- execute another step into. + /// Repeat this step until outside of a blackboxed range. + /// 4. Exceptions triggering the debugger pause- + /// (uncaught or if the user chooses to stop on all exceptions)- + /// ignore and continue execution + /// 5. Debugger statements- ignore and continue execution + /// 6. Explicit pause- keep stepping in until reaching a non-blackboxed range + /// 7. Manual breakpoints- allow stopping in blackboxed ranges + std::unordered_map>> + blackboxedRanges_; + /// Checks whether the passed location falls within a blackboxed range + /// in blackboxedRanges_. + /// Chrome looks at full functions ("frames") to detemine this. See: + /// https://source.chromium.org/chromium/chromium/src/+/318e9cfd9fbbbc70906f6a78d017a2708248dc6d:v8/src/inspector/v8-debugger-agent-impl.cc;l=984-1026 + /// We, on the other hand, look at individual lines since there's no + /// difference in practise because the current way functions are blackboxed is + /// by using ignoreList in source maps, which blackboxes full files, which + /// means also it blackboxes full functions, so there's no difference between + /// checking if a line in a function is blackboxed or if the whole function is + /// blackboxed. + /// This means that we receive one "Debugger.setBlackboxedRanges" per bundle + /// file comprised of source js files. + /// For each file appearing in the "ignoreList" in source maps, we receive the + /// start positions and end positions of the file inside the bundle file: + /// [ file 1 start position, + /// file 1 end position, + /// file 2 start position, + /// file 2 end position, + /// ... ] + bool isLocationBlackboxed( + debugger::ScriptID scriptID, + std::string scriptName, + int lineNumber, + int columnNumber); + /// Checks whether the location of the top frame of the call stack is + /// blackboxed or not using isLocationBlackboxed + bool isTopFrameLocationBlackboxed(); + bool checkDebuggerEnabled(const m::Request &req); bool checkDebuggerPaused(const m::Request &req); @@ -187,8 +271,9 @@ class DebuggerDomainAgent : public DomainAgent { std::unordered_map cdpBreakpoints_{}; /// CDP breakpoint IDs are assigned by the DebuggerDomainAgent. Keep track of - /// the next available ID. - CDPBreakpointID nextBreakpointID_ = 1; + /// the next available ID. Starts with 100 to avoid confusion with Hermes + /// breakpoints IDs that start with 1. + CDPBreakpointID nextBreakpointID_ = 100; DomainState &state_; @@ -204,7 +289,28 @@ class DebuggerDomainAgent : public DomainAgent { /// Whether to consider the debugger as currently paused. There are some /// debugger events such as ScriptLoaded where we don't consider the debugger /// to be paused. + /// Should only be set using setPaused and setUnpaused. bool paused_; + + /// Called when the runtime is paused. + void setPaused(PausedNotificationReason pausedNotificationReason); + + /// Called when the runtime is resumed. + void setUnpaused(); + + /// Set to true when the user selects to explicitly pause execution. + /// This is set back to false when the execution is paused. + bool explicitPausePending_ = false; + + /// Last explicit step type issued by the user. + /// * This is never reset because cdp can't tell if a step command was + /// completed since a step command that does not result in further operations + /// resolves to a "resume" without "stepFinished" or debugger pause. + /// That means that this member should only be used in situations where we are + /// sure that a step command was issued in the given scenario. For example, a + /// step into command followed by a resume would leave this member holding an + /// "StepInto" even when minutes later the execution stops on a breakpoint. + std::optional lastUserStepRequest_ = std::nullopt; }; } // namespace cdp diff --git a/NativeScript/napi/hermes/include/hermes/cdp/MessageTypes.h b/NativeScript/napi/hermes/include/hermes/cdp/MessageTypes.h index fcc86c32..bdc14d39 100644 --- a/NativeScript/napi/hermes/include/hermes/cdp/MessageTypes.h +++ b/NativeScript/napi/hermes/include/hermes/cdp/MessageTypes.h @@ -1,5 +1,5 @@ // Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. -// @generated SignedSource<> +// @generated SignedSource<<1284c402aedd087ebdf70e9e76596f1c>> #pragma once @@ -35,8 +35,10 @@ struct RemoveBreakpointRequest; struct ResumeRequest; struct ResumedNotification; struct Scope; +using ScriptLanguage = std::string; struct ScriptParsedNotification; struct ScriptPosition; +struct SetBlackboxPatternsRequest; struct SetBlackboxedRangesRequest; struct SetBreakpointByUrlRequest; struct SetBreakpointByUrlResponse; @@ -134,6 +136,7 @@ struct RequestHandler { virtual void handle(const debugger::PauseRequest &req) = 0; virtual void handle(const debugger::RemoveBreakpointRequest &req) = 0; virtual void handle(const debugger::ResumeRequest &req) = 0; + virtual void handle(const debugger::SetBlackboxPatternsRequest &req) = 0; virtual void handle(const debugger::SetBlackboxedRangesRequest &req) = 0; virtual void handle(const debugger::SetBreakpointRequest &req) = 0; virtual void handle(const debugger::SetBreakpointByUrlRequest &req) = 0; @@ -180,6 +183,7 @@ struct NoopRequestHandler : public RequestHandler { void handle(const debugger::PauseRequest &req) override {} void handle(const debugger::RemoveBreakpointRequest &req) override {} void handle(const debugger::ResumeRequest &req) override {} + void handle(const debugger::SetBlackboxPatternsRequest &req) override {} void handle(const debugger::SetBlackboxedRangesRequest &req) override {} void handle(const debugger::SetBreakpointRequest &req) override {} void handle(const debugger::SetBreakpointByUrlRequest &req) override {} @@ -652,6 +656,18 @@ struct debugger::ResumeRequest : public Request { std::optional terminateOnResume; }; +struct debugger::SetBlackboxPatternsRequest : public Request { + SetBlackboxPatternsRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::vector patterns; + std::optional skipAnonymous; +}; + struct debugger::SetBlackboxedRangesRequest : public Request { SetBlackboxedRangesRequest(); static std::unique_ptr tryMake( @@ -1181,6 +1197,7 @@ struct debugger::ScriptParsedNotification : public Notification { std::optional hasSourceURL; std::optional isModule; std::optional length; + std::optional scriptLanguage; }; struct heapProfiler::AddHeapSnapshotChunkNotification : public Notification { diff --git a/NativeScript/napi/hermes/include/hermes/hermes.h b/NativeScript/napi/hermes/include/hermes/hermes.h index 0d6d70fc..e34009ec 100644 --- a/NativeScript/napi/hermes/include/hermes/hermes.h +++ b/NativeScript/napi/hermes/include/hermes/hermes.h @@ -17,159 +17,164 @@ #include #include +#include #include #include -#include "js_native_api.h" - struct HermesTestHelper; +struct SHUnit; +struct SHRuntime; namespace hermes { - namespace vm { - class GCExecTrace; - class Runtime; - } // namespace vm +namespace vm { +class GCExecTrace; +class Runtime; +} // namespace vm } // namespace hermes namespace facebook { - namespace jsi { +namespace jsi { - class ThreadSafeRuntime; +class ThreadSafeRuntime; - } +} - namespace hermes { +namespace hermes { - namespace debugger { - class Debugger; - } +namespace debugger { +class Debugger; +} - class HermesRuntimeImpl; +class HermesRuntimeImpl; /// Represents a Hermes JS runtime. - class HERMES_EXPORT HermesRuntime : public jsi::Runtime { - public: - - napi_status createNapiEnv(napi_env *env); - - static bool isHermesBytecode(const uint8_t *data, size_t len); - // Returns the supported bytecode version. - static uint32_t getBytecodeVersion(); - // (EXPERIMENTAL) Issues madvise calls for portions of the given - // bytecode file that will likely be used when loading the bytecode - // file and running its global function. - static void prefetchHermesBytecode(const uint8_t *data, size_t len); - // Returns whether the data is valid HBC with more extensive checks than - // isHermesBytecode and returns why it isn't in errorMessage (if nonnull) - // if not. - static bool hermesBytecodeSanityCheck( - const uint8_t *data, - size_t len, - std::string *errorMessage = nullptr); - static void setFatalHandler(void (*handler)(const std::string &)); - - // Assuming that \p data is valid HBC bytecode data, returns a pointer to the - // first element of the epilogue, data append to the end of the bytecode - // stream. Return pair contain ptr to data and header. - static std::pair getBytecodeEpilogue( - const uint8_t *data, - size_t len); - - /// Enable sampling profiler. - /// Starts a separate thread that polls VM state with \p meanHzFreq frequency. - /// Any subsequent call to \c enableSamplingProfiler() is ignored until - /// next call to \c disableSamplingProfiler() - static void enableSamplingProfiler(double meanHzFreq = 100); - - /// Disable the sampling profiler - static void disableSamplingProfiler(); - - /// Dump sampled stack trace to the given file name. - static void dumpSampledTraceToFile(const std::string &fileName); - - /// Dump sampled stack trace to the given stream. - static void dumpSampledTraceToStream(std::ostream &stream); - - /// Serialize the sampled stack to the format expected by DevTools' - /// Profiler.stop return type. - void sampledTraceToStreamInDevToolsFormat(std::ostream &stream); - - /// Return the executed JavaScript function info. - /// This information holds the segmentID, Virtualoffset and sourceURL. - /// This information is needed specifically to be able to symbolicate non-CJS - /// bundles correctly. This API will be simplified later to simply return a - /// segmentID and virtualOffset, when we are able to only support CJS bundles. - static std::unordered_map> - getExecutedFunctions(); - - /// \return whether code coverage profiler is enabled or not. - static bool isCodeCoverageProfilerEnabled(); - - /// Enable code coverage profiler. - static void enableCodeCoverageProfiler(); - - /// Disable code coverage profiler. - static void disableCodeCoverageProfiler(); - - // The base class declares most of the interesting methods. This - // just declares new methods which are specific to HermesRuntime. - // The actual implementations of the pure virtual methods are - // provided by a class internal to the .cpp file, which is created - // by the factory. - - /// Load a new segment into the Runtime. - /// The \param context must be a valid RequireContext retrieved from JS - /// using `require.context`. - void loadSegment( - std::unique_ptr buffer, - const jsi::Value &context); - - /// Gets a guaranteed unique id for an Object (or, respectively, String - /// or PropNameId), which is assigned at allocation time and is - /// static throughout that object's (or string's, or PropNameID's) - /// lifetime. - uint64_t getUniqueID(const jsi::Object &o) const; - uint64_t getUniqueID(const jsi::BigInt &s) const; - uint64_t getUniqueID(const jsi::String &s) const; - uint64_t getUniqueID(const jsi::PropNameID &pni) const; - uint64_t getUniqueID(const jsi::Symbol &sym) const; - - /// Same as the other \c getUniqueID, except it can return 0 for some values. - /// 0 means there is no ID associated with the value. - uint64_t getUniqueID(const jsi::Value &val) const; - - /// From an ID retrieved from \p getUniqueID, go back to the object. - /// NOTE: This is much slower in general than the reverse operation, and takes - /// up more memory. Don't use this unless it's absolutely necessary. - /// \return a jsi::Object if a matching object is found, else returns null. - jsi::Value getObjectForID(uint64_t id); - - /// Get a structure representing the execution history (currently just of - /// GC, but will be generalized as necessary), to aid in debugging - /// non-deterministic execution. - const ::hermes::vm::GCExecTrace &getGCExecTrace() const; - - /// Get IO tracking (aka HBC page access) info as a JSON string. - /// See hermes::vm::Runtime::getIOTrackingInfoJSON() for conditions - /// needed for there to be useful output. - std::string getIOTrackingInfoJSON(); +class HERMES_EXPORT HermesRuntime : public jsi::Runtime { + public: + static bool isHermesBytecode(const uint8_t *data, size_t len); + // Returns the supported bytecode version. + static uint32_t getBytecodeVersion(); + // (EXPERIMENTAL) Issues madvise calls for portions of the given + // bytecode file that will likely be used when loading the bytecode + // file and running its global function. + static void prefetchHermesBytecode(const uint8_t *data, size_t len); + // Returns whether the data is valid HBC with more extensive checks than + // isHermesBytecode and returns why it isn't in errorMessage (if nonnull) + // if not. + static bool hermesBytecodeSanityCheck( + const uint8_t *data, + size_t len, + std::string *errorMessage = nullptr); + static void setFatalHandler(void (*handler)(const std::string &)); + + // Assuming that \p data is valid HBC bytecode data, returns a pointer to the + // first element of the epilogue, data append to the end of the bytecode + // stream. Return pair contain ptr to data and header. + static std::pair getBytecodeEpilogue( + const uint8_t *data, + size_t len); + + /// Enable sampling profiler. + /// Starts a separate thread that polls VM state with \p meanHzFreq frequency. + /// Any subsequent call to \c enableSamplingProfiler() is ignored until + /// next call to \c disableSamplingProfiler() + static void enableSamplingProfiler(double meanHzFreq = 100); + + /// Disable the sampling profiler + static void disableSamplingProfiler(); + + /// Dump sampled stack trace to the given file name. + static void dumpSampledTraceToFile(const std::string &fileName); + + /// Dump sampled stack trace to the given stream. + static void dumpSampledTraceToStream(std::ostream &stream); + + /// Return the executed JavaScript function info. + /// This information holds the segmentID, Virtualoffset and sourceURL. + /// This information is needed specifically to be able to symbolicate non-CJS + /// bundles correctly. This API will be simplified later to simply return a + /// segmentID and virtualOffset, when we are able to only support CJS bundles. + static std::unordered_map> + getExecutedFunctions(); + + /// \return whether code coverage profiler is enabled or not. + static bool isCodeCoverageProfilerEnabled(); + + /// Enable code coverage profiler. + static void enableCodeCoverageProfiler(); + + /// Disable code coverage profiler. + static void disableCodeCoverageProfiler(); + + /// Define a destructor to serve as the key function. + ~HermesRuntime() override; + + /// Serialize the sampled stack to the format expected by DevTools' + /// Profiler.stop return type. + virtual void sampledTraceToStreamInDevToolsFormat(std::ostream &stream) = 0; + + /// Dump sampled stack trace for a given runtime to a data structure that can + /// be used by third parties. + virtual sampling_profiler::Profile dumpSampledTraceToProfile() = 0; + + // The base class declares most of the interesting methods. This + // just declares new methods which are specific to HermesRuntime. + // The actual implementations of the pure virtual methods are + // provided by a class internal to the .cpp file, which is created + // by the factory. + + /// Load a new segment into the Runtime. + /// The \param context must be a valid RequireContext retrieved from JS + /// using `require.context`. + virtual void loadSegment( + std::unique_ptr buffer, + const jsi::Value &context) = 0; + + /// Gets a guaranteed unique id for an Object (or, respectively, String + /// or PropNameId), which is assigned at allocation time and is + /// static throughout that object's (or string's, or PropNameID's) + /// lifetime. + virtual uint64_t getUniqueID(const jsi::Object &o) const = 0; + virtual uint64_t getUniqueID(const jsi::BigInt &s) const = 0; + virtual uint64_t getUniqueID(const jsi::String &s) const = 0; + virtual uint64_t getUniqueID(const jsi::PropNameID &pni) const = 0; + virtual uint64_t getUniqueID(const jsi::Symbol &sym) const = 0; + + /// Same as the other \c getUniqueID, except it can return 0 for some values. + /// 0 means there is no ID associated with the value. + virtual uint64_t getUniqueID(const jsi::Value &val) const = 0; + + /// From an ID retrieved from \p getUniqueID, go back to the object. + /// NOTE: This is much slower in general than the reverse operation, and takes + /// up more memory. Don't use this unless it's absolutely necessary. + /// \return a jsi::Object if a matching object is found, else returns null. + virtual jsi::Value getObjectForID(uint64_t id) = 0; + + /// Get a structure representing the execution history (currently just of + /// GC, but will be generalized as necessary), to aid in debugging + /// non-deterministic execution. + virtual const ::hermes::vm::GCExecTrace &getGCExecTrace() const = 0; + + /// Get IO tracking (aka HBC page access) info as a JSON string. + /// See hermes::vm::Runtime::getIOTrackingInfoJSON() for conditions + /// needed for there to be useful output. + virtual std::string getIOTrackingInfoJSON() = 0; #ifdef HERMESVM_PROFILER_BB - /// Write the trace to the given stream. - void dumpBasicBlockProfileTrace(std::ostream &os) const; + /// Write the trace to the given stream. + virtual void dumpBasicBlockProfileTrace(std::ostream &os) const = 0; #endif #ifdef HERMESVM_PROFILER_OPCODE - /// Write the opcode stats to the given stream. - void dumpOpcodeStats(std::ostream &os) const; + /// Write the opcode stats to the given stream. + virtual void dumpOpcodeStats(std::ostream &os) const = 0; #endif - /// \return a reference to the Debugger for this Runtime. - debugger::Debugger &getDebugger(); + /// \return a reference to the Debugger for this Runtime. + virtual debugger::Debugger &getDebugger() = 0; #ifdef HERMES_ENABLE_DEBUGGER - struct DebugFlags { + struct DebugFlags { // Looking for the .lazy flag? It's no longer necessary. // Source is evaluated lazily by default. See // RuntimeConfig::CompilationMode. @@ -177,67 +182,71 @@ namespace facebook { /// Evaluate the given code in an unoptimized form, /// used for debugging. - void debugJavaScript( + virtual void debugJavaScript( const std::string &src, const std::string &sourceURL, - const DebugFlags &debugFlags); + const DebugFlags &debugFlags) = 0; #endif - /// Register this runtime and thread for sampling profiler. Before using the - /// runtime on another thread, invoke this function again from the new thread - /// to make the sampling profiler target the new thread (and forget the old - /// thread). - void registerForProfiling(); - /// Unregister this runtime for sampling profiler. - void unregisterForProfiling(); - - /// Define methods to interrupt JS execution and set time limits. - /// All JS compiled to bytecode via prepareJS, or evaluateJS, will support - /// interruption and time limit monitoring if the runtime is configured with - /// AsyncBreakCheckInEval. If JS prepared in other ways is executed, care must - /// be taken to ensure that it is compiled in a mode that supports it (i.e., - /// the emitted code contains async break checks). - - /// Asynchronously terminates the current execution. This can be called on - /// any thread. - void asyncTriggerTimeout(); - - /// Register this runtime for execution time limit monitoring, with a time - /// limit of \p timeoutInMs milliseconds. - /// See compilation notes above. - void watchTimeLimit(uint32_t timeoutInMs); - /// Unregister this runtime for execution time limit monitoring. - void unwatchTimeLimit(); - - /// Same as \c evaluate JavaScript but with a source map, which will be - /// applied to exception traces and debug information. - /// - /// This is an experimental Hermes-specific API. In the future it may be - /// renamed, moved or combined with another API, but the provided - /// functionality will continue to be available in some form. - jsi::Value evaluateJavaScriptWithSourceMap( - const std::shared_ptr &buffer, - const std::shared_ptr &sourceMapBuf, - const std::string &sourceURL); - - /// Returns the underlying low level Hermes VM runtime instance. - /// This function is considered unsafe and unstable. - /// Direct use of a vm::Runtime should be avoided as the lower level APIs are - /// unsafe and they can change without notice. - ::hermes::vm::Runtime *getVMRuntimeUnsafe() const; - - private: - // Only HermesRuntimeImpl can subclass this. - HermesRuntime() = default; - friend class HermesRuntimeImpl; - - friend struct ::HermesTestHelper; - size_t rootsListLengthForTests() const; - - // Do not add any members here. This ensures that there are no - // object size inconsistencies. All data should be in the impl - // class in the .cpp file. - }; + /// Register this runtime and thread for sampling profiler. Before using the + /// runtime on another thread, invoke this function again from the new thread + /// to make the sampling profiler target the new thread (and forget the old + /// thread). + virtual void registerForProfiling() = 0; + /// Unregister this runtime for sampling profiler. + virtual void unregisterForProfiling() = 0; + + /// Define methods to interrupt JS execution and set time limits. + /// All JS compiled to bytecode via prepareJS, or evaluateJS, will support + /// interruption and time limit monitoring if the runtime is configured with + /// AsyncBreakCheckInEval. If JS prepared in other ways is executed, care must + /// be taken to ensure that it is compiled in a mode that supports it (i.e., + /// the emitted code contains async break checks). + + /// Asynchronously terminates the current execution. This can be called on + /// any thread. + virtual void asyncTriggerTimeout() = 0; + + /// Register this runtime for execution time limit monitoring, with a time + /// limit of \p timeoutInMs milliseconds. + /// See compilation notes above. + virtual void watchTimeLimit(uint32_t timeoutInMs) = 0; + /// Unregister this runtime for execution time limit monitoring. + virtual void unwatchTimeLimit() = 0; + + /// Same as \c evaluate JavaScript but with a source map, which will be + /// applied to exception traces and debug information. + /// + /// This is an experimental Hermes-specific API. In the future it may be + /// renamed, moved or combined with another API, but the provided + /// functionality will continue to be available in some form. + virtual jsi::Value evaluateJavaScriptWithSourceMap( + const std::shared_ptr &buffer, + const std::shared_ptr &sourceMapBuf, + const std::string &sourceURL) = 0; + + /// Provided for compatibility with Static Hermes, but should not be called. + virtual jsi::Value evaluateSHUnit(SHUnit *(*shUnitCreator)()) = 0; + virtual SHRuntime *getSHRuntime() noexcept = 0; + + /// Returns the underlying low level Hermes VM runtime instance. + /// This function is considered unsafe and unstable. + /// Direct use of a vm::Runtime should be avoided as the lower level APIs are + /// unsafe and they can change without notice. + virtual ::hermes::vm::Runtime *getVMRuntimeUnsafe() const = 0; + + private: + // Only HermesRuntimeImpl can subclass this. + HermesRuntime() = default; + friend class HermesRuntimeImpl; + + friend struct ::HermesTestHelper; + virtual size_t rootsListLengthForTests() const = 0; + + // Do not add any members here. This ensures that there are no + // object size inconsistencies. All data should be in the impl + // class in the .cpp file. +}; /// Return a RuntimeConfig that is more suited for running untrusted JS than /// the default config. Disables some language features and may trade off some @@ -248,16 +257,16 @@ namespace facebook { /// conf.withArrayBuffer(true); /// ... /// auto runtime = makeHermesRuntime(conf.build()); - HERMES_EXPORT ::hermes::vm::RuntimeConfig hardenedHermesRuntimeConfig(); - - HERMES_EXPORT std::unique_ptr makeHermesRuntime( - const ::hermes::vm::RuntimeConfig &runtimeConfig = - ::hermes::vm::RuntimeConfig()); - HERMES_EXPORT std::unique_ptr - makeThreadSafeHermesRuntime( - const ::hermes::vm::RuntimeConfig &runtimeConfig = - ::hermes::vm::RuntimeConfig()); - } // namespace hermes +HERMES_EXPORT ::hermes::vm::RuntimeConfig hardenedHermesRuntimeConfig(); + +HERMES_EXPORT std::unique_ptr makeHermesRuntime( + const ::hermes::vm::RuntimeConfig &runtimeConfig = + ::hermes::vm::RuntimeConfig()); +HERMES_EXPORT std::unique_ptr +makeThreadSafeHermesRuntime( + const ::hermes::vm::RuntimeConfig &runtimeConfig = + ::hermes::vm::RuntimeConfig()); +} // namespace hermes } // namespace facebook -#endif \ No newline at end of file +#endif diff --git a/NativeScript/napi/hermes/include/jsi/JSIDynamic.h b/NativeScript/napi/hermes/include/jsi/JSIDynamic.h index a96cc281..d022b639 100644 --- a/NativeScript/napi/hermes/include/jsi/JSIDynamic.h +++ b/NativeScript/napi/hermes/include/jsi/JSIDynamic.h @@ -20,7 +20,7 @@ facebook::jsi::Value valueFromDynamic( folly::dynamic dynamicFromValue( facebook::jsi::Runtime& runtime, const facebook::jsi::Value& value, - std::function filterObjectKeys = nullptr); + const std::function& filterObjectKeys = nullptr); } // namespace jsi } // namespace facebook diff --git a/NativeScript/napi/hermes/include/jsi/decorator.h b/NativeScript/napi/hermes/include/jsi/decorator.h index c0d3cc6d..1940c3de 100644 --- a/NativeScript/napi/hermes/include/jsi/decorator.h +++ b/NativeScript/napi/hermes/include/jsi/decorator.h @@ -182,6 +182,10 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { PropNameID createPropNameIDFromString(const String& str) override { return plain_.createPropNameIDFromString(str); }; + PropNameID createPropNameIDFromUtf16(const char16_t* utf16, size_t length) + override { + return plain_.createPropNameIDFromUtf16(utf16, length); + } PropNameID createPropNameIDFromSymbol(const Symbol& sym) override { return plain_.createPropNameIDFromSymbol(sym); }; @@ -221,6 +225,9 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { String createStringFromUtf8(const uint8_t* utf8, size_t length) override { return plain_.createStringFromUtf8(utf8, length); }; + String createStringFromUtf16(const char16_t* utf16, size_t length) override { + return plain_.createStringFromUtf16(utf16, length); + } std::string utf8(const String& s) override { return plain_.utf8(s); } @@ -232,6 +239,26 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { return plain_.utf16(sym); } + void getStringData( + const jsi::String& str, + void* ctx, + void ( + *cb)(void* ctx, bool ascii, const void* data, size_t num)) override { + plain_.getStringData(str, ctx, cb); + } + + void getPropNameIdData( + const jsi::PropNameID& sym, + void* ctx, + void ( + *cb)(void* ctx, bool ascii, const void* data, size_t num)) override { + plain_.getPropNameIdData(sym, ctx, cb); + } + + Object createObjectWithPrototype(const Value& prototype) override { + return plain_.createObjectWithPrototype(prototype); + } + Object createObject() override { return plain_.createObject(); }; @@ -244,13 +271,12 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { std::shared_ptr dho = plain_.getHostObject(o); return static_cast(*dho).plainHO_; }; - -// HostFunctionType& getHostFunction(const jsi::Function& f) override { -// HostFunctionType& dhf = plain_.getHostFunction(f); -// // This will fail if a cpp file including this header is not compiled -// // with RTTI. -// return dhf.target()->plainHF_; -// }; + HostFunctionType& getHostFunction(const jsi::Function& f) override { + HostFunctionType& dhf = plain_.getHostFunction(f); + // This will fail if a cpp file including this header is not compiled + // with RTTI. + return dhf.target()->plainHF_; + }; bool hasNativeState(const Object& o) override { return plain_.hasNativeState(o); @@ -267,6 +293,14 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { plain_.setExternalMemoryPressure(obj, amt); } + void setPrototypeOf(const Object& object, const Value& prototype) override { + plain_.setPrototypeOf(object, prototype); + } + + Value getPrototypeOf(const Object& object) override { + return plain_.getPrototypeOf(object); + } + Value getProperty(const Object& o, const PropNameID& name) override { return plain_.getProperty(o, name); }; @@ -622,6 +656,11 @@ class WithRuntimeDecorator : public RuntimeDecorator { Around around{with_}; return RD::createPropNameIDFromUtf8(utf8, length); }; + PropNameID createPropNameIDFromUtf16(const char16_t* utf16, size_t length) + override { + Around around{with_}; + return RD::createPropNameIDFromUtf16(utf16, length); + } PropNameID createPropNameIDFromString(const String& str) override { Around around{with_}; return RD::createPropNameIDFromString(str); @@ -677,6 +716,10 @@ class WithRuntimeDecorator : public RuntimeDecorator { Around around{with_}; return RD::createStringFromUtf8(utf8, length); }; + String createStringFromUtf16(const char16_t* utf16, size_t length) override { + Around around{with_}; + return RD::createStringFromUtf16(utf16, length); + } std::string utf8(const String& s) override { Around around{with_}; return RD::utf8(s); @@ -691,11 +734,34 @@ class WithRuntimeDecorator : public RuntimeDecorator { return RD::utf16(sym); } + void getStringData( + const jsi::String& str, + void* ctx, + void ( + *cb)(void* ctx, bool ascii, const void* data, size_t num)) override { + Around around{with_}; + RD::getStringData(str, ctx, cb); + } + + void getPropNameIdData( + const jsi::PropNameID& sym, + void* ctx, + void ( + *cb)(void* ctx, bool ascii, const void* data, size_t num)) override { + Around around{with_}; + RD::getPropNameIdData(sym, ctx, cb); + } + Value createValueFromJsonUtf8(const uint8_t* json, size_t length) override { Around around{with_}; return RD::createValueFromJsonUtf8(json, length); }; + Object createObjectWithPrototype(const Value& prototype) override { + Around around{with_}; + return RD::createObjectWithPrototype(prototype); + } + Object createObject() override { Around around{with_}; return RD::createObject(); @@ -727,6 +793,16 @@ class WithRuntimeDecorator : public RuntimeDecorator { RD::setNativeState(o, state); }; + void setPrototypeOf(const Object& object, const Value& prototype) override { + Around around{with_}; + RD::setPrototypeOf(object, prototype); + } + + Value getPrototypeOf(const Object& object) override { + Around around{with_}; + return RD::getPrototypeOf(object); + } + Value getProperty(const Object& o, const PropNameID& name) override { Around around{with_}; return RD::getProperty(o, name); diff --git a/NativeScript/napi/hermes/include/jsi/jsi-inl.h b/NativeScript/napi/hermes/include/jsi/jsi-inl.h index 111a4702..6076c495 100644 --- a/NativeScript/napi/hermes/include/jsi/jsi-inl.h +++ b/NativeScript/napi/hermes/include/jsi/jsi-inl.h @@ -84,6 +84,10 @@ inline const Runtime::PointerValue* Runtime::getPointerValue( return value.data_.pointer.ptr_; } +Value Object::getPrototype(Runtime& runtime) const { + return runtime.getPrototypeOf(*this); +} + inline Value Object::getProperty(Runtime& runtime, const char* name) const { return getProperty(runtime, String::createFromAscii(runtime, name)); } diff --git a/NativeScript/napi/hermes/include/jsi/jsi.h b/NativeScript/napi/hermes/include/jsi/jsi.h index be48bb82..4fbbaae3 100644 --- a/NativeScript/napi/hermes/include/jsi/jsi.h +++ b/NativeScript/napi/hermes/include/jsi/jsi.h @@ -267,6 +267,12 @@ class JSI_EXPORT Runtime { /// which returns no metrics. virtual Instrumentation& instrumentation(); + /// Creates a Node-API environment. + /// \throw a \c JSINativeException if the runtime does not support Node-API. + /// \param apiVersion the version of Node-API to use. + /// \return the newly created Node-API environment. + virtual void* createNodeApiEnv(int32_t apiVersion); + protected: friend class Pointer; friend class PropNameID; @@ -306,6 +312,9 @@ class JSI_EXPORT Runtime { virtual PropNameID createPropNameIDFromUtf8( const uint8_t* utf8, size_t length) = 0; + virtual PropNameID createPropNameIDFromUtf16( + const char16_t* utf16, + size_t length); virtual PropNameID createPropNameIDFromString(const String& str) = 0; virtual PropNameID createPropNameIDFromSymbol(const Symbol& sym) = 0; virtual std::string utf8(const PropNameID&) = 0; @@ -322,6 +331,7 @@ class JSI_EXPORT Runtime { virtual String createStringFromAscii(const char* str, size_t length) = 0; virtual String createStringFromUtf8(const uint8_t* utf8, size_t length) = 0; + virtual String createStringFromUtf16(const char16_t* utf16, size_t length); virtual std::string utf8(const String&) = 0; // \return a \c Value created from a utf8-encoded JSON string. The default @@ -333,12 +343,18 @@ class JSI_EXPORT Runtime { virtual std::shared_ptr getHostObject(const jsi::Object&) = 0; virtual HostFunctionType& getHostFunction(const jsi::Function&) = 0; + // Creates a new Object with the custom prototype + virtual Object createObjectWithPrototype(const Value& prototype); + virtual bool hasNativeState(const jsi::Object&) = 0; virtual std::shared_ptr getNativeState(const jsi::Object&) = 0; virtual void setNativeState( const jsi::Object&, std::shared_ptr state) = 0; + virtual void setPrototypeOf(const Object& object, const Value& prototype); + virtual Value getPrototypeOf(const Object& object); + virtual Value getProperty(const Object&, const PropNameID& name) = 0; virtual Value getProperty(const Object&, const String& name) = 0; virtual bool hasProperty(const Object&, const PropNameID& name) = 0; @@ -402,6 +418,34 @@ class JSI_EXPORT Runtime { virtual std::u16string utf16(const String& str); virtual std::u16string utf16(const PropNameID& sym); + /// Invokes the provided callback \p cb with the String content in \p str. + /// The callback must take in three arguments: bool ascii, const void* data, + /// and size_t num, respectively. \p ascii indicates whether the \p data + /// passed to the callback should be interpreted as a pointer to a sequence of + /// \p num ASCII characters or UTF16 characters. Depending on the internal + /// representation of the string, the function may invoke the callback + /// multiple times, with a different format on each invocation. The callback + /// must not access runtime functionality, as any operation on the runtime may + /// invalidate the data pointers. + virtual void getStringData( + const jsi::String& str, + void* ctx, + void (*cb)(void* ctx, bool ascii, const void* data, size_t num)); + + /// Invokes the provided callback \p cb with the PropNameID content in \p sym. + /// The callback must take in three arguments: bool ascii, const void* data, + /// and size_t num, respectively. \p ascii indicates whether the \p data + /// passed to the callback should be interpreted as a pointer to a sequence of + /// \p num ASCII characters or UTF16 characters. Depending on the internal + /// representation of the string, the function may invoke the callback + /// multiple times, with a different format on each invocation. The callback + /// must not access runtime functionality, as any operation on the runtime may + /// invalidate the data pointers. + virtual void getPropNameIdData( + const jsi::PropNameID& sym, + void* ctx, + void (*cb)(void* ctx, bool ascii, const void* data, size_t num)); + // These exist so derived classes can access the private parts of // Value, Symbol, String, and Object, which are all friends of Runtime. template @@ -481,6 +525,21 @@ class JSI_EXPORT PropNameID : public Pointer { reinterpret_cast(utf8.data()), utf8.size()); } + /// Given a series of UTF-16 encoded code units, create a PropNameId. The + /// input may contain unpaired surrogates, which will be interpreted as a code + /// point of the same value. + static PropNameID + forUtf16(Runtime& runtime, const char16_t* utf16, size_t length) { + return runtime.createPropNameIDFromUtf16(utf16, length); + } + + /// Given a series of UTF-16 encoded code units stored inside std::u16string, + /// create a PropNameId. The input may contain unpaired surrogates, which + /// will be interpreted as a code point of the same value. + static PropNameID forUtf16(Runtime& runtime, const std::u16string& str) { + return runtime.createPropNameIDFromUtf16(str.data(), str.size()); + } + /// Create a PropNameID from a JS string. static PropNameID forString(Runtime& runtime, const jsi::String& str) { return runtime.createPropNameIDFromString(str); @@ -509,6 +568,22 @@ class JSI_EXPORT PropNameID : public Pointer { return runtime.utf16(*this); } + /// Invokes the user provided callback to process the content in PropNameId. + /// The callback must take in three arguments: bool ascii, const void* data, + /// and size_t num, respectively. \p ascii indicates whether the \p data + /// passed to the callback should be interpreted as a pointer to a sequence of + /// \p num ASCII characters or UTF16 characters. The function may invoke the + /// callback multiple times, with a different format on each invocation. The + /// callback must not access runtime functionality, as any operation on the + /// runtime may invalidate the data pointers. + template + void getPropNameIdData(Runtime& runtime, CB& cb) const { + runtime.getPropNameIdData( + *this, &cb, [](void* ctx, bool ascii, const void* data, size_t num) { + (*((CB*)ctx))(ascii, data, num); + }); + } + static bool compare( Runtime& runtime, const jsi::PropNameID& a, @@ -649,6 +724,21 @@ class JSI_EXPORT String : public Pointer { reinterpret_cast(utf8.data()), utf8.length()); } + /// Given a series of UTF-16 encoded code units, create a JS String. The input + /// may contain unpaired surrogates, which will be interpreted as a code point + /// of the same value. + static String + createFromUtf16(Runtime& runtime, const char16_t* utf16, size_t length) { + return runtime.createStringFromUtf16(utf16, length); + } + + /// Given a series of UTF-16 encoded code units stored inside std::u16string, + /// create a JS String. The input may contain unpaired surrogates, which will + /// be interpreted as a code point of the same value. + static String createFromUtf16(Runtime& runtime, const std::u16string& utf16) { + return runtime.createStringFromUtf16(utf16.data(), utf16.length()); + } + /// \return whether a and b contain the same characters. static bool strictEquals(Runtime& runtime, const String& a, const String& b) { return runtime.strictEquals(a, b); @@ -664,6 +754,22 @@ class JSI_EXPORT String : public Pointer { return runtime.utf16(*this); } + /// Invokes the user provided callback to process content in String. The + /// callback must take in three arguments: bool ascii, const void* data, and + /// size_t num, respectively. \p ascii indicates whether the \p data passed to + /// the callback should be interpreted as a pointer to a sequence of \p num + /// ASCII characters or UTF16 characters. The function may invoke the callback + /// multiple times, with a different format on each invocation. The callback + /// must not access runtime functionality, as any operation on the runtime may + /// invalidate the data pointers. + template + void getStringData(Runtime& runtime, CB& cb) const { + runtime.getStringData( + *this, &cb, [](void* ctx, bool ascii, const void* data, size_t num) { + (*((CB*)ctx))(ascii, data, num); + }); + } + friend class Runtime; friend class Value; }; @@ -688,6 +794,11 @@ class JSI_EXPORT Object : public Pointer { return runtime.createObject(ho); } + /// Creates a new Object with the custom prototype + static Object create(Runtime& runtime, const Value& prototype) { + return runtime.createObjectWithPrototype(prototype); + } + /// \return whether this and \c obj are the same JSObject or not. static bool strictEquals(Runtime& runtime, const Object& a, const Object& b) { return runtime.strictEquals(a, b); @@ -698,6 +809,16 @@ class JSI_EXPORT Object : public Pointer { return rt.instanceOf(*this, ctor); } + /// Sets \p prototype as the prototype of the object. The prototype must be + /// either an Object or null. If the prototype was not set successfully, this + /// method will throw. + void setPrototype(Runtime& runtime, const Value& prototype) const { + return runtime.setPrototypeOf(*this, prototype); + } + + /// \return the prototype of the object + inline Value getPrototype(Runtime& runtime) const; + /// \return the property of the object with the given ascii name. /// If the name isn't a property on the object, returns the /// undefined value. diff --git a/NativeScript/napi/hermes/include/old/js_native_api.h b/NativeScript/napi/hermes/include/old/js_native_api.h new file mode 100644 index 00000000..9e7073cf --- /dev/null +++ b/NativeScript/napi/hermes/include/old/js_native_api.h @@ -0,0 +1,600 @@ +#ifndef SRC_JS_NATIVE_API_H_ +#define SRC_JS_NATIVE_API_H_ + +// This file needs to be compatible with C compilers. +#include // NOLINT(modernize-deprecated-headers) +#include // NOLINT(modernize-deprecated-headers) + +// Use INT_MAX, this should only be consumed by the pre-processor anyway. +#define NAPI_VERSION_EXPERIMENTAL 2147483647 +#ifndef NAPI_VERSION +// The baseline version for N-API. +// The NAPI_VERSION controls which version will be used by default when +// compilling a native addon. If the addon developer specifically wants to use +// functions available in a new version of N-API that is not yet ported in all +// LTS versions, they can set NAPI_VERSION knowing that they have specifically +// depended on that version. +#define NAPI_VERSION 8 +#endif + +#include "js_native_api_types.h" + +// If you need __declspec(dllimport), either include instead, or +// define NAPI_EXTERN as __declspec(dllimport) on the compiler's command line. +#ifndef NAPI_EXTERN +#ifdef _WIN32 +#define NAPI_EXTERN __declspec(dllexport) +#elif defined(__wasm__) +#define NAPI_EXTERN \ + __attribute__((visibility("default"))) \ + __attribute__((__import_module__("napi"))) +#else +#define NAPI_EXTERN __attribute__((visibility("default"))) +#endif +#endif + +#define NAPI_AUTO_LENGTH SIZE_MAX + +#ifdef __cplusplus +#define EXTERN_C_START extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_START +#define EXTERN_C_END +#endif + +EXTERN_C_START + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_last_error_info( + node_api_basic_env env, const napi_extended_error_info** result); + +// Getters for defined singletons +NAPI_EXTERN napi_status NAPI_CDECL napi_get_undefined(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_null(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_global(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_boolean(napi_env env, + bool value, + napi_value* result); + +// Methods to create Primitive types/Objects +NAPI_EXTERN napi_status NAPI_CDECL napi_create_object(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_array(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_array_with_length(napi_env env, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_double(napi_env env, + double value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_int32(napi_env env, + int32_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_uint32(napi_env env, + uint32_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_int64(napi_env env, + int64_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_latin1( + napi_env env, const char* str, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf8(napi_env env, + const char* str, + size_t length, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf16(napi_env env, + const char16_t* str, + size_t length, + napi_value* result); +#if NAPI_VERSION >= 10 +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_external_string_latin1( + napi_env env, + char* str, + size_t length, + node_api_basic_finalize finalize_callback, + void* finalize_hint, + napi_value* result, + bool* copied); +NAPI_EXTERN napi_status NAPI_CDECL +node_api_create_external_string_utf16(napi_env env, + char16_t* str, + size_t length, + node_api_basic_finalize finalize_callback, + void* finalize_hint, + napi_value* result, + bool* copied); + +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_latin1( + napi_env env, const char* str, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf8( + napi_env env, const char* str, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf16( + napi_env env, const char16_t* str, size_t length, napi_value* result); +#endif // NAPI_VERSION >= 10 + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_symbol(napi_env env, + napi_value description, + napi_value* result); +#if NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL +node_api_symbol_for(napi_env env, + const char* utf8description, + size_t length, + napi_value* result); +#endif // NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL napi_create_function(napi_env env, + const char* utf8name, + size_t length, + napi_callback cb, + void* data, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_type_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_range_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +#if NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_syntax_error( + napi_env env, napi_value code, napi_value msg, napi_value* result); +#endif // NAPI_VERSION >= 9 + +// Methods to get the native napi_value from Primitive type +NAPI_EXTERN napi_status NAPI_CDECL napi_typeof(napi_env env, + napi_value value, + napi_valuetype* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_double(napi_env env, + napi_value value, + double* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int32(napi_env env, + napi_value value, + int32_t* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_uint32(napi_env env, + napi_value value, + uint32_t* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int64(napi_env env, + napi_value value, + int64_t* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bool(napi_env env, + napi_value value, + bool* result); + +// Copies LATIN-1 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_latin1( + napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result); + +// Copies UTF-8 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_utf8( + napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result); + +// Copies UTF-16 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_utf16(napi_env env, + napi_value value, + char16_t* buf, + size_t bufsize, + size_t* result); + +// Methods to coerce values +// These APIs may execute user scripts +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_bool(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_number(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_object(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_string(napi_env env, + napi_value value, + napi_value* result); + +// Methods to work with Objects +NAPI_EXTERN napi_status NAPI_CDECL napi_get_prototype(napi_env env, + napi_value object, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_property_names(napi_env env, + napi_value object, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_set_property(napi_env env, + napi_value object, + napi_value key, + napi_value value); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_property(napi_env env, + napi_value object, + napi_value key, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_own_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_set_named_property(napi_env env, + napi_value object, + const char* utf8name, + napi_value value); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_named_property(napi_env env, + napi_value object, + const char* utf8name, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_named_property(napi_env env, + napi_value object, + const char* utf8name, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_set_element(napi_env env, + napi_value object, + uint32_t index, + napi_value value); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_element(napi_env env, + napi_value object, + uint32_t index, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_element(napi_env env, + napi_value object, + uint32_t index, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_element(napi_env env, + napi_value object, + uint32_t index, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_define_properties(napi_env env, + napi_value object, + size_t property_count, + const napi_property_descriptor* properties); + +// Methods to work with Arrays +NAPI_EXTERN napi_status NAPI_CDECL napi_is_array(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_array_length(napi_env env, + napi_value value, + uint32_t* result); + +// Methods to compare values +NAPI_EXTERN napi_status NAPI_CDECL napi_strict_equals(napi_env env, + napi_value lhs, + napi_value rhs, + bool* result); + +// Methods to work with Functions +NAPI_EXTERN napi_status NAPI_CDECL napi_call_function(napi_env env, + napi_value recv, + napi_value func, + size_t argc, + const napi_value* argv, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_new_instance(napi_env env, + napi_value constructor, + size_t argc, + const napi_value* argv, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_instanceof(napi_env env, + napi_value object, + napi_value constructor, + bool* result); + +// Methods to work with napi_callbacks + +// Gets all callback info in a single call. (Ugly, but faster.) +NAPI_EXTERN napi_status NAPI_CDECL napi_get_cb_info( + napi_env env, // [in] Node-API environment handle + napi_callback_info cbinfo, // [in] Opaque callback-info handle + size_t* argc, // [in-out] Specifies the size of the provided argv array + // and receives the actual count of args. + napi_value* argv, // [out] Array of values + napi_value* this_arg, // [out] Receives the JS 'this' arg for the call + void** data); // [out] Receives the data pointer for the callback. + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_new_target( + napi_env env, napi_callback_info cbinfo, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_define_class(napi_env env, + const char* utf8name, + size_t length, + napi_callback constructor, + void* data, + size_t property_count, + const napi_property_descriptor* properties, + napi_value* result); + +// Methods to work with external data objects +NAPI_EXTERN napi_status NAPI_CDECL +napi_wrap(napi_env env, + napi_value js_object, + void* native_object, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_ref* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_unwrap(napi_env env, + napi_value js_object, + void** result); +NAPI_EXTERN napi_status NAPI_CDECL napi_remove_wrap(napi_env env, + napi_value js_object, + void** result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_external(napi_env env, + void* data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_external(napi_env env, + napi_value value, + void** result); + +// Methods to control object lifespan + +// Set initial_refcount to 0 for a weak reference, >0 for a strong reference. +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_reference(napi_env env, + napi_value value, + uint32_t initial_refcount, + napi_ref* result); + +// Deletes a reference. The referenced value is released, and may +// be GC'd unless there are other references to it. +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_reference(napi_env env, + napi_ref ref); + +// Increments the reference count, optionally returning the resulting count. +// After this call the reference will be a strong reference because its +// refcount is >0, and the referenced object is effectively "pinned". +// Calling this when the refcount is 0 and the object is unavailable +// results in an error. +NAPI_EXTERN napi_status NAPI_CDECL napi_reference_ref(napi_env env, + napi_ref ref, + uint32_t* result); + +// Decrements the reference count, optionally returning the resulting count. +// If the result is 0 the reference is now weak and the object may be GC'd +// at any time if there are no other references. Calling this when the +// refcount is already 0 results in an error. +NAPI_EXTERN napi_status NAPI_CDECL napi_reference_unref(napi_env env, + napi_ref ref, + uint32_t* result); + +// Attempts to get a referenced value. If the reference is weak, +// the value might no longer be available, in that case the call +// is still successful but the result is NULL. +NAPI_EXTERN napi_status NAPI_CDECL napi_get_reference_value(napi_env env, + napi_ref ref, + napi_value* result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_open_handle_scope(napi_env env, napi_handle_scope* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_close_handle_scope(napi_env env, napi_handle_scope scope); +NAPI_EXTERN napi_status NAPI_CDECL napi_open_escapable_handle_scope( + napi_env env, napi_escapable_handle_scope* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_close_escapable_handle_scope( + napi_env env, napi_escapable_handle_scope scope); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_escape_handle(napi_env env, + napi_escapable_handle_scope scope, + napi_value escapee, + napi_value* result); + +// Methods to support error handling +NAPI_EXTERN napi_status NAPI_CDECL napi_throw(napi_env env, napi_value error); +NAPI_EXTERN napi_status NAPI_CDECL napi_throw_error(napi_env env, + const char* code, + const char* msg); +NAPI_EXTERN napi_status NAPI_CDECL napi_throw_type_error(napi_env env, + const char* code, + const char* msg); +NAPI_EXTERN napi_status NAPI_CDECL napi_throw_range_error(napi_env env, + const char* code, + const char* msg); +#if NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL node_api_throw_syntax_error(napi_env env, + const char* code, + const char* msg); +#endif // NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL napi_is_error(napi_env env, + napi_value value, + bool* result); + +// Methods to support catching exceptions +NAPI_EXTERN napi_status NAPI_CDECL napi_is_exception_pending(napi_env env, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_and_clear_last_exception(napi_env env, napi_value* result); + +// Methods to work with array buffers and typed arrays +NAPI_EXTERN napi_status NAPI_CDECL napi_is_arraybuffer(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_arraybuffer(napi_env env, + size_t byte_length, + void** data, + napi_value* result); +#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_external_arraybuffer(napi_env env, + void* external_data, + size_t byte_length, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED +NAPI_EXTERN napi_status NAPI_CDECL napi_get_arraybuffer_info( + napi_env env, napi_value arraybuffer, void** data, size_t* byte_length); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_typedarray(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_typedarray(napi_env env, + napi_typedarray_type type, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_typedarray_info(napi_env env, + napi_value typedarray, + napi_typedarray_type* type, + size_t* length, + void** data, + napi_value* arraybuffer, + size_t* byte_offset); + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_dataview(napi_env env, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_dataview(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_dataview_info(napi_env env, + napi_value dataview, + size_t* bytelength, + void** data, + napi_value* arraybuffer, + size_t* byte_offset); + +// version management +NAPI_EXTERN napi_status NAPI_CDECL napi_get_version(node_api_basic_env env, + uint32_t* result); + +// Promises +NAPI_EXTERN napi_status NAPI_CDECL napi_create_promise(napi_env env, + napi_deferred* deferred, + napi_value* promise); +NAPI_EXTERN napi_status NAPI_CDECL napi_resolve_deferred(napi_env env, + napi_deferred deferred, + napi_value resolution); +NAPI_EXTERN napi_status NAPI_CDECL napi_reject_deferred(napi_env env, + napi_deferred deferred, + napi_value rejection); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_promise(napi_env env, + napi_value value, + bool* is_promise); + +// Running a script +NAPI_EXTERN napi_status NAPI_CDECL napi_run_script(napi_env env, + napi_value script, + napi_value* result); + +// Memory management +NAPI_EXTERN napi_status NAPI_CDECL napi_adjust_external_memory( + node_api_basic_env env, int64_t change_in_bytes, int64_t* adjusted_value); + +#if NAPI_VERSION >= 5 + +// Dates +NAPI_EXTERN napi_status NAPI_CDECL napi_create_date(napi_env env, + double time, + napi_value* result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_is_date(napi_env env, + napi_value value, + bool* is_date); + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_date_value(napi_env env, + napi_value value, + double* result); + +// Add finalizer for pointer +NAPI_EXTERN napi_status NAPI_CDECL +napi_add_finalizer(napi_env env, + napi_value js_object, + void* finalize_data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_ref* result); + +#endif // NAPI_VERSION >= 5 + +#if NAPI_VERSION >= 6 + +// BigInt +NAPI_EXTERN napi_status NAPI_CDECL napi_create_bigint_int64(napi_env env, + int64_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_bigint_uint64(napi_env env, uint64_t value, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_bigint_words(napi_env env, + int sign_bit, + size_t word_count, + const uint64_t* words, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_int64(napi_env env, + napi_value value, + int64_t* result, + bool* lossless); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_uint64( + napi_env env, napi_value value, uint64_t* result, bool* lossless); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_value_bigint_words(napi_env env, + napi_value value, + int* sign_bit, + size_t* word_count, + uint64_t* words); + +// Object +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_all_property_names(napi_env env, + napi_value object, + napi_key_collection_mode key_mode, + napi_key_filter key_filter, + napi_key_conversion key_conversion, + napi_value* result); + +// Instance data +NAPI_EXTERN napi_status NAPI_CDECL +napi_set_instance_data(node_api_basic_env env, + void* data, + napi_finalize finalize_cb, + void* finalize_hint); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_instance_data(node_api_basic_env env, void** data); +#endif // NAPI_VERSION >= 6 + +#if NAPI_VERSION >= 7 +// ArrayBuffer detaching +NAPI_EXTERN napi_status NAPI_CDECL +napi_detach_arraybuffer(napi_env env, napi_value arraybuffer); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_is_detached_arraybuffer(napi_env env, napi_value value, bool* result); +#endif // NAPI_VERSION >= 7 + +#if NAPI_VERSION >= 8 +// Type tagging +NAPI_EXTERN napi_status NAPI_CDECL napi_type_tag_object( + napi_env env, napi_value value, const napi_type_tag* type_tag); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_check_object_type_tag(napi_env env, + napi_value value, + const napi_type_tag* type_tag, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_object_freeze(napi_env env, + napi_value object); +NAPI_EXTERN napi_status NAPI_CDECL napi_object_seal(napi_env env, + napi_value object); +#endif // NAPI_VERSION >= 8 + +EXTERN_C_END + +#endif // SRC_JS_NATIVE_API_H_ diff --git a/NativeScript/napi/hermes/include/old/js_native_api_types.h b/NativeScript/napi/hermes/include/old/js_native_api_types.h new file mode 100644 index 00000000..7853a8d7 --- /dev/null +++ b/NativeScript/napi/hermes/include/old/js_native_api_types.h @@ -0,0 +1,195 @@ +#ifndef SRC_JS_NATIVE_API_TYPES_H_ +#define SRC_JS_NATIVE_API_TYPES_H_ + +// This file needs to be compatible with C compilers. +// This is a public include file, and these includes have essentially +// became part of it's API. +#include // NOLINT(modernize-deprecated-headers) +#include // NOLINT(modernize-deprecated-headers) + +#if !defined __cplusplus || (defined(_MSC_VER) && _MSC_VER < 1900) +typedef uint16_t char16_t; +#endif + +#ifndef NAPI_CDECL +#ifdef _WIN32 +#define NAPI_CDECL __cdecl +#else +#define NAPI_CDECL +#endif +#endif + +// JSVM API types are all opaque pointers for ABI stability +// typedef undefined structs instead of void* for compile time type safety +typedef struct napi_env__* napi_env; + +// We need to mark APIs which can be called during garbage collection (GC), +// meaning that they do not affect the state of the JS engine, and can +// therefore be called synchronously from a finalizer that itself runs +// synchronously during GC. Such APIs can receive either a `napi_env` or a +// `node_api_basic_env` as their first parameter, because we should be able to +// also call them during normal, non-garbage-collecting operations, whereas +// APIs that affect the state of the JS engine can only receive a `napi_env` as +// their first parameter, because we must not call them during GC. In lieu of +// inheritance, we use the properties of the const qualifier to accomplish +// this, because both a const and a non-const value can be passed to an API +// expecting a const value, but only a non-const value can be passed to an API +// expecting a non-const value. +// +// In conjunction with appropriate CFLAGS to warn us if we're passing a const +// (basic) environment into an API that expects a non-const environment, and +// the definition of basic finalizer function pointer types below, which +// receive a basic environment as their first parameter, and can thus only call +// basic APIs (unless the user explicitly casts the environment), we achieve +// the ability to ensure at compile time that we do not call APIs that affect +// the state of the JS engine from a synchronous (basic) finalizer. +typedef struct napi_env__* node_api_nogc_env; +typedef node_api_nogc_env node_api_basic_env; + +typedef struct napi_value__* napi_value; +typedef struct napi_ref__* napi_ref; +typedef struct napi_handle_scope__* napi_handle_scope; +typedef struct napi_escapable_handle_scope__* napi_escapable_handle_scope; +typedef struct napi_callback_info__* napi_callback_info; +typedef struct napi_deferred__* napi_deferred; + +typedef enum { + napi_default = 0, + napi_writable = 1 << 0, + napi_enumerable = 1 << 1, + napi_configurable = 1 << 2, + + // Used with napi_define_class to distinguish static properties + // from instance properties. Ignored by napi_define_properties. + napi_static = 1 << 10, + +#if NAPI_VERSION >= 8 + // Default for class methods. + napi_default_method = napi_writable | napi_configurable, + + // Default for object properties, like in JS obj[prop]. + napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable, +#endif // NAPI_VERSION >= 8 +} napi_property_attributes; + +typedef enum { + // ES6 types (corresponds to typeof) + napi_undefined, + napi_null, + napi_boolean, + napi_number, + napi_string, + napi_symbol, + napi_object, + napi_function, + napi_external, + napi_bigint, +} napi_valuetype; + +typedef enum { + napi_int8_array, + napi_uint8_array, + napi_uint8_clamped_array, + napi_int16_array, + napi_uint16_array, + napi_int32_array, + napi_uint32_array, + napi_float32_array, + napi_float64_array, + napi_bigint64_array, + napi_biguint64_array, +} napi_typedarray_type; + +typedef enum { + napi_ok, + napi_invalid_arg, + napi_object_expected, + napi_string_expected, + napi_name_expected, + napi_function_expected, + napi_number_expected, + napi_boolean_expected, + napi_array_expected, + napi_generic_failure, + napi_pending_exception, + napi_cancelled, + napi_escape_called_twice, + napi_handle_scope_mismatch, + napi_callback_scope_mismatch, + napi_queue_full, + napi_closing, + napi_bigint_expected, + napi_date_expected, + napi_arraybuffer_expected, + napi_detachable_arraybuffer_expected, + napi_would_deadlock, // unused + napi_no_external_buffers_allowed, + napi_cannot_run_js, +} napi_status; +// Note: when adding a new enum value to `napi_status`, please also update +// * `const int last_status` in the definition of `napi_get_last_error_info()' +// in file js_native_api_v8.cc. +// * `const char* error_messages[]` in file js_native_api_v8.cc with a brief +// message explaining the error. +// * the definition of `napi_status` in doc/api/n-api.md to reflect the newly +// added value(s). + +typedef napi_value(NAPI_CDECL* napi_callback)(napi_env env, + napi_callback_info info); +typedef void(NAPI_CDECL* napi_finalize)(napi_env env, + void* finalize_data, + void* finalize_hint); + +typedef napi_finalize node_api_nogc_finalize; +typedef node_api_nogc_finalize node_api_basic_finalize; + +typedef struct { + // One of utf8name or name should be NULL. + const char* utf8name; + napi_value name; + + napi_callback method; + napi_callback getter; + napi_callback setter; + napi_value value; + + napi_property_attributes attributes; + void* data; +} napi_property_descriptor; + +typedef struct { + const char* error_message; + void* engine_reserved; + uint32_t engine_error_code; + napi_status error_code; +} napi_extended_error_info; + +#if NAPI_VERSION >= 6 +typedef enum { + napi_key_include_prototypes, + napi_key_own_only +} napi_key_collection_mode; + +typedef enum { + napi_key_all_properties = 0, + napi_key_writable = 1, + napi_key_enumerable = 1 << 1, + napi_key_configurable = 1 << 2, + napi_key_skip_strings = 1 << 3, + napi_key_skip_symbols = 1 << 4 +} napi_key_filter; + +typedef enum { + napi_key_keep_numbers, + napi_key_numbers_to_strings +} napi_key_conversion; +#endif // NAPI_VERSION >= 6 + +#if NAPI_VERSION >= 8 +typedef struct { + uint64_t lower; + uint64_t upper; +} napi_type_tag; +#endif // NAPI_VERSION >= 8 + +#endif // SRC_JS_NATIVE_API_TYPES_H_ diff --git a/NativeScript/napi/hermes/include/old/node_api.h b/NativeScript/napi/hermes/include/old/node_api.h new file mode 100644 index 00000000..4ebfbd46 --- /dev/null +++ b/NativeScript/napi/hermes/include/old/node_api.h @@ -0,0 +1,270 @@ +#ifndef SRC_NODE_API_H_ +#define SRC_NODE_API_H_ + +#if defined(BUILDING_NODE_EXTENSION) && !defined(NAPI_EXTERN) +#ifdef _WIN32 +// Building native addon against node +#define NAPI_EXTERN __declspec(dllimport) +#elif defined(__wasm__) +#define NAPI_EXTERN __attribute__((__import_module__("napi"))) +#endif +#endif +#include "js_native_api.h" +#include "node_api_types.h" + +struct uv_loop_s; // Forward declaration. + +#ifdef _WIN32 +#define NAPI_MODULE_EXPORT __declspec(dllexport) +#else +#ifdef __EMSCRIPTEN__ +#define NAPI_MODULE_EXPORT \ + __attribute__((visibility("default"))) __attribute__((used)) +#else +#define NAPI_MODULE_EXPORT __attribute__((visibility("default"))) +#endif +#endif + +#if defined(__GNUC__) +#define NAPI_NO_RETURN __attribute__((noreturn)) +#elif defined(_WIN32) +#define NAPI_NO_RETURN __declspec(noreturn) +#else +#define NAPI_NO_RETURN +#endif + +typedef napi_value(NAPI_CDECL* napi_addon_register_func)(napi_env env, + napi_value exports); +typedef int32_t(NAPI_CDECL* node_api_addon_get_api_version_func)(void); + +// Used by deprecated registration method napi_module_register. +typedef struct napi_module { + int nm_version; + unsigned int nm_flags; + const char* nm_filename; + napi_addon_register_func nm_register_func; + const char* nm_modname; + void* nm_priv; + void* reserved[4]; +} napi_module; + +#define NAPI_MODULE_VERSION 1 + +#define NAPI_MODULE_INITIALIZER_X(base, version) \ + NAPI_MODULE_INITIALIZER_X_HELPER(base, version) +#define NAPI_MODULE_INITIALIZER_X_HELPER(base, version) base##version + +#ifdef __wasm__ +#define NAPI_MODULE_INITIALIZER_BASE napi_register_wasm_v +#else +#define NAPI_MODULE_INITIALIZER_BASE napi_register_module_v +#endif + +#define NODE_API_MODULE_GET_API_VERSION_BASE node_api_module_get_api_version_v + +#define NAPI_MODULE_INITIALIZER \ + NAPI_MODULE_INITIALIZER_X(NAPI_MODULE_INITIALIZER_BASE, NAPI_MODULE_VERSION) + +#define NODE_API_MODULE_GET_API_VERSION \ + NAPI_MODULE_INITIALIZER_X(NODE_API_MODULE_GET_API_VERSION_BASE, \ + NAPI_MODULE_VERSION) + +#define NAPI_MODULE_INIT() \ + EXTERN_C_START \ + NAPI_MODULE_EXPORT int32_t NODE_API_MODULE_GET_API_VERSION(void) { \ + return NAPI_VERSION; \ + } \ + NAPI_MODULE_EXPORT napi_value NAPI_MODULE_INITIALIZER(napi_env env, \ + napi_value exports); \ + EXTERN_C_END \ + napi_value NAPI_MODULE_INITIALIZER(napi_env env, napi_value exports) + +#define NAPI_MODULE(modname, regfunc) \ + NAPI_MODULE_INIT() { \ + return regfunc(env, exports); \ + } + +// Deprecated. Use NAPI_MODULE. +#define NAPI_MODULE_X(modname, regfunc, priv, flags) \ + NAPI_MODULE(modname, regfunc) + +EXTERN_C_START + +// Deprecated. Replaced by symbol-based registration defined by NAPI_MODULE +// and NAPI_MODULE_INIT macros. +NAPI_EXTERN void NAPI_CDECL napi_module_register(napi_module* mod); + +NAPI_EXTERN NAPI_NO_RETURN void NAPI_CDECL +napi_fatal_error(const char* location, + size_t location_len, + const char* message, + size_t message_len); + +// Methods for custom handling of async operations +NAPI_EXTERN napi_status NAPI_CDECL +napi_async_init(napi_env env, + napi_value async_resource, + napi_value async_resource_name, + napi_async_context* result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_async_destroy(napi_env env, napi_async_context async_context); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_make_callback(napi_env env, + napi_async_context async_context, + napi_value recv, + napi_value func, + size_t argc, + const napi_value* argv, + napi_value* result); + +// Methods to provide node::Buffer functionality with napi types +NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer(napi_env env, + size_t length, + void** data, + napi_value* result); +#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_external_buffer(napi_env env, + size_t length, + void* data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED + +#if NAPI_VERSION >= 10 + +NAPI_EXTERN napi_status NAPI_CDECL +node_api_create_buffer_from_arraybuffer(napi_env env, + napi_value arraybuffer, + size_t byte_offset, + size_t byte_length, + napi_value* result); +#endif // NAPI_VERSION >= 10 + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer_copy(napi_env env, + size_t length, + const void* data, + void** result_data, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_buffer(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_buffer_info(napi_env env, + napi_value value, + void** data, + size_t* length); + +// Methods to manage simple async operations +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_async_work(napi_env env, + napi_value async_resource, + napi_value async_resource_name, + napi_async_execute_callback execute, + napi_async_complete_callback complete, + void* data, + napi_async_work* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_async_work(napi_env env, + napi_async_work work); +NAPI_EXTERN napi_status NAPI_CDECL napi_queue_async_work(node_api_basic_env env, + napi_async_work work); +NAPI_EXTERN napi_status NAPI_CDECL +napi_cancel_async_work(node_api_basic_env env, napi_async_work work); + +// version management +NAPI_EXTERN napi_status NAPI_CDECL napi_get_node_version( + node_api_basic_env env, const napi_node_version** version); + +#if NAPI_VERSION >= 2 + +// Return the current libuv event loop for a given environment +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_uv_event_loop(node_api_basic_env env, struct uv_loop_s** loop); + +#endif // NAPI_VERSION >= 2 + +#if NAPI_VERSION >= 3 + +NAPI_EXTERN napi_status NAPI_CDECL napi_fatal_exception(napi_env env, + napi_value err); + +NAPI_EXTERN napi_status NAPI_CDECL napi_add_env_cleanup_hook( + node_api_basic_env env, napi_cleanup_hook fun, void* arg); + +NAPI_EXTERN napi_status NAPI_CDECL napi_remove_env_cleanup_hook( + node_api_basic_env env, napi_cleanup_hook fun, void* arg); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_open_callback_scope(napi_env env, + napi_value resource_object, + napi_async_context context, + napi_callback_scope* result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_close_callback_scope(napi_env env, napi_callback_scope scope); + +#endif // NAPI_VERSION >= 3 + +#if NAPI_VERSION >= 4 + +// Calling into JS from other threads +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_threadsafe_function(napi_env env, + napi_value func, + napi_value async_resource, + napi_value async_resource_name, + size_t max_queue_size, + size_t initial_thread_count, + void* thread_finalize_data, + napi_finalize thread_finalize_cb, + void* context, + napi_threadsafe_function_call_js call_js_cb, + napi_threadsafe_function* result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_threadsafe_function_context( + napi_threadsafe_function func, void** result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_call_threadsafe_function(napi_threadsafe_function func, + void* data, + napi_threadsafe_function_call_mode is_blocking); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_acquire_threadsafe_function(napi_threadsafe_function func); + +NAPI_EXTERN napi_status NAPI_CDECL napi_release_threadsafe_function( + napi_threadsafe_function func, napi_threadsafe_function_release_mode mode); + +NAPI_EXTERN napi_status NAPI_CDECL napi_unref_threadsafe_function( + node_api_basic_env env, napi_threadsafe_function func); + +NAPI_EXTERN napi_status NAPI_CDECL napi_ref_threadsafe_function( + node_api_basic_env env, napi_threadsafe_function func); + +#endif // NAPI_VERSION >= 4 + +#if NAPI_VERSION >= 8 + +NAPI_EXTERN napi_status NAPI_CDECL +napi_add_async_cleanup_hook(node_api_basic_env env, + napi_async_cleanup_hook hook, + void* arg, + napi_async_cleanup_hook_handle* remove_handle); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_remove_async_cleanup_hook(napi_async_cleanup_hook_handle remove_handle); + +#endif // NAPI_VERSION >= 8 + +#if NAPI_VERSION >= 9 + +NAPI_EXTERN napi_status NAPI_CDECL +node_api_get_module_file_name(node_api_basic_env env, const char** result); + +#endif // NAPI_VERSION >= 9 + +EXTERN_C_END + +#endif // SRC_NODE_API_H_ diff --git a/NativeScript/napi/hermes/include/old/node_api_types.h b/NativeScript/napi/hermes/include/old/node_api_types.h new file mode 100644 index 00000000..9c2f03f4 --- /dev/null +++ b/NativeScript/napi/hermes/include/old/node_api_types.h @@ -0,0 +1,52 @@ +#ifndef SRC_NODE_API_TYPES_H_ +#define SRC_NODE_API_TYPES_H_ + +#include "js_native_api_types.h" + +typedef struct napi_callback_scope__* napi_callback_scope; +typedef struct napi_async_context__* napi_async_context; +typedef struct napi_async_work__* napi_async_work; + +#if NAPI_VERSION >= 3 +typedef void(NAPI_CDECL* napi_cleanup_hook)(void* arg); +#endif // NAPI_VERSION >= 3 + +#if NAPI_VERSION >= 4 +typedef struct napi_threadsafe_function__* napi_threadsafe_function; +#endif // NAPI_VERSION >= 4 + +#if NAPI_VERSION >= 4 +typedef enum { + napi_tsfn_release, + napi_tsfn_abort +} napi_threadsafe_function_release_mode; + +typedef enum { + napi_tsfn_nonblocking, + napi_tsfn_blocking +} napi_threadsafe_function_call_mode; +#endif // NAPI_VERSION >= 4 + +typedef void(NAPI_CDECL* napi_async_execute_callback)(napi_env env, void* data); +typedef void(NAPI_CDECL* napi_async_complete_callback)(napi_env env, + napi_status status, + void* data); +#if NAPI_VERSION >= 4 +typedef void(NAPI_CDECL* napi_threadsafe_function_call_js)( + napi_env env, napi_value js_callback, void* context, void* data); +#endif // NAPI_VERSION >= 4 + +typedef struct { + uint32_t major; + uint32_t minor; + uint32_t patch; + const char* release; +} napi_node_version; + +#if NAPI_VERSION >= 8 +typedef struct napi_async_cleanup_hook_handle__* napi_async_cleanup_hook_handle; +typedef void(NAPI_CDECL* napi_async_cleanup_hook)( + napi_async_cleanup_hook_handle handle, void* data); +#endif // NAPI_VERSION >= 8 + +#endif // SRC_NODE_API_TYPES_H_ diff --git a/NativeScript/napi/hermes/include_old/hermes/AsyncDebuggerAPI.h b/NativeScript/napi/hermes/include_old/hermes/AsyncDebuggerAPI.h new file mode 100644 index 00000000..ea718dd4 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/AsyncDebuggerAPI.h @@ -0,0 +1,309 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_ASYNCDEBUGGERAPI_H +#define HERMES_ASYNCDEBUGGERAPI_H + +#ifdef HERMES_ENABLE_DEBUGGER + +#include +#include +#include +#include +#include + +#include +#include +#include + +#if defined(__clang__) && (!defined(SWIG)) && defined(_LIBCPP_VERSION) && \ + defined(_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS) +#include +#else +#ifndef TSA_GUARDED_BY +#define TSA_GUARDED_BY(x) +#endif +#ifndef TSA_NO_THREAD_SAFETY_ANALYSIS +#define TSA_NO_THREAD_SAFETY_ANALYSIS +#endif +#endif + +namespace facebook { +namespace hermes { +namespace debugger { + +class AsyncDebuggerAPI; + +enum class DebuggerEventType { + // Informational Events + ScriptLoaded, /// A script file was loaded, and the debugger has requested + /// pausing after script load. + Exception, /// An Exception was thrown. + Resumed, /// Script execution has resumed. + + // Events Requiring Next Command + DebuggerStatement, /// A debugger; statement was hit. + Breakpoint, /// A breakpoint was hit. + StepFinish, /// A Step operation completed. + ExplicitPause, /// A pause requested using Explicit AsyncBreak +}; + +/// This represents the list of possible commands that can be given to +/// \p resumeFromPaused. This is used instead of DebuggerAPI's Command class in +/// order to prevent callers from constructing an eval Command. The eval +/// functionality is implemented as a separate mechansim with +/// \p evalWhilePaused. +enum class AsyncDebugCommand { + Continue, /// Continues execution + StepInto, /// Perform a step into and then pause again + StepOver, /// Steps over the current instruction and then pause again + StepOut, /// Step out from the current scope and then pause again +}; + +using DebuggerEventCallback = std::function; +using DebuggerEventCallbackID = uint32_t; +constexpr const uint32_t kInvalidDebuggerEventCallbackID = 0; +using InterruptCallback = std::function; +using EvalCompleteCallback = std::function< + void(HermesRuntime &runtime, const debugger::EvalResult &result)>; + +/// This class wraps the DebuggerAPI to expose an asynchronous didPause +/// functionality as well as an interrupt API. This class must be constructed at +/// the same time as HermesRuntime. +/// +/// Functions in this class with the suffix "_TS" (Thread-Safe) are the only +/// functions that are safe to call on any thread. All other functions must be +/// called on the runtime thread. +class HERMES_EXPORT AsyncDebuggerAPI : private debugger::EventObserver { + /// Hide the constructor so users can only construct via static create + /// methods. + AsyncDebuggerAPI(HermesRuntime &runtime); + + public: + /// Creates an AsyncDebuggerAPI for use with the provided HermesRuntime. This + /// should be called and created at the same time as creating HermesRuntime. + static std::unique_ptr create(HermesRuntime &runtime); + + /// Must be destroyed on the runtime thread or when you're sure nothing is + /// interacting with the runtime. Must be destroyed before destroying + /// HermesRuntime. + ~AsyncDebuggerAPI() override; + + /// Add a callback function to invoke when the runtime pauses due to various + /// conditions such as hitting a "debugger;" statement. Can be called from any + /// thread. If there are no DebuggerEventCallback, then any reason that might + /// trigger a pause, such as a "debugger;" statement or breakpoints, will not + /// actually pause and will simply continue execution. Any caller that adds an + /// event callback cannot just be observing events and never call + /// \p resumeFromPaused in any of its code paths. The caller must either + /// expose UI enabling human action for controlling the debugger, or it must + /// have programmatic logic that controls the debugger via + /// \p resumeFromPaused. + DebuggerEventCallbackID addDebuggerEventCallback_TS( + DebuggerEventCallback callback); + + /// Remove a previously added callback function. If there is no callback + /// registered using the provided \p id, the function does nothing. + void removeDebuggerEventCallback_TS(DebuggerEventCallbackID id); + + /// Whether the runtime is currently paused waiting for the next action. + /// Should only be called from the runtime thread. + bool isWaitingForCommand(); + + /// Whether the runtime is currently paused for any reason (e.g. script + /// parsed, running interrupts, or waiting for a command). + /// Should only be called from the runtime thread. + bool isPaused(); + + /// Provide the next action to perform. Should only be called from the runtime + /// thread and only if the next command is expected to be set. + bool resumeFromPaused(AsyncDebugCommand command); + + /// Evaluate JavaScript code \p expression in the frame at index + /// \p frameIndex. Receives evaluation result in the \p callback. Should only + /// be called from the runtime thread and only if debugger is paused waiting + /// for the next action. + bool evalWhilePaused( + const std::string &expression, + uint32_t frameIndex, + EvalCompleteCallback callback); + + /// Request to interrupt the runtime at a convenient time and get a callback + /// on the runtime thread. Guaranteed to run "exactly once". This function can + /// be called from any thread, but cannot be called while inside a + /// DebuggerEventCallback. + void triggerInterrupt_TS(InterruptCallback callback); + + /// EventObserver implementation + debugger::Command didPause(debugger::Debugger &debugger) override; + + private: + struct EventCallbackEntry { + DebuggerEventCallbackID id; + DebuggerEventCallback callback; + }; + + /// This function infinite loops and uses \p signal_ to block the runtime + /// thread. It gets woken up if new InterruptCallback is queued or if + /// DebuggerEventCallback changes. + void processInterruptWhilePaused() TSA_NO_THREAD_SAFETY_ANALYSIS; + + /// Dequeues the next InterruptCallback if any. + std::optional takeNextInterruptCallback(); + + /// If \p ignoreNextCommand is true, then runs every InterruptCallback that + /// has been queued up so far. If \p ignoreNextCommand is false, then attempt + /// to run all interrupts, but will stop if any interrupt sets a next command. + void runInterrupts(bool ignoreNextCommand = true); + + /// Returns the next DebuggerEventCallback to execute if any. + std::optional takeNextEventCallback(); + + /// Runs every DebuggerEventCallback that has been registered. + void runEventCallbacks(DebuggerEventType event); + + HermesRuntime &runtime_; + + /// Whether the runtime thread is currently paused in \p didPause and needs to + /// be told what action to take next. + bool isWaitingForCommand_; + + /// Stores the command to return from \p didPause. + debugger::Command nextCommand_; + + /// Callback function to invoke after getting EvalResult from EvalComplete in + /// didPause. Used once and then cleared out. + EvalCompleteCallback oneTimeEvalCompleteCallback_{}; + + /// Tracks whether we are already in a didPause callback to detect recursive + /// calls to didPause. + bool inDidPause_ = false; + + /// Next ID to use when adding a DebuggerEventCallback. + uint32_t nextEventCallbackID_ TSA_GUARDED_BY(mutex_); + + /// Callback functions to invoke to notify events in \p didPause. Using + /// std::list which requires O(N) search when removing an element, but removal + /// should be a rare event. So the choice of using std::list is to optimize + /// for typical usage. + std::list eventCallbacks_ TSA_GUARDED_BY(mutex_){}; + + /// Iterator for eventCallbacks_. Used to traverse through the list when + /// running the callbacks. + std::list::iterator eventCallbackIterator_ + TSA_GUARDED_BY(mutex_); + + /// Queue of interrupt callback functions to invoke. + std::queue interruptCallbacks_ TSA_GUARDED_BY(mutex_){}; + + /// Used as a mechanism to block the runtime thread in \p didPause and for + /// protecting variables used across threads. + std::mutex mutex_{}; + /// Used to implement \p triggerInterrupt while \p didPause is holding onto + /// the runtime thread. + std::condition_variable signal_{}; +}; + +} // namespace debugger +} // namespace hermes +} // namespace facebook + +#else // !HERMES_ENABLE_DEBUGGER + +#include +#include +#include + +namespace facebook { +namespace hermes { +namespace debugger { + +class AsyncDebuggerAPI; + +enum class DebuggerEventType { + // Informational Events + ScriptLoaded, /// A script file was loaded, and the debugger has requested + /// pausing after script load. + Exception, /// An Exception was thrown. + Resumed, /// Script execution has resumed. + + // Events Requiring Next Command + DebuggerStatement, /// A debugger; statement was hit. + Breakpoint, /// A breakpoint was hit. + StepFinish, /// A Step operation completed. + ExplicitPause, /// A pause requested using Explicit AsyncBreak +}; + +/// This represents the list of possible commands that can be given to +/// \p resumeFromPaused. This is used instead of DebuggerAPI's Command class in +/// order to prevent callers from constructing an eval Command. The eval +/// functionality is implemented as a separate mechansim with +/// \p evalWhilePaused. +enum class AsyncDebugCommand { + Continue, /// Continues execution + StepInto, /// Perform a step into and then pause again + StepOver, /// Steps over the current instruction and then pause again + StepOut, /// Step out from the current scope and then pause again +}; + +using DebuggerEventCallback = std::function; +using DebuggerEventCallbackID = uint32_t; +constexpr const uint32_t kInvalidDebuggerEventCallbackID = 0; +using InterruptCallback = std::function; +using EvalCompleteCallback = std::function< + void(HermesRuntime &runtime, const debugger::EvalResult &result)>; + +class HERMES_EXPORT AsyncDebuggerAPI { + public: + static std::unique_ptr create(HermesRuntime &runtime) { + return nullptr; + } + + ~AsyncDebuggerAPI() {} + + DebuggerEventCallbackID addDebuggerEventCallback_TS( + DebuggerEventCallback callback) { + return kInvalidDebuggerEventCallbackID; + } + + void removeDebuggerEventCallback_TS(DebuggerEventCallbackID id) {} + + bool isWaitingForCommand() { + return false; + } + + bool isPaused() { + return false; + } + + bool resumeFromPaused(AsyncDebugCommand command) { + return false; + } + + bool evalWhilePaused( + const std::string &expression, + uint32_t frameIndex, + EvalCompleteCallback callback) { + return false; + } + + void triggerInterrupt_TS(InterruptCallback callback) {} +}; + +} // namespace debugger +} // namespace hermes +} // namespace facebook + +#endif // !HERMES_ENABLE_DEBUGGER + +#endif // HERMES_ASYNCDEBUGGERAPI_H diff --git a/NativeScript/napi/hermes/include_old/hermes/CompileJS.h b/NativeScript/napi/hermes/include_old/hermes/CompileJS.h new file mode 100644 index 00000000..562eeae7 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/CompileJS.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_COMPILEJS_H +#define HERMES_COMPILEJS_H + +#include +#include +#include + +namespace hermes { + +/// Interface for receiving errors, warnings and notes produced by compileJS. +class DiagnosticHandler { + public: + enum Kind { + Error, + Warning, + Note, + }; + + struct Diagnostic { + Kind kind; + int line; /// 1-based index + int column; /// 1-based index + std::string message; + /// 0-based char indices in half-open intervals + std::vector> ranges; + }; + + /// Called once for each diagnostic message produced during compilation. + virtual void handle(const Diagnostic &diagnostic) = 0; + virtual ~DiagnosticHandler() = default; +}; + +/// Compiles JS source \p str and if compilation is successful, returns true +/// and outputs to \p bytecode otherwise returns false. +/// \param sourceURL this will be used as the "file name" of the buffer for +/// errors, stack traces, etc. +/// \param optimize this will enable optimizations. +/// \param emitAsyncBreakCheck this will make the bytecode interruptable. +/// \param diagHandler if not null, receives any and all errors, warnings and +/// notes produced during compilation. +/// \param sourceMapBuf optional source map string. +/// \param debug Wether to generate debugging information in generated bytecode. +bool compileJS( + const std::string &str, + const std::string &sourceURL, + std::string &bytecode, + bool optimize, + bool emitAsyncBreakCheck, + DiagnosticHandler *diagHandler, + std::optional sourceMapBuf = std::nullopt, + bool debug = false); + +bool compileJS( + const std::string &str, + std::string &bytecode, + bool optimize = true); + +bool compileJS( + const std::string &str, + const std::string &sourceURL, + std::string &bytecode, + bool optimize = true); + +} // namespace hermes + +#endif diff --git a/NativeScript/napi/hermes/include_old/hermes/DebuggerAPI.h b/NativeScript/napi/hermes/include_old/hermes/DebuggerAPI.h new file mode 100644 index 00000000..e444c41c --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/DebuggerAPI.h @@ -0,0 +1,501 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_DEBUGGERAPI_H +#define HERMES_DEBUGGERAPI_H + +#ifdef HERMES_ENABLE_DEBUGGER + +#include +#include +#include +#include + +#include "hermes/Public/DebuggerTypes.h" + +// Forward declarations of internal types. +namespace hermes { +namespace vm { +class CodeBlock; +class Debugger; +class Runtime; +struct DebugCommand; +class HermesValue; +} // namespace vm +} // namespace hermes + +namespace facebook { +namespace hermes { +class HermesRuntime; + +namespace debugger { + +class Debugger; +class EventObserver; + +/// Represents a variable in the debugger. +struct HERMES_EXPORT VariableInfo { + /// Name of the variable in the source. + String name; + + /// Value of the variable. + ::facebook::jsi::Value value; +}; + +/// An EvalResult represents the result of an Eval command. +struct HERMES_EXPORT EvalResult { + /// The resulting JavaScript object, or the thrown exception. + ::facebook::jsi::Value value; + + /// Indicates that the result was an exception. + bool isException = false; + + /// If isException is true, details about the exception. + ExceptionDetails exceptionDetails; + + EvalResult(EvalResult &&) = default; + EvalResult() = default; + + EvalResult( + ::facebook::jsi::Value value, + bool isException, + ExceptionDetails exceptionDetails) + : value(std::move(value)), + isException(isException), + exceptionDetails(std::move(exceptionDetails)) {} +}; + +/// ProgramState represents the state of a paused program. An instance of +/// ProgramState is available as the getProgramState() member function of class +/// Debugger. +class HERMES_EXPORT ProgramState { + public: + /// \return the reason for the Pause. + PauseReason getPauseReason() const { + return pauseReason_; + } + + /// \return the breakpoint if the PauseReason is Breakpoint, otherwise + /// kInvalidBreakpoint. + BreakpointID getBreakpoint() const { + return breakpoint_; + } + + /// \return the evaluation result if the PauseReason is due to EvalComplete. + EvalResult getEvalResult() const; + + /// \returns a stack trace for the current execution. + const StackTrace &getStackTrace() const { + return stackTrace_; + } + + /// \returns lexical information about the state in a given frame. + LexicalInfo getLexicalInfo(uint32_t frameIndex) const; + + /// \return information about a variable in a given lexical scope, in a given + /// frame. + VariableInfo getVariableInfo( + uint32_t frameIndex, + ScopeDepth scopeDepth, + uint32_t variableIndexInScope) const; + + /// \return information about the `this` value at a given stack depth. + VariableInfo getVariableInfoForThis(uint32_t frameIndex) const; + + /// \return the number of variables in a given frame. + /// This is deprecated: prefer using getLexicalInfoInFrame(). + uint32_t getVariablesCountInFrame(uint32_t frameIndex) const { + auto info = getLexicalInfo(frameIndex); + uint32_t result = 0; + for (ScopeDepth i = 0, max = info.getScopesCount(); i < max; i++) + result += info.getVariablesCountInScope(i); + return result; + } + + /// \return info for a variable at a given index \p variableIndex, in a given + /// frame at index \p frameIndex. + /// This is deprecated. Prefer the getVariableInfo() that takes three + /// parameters. + VariableInfo getVariableInfo(uint32_t frameIndex, uint32_t variableIndex) + const { + LexicalInfo info = getLexicalInfo(frameIndex); + uint32_t remaining = variableIndex; + for (ScopeDepth scope = 0;; scope++) { + assert(scope < info.getScopesCount() && "Index out of bounds"); + uint32_t count = info.getVariablesCountInScope(scope); + if (remaining < count) { + return getVariableInfo(frameIndex, scope, remaining); + } + remaining -= count; + } + } + + private: + friend Debugger; + /// ProgramState must not be copied, because some of its implementation + /// requires querying the live program state and so the state must not be + /// retained after the pause returns. + /// ProgramState must not be copied. + ProgramState(const ProgramState &) = delete; + ProgramState &operator=(const ProgramState &) = delete; + + ::hermes::vm::Debugger *impl() const; + + ProgramState(Debugger *dbg) : dbg_(dbg) {} + Debugger *dbg_; + PauseReason pauseReason_{}; + StackTrace stackTrace_; + EvalResult evalResult_; + BreakpointID breakpoint_{kInvalidBreakpoint}; +}; + +/// Command represents an action that you can request the debugger to perform +/// when returned from didPause(). +class HERMES_EXPORT Command { + public: + /// Commands may be moved. + Command(Command &&); + Command &operator=(Command &&); + ~Command(); + + /// \return a Command that steps with the given StepMode \p mode. + static Command step(StepMode mode); + + /// \return a Command that continues execution. + static Command continueExecution(); + + /// \return a Command that evaluates JavaScript code \p src in the + /// frame at index \p frameIndex. + static Command eval(const String &src, uint32_t frameIndex); + + /// \return a boolean whether this Command was constructed using the static + /// eval() method + bool isEval(); + + private: + friend Debugger; + explicit Command(::hermes::vm::DebugCommand &&); + std::unique_ptr<::hermes::vm::DebugCommand> debugCommand_; +}; + +/// Debugger allows access to the Hermes debugging functionality. An instance of +/// Debugger is available from HermesRuntime, and also passed to your +/// EventObserver. +class HERMES_EXPORT Debugger { + public: + /// Set the Debugger event observer. The event observer is notified of + /// debugging event, specifically when the program pauses. This is simply a + /// raw pointer: it is the client's responsibility to clear the event observer + /// if the event observer is deallocated before the Debugger. + void setEventObserver(EventObserver *observer); + + /// Sets the property %isDebuggerAttached in %DebuggerInternal object. Can be + /// called from any thread. + void setIsDebuggerAttached(bool isAttached); + + /// Asynchronously triggers a pause. This may be called from any thread. This + /// is inherently racey and the exact point at which the program pauses is not + /// guaranteed. You can discover when the program has paused through the event + /// observer. + void triggerAsyncPause(AsyncPauseKind kind); + + /// \return the ProgramState representing the state of the paused program. + /// This may only be invoked when the program is paused. + const ProgramState &getProgramState() const { + return state_; + } + + /// \return the source map URL for the \p fileId. + String getSourceMappingUrl(uint32_t fileId) const; + + /// Gets the list of loaded scripts. The order of the scripts in the vector + /// will be the same across calls. + /// \return list of loaded scripts + std::vector getLoadedScripts() const; + + /// Gets the current stack trace. + /// \return stack trace with call frames if runtime is in the interpreter + /// loop, otherwise return no call frames + StackTrace captureStackTrace() const; + + /// -- Breakpoint Management -- + + /// Sets a breakpoint on a given SourceLocation. + /// \return the ID of the breakpoint, 0 if it wasn't created. + BreakpointID setBreakpoint(SourceLocation loc); + + /// Sets the condition on breakpoint \p breakpoint. + /// The condition will be stored with the breakpoint, + /// and if non-empty, will be executed to determine whether to actually + /// pause on the breakpoint; only if ToBoolean(condition) is true + /// and does not throw will the debugger pause on \p breakpoint. + /// \param condition the code to execute to determine whether to break; + /// if empty, the condition is considered to not be set. + void setBreakpointCondition(BreakpointID breakpoint, const String &condition); + + /// Deletes a breakpoint. + void deleteBreakpoint(BreakpointID breakpoint); + + /// Deletes all breakpoints. + void deleteAllBreakpoints(); + + /// Mark a breakpoint as enabled. Breakpoints are by default enabled. + void setBreakpointEnabled(BreakpointID breakpoint, bool enable); + + /// \return information on a breakpoint. + BreakpointInfo getBreakpointInfo(BreakpointID breakpoint); + + /// \return a list of extant breakpoints. + std::vector getBreakpoints(); + + /// Set whether the debugger should pause when an exception is thrown. + void setPauseOnThrowMode(PauseOnThrowMode mode); + + /// \return whether the debugger pauses when an exception is thrown. + PauseOnThrowMode getPauseOnThrowMode() const; + + /// Set whether the debugger should pause after a script was loaded. + void setShouldPauseOnScriptLoad(bool flag); + + /// \return whether the debugger should pause after a script was loaded. + bool getShouldPauseOnScriptLoad() const; + + /// \return the thrown value if paused on an exception, or + /// jsi::Value::undefined() if not. + ::facebook::jsi::Value getThrownValue(); + + private: + friend std::unique_ptr hermes::makeHermesRuntime( + const ::hermes::vm::RuntimeConfig &); + friend std::unique_ptr + hermes::makeThreadSafeHermesRuntime(const ::hermes::vm::RuntimeConfig &); + friend ProgramState; + + /// Debuggers may not be moved or copied. + Debugger(const Debugger &) = delete; + void operator=(const Debugger &) = delete; + Debugger(Debugger &&) = delete; + void operator=(Debugger &&) = delete; + + /// Implementation detail used by ProgramState. + ::facebook::jsi::Value jsiValueFromHermesValue(::hermes::vm::HermesValue hv); + + explicit Debugger( + ::facebook::hermes::HermesRuntime *runtime, + ::hermes::vm::Runtime &vmRuntime); + + ::facebook::hermes::HermesRuntime *const runtime_; + EventObserver *eventObserver_ = nullptr; + ::hermes::vm::Runtime &vmRuntime_; + ::hermes::vm::Debugger *impl_; + ProgramState state_; +}; + +/// A subclass of EventObserver may be set on the Debugger via +/// setEventObserver(). It receives notifications when the Debugger pauses. +class HERMES_EXPORT EventObserver { + public: + /// didPause() is invoked when the JavaScript program has paused. The + /// The Debugger \p debugger can be used to manipulate breakpoints and enqueue + /// debugger commands such as stepping, etc. It can also be used to discover + /// the call stack and variables via debugger.getProgramState(). + /// \return a Command for the debugger to perform. + virtual Command didPause(Debugger &debugger) = 0; + + /// Invoked when the debugger resolves a previously unresolved breakpoint. + /// Note that the debugger is *not* paused during this, + /// and thus debugger.getProgramState() is not valid. + /// This callback may not invoke JavaScript or enqueue debugger commands. + virtual void breakpointResolved(Debugger &debugger, BreakpointID breakpoint) { + } + + virtual ~EventObserver(); +}; + +} // namespace debugger +} // namespace hermes +} // namespace facebook + +#else // !HERMES_ENABLE_DEBUGGER + +#include + +#include "hermes/Public/DebuggerTypes.h" + +namespace facebook { +namespace hermes { +namespace debugger { + +class EventObserver; + +struct VariableInfo { + String name; + ::facebook::jsi::Value value; +}; + +struct EvalResult { + ::facebook::jsi::Value value; + bool isException = false; + ExceptionDetails exceptionDetails; + + EvalResult(EvalResult &&) = default; + EvalResult() = default; + + EvalResult( + ::facebook::jsi::Value value, + bool isException, + ExceptionDetails exceptionDetails) + : value(std::move(value)), + isException(isException), + exceptionDetails(std::move(exceptionDetails)) {} +}; + +class ProgramState { + public: + ProgramState() {} + + PauseReason getPauseReason() const { + return PauseReason::Exception; + } + + BreakpointID getBreakpoint() const { + return 0; + } + + EvalResult getEvalResult() const { + return EvalResult(); + } + + const StackTrace &getStackTrace() const { + return stackTrace_; + } + + LexicalInfo getLexicalInfo(uint32_t frameIndex) const { + return LexicalInfo(); + } + + VariableInfo getVariableInfo( + uint32_t frameIndex, + ScopeDepth scopeDepth, + uint32_t variableIndexInScope) const { + return VariableInfo(); + } + + VariableInfo getVariableInfoForThis(uint32_t frameIndex) const { + return VariableInfo(); + } + + uint32_t getVariablesCountInFrame(uint32_t frameIndex) const { + return 0; + } + + VariableInfo getVariableInfo(uint32_t frameIndex, uint32_t variableIndex) + const { + return VariableInfo(); + } + + private: + ProgramState(const ProgramState &) = delete; + ProgramState &operator=(const ProgramState &) = delete; + + StackTrace stackTrace_; +}; + +class Command { + public: + Command(Command &&) {} + Command &operator=(Command &&); + ~Command() {} + + static Command step(StepMode mode) { + return Command(); + } + static Command continueExecution() { + return Command(); + } + static Command eval(const String &src, uint32_t frameIndex) { + return Command(); + } + bool isEval() { + return false; + } + + private: + Command() {} +}; + +class Debugger { + public: + explicit Debugger() {} + + void setEventObserver(EventObserver *observer) {} + void setIsDebuggerAttached(bool isAttached) {} + void triggerAsyncPause(AsyncPauseKind kind) {} + const ProgramState &getProgramState() const { + return programState_; + } + String getSourceMappingUrl(uint32_t fileId) const { + return ""; + }; + std::vector getLoadedScripts() const { + return {}; + } + StackTrace captureStackTrace() const { + return StackTrace{}; + } + BreakpointID setBreakpoint(SourceLocation loc) { + return 0; + } + void setBreakpointCondition( + BreakpointID breakpoint, + const String &condition) {} + void deleteBreakpoint(BreakpointID breakpoint) {} + void deleteAllBreakpoints() {} + void setBreakpointEnabled(BreakpointID breakpoint, bool enable) {} + BreakpointInfo getBreakpointInfo(BreakpointID breakpoint) { + return BreakpointInfo(); + } + std::vector getBreakpoints() { + return std::vector(); + } + void setPauseOnThrowMode(PauseOnThrowMode mode) {} + PauseOnThrowMode getPauseOnThrowMode() const { + return PauseOnThrowMode::None; + } + void setShouldPauseOnScriptLoad(bool flag) {} + bool getShouldPauseOnScriptLoad() const { + return false; + } + ::facebook::jsi::Value getThrownValue() { + return ::facebook::jsi::Value::undefined(); + } + + private: + Debugger(const Debugger &) = delete; + void operator=(const Debugger &) = delete; + Debugger(Debugger &&) = delete; + void operator=(Debugger &&) = delete; + + ProgramState programState_; +}; + +class EventObserver { + public: + virtual Command didPause(Debugger &debugger) = 0; + virtual void breakpointResolved(Debugger &debugger, BreakpointID breakpoint) { + } + + virtual ~EventObserver() {} +}; + +} // namespace debugger +} // namespace hermes +} // namespace facebook + +#endif // !HERMES_ENABLE_DEBUGGER + +#endif // HERMES_DEBUGGERAPI_H diff --git a/NativeScript/napi/hermes/include/hermes/MurmurHash.h b/NativeScript/napi/hermes/include_old/hermes/MurmurHash.h similarity index 100% rename from NativeScript/napi/hermes/include/hermes/MurmurHash.h rename to NativeScript/napi/hermes/include_old/hermes/MurmurHash.h diff --git a/NativeScript/napi/hermes/include_old/hermes/Public/Buffer.h b/NativeScript/napi/hermes/include_old/hermes/Public/Buffer.h new file mode 100644 index 00000000..3a4e8c26 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/Public/Buffer.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_PUBLIC_BUFFER_H +#define HERMES_PUBLIC_BUFFER_H + +#include + +#include +#include + +namespace hermes { + +/// A generic buffer interface. E.g. for memmapped bytecode. +class HERMES_EXPORT Buffer { + public: + Buffer() : data_(nullptr), size_(0) {} + + Buffer(const uint8_t *data, size_t size) : data_(data), size_(size) {} + + virtual ~Buffer(); + + const uint8_t *data() const { + return data_; + }; + + size_t size() const { + return size_; + } + + protected: + const uint8_t *data_ = nullptr; + size_t size_ = 0; +}; + +} // namespace hermes + +#endif diff --git a/NativeScript/napi/hermes/include_old/hermes/Public/CrashManager.h b/NativeScript/napi/hermes/include_old/hermes/Public/CrashManager.h new file mode 100644 index 00000000..07a9b592 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/Public/CrashManager.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_PUBLIC_CRASHMANAGER_H +#define HERMES_PUBLIC_CRASHMANAGER_H + +#include + +#include +#include + +namespace hermes { +namespace vm { + +/// A CrashManager provides functions that determine what memory and data is +/// included in dumps in case of crashes. +class HERMES_EXPORT CrashManager { + public: + /// CallbackKey is the type of an identifier for a callback supplied to the + /// CrashManager. + using CallbackKey = int; + /// Type for the callback function invoked on crash. The fd supplied is a raw + /// file stream an implementation should write a JSON object to. + using CallbackFunc = std::function; + + /// Registers some memory to be included in any crash dump that occurs. + /// \param mem A pointer to allocated memory. It must be unregistered + /// before being freed. + /// \param length The number of bytes the memory controls. + virtual void registerMemory(void *mem, size_t length) = 0; + + /// Unregisters some memory from being included in any crash dump that occurs. + virtual void unregisterMemory(void *mem) = 0; + + /// Registers custom data to be included in any crash dump that occurs. + /// Calling \c setCustomData on the same key twice will overwrite the previous + /// value. + /// \param key A tag to look for in the custom data output. Distinguishes + /// between multiple values. + /// \param val The value to store for the given key. + virtual void setCustomData(const char *key, const char *val) = 0; + + /// If the given \p key has an associated custom data string, remove the + /// association. If the key hasn't been set before, is a no-op. + virtual void removeCustomData(const char *key) = 0; + + /// Same as \c setCustomData, except it is only set for the current thread. + virtual void setContextualCustomData(const char *key, const char *val) = 0; + + /// Same as \c removeCustomData, except it is for keys set with \c + /// setContextualCustomData. + virtual void removeContextualCustomData(const char *key) = 0; + + /// Registers a function to be called after a crash has occurred. This + /// function can examine memory and serialize this to a JSON output stream. + /// Implmentations decide where the stream is routed to. + /// \param callback A function to called after a crash. + /// \return A CallbackKey representing the function you provided. Pass this + /// key into unregisterCallback when it that callback is no longer needed. + virtual CallbackKey registerCallback(CallbackFunc callback) = 0; + + /// Unregisters a previously registered callback. After this function returns, + /// the previously registered function will not be executed by this + /// CrashManager during a crash. + virtual void unregisterCallback(CallbackKey key) = 0; + + /// the heap information. + struct HeapInformation { + /// The amount of memory that is currently in use + size_t used_{0}; + /// The amount of memory that can currently be allocated + /// before a full GC is triggered. + size_t size_{0}; + }; + + /// Record the heap information. + /// \param heapInfo The current heap information + virtual void setHeapInfo(const HeapInformation &heapInfo) = 0; + + virtual ~CrashManager(); +}; + +/// A CrashManager that does nothing. +class HERMES_EXPORT NopCrashManager final : public CrashManager { + public: + void registerMemory(void *, size_t) override {} + void unregisterMemory(void *) override {} + void setCustomData(const char *, const char *) override {} + void removeCustomData(const char *) override {} + void setContextualCustomData(const char *, const char *) override {} + void removeContextualCustomData(const char *) override {} + CallbackKey registerCallback(CallbackFunc /*callback*/) override { + return 0; + } + void unregisterCallback(CallbackKey /*key*/) override {} + void setHeapInfo(const HeapInformation & /*heapInfo*/) override {} + + ~NopCrashManager() override; +}; + +} // namespace vm +} // namespace hermes +#endif diff --git a/NativeScript/napi/hermes/include_old/hermes/Public/CtorConfig.h b/NativeScript/napi/hermes/include_old/hermes/Public/CtorConfig.h new file mode 100644 index 00000000..aff3f398 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/Public/CtorConfig.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_PUBLIC_CTORCONFIG_H +#define HERMES_PUBLIC_CTORCONFIG_H + +#include + +/// Defines a new class, called \p NAME representing a constructor config, and +/// an associated builder class. +/// +/// The fields of the class (along with their types and default values) are +/// encoded in the \p FIELDS parameter, and any logic to be run whilst building +/// the config can be passed as a code block in \p BUILD_BODY. +/// +/// Example: +/// +/// Suppose we wish to define a configuration class called Foo, with the +/// following fields and default values: +/// +/// int A = 0; +/// int B = 42; +/// std::string C = "hello"; +/// +/// Such that the value in A is at most the length of \c C. +/// +/// We can do so with the following declaration: +/// +/// " #define FIELDS(F) \ " +/// " F(int, A) \ " +/// " F(int, B, 42) \ " +/// " F(std::string, C, "hello") " +/// " " +/// " _HERMES_CTORCONFIG_STRUCT(Foo, FIELDS, { " +/// " A_ = std::min(A_, C_.length()); " +/// " }); " +/// +/// N.B. +/// - The definition of A does not mention any value -- meaning it is +/// default initialised. +/// - References to the fields in the validation logic have a trailling +/// underscore. +/// +#define _HERMES_CTORCONFIG_STRUCT(NAME, FIELDS, BUILD_BODY) \ + class NAME { \ + FIELDS(_HERMES_CTORCONFIG_FIELD_DECL) \ + \ + public: \ + class Builder; \ + friend Builder; \ + FIELDS(_HERMES_CTORCONFIG_GETTER) \ + \ + /* returns a Builder that starts with the current config. */ \ + inline Builder rebuild() const; \ + \ + private: \ + inline void doBuild(const Builder &builder); \ + }; \ + \ + class NAME::Builder { \ + NAME config_; \ + \ + FIELDS(_HERMES_CTORCONFIG_FIELD_EXPLICIT_BOOL_DECL) \ + \ + public: \ + Builder() = default; \ + \ + explicit Builder(const NAME &config) : config_(config) {} \ + \ + inline const NAME build() { \ + config_.doBuild(*this); \ + return config_; \ + } \ + \ + /* The explicitly set fields of \p newconfig update \ + * the corresponding fields of \p this. */ \ + inline Builder update(const NAME::Builder &newConfig); \ + \ + FIELDS(_HERMES_CTORCONFIG_SETTER) \ + FIELDS(_HERMES_CTORCONFIG_FIELD_EXPLICIT_BOOL_ACCESSOR) \ + }; \ + \ + NAME::Builder NAME::rebuild() const { \ + return Builder(*this); \ + } \ + \ + NAME::Builder NAME::Builder::update(const NAME::Builder &newConfig) { \ + FIELDS(_HERMES_CTORCONFIG_UPDATE) \ + return *this; \ + } \ + \ + void NAME::doBuild(const NAME::Builder &builder) { \ + (void)builder; \ + BUILD_BODY \ + } + +/// Helper Macros + +#define _HERMES_CTORCONFIG_FIELD_DECL(CX, TYPE, NAME, ...) \ + TYPE NAME##_{__VA_ARGS__}; + +/// This ignores the first and trailing arguments, and defines a member +/// indicating whether field NAME was set explicitly. +#define _HERMES_CTORCONFIG_FIELD_EXPLICIT_BOOL_DECL(CX, TYPE, NAME, ...) \ + bool NAME##Explicit_{false}; + +/// This defines an accessor for the "Explicit_" fields defined above. +#define _HERMES_CTORCONFIG_FIELD_EXPLICIT_BOOL_ACCESSOR(CX, TYPE, NAME, ...) \ + bool has##NAME() const { \ + return NAME##Explicit_; \ + } + +/// Placeholder token for fields whose defaults are not constexpr, to make the +/// listings more readable. +#define HERMES_NON_CONSTEXPR + +#define _HERMES_CTORCONFIG_GETTER(CX, TYPE, NAME, ...) \ + inline TYPE get##NAME() const { \ + return NAME##_; \ + } \ + static CX TYPE getDefault##NAME() { \ + /* Instead of parens around TYPE (non-standard) */ \ + using TypeAsSingleToken = TYPE; \ + return TypeAsSingleToken{__VA_ARGS__}; \ + } + +#define _HERMES_CTORCONFIG_SETTER(CX, TYPE, NAME, ...) \ + inline auto with##NAME(TYPE NAME)->decltype(*this) { \ + config_.NAME##_ = std::move(NAME); \ + NAME##Explicit_ = true; \ + return *this; \ + } + +#define _HERMES_CTORCONFIG_BUILDER_GETTER(CX, TYPE, NAME, ...) \ + TYPE get##NAME() const { \ + return config_.NAME##_; \ + } + +#define _HERMES_CTORCONFIG_UPDATE(CX, TYPE, NAME, ...) \ + if (newConfig.has##NAME()) { \ + with##NAME(newConfig.config_.get##NAME()); \ + } + +#endif // HERMES_PUBLIC_CTORCONFIG_H diff --git a/NativeScript/napi/hermes/include_old/hermes/Public/DebuggerTypes.h b/NativeScript/napi/hermes/include_old/hermes/Public/DebuggerTypes.h new file mode 100644 index 00000000..88184c07 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/Public/DebuggerTypes.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_PUBLIC_DEBUGGERTYPES_H +#define HERMES_PUBLIC_DEBUGGERTYPES_H + +#include +#include +#include +#pragma GCC diagnostic push + +#ifdef HERMES_COMPILER_SUPPORTS_WSHORTEN_64_TO_32 +#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#endif +namespace hermes { +namespace vm { +class Debugger; +} +} // namespace hermes + +namespace facebook { +namespace hermes { +namespace debugger { + +class ProgramState; + +/// Strings in the Debugger are UTF-8 encoded. When converting from a JavaScript +/// string, valid UTF-16 surrogate pairs are decoded. Surrogate halves are +/// converted into the Unicode replacement character. +using String = std::string; + +/// Debugging entities like breakpoints are identified by a unique ID. The +/// Debugger will not re-use IDs even across different entity types. 0 is an +/// invalid ID. +using BreakpointID = uint64_t; +// NOTE: Can't be kInvalidID due to a clash with MacTypes.h's define kInvalidID. +constexpr uint64_t kInvalidBreakpoint = 0; + +/// Scripts when loaded are identified by a script ID. +/// These are not reused within one invocation of the VM. +using ScriptID = uint32_t; + +/// A SourceLocation is a small value-type representing a location in a source +/// file. +constexpr uint32_t kInvalidLocation = ~0u; +struct SourceLocation { + /// Line in the source. 1 based. + uint32_t line = kInvalidLocation; + + /// Column in the source. 1 based. + uint32_t column = kInvalidLocation; + + /// Identifier of the source file. + ScriptID fileId = kInvalidLocation; + + /// Name of the source file. + String fileName; +}; + +/// CallFrameInfo is a value type representing an entry in a call stack. +struct CallFrameInfo { + /// Name of the function executing in this frame. + String functionName; + + /// Source location of the program counter for this frame. + SourceLocation location; +}; + +/// StackTrace represents a list of call frames, either in the current execution +/// or captured in an exception. +struct StackTrace { + /// \return the number of call frames. + uint32_t callFrameCount() const { + return frames_.size(); + } + + /// \return call frame info at a given index. 0 represents the topmost + /// (current) frame on the call stack. + CallFrameInfo callFrameForIndex(uint32_t index) const { + return frames_.at(index); + } + + StackTrace() {} + + private: + explicit StackTrace(std::vector frames) + : frames_(std::move(frames)){}; + friend ProgramState; + friend ::hermes::vm::Debugger; + std::vector frames_; +}; + +/// ExceptionDetails is a value type describing an exception. +struct ExceptionDetails { + /// Textual description of the exception. + String text; + + /// Location where the exception was thrown. + SourceLocation location; + + /// Get the stack trace associated with the exception. + const StackTrace &getStackTrace() const { + return stackTrace_; + } + + private: + friend ::hermes::vm::Debugger; + StackTrace stackTrace_; +}; + +/// A list of possible reasons for a Pause. +enum class PauseReason { + ScriptLoaded, /// A script file was loaded, and the debugger has requested + /// pausing after script load. + DebuggerStatement, /// A debugger; statement was hit. + Breakpoint, /// A breakpoint was hit. + StepFinish, /// A Step operation completed. + Exception, /// An Exception was thrown. + AsyncTriggerImplicit, /// The Pause is the result of + /// triggerAsyncPause(Implicit). + AsyncTriggerExplicit, /// The Pause is the result of + /// triggerAsyncPause(Explicit). + EvalComplete, /// An eval() function finished. +}; + +/// When stepping, the mode with which to step. +enum class StepMode { + Into, /// Enter into any function calls. + Over, /// Skip over any function calls. + Out, /// Step until the current function exits. +}; + +/// When setting pause on throw, this specifies when to pause. +enum class PauseOnThrowMode { + None, /// Never pause on exceptions. + Uncaught, /// Only pause on uncaught exceptions. + All, /// Pause any time an exception is thrown. +}; + +/// When requesting an async break, this specifies whether it was an implicit +/// break from the inspector or a user-requested explicit break. +enum class AsyncPauseKind { + /// Implicit pause to allow movement of jsi::Value types between threads. + /// The user will not be running commands and the inspector will immediately + /// request a Continue. + Implicit, + + /// Explicit pause requested by the user. + /// Clears any stepping state and allows the user to run their own commands. + Explicit, +}; + +/// A type representing depth in a lexical scope chain. +using ScopeDepth = uint32_t; + +/// Information about lexical entities (for now, just variable names). +struct LexicalInfo { + /// \return the number of scopes. + ScopeDepth getScopesCount() const { + return variableCountsByScope_.size(); + } + + /// \return the number of variables in a given scope. + uint32_t getVariablesCountInScope(ScopeDepth depth) const { + return variableCountsByScope_.at(depth); + } + + private: + friend ::hermes::vm::Debugger; + std::vector variableCountsByScope_; +}; + +/// Information about a breakpoint. +struct BreakpointInfo { + /// ID of the breakpoint. + /// kInvalidBreakpoint if the info is not valid. + BreakpointID id; + + /// Whether the breakpoint is enabled. + bool enabled; + + /// Whether the breakpoint has been resolved. + bool resolved; + + /// The originally requested location of the breakpoint. + SourceLocation requestedLocation; + + /// The resolved location of the breakpoint if resolved is true. + SourceLocation resolvedLocation; +}; + +} // namespace debugger +} // namespace hermes +} // namespace facebook + +#endif diff --git a/NativeScript/napi/hermes/include_old/hermes/Public/GCConfig.h b/NativeScript/napi/hermes/include_old/hermes/Public/GCConfig.h new file mode 100644 index 00000000..8d3f316f --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/Public/GCConfig.h @@ -0,0 +1,231 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_PUBLIC_GCCONFIG_H +#define HERMES_PUBLIC_GCCONFIG_H + +#include "hermes/Public/CtorConfig.h" +#include "hermes/Public/GCTripwireContext.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace hermes { +namespace vm { + +/// A type big enough to accomodate the entire allocated address space. +/// Individual allocations are always 'uint32_t', but on a 64-bit machine we +/// might want to accommodate a larger total heap (or not, in which case we keep +/// it 32-bit). +using gcheapsize_t = uint32_t; + +/// Represents a value before and after an event. +/// NOTE: Not a std::pair because using the names are more readable than first +/// and second. +struct BeforeAndAfter { + uint64_t before; + uint64_t after; +}; + +struct GCAnalyticsEvent { + /// The same value as \p Name from GCConfig. Stored here for simplicity of + /// the API since this is passed in callbacks that might not be able to store + /// the name. For a given Runtime, this will be the same value every time. + std::string runtimeDescription; + + /// The kind of GC this was. For a given Runtime, this will be the same value + /// every time. + std::string gcKind; + + /// The type of collection that ran, typically differentiating a "young" + /// generation GC and an "old" generation GC. When other values say they're + /// "scoped to the collectionType", it means that for a generation GC + /// they're only reporting the numbers for that generation. + std::string collectionType; + + /// The cause of this GC. Can be an arbitrary string describing the cause. + /// Typically "natural" is used to mean that the GC decided it was time, and + /// other causes mean it was forced by some other condition. + std::string cause; + + /// The wall time a collection took from start to end. + std::chrono::milliseconds duration; + + /// The CPU time a collection took from start to end. This time measure will + /// exclude time waiting on disk, mutexes, or time spent not scheduled to run. + std::chrono::milliseconds cpuDuration; + + /// The number of bytes allocated in the heap before and after the collection. + /// measurement does not include fragmentation, and is the same as the sum of + /// all sizes in calls to \p GC::makeA into that generation (including any + /// rounding up the GC does). + /// The value is scoped to the \p collectionType. + BeforeAndAfter allocated; + + /// The number of bytes in use by the heap before and after the collection. + /// This measurement can include fragmentation if the \p gcKind has that + /// concept. + /// The value is scoped to the \p collectionType. + BeforeAndAfter size; + + /// The number of bytes external to the JS heap before and after the + /// collection. + /// The value is scoped to the \p collectionType. + BeforeAndAfter external; + + /// The ratio of cells that survived the collection to all cells before + /// the collection. Note that this is in term of sizes of cells, not the + /// numbers of cells. Excludes any cells not in direct use by the JS program, + /// such as FillerCell or FreelistCell. + /// The value is scoped to the \p collectionType. + double survivalRatio; + + /// A list of metadata tags to annotate this event with. + std::vector tags; +}; + +/// Parameters to control a tripwire function called when the live set size +/// surpasses a given threshold after collections. Check documentation in +/// README.md +#define GC_TRIPWIRE_FIELDS(F) \ + /* If the heap size is above this threshold after a collection, the tripwire \ + * is triggered. */ \ + F(constexpr, gcheapsize_t, Limit, std::numeric_limits::max()) \ + \ + /* The callback to call when the tripwire is considered triggered. */ \ + F(HERMES_NON_CONSTEXPR, \ + std::function, \ + Callback, \ + nullptr) \ + /* GC_TRIPWIRE_FIELDS END */ + +_HERMES_CTORCONFIG_STRUCT(GCTripwireConfig, GC_TRIPWIRE_FIELDS, {}) + +#undef HEAP_TRIPWIRE_FIELDS + +#define GC_HANDLESAN_FIELDS(F) \ + /* The probability with which the GC should keep moving the heap */ \ + /* to detect stale GC handles. */ \ + F(constexpr, double, SanitizeRate, 0.0) \ + /* Random seed to use for basis of decisions whether or not to */ \ + /* sanitize. A negative value will mean a seed will be chosen at */ \ + /* random. */ \ + F(constexpr, int64_t, RandomSeed, -1) \ + /* GC_HANDLESAN_FIELDS END */ + +_HERMES_CTORCONFIG_STRUCT(GCSanitizeConfig, GC_HANDLESAN_FIELDS, {}) + +#undef GC_HANDLESAN_FIELDS + +/// How aggressively to return unused memory to the OS. +enum ReleaseUnused { + kReleaseUnusedNone = 0, /// Don't try to release unused memory. + kReleaseUnusedOld, /// Only old gen, on full collections. + kReleaseUnusedYoungOnFull, /// Also young gen, but only on full collections. + kReleaseUnusedYoungAlways /// Also young gen, also on young gen collections. +}; + +enum class GCEventKind { + CollectionStart, + CollectionEnd, +}; + +/// Parameters for GC Initialisation. Check documentation in README.md +/// constexpr indicates that the default value is constexpr. +#define GC_FIELDS(F) \ + /* Minimum heap size hint. */ \ + F(constexpr, gcheapsize_t, MinHeapSize, 0) \ + \ + /* Initial heap size hint. */ \ + F(constexpr, gcheapsize_t, InitHeapSize, 32 << 20) \ + \ + /* Maximum heap size hint. */ \ + F(constexpr, gcheapsize_t, MaxHeapSize, 3u << 30) \ + \ + /* Sizing heuristic: fraction of heap to be occupied by live data. */ \ + F(constexpr, double, OccupancyTarget, 0.5) \ + \ + /* Number of consecutive full collections considered to be an OOM. */ \ + F(constexpr, \ + unsigned, \ + EffectiveOOMThreshold, \ + std::numeric_limits::max()) \ + \ + /* Sanitizer configuration for the GC. */ \ + F(constexpr, GCSanitizeConfig, SanitizeConfig) \ + \ + /* Whether to Keep track of GC Statistics. */ \ + F(constexpr, bool, ShouldRecordStats, false) \ + \ + /* How aggressively to return unused memory to the OS. */ \ + F(constexpr, ReleaseUnused, ShouldReleaseUnused, kReleaseUnusedOld) \ + \ + /* Name for this heap in logs. */ \ + F(HERMES_NON_CONSTEXPR, std::string, Name, "") \ + \ + /* Configuration for the Heap Tripwire. */ \ + F(HERMES_NON_CONSTEXPR, GCTripwireConfig, TripwireConfig) \ + \ + /* Whether to (initially) allocate from the young gen (true) or the */ \ + /* old gen (false). */ \ + F(constexpr, bool, AllocInYoung, true) \ + \ + /* Whether to fill the YG with invalid data after each collection. */ \ + F(constexpr, bool, OverwriteDeadYGObjects, false) \ + \ + /* Whether to revert, if necessary, to young-gen allocation at TTI. */ \ + F(constexpr, bool, RevertToYGAtTTI, false) \ + \ + /* Whether to use mprotect on GC metadata between GCs. */ \ + F(constexpr, bool, ProtectMetadata, false) \ + \ + /* Callout for an analytics event. */ \ + F(HERMES_NON_CONSTEXPR, \ + std::function, \ + AnalyticsCallback, \ + nullptr) \ + \ + /* Called at GC events (see GCEventKind enum for the list). The */ \ + /* second argument contains human-readable details about the event. */ \ + /* NOTE: The function MUST NOT invoke any methods on the Runtime. */ \ + F(HERMES_NON_CONSTEXPR, \ + std::function, \ + Callback, \ + nullptr) \ + /* GC_FIELDS END */ + +_HERMES_CTORCONFIG_STRUCT(GCConfig, GC_FIELDS, { + if (builder.hasMinHeapSize()) { + if (builder.hasInitHeapSize()) { + // If both are specified, normalize the initial size up to the minimum, + // if necessary. + InitHeapSize_ = std::max(MinHeapSize_, InitHeapSize_); + } else { + // If the minimum is set explicitly, but the initial heap size is not, + // use the minimum as the initial size. + InitHeapSize_ = MinHeapSize_; + } + } + assert(InitHeapSize_ >= MinHeapSize_); + + // Make sure the max is at least the Init. + MaxHeapSize_ = std::max(InitHeapSize_, MaxHeapSize_); +}) + +#undef GC_FIELDS + +} // namespace vm +} // namespace hermes + +#endif // HERMES_PUBLIC_GCCONFIG_H diff --git a/NativeScript/napi/hermes/include_old/hermes/Public/GCTripwireContext.h b/NativeScript/napi/hermes/include_old/hermes/Public/GCTripwireContext.h new file mode 100644 index 00000000..4a8f500f --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/Public/GCTripwireContext.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_PUBLIC_GCTRIPWIRECONTEXT_H +#define HERMES_PUBLIC_GCTRIPWIRECONTEXT_H + +#include + +#include +#include +#include + +namespace hermes { +namespace vm { + +/// Interface passed to the GC tripwire callback when it fires. +class HERMES_EXPORT GCTripwireContext { + public: + virtual ~GCTripwireContext(); + + /// Captures the heap to a file. + /// \param path to save the heap capture. + /// \return Empty error code if the heap capture succeeded, else a real error + /// code. + virtual std::error_code createSnapshotToFile(const std::string &path) = 0; + + /// Captures the heap to a stream. + /// \param os stream to save the heap capture to. + /// \return Empty error code if the heap capture succeeded, else a real error + /// code. + virtual std::error_code createSnapshot( + std::ostream &os, + bool captureNumericValue) = 0; +}; + +} // namespace vm +} // namespace hermes + +#endif // HERMES_PUBLIC_GCTRIPWIRECONTEXT_H diff --git a/NativeScript/napi/hermes/include_old/hermes/Public/HermesExport.h b/NativeScript/napi/hermes/include_old/hermes/Public/HermesExport.h new file mode 100644 index 00000000..f9832cb5 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/Public/HermesExport.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_EXPORT +#ifdef _MSC_VER +#define HERMES_EXPORT __declspec(dllexport) +#else // _MSC_VER +#define HERMES_EXPORT __attribute__((visibility("default"))) +#endif // _MSC_VER +#endif // !defined(HERMES_EXPORT) diff --git a/NativeScript/napi/hermes/include_old/hermes/Public/JSOutOfMemoryError.h b/NativeScript/napi/hermes/include_old/hermes/Public/JSOutOfMemoryError.h new file mode 100644 index 00000000..95093ab7 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/Public/JSOutOfMemoryError.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_PUBLIC_JSOUTOFMEMORYERROR_H +#define HERMES_PUBLIC_JSOUTOFMEMORYERROR_H + +#include + +#include +#include + +namespace hermes { +namespace vm { + +/// A std::runtime_error class for out-of-memory. +class HERMES_EXPORT JSOutOfMemoryError : public std::runtime_error { + friend class GCBase; + JSOutOfMemoryError(const std::string &what_arg) + : std::runtime_error(what_arg) {} + ~JSOutOfMemoryError() override; +}; + +} // namespace vm +} // namespace hermes + +#endif // HERMES_PUBLIC_JSOUTOFMEMORYERROR_H diff --git a/NativeScript/napi/hermes/include_old/hermes/Public/RuntimeConfig.h b/NativeScript/napi/hermes/include_old/hermes/Public/RuntimeConfig.h new file mode 100644 index 00000000..858f1f50 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/Public/RuntimeConfig.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_PUBLIC_RUNTIMECONFIG_H +#define HERMES_PUBLIC_RUNTIMECONFIG_H + +#include "hermes/Public/CrashManager.h" +#include "hermes/Public/CtorConfig.h" +#include "hermes/Public/GCConfig.h" + +#include +#include + +namespace hermes { +namespace vm { + +enum CompilationMode { + SmartCompilation, + ForceEagerCompilation, + ForceLazyCompilation +}; + +enum class SynthTraceMode : int8_t { + None, + Replaying, + Tracing, + TracingAndReplaying, +}; + +class PinnedHermesValue; + +// Parameters for Runtime initialisation. Check documentation in README.md +// constexpr indicates that the default value is constexpr. +#define RUNTIME_FIELDS(F) \ + /* Parameters to be passed on to the GC. */ \ + F(HERMES_NON_CONSTEXPR, vm::GCConfig, GCConfig) \ + \ + /* Pre-allocated Register Stack */ \ + F(constexpr, PinnedHermesValue *, RegisterStack, nullptr) \ + \ + /* Register Stack Size */ \ + F(constexpr, unsigned, MaxNumRegisters, 128 * 1024) \ + \ + /* Native stack remaining before assuming overflow */ \ + F(constexpr, unsigned, NativeStackGap, 64 * 1024) \ + \ + /* Whether to allow eval and Function ctor */ \ + F(constexpr, bool, EnableEval, true) \ + \ + /* Whether to verify the IR generated by eval and Function ctor */ \ + F(constexpr, bool, VerifyEvalIR, false) \ + \ + /* Whether to optimize the code inside eval and Function ctor */ \ + F(constexpr, bool, OptimizedEval, false) \ + \ + /* Whether to emit async break check instructions in eval code */ \ + F(constexpr, bool, AsyncBreakCheckInEval, true) \ + \ + /* Support for ES6 Promise. */ \ + F(constexpr, bool, ES6Promise, true) \ + \ + /* Support for ES6 Proxy. */ \ + F(constexpr, bool, ES6Proxy, true) \ + \ + /* Support for ES6 Class. */ \ + F(constexpr, bool, ES6Class, false) \ + \ + /* Support for ECMA-402 Intl APIs. */ \ + F(constexpr, bool, Intl, true) \ + \ + /* Support for ArrayBuffer, DataView and typed arrays. */ \ + F(constexpr, bool, ArrayBuffer, true) \ + \ + /* Support for using microtasks. */ \ + F(constexpr, bool, MicrotaskQueue, false) \ + \ + /* Runtime set up for synth trace. */ \ + F(constexpr, SynthTraceMode, SynthTraceMode, SynthTraceMode::None) \ + \ + /* Enable sampling certain statistics. */ \ + F(constexpr, bool, EnableSampledStats, false) \ + \ + /* Whether to enable automatic sampling profiler registration */ \ + F(constexpr, bool, EnableSampleProfiling, false) \ + \ + /* Whether to randomize stack placement etc. */ \ + F(constexpr, bool, RandomizeMemoryLayout, false) \ + \ + /* Eagerly read bytecode into page cache. */ \ + F(constexpr, unsigned, BytecodeWarmupPercent, 0) \ + \ + /* Signal-based I/O tracking. Slows down execution. If enabled, */ \ + /* all bytecode buffers > 64 kB passed to Hermes must be mmap:ed. */ \ + F(constexpr, bool, TrackIO, false) \ + \ + /* Enable contents of HermesInternal */ \ + F(constexpr, bool, EnableHermesInternal, true) \ + \ + /* Enable methods exposed to JS for testing */ \ + F(constexpr, bool, EnableHermesInternalTestMethods, false) \ + \ + /* Choose lazy/eager compilation mode. */ \ + F(constexpr, \ + CompilationMode, \ + CompilationMode, \ + CompilationMode::SmartCompilation) \ + \ + /* Choose whether generators are enabled. */ \ + F(constexpr, bool, EnableGenerator, true) \ + \ + /* An interface for managing crashes. */ \ + F(HERMES_NON_CONSTEXPR, \ + std::shared_ptr, \ + CrashMgr, \ + new NopCrashManager) \ + \ + /* The flags passed from a VM experiment */ \ + F(constexpr, uint32_t, VMExperimentFlags, 0) \ + \ + /* Whether or not block scoping is enabled */ \ + F(constexpr, bool, EnableBlockScoping, false) \ + /* RUNTIME_FIELDS END */ + +_HERMES_CTORCONFIG_STRUCT(RuntimeConfig, RUNTIME_FIELDS, {}) + +#undef RUNTIME_FIELDS + +} // namespace vm +} // namespace hermes + +#endif // HERMES_PUBLIC_RUNTIMECONFIG_H diff --git a/NativeScript/napi/hermes/include_old/hermes/RuntimeTaskRunner.h b/NativeScript/napi/hermes/include_old/hermes/RuntimeTaskRunner.h new file mode 100644 index 00000000..367b267a --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/RuntimeTaskRunner.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_RUNTIMETASKRUNNER_H +#define HERMES_RUNTIMETASKRUNNER_H + +#include "AsyncDebuggerAPI.h" + +namespace facebook { +namespace hermes { +namespace debugger { + +using RuntimeTask = std::function; +using EnqueueRuntimeTaskFunc = std::function; + +enum class TaskQueues { + All, + Integrator, +}; + +/// Helper for users of AsyncDebuggerAPI that makes it easy to find the +/// earliest opportunity to use the runtime. There are two ways to become +/// the exclusive user of the runtime: +/// - Ask the AsyncDebuggerAPI to interrupt execution and provide a reference +/// to the runtime. Interrupting will only succeed when JavaScript is +/// running, so this method won't produce a prompt response if JavaScript is +/// not running. +/// - Ask the owner of the runtime to provide a reference to the runtime. If +/// the owner is currently running JavaScript (e.g. via a call to +/// evaluateJavaScript), this method won't produce a prompt response. +/// To cover both cases (when JavaScript is running, and when JavaScript isn't +/// running), this helper requests the runtime from both sources, executes the +/// task via the first responder, and sets a flag to indicate to the second +/// responder that nothing more needs to be done. +class RuntimeTaskRunner + : public std::enable_shared_from_this { + public: + RuntimeTaskRunner( + debugger::AsyncDebuggerAPI &debugger, + EnqueueRuntimeTaskFunc enqueueRuntimeTaskFunc); + ~RuntimeTaskRunner(); + + /// Schedule a task to be run with access to the runtime at the earliest + /// opportunity. Before returning, the task is added to the relevant task + /// queues managed by the \p AsyncDebuggerAPI and/or the intergator, with no + /// lingering references to the \p RuntimeTaskRunner. Thus, tasks can be + /// enqueued even if the task runner will be destroyed shortly after. + void enqueueTask(RuntimeTask task, TaskQueues queues = TaskQueues::All); + + private: + /// API where the runtime can be obtained when JavaScript is running. + debugger::AsyncDebuggerAPI &debugger_; + + /// Function provided by the integrator that enqueues a task to be run + /// when JavaScript is not running. + EnqueueRuntimeTaskFunc enqueueRuntimeTask_; +}; + +} // namespace debugger +} // namespace hermes +} // namespace facebook + +#endif // HERMES_RUNTIMETASKRUNNER_H diff --git a/NativeScript/napi/hermes/include/hermes/ScriptStore.h b/NativeScript/napi/hermes/include_old/hermes/ScriptStore.h similarity index 100% rename from NativeScript/napi/hermes/include/hermes/ScriptStore.h rename to NativeScript/napi/hermes/include_old/hermes/ScriptStore.h diff --git a/NativeScript/napi/hermes/include_old/hermes/SynthTrace.h b/NativeScript/napi/hermes/include_old/hermes/SynthTrace.h new file mode 100644 index 00000000..f8d174c8 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/SynthTrace.h @@ -0,0 +1,1316 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_SYNTHTRACE_H +#define HERMES_SYNTHTRACE_H + +#include "hermes/Public/RuntimeConfig.h" +#include "hermes/Support/JSONEmitter.h" +#include "hermes/Support/SHA1.h" +#include "hermes/Support/StringSetVector.h" +#include "hermes/VM/GCExecTrace.h" + +#include +#include +#include +#include +#include +#include + +namespace llvh { +// Forward declaration to avoid including llvm headers. +class raw_ostream; +} // namespace llvh + +namespace facebook { +namespace hermes { +namespace tracing { + +/// A SynthTrace is a list of events that occur in a run of a JS file by a +/// runtime that uses JSI. +/// It can be serialized into JSON and written to a llvh::raw_ostream. +class SynthTrace { + public: + using ObjectID = uint64_t; + + /// A tagged union representing different types available in the trace. + /// We use a an API very similar to HermesValue, but: + /// a) also represent the JSI type PropNameID, and + /// b) the "payloads" for some the types (Objects, Strings, BigInts, Symbols + /// and PropNameIDs) are unique ObjectIDs, rather than actual values. + /// (This could probably become a std::variant when we could use C++17.) + class TraceValue { + public: + bool isUndefined() const { + return tag_ == Tag::Undefined; + } + + bool isNull() const { + return tag_ == Tag::Null; + } + + bool isNumber() const { + return tag_ == Tag::Number; + } + + bool isBool() const { + return tag_ == Tag::Bool; + } + + bool isObject() const { + return tag_ == Tag::Object; + } + + bool isBigInt() const { + return tag_ == Tag::BigInt; + } + + bool isString() const { + return tag_ == Tag::String; + } + + bool isPropNameID() const { + return tag_ == Tag::PropNameID; + } + + bool isSymbol() const { + return tag_ == Tag::Symbol; + } + + bool isUID() const { + return isObject() || isBigInt() || isString() || isPropNameID() || + isSymbol(); + } + + static TraceValue encodeUndefinedValue() { + return TraceValue(Tag::Undefined); + } + + static TraceValue encodeNullValue() { + return TraceValue(Tag::Null); + } + + static TraceValue encodeBoolValue(bool value) { + return TraceValue(value); + } + + static TraceValue encodeNumberValue(double value) { + return TraceValue(value); + } + + static TraceValue encodeObjectValue(uint64_t uid) { + return TraceValue(Tag::Object, uid); + } + + static TraceValue encodeBigIntValue(uint64_t uid) { + return TraceValue(Tag::BigInt, uid); + } + + static TraceValue encodeStringValue(uint64_t uid) { + return TraceValue(Tag::String, uid); + } + + static TraceValue encodePropNameIDValue(uint64_t uid) { + return TraceValue(Tag::PropNameID, uid); + } + + static TraceValue encodeSymbolValue(uint64_t uid) { + return TraceValue(Tag::Symbol, uid); + } + + bool operator==(const TraceValue &that) const; + + ObjectID getUID() const { + assert(isUID()); + return val_.uid; + } + + bool getBool() const { + assert(isBool()); + return val_.b; + } + + double getNumber() const { + assert(isNumber()); + return val_.n; + } + + private: + enum class Tag { + Undefined, + Null, + Bool, + Number, + Object, + String, + PropNameID, + Symbol, + BigInt, + }; + + explicit TraceValue(Tag tag) : tag_(tag) {} + TraceValue(bool b) : tag_(Tag::Bool) { + val_.b = b; + } + TraceValue(double n) : tag_(Tag::Number) { + val_.n = n; + } + TraceValue(Tag tag, uint64_t uid) : tag_(tag) { + val_.uid = uid; + } + + Tag tag_; + union { + bool b; + double n; + ObjectID uid; + } val_; + }; + + /// A TimePoint is a time when some event occurred. + using TimePoint = std::chrono::steady_clock::time_point; + using TimeSinceStart = std::chrono::milliseconds; + +#define SYNTH_TRACE_RECORD_TYPES(RECORD) \ + RECORD(BeginExecJS) \ + RECORD(EndExecJS) \ + RECORD(Marker) \ + RECORD(CreateObject) \ + RECORD(CreateString) \ + RECORD(CreatePropNameID) \ + RECORD(CreateHostObject) \ + RECORD(CreateHostFunction) \ + RECORD(QueueMicrotask) \ + RECORD(DrainMicrotasks) \ + RECORD(GetProperty) \ + RECORD(SetProperty) \ + RECORD(HasProperty) \ + RECORD(GetPropertyNames) \ + RECORD(CreateArray) \ + RECORD(ArrayRead) \ + RECORD(ArrayWrite) \ + RECORD(CallFromNative) \ + RECORD(ConstructFromNative) \ + RECORD(ReturnFromNative) \ + RECORD(ReturnToNative) \ + RECORD(CallToNative) \ + RECORD(GetPropertyNative) \ + RECORD(GetPropertyNativeReturn) \ + RECORD(SetPropertyNative) \ + RECORD(SetPropertyNativeReturn) \ + RECORD(GetNativePropertyNames) \ + RECORD(GetNativePropertyNamesReturn) \ + RECORD(CreateBigInt) \ + RECORD(BigIntToString) \ + RECORD(SetExternalMemoryPressure) \ + RECORD(Utf8) \ + RECORD(Global) + + /// RecordType is a tag used to differentiate which type of record it is. + /// There should be a unique tag for each record type. + enum class RecordType { +#define RECORD(name) name, + SYNTH_TRACE_RECORD_TYPES(RECORD) +#undef RECORD + }; + + /// A Record is one element of a trace. + struct Record { + /// The time at which this event occurred with respect to the start of + /// execution. + /// NOTE: This is not compared in the \c operator= in order for tests to + /// pass. + const TimeSinceStart time_; + explicit Record() = delete; + explicit Record(TimeSinceStart time) : time_(time) {} + virtual ~Record() = default; + + /// Write out a serialization of this Record. + /// \param json An emitter connected to an ostream which will write out + /// JSON. + void toJSON(::hermes::JSONEmitter &json) const; + virtual RecordType getType() const = 0; + + // If \p val is an object (that is, an Object or String), push its + // decoding onto objs. + static void pushIfTrackedValue( + const TraceValue &val, + std::vector &objs) { + if (val.isUID()) { + objs.push_back(val.getUID()); + } + } + + /// \return A list of object ids that are defined by this record. + /// Defined means that the record would produce that object, + /// string, or PropNameID as a locally accessible value if it were + /// executed. + virtual std::vector defs() const { + return {}; + } + + /// \return A list of object ids that are used by this record. + /// Used means that the record would use that object, string, or + /// PropNameID as a value if it were executed. + /// If a record uses an object id, then some preceding record + /// (either in the same function invocation, or somewhere + /// globally) must provide a definition. + virtual std::vector uses() const { + return {}; + } + + protected: + /// Emit JSON fields into \p os, excluding the closing curly brace. + /// NOTE: This is overridable, and non-abstract children should call the + /// parent. + virtual void toJSONInternal(::hermes::JSONEmitter &json) const; + }; + + /// If \p traceStream is non-null, the trace will be written to that + /// stream. Otherwise, no trace is written. + explicit SynthTrace( + const ::hermes::vm::RuntimeConfig &conf, + std::unique_ptr traceStream = nullptr, + std::optional = {}); + + template + void emplace_back(Args &&...args) { + records_.emplace_back(new T(std::forward(args)...)); + flushRecordsIfNecessary(); + } + + const std::vector> &records() const { + return records_; + } + + std::optional globalObjID() const { + return globalObjID_; + } + + /// Given a trace value, turn it into its typed string. + static std::string encode(TraceValue value); + /// Encode an undefined JS value for the trace. + static TraceValue encodeUndefined(); + /// Encode a null JS value for the trace. + static TraceValue encodeNull(); + /// Encode a boolean JS value for the trace. + static TraceValue encodeBool(bool value); + /// Encodes a numeric value for the trace. + static TraceValue encodeNumber(double value); + /// Encodes an object for the trace as a unique id. + static TraceValue encodeObject(ObjectID objID); + /// Encodes a bigint for the trace as a unique id. + static TraceValue encodeBigInt(ObjectID objID); + /// Encodes a string for the trace as a unique id. + static TraceValue encodeString(ObjectID objID); + /// Encodes a PropNameID for the trace as a unique id. + static TraceValue encodePropNameID(ObjectID objID); + /// Encodes a Symbol for the trace as a unique id. + static TraceValue encodeSymbol(ObjectID objID); + + /// Decodes a string into a trace value. + static TraceValue decode(const std::string &); + + /// The version of the Synth Benchmark + constexpr static uint32_t synthVersion() { + return 4; + } + + static const char *nameFromReleaseUnused(::hermes::vm::ReleaseUnused ru); + static ::hermes::vm::ReleaseUnused releaseUnusedFromName(const char *name); + + private: + llvh::raw_ostream &os() const { + return (*traceStream_); + } + + /// If we're tracing to a file, and the number of accumulated + /// records has reached the limit kTraceRecordsToFlush, below, + /// flush the records to the file, and reset the accumulated records + /// to be empty. + void flushRecordsIfNecessary(); + + /// Assumes we're tracing to a file; flush accumulated records to + /// the file, and reset the accumulated records to be empty. + void flushRecords(); + + static constexpr unsigned kTraceRecordsToFlush = 100; + + /// If we're tracing to a file, pointer to a stream onto + /// traceFilename_. Null otherwise. + std::unique_ptr traceStream_; + /// If we're tracing to a file, pointer to a JSONEmitter writting + /// into *traceStream_. Null otherwise. + std::unique_ptr<::hermes::JSONEmitter> json_; + /// The records currently being accumulated in the trace. If we are + /// tracing to a file, these will be only the records not yet + /// written to the file. + std::vector> records_; + /// The id of the global object. + /// Note: Keeping this as optional to support replaying the older trace + /// records before the change of TracingRuntime's PointerValue based ObjectID. + /// We can remove this once we remove old traces. + /// TODO: T189113203 + const std::optional globalObjID_; + + public: + /// @name Record classes + /// @{ + + /// A MarkerRecord is an event that simply records an interesting event that + /// is not necessarily meaningful to the interpreter. It comes with a tag that + /// says what type of marker it was. + struct MarkerRecord : public Record { + static constexpr RecordType type{RecordType::Marker}; + const std::string tag_; + explicit MarkerRecord(TimeSinceStart time, const std::string &tag) + : Record(time), tag_(tag) {} + RecordType getType() const override { + return type; + } + + protected: + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + + /// A BeginExecJSRecord is an event where execution begins of JS source + /// code. This is not necessarily the first record, since native code can + /// inject values into the VM before any source code is run. + struct BeginExecJSRecord final : public Record { + static constexpr RecordType type{RecordType::BeginExecJS}; + explicit BeginExecJSRecord( + TimeSinceStart time, + std::string sourceURL, + ::hermes::SHA1 sourceHash, + bool sourceIsBytecode) + : Record(time), + sourceURL_(std::move(sourceURL)), + sourceHash_(std::move(sourceHash)), + sourceIsBytecode_(sourceIsBytecode) {} + + RecordType getType() const override { + return type; + } + + const std::string &sourceURL() const { + return sourceURL_; + } + + const ::hermes::SHA1 &sourceHash() const { + return sourceHash_; + } + + private: + void toJSONInternal(::hermes::JSONEmitter &json) const override; + + /// The URL providing the source file mapping for the file being executed. + /// Can be empty. + std::string sourceURL_; + + /// A hash of the source that was executed. The source hash must match up + /// when the file is replayed. + /// The hash is optional, and will be all zeros if not provided. + ::hermes::SHA1 sourceHash_; + + /// Whether the input file was source or bytecode. + bool sourceIsBytecode_; + }; + + struct ReturnMixin { + const TraceValue retVal_; + + explicit ReturnMixin(TraceValue value) : retVal_(value) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const; + }; + + /// A EndExecJSRecord is an event where execution of JS source code stops. + /// This does not mean that the source code will never be entered again, just + /// that it has an entered a phase where it is waiting for native code to call + /// into the JS. This event is not guaranteed to be the last event, for the + /// aforementioned reason. The logged retVal is the result of the evaluation + /// ("undefined" in the majority of cases). + struct EndExecJSRecord final : public MarkerRecord, public ReturnMixin { + static constexpr RecordType type{RecordType::EndExecJS}; + EndExecJSRecord(TimeSinceStart time, TraceValue retVal) + : MarkerRecord(time, "end_global_code"), ReturnMixin(retVal) {} + + RecordType getType() const override { + return type; + } + virtual void toJSONInternal(::hermes::JSONEmitter &json) const final; + std::vector defs() const override { + auto defs = MarkerRecord::defs(); + pushIfTrackedValue(retVal_, defs); + return defs; + } + }; + + /// A CreateObjectRecord is an event where an empty object is created by the + /// native code. + struct CreateObjectRecord : public Record { + static constexpr RecordType type{RecordType::CreateObject}; + /// The ObjectID of the object that was created by native function calls + /// like Runtime::createObject(). + const ObjectID objID_; + + explicit CreateObjectRecord(TimeSinceStart time, ObjectID objID) + : Record(time), objID_(objID) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + RecordType getType() const override { + return type; + } + + std::vector defs() const override { + return {objID_}; + } + + std::vector uses() const override { + return {}; + } + }; + + /// A CreateBigIntRecord is an event where a jsi::BigInt (and thus a + /// Hermes BigIntPrimitive) is created by the native code. + struct CreateBigIntRecord : public Record { + static constexpr RecordType type{RecordType::CreateBigInt}; + /// The ObjectID of the BigInt that was created by + /// Runtime::createBigIntFromInt64() or Runtime::createBigIntFromUint64(). + const ObjectID objID_; + enum class Method { + FromInt64, + FromUint64, + }; + /// The method used for creating the BigInt. + Method method_; + /// The value used for creating the BigInt. + uint64_t bits_; + + CreateBigIntRecord( + TimeSinceStart time, + ObjectID objID, + Method m, + uint64_t bits) + : Record(time), objID_(objID), method_(m), bits_(bits) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + + RecordType getType() const override { + return type; + } + + std::vector defs() const override { + return {objID_}; + } + + std::vector uses() const override { + return {}; + } + }; + + /// A BigIntToStringRecord is an event where a jsi::BigInt is converted to a + /// string by native code + struct BigIntToStringRecord : public Record { + static constexpr RecordType type{RecordType::BigIntToString}; + /// The ObjectID of the string that was returned from + /// Runtime::bigintToString(). + const ObjectID strID_; + /// The ObjectID of the BigInt that was passed to Runtime::bigintToString(). + const ObjectID bigintID_; + /// The radix used for converting the BigInt to a string. + int radix_; + + BigIntToStringRecord( + TimeSinceStart time, + ObjectID strID, + ObjectID bigintID, + int radix) + : Record(time), strID_(strID), bigintID_(bigintID), radix_(radix) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + + RecordType getType() const override { + return type; + } + + std::vector defs() const override { + return {strID_}; + } + + std::vector uses() const override { + return {bigintID_}; + } + }; + + /// A CreateStringRecord is an event where a jsi::String (and thus a + /// Hermes StringPrimitive) is created by the native code. + struct CreateStringRecord : public Record { + static constexpr RecordType type{RecordType::CreateString}; + /// The ObjectID of the string that was created by + /// Runtime::createStringFromAscii() or Runtime::createStringFromUtf8(). + const ObjectID objID_; + /// The string that was passed to Runtime::createStringFromAscii() or + /// Runtime::createStringFromUtf8() when the string was created. + std::string chars_; + /// Whether the string was created from ASCII (true) or UTF8 (false). + bool ascii_; + + // General UTF-8. + CreateStringRecord( + TimeSinceStart time, + ObjectID objID, + const uint8_t *chars, + size_t length) + : Record(time), + objID_(objID), + chars_(reinterpret_cast(chars), length), + ascii_(false) {} + // Ascii. + CreateStringRecord( + TimeSinceStart time, + ObjectID objID, + const char *chars, + size_t length) + : Record(time), objID_(objID), chars_(chars, length), ascii_(true) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + RecordType getType() const override { + return type; + } + + std::vector defs() const override { + return {objID_}; + } + + std::vector uses() const override { + return {}; + } + }; + + /// A CreatePropNameIDRecord is an event where a jsi::PropNameID is + /// created by the native code. + struct CreatePropNameIDRecord : public Record { + static constexpr RecordType type{RecordType::CreatePropNameID}; + /// The ObjectID of the PropNameID that was created by + /// Runtime::createPropNameIDFromXxx() functions. + const ObjectID propNameID_; + /// The string that was passed to Runtime::createPropNameIDFromAscii() or + /// Runtime::createPropNameIDFromUtf8(). + std::string chars_; + /// The String for Symbol that was passed to + /// Runtime::createPropNameIDFromString() or + /// Runtime::createPropNameIDFromSymbol(). + const TraceValue traceValue_{TraceValue::encodeUndefinedValue()}; + /// Whether the PropNameID was created from ASCII, UTF8, jsi::String + /// (TRACEVALUE) or jsi::Symbol (TRACEVALUE). + enum ValueType { ASCII, UTF8, TRACEVALUE } valueType_; + + // General UTF-8. + CreatePropNameIDRecord( + TimeSinceStart time, + ObjectID propNameID, + const uint8_t *chars, + size_t length) + : Record(time), + propNameID_(propNameID), + chars_(reinterpret_cast(chars), length), + valueType_(UTF8) {} + // Ascii. + CreatePropNameIDRecord( + TimeSinceStart time, + ObjectID propNameID, + const char *chars, + size_t length) + : Record(time), + propNameID_(propNameID), + chars_(chars, length), + valueType_(ASCII) {} + // jsi::String or jsi::Symbol. + CreatePropNameIDRecord( + TimeSinceStart time, + ObjectID propNameID, + TraceValue traceValue) + : Record(time), + propNameID_(propNameID), + traceValue_(traceValue), + valueType_(TRACEVALUE) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + RecordType getType() const override { + return type; + } + + std::vector defs() const override { + return {propNameID_}; + } + + std::vector uses() const override { + std::vector vec; + pushIfTrackedValue(traceValue_, vec); + return vec; + } + }; + + struct CreateHostObjectRecord final : public CreateObjectRecord { + static constexpr RecordType type{RecordType::CreateHostObject}; + using CreateObjectRecord::CreateObjectRecord; + RecordType getType() const override { + return type; + } + }; + + struct CreateHostFunctionRecord final : public CreateObjectRecord { + static constexpr RecordType type{RecordType::CreateHostFunction}; + /// The ObjectID of the PropNameID that was passed to + /// Runtime::createFromHostFunction(). + uint32_t propNameID_; +#ifdef HERMESVM_API_TRACE_DEBUG + const std::string functionName_; +#endif + /// The number of parameters that the created host function takes. + const unsigned paramCount_; + + CreateHostFunctionRecord( + TimeSinceStart time, + ObjectID objID, + ObjectID propNameID, +#ifdef HERMESVM_API_TRACE_DEBUG + std::string functionName, +#endif + unsigned paramCount) + : CreateObjectRecord(time, objID), + propNameID_(propNameID), +#ifdef HERMESVM_API_TRACE_DEBUG + functionName_(std::move(functionName)), +#endif + paramCount_(paramCount) { + } + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + + RecordType getType() const override { + return type; + } + + std::vector uses() const override { + return {propNameID_}; + } + }; + + struct QueueMicrotaskRecord : public Record { + static constexpr RecordType type{RecordType::QueueMicrotask}; + /// The ObjectID of the callback function that was queued. + const ObjectID callbackID_; + + QueueMicrotaskRecord(TimeSinceStart time, ObjectID callbackID) + : Record(time), callbackID_(callbackID) {} + + RecordType getType() const override { + return type; + } + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + + std::vector uses() const override { + return {callbackID_}; + } + }; + + struct DrainMicrotasksRecord : public Record { + static constexpr RecordType type{RecordType::DrainMicrotasks}; + /// maxMicrotasksHint value passed to Runtime::drainMicrotasks() call. + int maxMicrotasksHint_; + + DrainMicrotasksRecord(TimeSinceStart time, int tasksHint = -1) + : Record(time), maxMicrotasksHint_(tasksHint) {} + + RecordType getType() const override { + return type; + } + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + + /// A GetPropertyRecord is an event where native code accesses the property + /// of a JS object. + struct GetPropertyRecord : public Record { + /// The ObjectID of the object that was accessed for its property. + const ObjectID objID_; + /// String or PropNameID passed to getProperty. + const TraceValue propID_; +#ifdef HERMESVM_API_TRACE_DEBUG + std::string propNameDbg_; +#endif + + GetPropertyRecord( + TimeSinceStart time, + ObjectID objID, + TraceValue propID +#ifdef HERMESVM_API_TRACE_DEBUG + , + const std::string &propNameDbg +#endif + ) + : Record(time), + objID_(objID), + propID_(propID) +#ifdef HERMESVM_API_TRACE_DEBUG + , + propNameDbg_(propNameDbg) +#endif + { + } + + static constexpr RecordType type{RecordType::GetProperty}; + RecordType getType() const override { + return type; + } + + std::vector uses() const override { + std::vector uses{objID_}; + pushIfTrackedValue(propID_, uses); + return uses; + } + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + + /// A SetPropertyRecord is an event where native code writes to the property + /// of a JS object. + struct SetPropertyRecord : public Record { + /// The ObjectID of the object that was accessed for its property. + const ObjectID objID_; + /// String or PropNameID passed to setProperty. + const TraceValue propID_; +#ifdef HERMESVM_API_TRACE_DEBUG + std::string propNameDbg_; +#endif + /// The value being assigned. + const TraceValue value_; + + SetPropertyRecord( + TimeSinceStart time, + ObjectID objID, + TraceValue propID, +#ifdef HERMESVM_API_TRACE_DEBUG + const std::string &propNameDbg, +#endif + TraceValue value) + : Record(time), + objID_(objID), + propID_(propID), +#ifdef HERMESVM_API_TRACE_DEBUG + propNameDbg_(propNameDbg), +#endif + value_(value) { + } + + static constexpr RecordType type{RecordType::SetProperty}; + RecordType getType() const override { + return type; + } + + std::vector uses() const override { + std::vector uses{objID_}; + pushIfTrackedValue(propID_, uses); + pushIfTrackedValue(value_, uses); + return uses; + } + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + + /// A HasPropertyRecord is an event where native code queries whether a + /// property exists on an object. (We don't care about the result because + /// it cannot influence the trace.) + struct HasPropertyRecord final : public Record { + static constexpr RecordType type{RecordType::HasProperty}; + /// The ObjectID of the object that was accessed for its property. + const ObjectID objID_; +#ifdef HERMESVM_API_TRACE_DEBUG + std::string propNameDbg_; +#endif + /// The property name that was passed to hasProperty(). + const TraceValue propID_; + + HasPropertyRecord( + TimeSinceStart time, + ObjectID objID, + TraceValue propID +#ifdef HERMESVM_API_TRACE_DEBUG + , + const std::string &propNameDbg +#endif + ) + : Record(time), + objID_(objID), +#ifdef HERMESVM_API_TRACE_DEBUG + propNameDbg_(propNameDbg), +#endif + propID_(propID) { + } + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + RecordType getType() const override { + return type; + } + std::vector uses() const override { + std::vector vec{objID_}; + pushIfTrackedValue(propID_, vec); + return vec; + } + }; + + struct GetPropertyNamesRecord final : public Record { + static constexpr RecordType type{RecordType::GetPropertyNames}; + /// The ObjectID of the object that was accessed for its property. + const ObjectID objID_; + + explicit GetPropertyNamesRecord(TimeSinceStart time, ObjectID objID) + : Record(time), objID_(objID) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + RecordType getType() const override { + return type; + } + std::vector uses() const override { + return {objID_}; + } + }; + + /// A CreateArrayRecord is an event where a new array is created of a specific + /// length. + struct CreateArrayRecord final : public Record { + static constexpr RecordType type{RecordType::CreateArray}; + /// The ObjectID of the array that was created by the createArray(). + const ObjectID objID_; + /// The length of the array that was passed to createArray(). + const size_t length_; + + explicit CreateArrayRecord( + TimeSinceStart time, + ObjectID objID, + size_t length) + : Record(time), objID_(objID), length_(length) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + RecordType getType() const override { + return type; + } + std::vector defs() const override { + return {objID_}; + } + }; + + /// An ArrayReadRecord is an event where a value was read from an index + /// of an array. + /// It is modeled separately from GetProperty because it is more efficient to + /// read from a numeric index on an array than a string. + struct ArrayReadRecord final : public Record { + /// The ObjectID of the array that was accessed. + const ObjectID objID_; + /// The index of the element that was accessed in the array. + const size_t index_; + + explicit ArrayReadRecord(TimeSinceStart time, ObjectID objID, size_t index) + : Record(time), objID_(objID), index_(index) {} + + static constexpr RecordType type{RecordType::ArrayRead}; + RecordType getType() const override { + return type; + } + std::vector uses() const override { + return {objID_}; + } + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + + /// An ArrayWriteRecord is an event where a value was written into an index + /// of an array. + struct ArrayWriteRecord final : public Record { + /// The ObjectID of the array that was accessed. + const ObjectID objID_; + /// The index of the element that was accessed in the array. + const size_t index_; + /// The value that was written to the array. + const TraceValue value_; + + explicit ArrayWriteRecord( + TimeSinceStart time, + ObjectID objID, + size_t index, + TraceValue value) + : Record(time), objID_(objID), index_(index), value_(value) {} + + static constexpr RecordType type{RecordType::ArrayWrite}; + RecordType getType() const override { + return type; + } + std::vector uses() const override { + std::vector uses{objID_}; + pushIfTrackedValue(value_, uses); + return uses; + } + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + + struct CallRecord : public Record { + /// The ObjectID of the function JS object that was called from + /// JS or native. + const ObjectID functionID_; + /// The value of the this argument passed to the function call. + const TraceValue thisArg_; + /// The arguments given to a call (excluding the this parameter), + /// already JSON stringified. + const std::vector args_; + + explicit CallRecord( + TimeSinceStart time, + ObjectID functionID, + TraceValue thisArg, + const std::vector &args) + : Record(time), + functionID_(functionID), + thisArg_(thisArg), + args_(args) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + std::vector uses() const override { + // The function is used regardless of direction. + return {functionID_}; + } + + protected: + std::vector getArgTrackedIDs() const { + std::vector objs; + pushIfTrackedValue(thisArg_, objs); + for (const auto &arg : args_) { + pushIfTrackedValue(arg, objs); + } + return objs; + } + }; + + /// A CallFromNativeRecord is an event where native code calls into a JS + /// function. + struct CallFromNativeRecord : public CallRecord { + static constexpr RecordType type{RecordType::CallFromNative}; + using CallRecord::CallRecord; + RecordType getType() const override { + return type; + } + std::vector uses() const override { + auto uses = CallRecord::uses(); + auto objs = CallRecord::getArgTrackedIDs(); + uses.insert(uses.end(), objs.begin(), objs.end()); + return uses; + } + }; + + /// A ConstructFromNativeRecord is the same as \c CallFromNativeRecord, except + /// the function is called with the new operator. + struct ConstructFromNativeRecord final : public CallFromNativeRecord { + static constexpr RecordType type{RecordType::ConstructFromNative}; + using CallFromNativeRecord::CallFromNativeRecord; + RecordType getType() const override { + return type; + } + }; + + /// A ReturnFromNativeRecord is an event where a native function returns to a + /// JS caller. + /// It pairs with \c CallToNativeRecord. + struct ReturnFromNativeRecord final : public Record, public ReturnMixin { + static constexpr RecordType type{RecordType::ReturnFromNative}; + ReturnFromNativeRecord(TimeSinceStart time, TraceValue retVal) + : Record(time), ReturnMixin(retVal) {} + RecordType getType() const override { + return type; + } + std::vector uses() const override { + auto uses = Record::uses(); + pushIfTrackedValue(retVal_, uses); + return uses; + } + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + + /// A ReturnToNativeRecord is an event where a JS function returns to a native + /// caller. + /// It pairs with \c CallFromNativeRecord. + struct ReturnToNativeRecord final : public Record, public ReturnMixin { + static constexpr RecordType type{RecordType::ReturnToNative}; + ReturnToNativeRecord(TimeSinceStart time, TraceValue retVal) + : Record(time), ReturnMixin(retVal) {} + RecordType getType() const override { + return type; + } + std::vector defs() const override { + auto defs = Record::defs(); + pushIfTrackedValue(retVal_, defs); + return defs; + } + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + + /// A CallToNativeRecord is an event where JS code calls into a natively + /// defined function. + struct CallToNativeRecord final : public CallRecord { + static constexpr RecordType type{RecordType::CallToNative}; + using CallRecord::CallRecord; + RecordType getType() const override { + return type; + } + std::vector defs() const override { + auto defs = CallRecord::defs(); + auto objs = CallRecord::getArgTrackedIDs(); + defs.insert(defs.end(), objs.begin(), objs.end()); + return defs; + } + }; + + struct GetOrSetPropertyNativeRecord : public Record { + /// The ObjectID of the host object that was being accessed for its + /// property. + const ObjectID hostObjectID_; + /// The ObjectID of the PropNameID that was passed to HostObject::get() + /// or HostObject::set(). + const ObjectID propNameID_; + /// The UTF-8 string of the PropNameID that was passed to HostObject::get() + /// or HostObject::set(). + const std::string propName_; + + GetOrSetPropertyNativeRecord( + TimeSinceStart time, + ObjectID hostObjectID, + ObjectID propNameID, + const std::string &propName) + : Record(time), + hostObjectID_(hostObjectID), + propNameID_(propNameID), + propName_(propName) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + std::vector defs() const override { + return {propNameID_}; + } + std::vector uses() const override { + return {hostObjectID_}; + } + + protected: + }; + + /// A GetPropertyNativeRecord is an event where JS tries to access a property + /// on a native object. + /// This needs to be modeled as a call with no arguments, since native code + /// can arbitrarily affect the JS heap during the accessor. + struct GetPropertyNativeRecord final : public GetOrSetPropertyNativeRecord { + static constexpr RecordType type{RecordType::GetPropertyNative}; + using GetOrSetPropertyNativeRecord::GetOrSetPropertyNativeRecord; + RecordType getType() const override { + return type; + } + }; + + struct GetPropertyNativeReturnRecord final : public Record, + public ReturnMixin { + static constexpr RecordType type{RecordType::GetPropertyNativeReturn}; + GetPropertyNativeReturnRecord(TimeSinceStart time, TraceValue retVal) + : Record(time), ReturnMixin(retVal) {} + RecordType getType() const override { + return type; + } + std::vector uses() const override { + auto uses = Record::uses(); + pushIfTrackedValue(retVal_, uses); + return uses; + } + + protected: + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + + /// A SetPropertyNativeRecord is an event where JS code writes to the property + /// of a Native object. + /// This needs to be modeled as a call with one argument, since native code + /// can arbitrarily affect the JS heap during the accessor. + struct SetPropertyNativeRecord final : public GetOrSetPropertyNativeRecord { + static constexpr RecordType type{RecordType::SetPropertyNative}; + /// The value that was passed to HostObject::set() call. + TraceValue value_; + + SetPropertyNativeRecord( + TimeSinceStart time, + ObjectID hostObjectID, + ObjectID propNameID, + const std::string &propName, + TraceValue value) + : GetOrSetPropertyNativeRecord( + time, + hostObjectID, + propNameID, + propName), + value_(value) {} + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + RecordType getType() const override { + return type; + } + std::vector defs() const override { + auto defs = GetOrSetPropertyNativeRecord::defs(); + pushIfTrackedValue(value_, defs); + return defs; + } + }; + + /// A SetPropertyNativeReturnRecord needs to record no extra information + struct SetPropertyNativeReturnRecord final : public Record { + static constexpr RecordType type{RecordType::SetPropertyNativeReturn}; + using Record::Record; + RecordType getType() const override { + return type; + } + }; + + /// A GetNativePropertyNamesRecord records an event where JS asked for a list + /// of property names available on a host object. It records the object, and + /// the returned list of property names. + struct GetNativePropertyNamesRecord : public Record { + static constexpr RecordType type{RecordType::GetNativePropertyNames}; + /// The ObjectID of the host object that was being accessed for + /// HostObjet::getPropertyNames() call. + const ObjectID hostObjectID_; + + explicit GetNativePropertyNamesRecord( + TimeSinceStart time, + ObjectID hostObjectID) + : Record(time), hostObjectID_(hostObjectID) {} + + RecordType getType() const override { + return type; + } + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + + std::vector uses() const override { + return {hostObjectID_}; + } + }; + + /// A GetNativePropertyNamesReturnRecord records what property names were + /// returned by the GetNativePropertyNames query. + struct GetNativePropertyNamesReturnRecord final : public Record { + static constexpr RecordType type{RecordType::GetNativePropertyNamesReturn}; + + /// Returned list of property names + const std::vector propNameIDs_; + + explicit GetNativePropertyNamesReturnRecord( + TimeSinceStart time, + const std::vector &propNameIDs) + : Record(time), propNameIDs_(propNameIDs) {} + + RecordType getType() const override { + return type; + } + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + + std::vector uses() const override { + auto uses = Record::uses(); + for (const auto &val : propNameIDs_) { + pushIfTrackedValue(val, uses); + } + return uses; + } + }; + + struct SetExternalMemoryPressureRecord final : public Record { + static constexpr RecordType type{RecordType::SetExternalMemoryPressure}; + /// The ObjectID of the object that was passed to + /// Runtime::setExternalMemoryPressure() call. + const ObjectID objID_; + /// The value passed to Runtime::setExternalMemoryPressure() call. + const size_t amount_; + + explicit SetExternalMemoryPressureRecord( + TimeSinceStart time, + const ObjectID objID, + const size_t amount) + : Record(time), objID_(objID), amount_(amount) {} + + RecordType getType() const override { + return type; + } + + std::vector uses() const override { + return {objID_}; + } + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + + /// An Utf8Record is an event where a PropNameID or String or Symbol was + /// converted to utf8. + struct Utf8Record final : public Record { + static constexpr RecordType type{RecordType::Utf8}; + /// PropNameID, String or Symbol passed to utf8() or symbolToString() as an + /// argument + const TraceValue objID_; + /// Returned string from utf8() or symbolToString() + const std::string retVal_; + + explicit Utf8Record( + TimeSinceStart time, + const TraceValue objID, + std::string retval) + : Record(time), objID_(objID), retVal_(std::move(retval)) {} + + RecordType getType() const override { + return type; + } + + std::vector uses() const override { + std::vector vec; + pushIfTrackedValue(objID_, vec); + return vec; + } + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + + struct GlobalRecord final : public Record { + static constexpr RecordType type{RecordType::Global}; + const ObjectID objID_; // global's ObjectID returned from Runtime::global(). + + explicit GlobalRecord(TimeSinceStart time, ObjectID objID) + : Record(time), objID_(objID) {} + + RecordType getType() const override { + return type; + } + + std::vector defs() const override { + return {objID_}; + } + + void toJSONInternal(::hermes::JSONEmitter &json) const override; + }; + + /// Completes writing of the trace to the trace stream. If writing + /// to a file, disables further writing to the file, or accumulation + /// of data. + void flushAndDisable(const ::hermes::vm::GCExecTrace &gcTrace); +}; + +} // namespace tracing +} // namespace hermes +} // namespace facebook + +#endif // HERMES_SYNTHTRACE_H diff --git a/NativeScript/napi/hermes/include_old/hermes/SynthTraceParser.h b/NativeScript/napi/hermes/include_old/hermes/SynthTraceParser.h new file mode 100644 index 00000000..7844ee50 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/SynthTraceParser.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_SYNTHTRACEPARSER_H +#define HERMES_SYNTHTRACEPARSER_H + +#include + +#include "hermes/Public/RuntimeConfig.h" +#include "hermes/SynthTrace.h" + +#include "llvh/Support/MemoryBuffer.h" + +namespace facebook { +namespace hermes { +namespace tracing { + +/// Parse a trace from a JSON string stored in a MemoryBuffer. +std::tuple< + SynthTrace, + ::hermes::vm::RuntimeConfig::Builder, + ::hermes::vm::GCConfig::Builder> +parseSynthTrace(std::unique_ptr trace); + +/// Parse a trace from a JSON string stored in the given file name. +std::tuple< + SynthTrace, + ::hermes::vm::RuntimeConfig::Builder, + ::hermes::vm::GCConfig::Builder> +parseSynthTrace(const std::string &tracefile); + +} // namespace tracing +} // namespace hermes +} // namespace facebook + +#endif // HERMES_SYNTHTRACEPARSER_H diff --git a/NativeScript/napi/hermes/include_old/hermes/ThreadSafetyAnalysis.h b/NativeScript/napi/hermes/include_old/hermes/ThreadSafetyAnalysis.h new file mode 100644 index 00000000..39e6cf66 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/ThreadSafetyAnalysis.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// Based on mutex.h from https://clang.llvm.org/docs/ThreadSafetyAnalysis.html + +#ifndef THREAD_SAFETY_ANALYSIS_MUTEX_H +#define THREAD_SAFETY_ANALYSIS_MUTEX_H + +// Enable thread safety attributes only with clang. +// The attributes can be safely erased when compiling with other compilers. +#if defined(__clang__) && (!defined(SWIG)) && defined(_LIBCPP_VERSION) && \ + defined(_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS) +#define TSA_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) +#else +#define TSA_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op +#endif + +#define TSA_CAPABILITY(x) TSA_THREAD_ANNOTATION_ATTRIBUTE__(capability(x)) + +#define TSA_SCOPED_CAPABILITY TSA_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) + +#define TSA_GUARDED_BY(x) TSA_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) + +#define TSA_PT_GUARDED_BY(x) TSA_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) + +#define TSA_ACQUIRED_BEFORE(...) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) + +#define TSA_ACQUIRED_AFTER(...) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) + +#define TSA_REQUIRES(...) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__)) + +#define TSA_REQUIRES_SHARED(...) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) + +#define TSA_ACQUIRE(...) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) + +#define TSA_ACQUIRE_SHARED(...) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) + +#define TSA_RELEASE(...) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__)) + +#define TSA_RELEASE_SHARED(...) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) + +#define TSA_RELEASE_GENERIC(...) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__)) + +#define TSA_TRY_ACQUIRE(...) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) + +#define TSA_TRY_ACQUIRE_SHARED(...) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) + +#define TSA_EXCLUDES(...) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) + +#define TSA_ASSERT_CAPABILITY(x) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x)) + +#define TSA_ASSERT_SHARED_CAPABILITY(x) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x)) + +#define TSA_RETURN_CAPABILITY(x) \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) + +#define TSA_NO_THREAD_SAFETY_ANALYSIS \ + TSA_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) + +#endif // THREAD_SAFETY_ANALYSIS_MUTEX_H diff --git a/NativeScript/napi/hermes/include_old/hermes/TimerStats.h b/NativeScript/napi/hermes/include_old/hermes/TimerStats.h new file mode 100644 index 00000000..6b3e84ec --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/TimerStats.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include + +namespace facebook { +namespace hermes { + +/// Creates and returns a Runtime that computes the time spent in invocations to +/// the Hermes VM. +std::unique_ptr makeTimedRuntime( + std::unique_ptr hermesRuntime); + +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/TraceInterpreter.h b/NativeScript/napi/hermes/include_old/hermes/TraceInterpreter.h new file mode 100644 index 00000000..0a1240c1 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/TraceInterpreter.h @@ -0,0 +1,284 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace facebook { +namespace hermes { + +namespace tracing { + +class TraceInterpreter final { + public: + /// Options for executing the trace. + struct ExecuteOptions { + /// Customizes the GCConfig of the Runtime. + ::hermes::vm::GCConfig::Builder gcConfigBuilder; + + /// If true, trace again while replaying. After normalization (see + /// hermes/tools/synth/trace_normalize.py) the output trace should be + /// identical to the input trace. If they're not, there was a bug in replay. + mutable bool traceEnabled{false}; + + /// If true, verify that the replay results such as returned values from JS + /// execution, inputs from JS to native function calls are matching with the + /// trace record. + bool verificationEnabled{false}; + + /// If true, command-line options override the config options recorded in + /// the trace. If false, start from the default config. + bool useTraceConfig{false}; + + /// Number of initial executions whose stats are discarded. + int warmupReps{0}; + + /// Number of repetitions of execution. Stats returned are those for the rep + /// with the median totalTime. + int reps{1}; + + /// If true, run a complete collection before printing stats. Useful for + /// guaranteeing there's no garbage in heap size numbers. + bool forceGCBeforeStats{false}; + + /// If true, remove the requirement that the input bytecode was compiled + /// from the same source used to record the trace. There must only be one + /// input bytecode file in this case. If its observable behavior deviates + /// from the trace, the results are undefined. + bool disableSourceHashCheck{false}; + + /// A trace contains many MarkerRecords which have a name used to identify + /// them. If the replay encounters this given marker, perform an action + /// described by MarkerAction. All actions will stop the trace early and + /// collect stats at the marker point, unless the marker is set to the + /// special marker "end". In that case the trace will run to completion. + std::string marker{"end"}; + + enum class MarkerAction { + NONE, + /// Take a snapshot at marker. + SNAPSHOT, + /// Take a heap timeline that ends at marker. + TIMELINE, + /// Take a sampling heap profile that ends at marker. + SAMPLE_MEMORY, + /// Take a sampling time profile that ends at marker. + SAMPLE_TIME, + }; + + /// Sets the action to take upon encountering the marker. The action will + /// write results into the \p profileFileName. + MarkerAction action{MarkerAction::NONE}; + + /// Output file name for any profiling information. + std::string profileFileName; + + // These are the config parameters. We wrap them in llvh::Optional + // to indicate whether the corresponding command line flag was set + // explicitly. We override the trace's config only when that is true. + + /// If true, track all disk I/O done by the runtime and print a report at + /// the end to stdout. + llvh::Optional shouldTrackIO; + + /// If present, do a bytecode warmup run that touches a percentage of the + /// bytecode. A value of 50 here means 50% of the bytecode should be warmed. + llvh::Optional bytecodeWarmupPercent; + }; + + private: + jsi::Runtime &rt_; + ExecuteOptions options_; + llvh::raw_ostream *traceStream_; + // Map from source hash to source file to run. + std::map<::hermes::SHA1, std::shared_ptr> bundles_; + const SynthTrace &trace_; + + /// The last use of each object. + std::unordered_map lastUsePerObj_; + + /// The list of pairs from record index to ObjectID. Each record index is the + /// lastly used position of each Object, at which we can remove the object + /// from gom_ and gpnm_. + std::vector> lastUses_; + /// Index of lastUses_ vector that the interpreter is currently processing. + uint64_t lastUsesIndex_{0}; + + // Invariant: the value is either jsi::Object, jsi::String, jsi::Symbol, + // jsi::BigInt. + std::unordered_map gom_; + // For the PropNameIDs, which are not representable as jsi::Value. + std::unordered_map gpnm_; + + std::string stats_; + /// Whether the marker was reached. + bool markerFound_{false}; + /// Depth in the execution stack. Zero is the outermost function. + uint64_t depth_{0}; + + /// The index of the record that the TraceInterpreter is executing. + uint64_t nextExecIndex_{0}; + + public: + /// Execute the trace given by \p traceFile, that was the trace of executing + /// the bundle given by \p bytecodeFile. + /// \return The stats collected by the runtime about times and memory usage. + static std::string execAndGetStats( + const std::string &traceFile, + const std::vector &bytecodeFiles, + const ExecuteOptions &options); + + /// Same as execAndGetStats, except it additionally accepts a function to + /// create the runtime instance for replaying. This can be used to pass, for + /// example, TracingRuntime to trace while replaying. + static std::string execWithRuntime( + const std::string &traceFile, + const std::vector &bytecodeFiles, + const ExecuteOptions &options, + const std::function( + const ::hermes::vm::RuntimeConfig &runtimeConfig)> &createRuntime); + + /// \param traceStream If non-null, write a trace of the execution into this + /// stream. + /// \return Tuple of GC stats and the runtime instance used for replaying. + static std::tuple> + execFromMemoryBuffer( + std::unique_ptr &&traceBuf, + std::vector> &&codeBufs, + const ExecuteOptions &options, + const std::function( + const ::hermes::vm::RuntimeConfig &runtimeConfig)> &createRuntime); + + private: + TraceInterpreter( + jsi::Runtime &rt, + const ExecuteOptions &options, + const SynthTrace &trace, + std::map<::hermes::SHA1, std::shared_ptr> bundles); + + static std::string exec( + jsi::Runtime &rt, + const ExecuteOptions &options, + const SynthTrace &trace, + std::map<::hermes::SHA1, std::shared_ptr> bundles); + + static ::hermes::vm::RuntimeConfig merge( + ::hermes::vm::RuntimeConfig::Builder &, + const ::hermes::vm::GCConfig::Builder &, + const ExecuteOptions &, + bool, + bool); + + /// Requires \p codeBufs to be the memory buffers containing the code + /// referenced (via source hash) by the given \p trace. Returns a map from + /// the source hash to the memory buffer. In addition, if \p codeIsMmapped is + /// non-null, sets \p *codeIsMmapped to indicate whether all the code is + /// mmapped, and, if \p isBytecode is non-null, sets \p *isBytecode + /// to indicate whether all the code is bytecode. + static std::map<::hermes::SHA1, std::shared_ptr> + getSourceHashToBundleMap( + std::vector> &&codeBufs, + const SynthTrace &trace, + const ExecuteOptions &options, + bool *codeIsMmapped = nullptr, + bool *isBytecode = nullptr); + + jsi::Function createHostFunction( + const SynthTrace::CreateHostFunctionRecord &rec, + const jsi::PropNameID &propNameID); + + jsi::Object createHostObject(SynthTrace::ObjectID objID); + + /// Execute the records with the given ExecuteOptions::MarkerOption + std::string executeRecordsWithMarkerOptions(); + + /// Execute the records. JS might call this recursively when HostFunction or + /// HostObject's functions are called. + void executeRecords(); + + /// Requires that \p valID is the proper id for \p val, and that a + /// defining occurrence of \p valID occurs at the current \p defIndex. Decides + /// whether the definition should be recorded, and, if so, adds the + /// association between \p valID and \p val \p gom_ as appropriate. + void addToObjectMap( + SynthTrace::ObjectID valID, + jsi::Value &&val, + uint64_t defIndex); + + /// Similar to addToObjectMap, but for PropNameIDs. + void addToPropNameIDMap( + SynthTrace::ObjectID id, + jsi::PropNameID &&val, + uint64_t defIndex); + + /// If \p traceValue specifies an Object, String, BigInt or Symbol, requires + /// \p val to be of the corresponding runtime type. Adds this \p val to gom_. + /// + /// \p isThis should be true if and only if the value is a 'this' in a call + /// (only used for validation). TODO(T84791675): Remove this parameter. + /// + /// N.B. This method should be called even if you happen to know that the + /// value cannot be an Object, String, Symbol or BigInt, since it performs + /// useful validation. + void ifObjectAddToObjectMap( + SynthTrace::TraceValue traceValue, + const jsi::Value &val, + uint64_t defIndex, + bool isThis = false); + + /// Same as above, except it avoids copies on temporary objects. + void ifObjectAddToObjectMap( + SynthTrace::TraceValue traceValue, + jsi::Value &&val, + uint64_t defIndex, + bool isThis = false); + + /// Check if the \p marker is the one that is being searched for. If this is + /// the first time encountering the matching marker, perform the actions set + /// up for that marker. + void checkMarker(const std::string &marker); + + /// Get a jsi::Value from gom_ for given ObjectID. + jsi::Value getJSIValueForUse(SynthTrace::ObjectID id); + + /// Get a jsi::PropNameID from gpnm_ for given ObjectID. + jsi::PropNameID getPropNameIDForUse(SynthTrace::ObjectID id); + + /// Convert a TraceValue to a jsi::Value. This calls \p getJSIValueForUse, + /// which will remove the entry from gom_ and globalDefsAndUses_. + jsi::Value traceValueToJSIValue(SynthTrace::TraceValue value); + + /// Erase all references to objects of which last use is before the given + /// record index. + void eraseRefsBefore(uint64_t index); + + std::string printStats(); + + LLVM_ATTRIBUTE_NORETURN void crashOnException( + const std::exception &e, + ::hermes::OptValue globalRecordNum); + + void assertMatch( + const SynthTrace::TraceValue &traceValue, + const jsi::Value &val) const; +}; + +} // namespace tracing +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/TracingRuntime.h b/NativeScript/napi/hermes/include_old/hermes/TracingRuntime.h new file mode 100644 index 00000000..f3d082d5 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/TracingRuntime.h @@ -0,0 +1,280 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_TRACINGRUNTIME_H +#define HERMES_TRACINGRUNTIME_H + +#include "SynthTrace.h" + +#include +#include +#include "llvh/Support/raw_ostream.h" + +namespace facebook { +namespace hermes { +namespace tracing { + +class TracingRuntime : public jsi::RuntimeDecorator { + public: + using RD = RuntimeDecorator; + + TracingRuntime( + std::unique_ptr runtime, + const ::hermes::vm::RuntimeConfig &conf, + std::unique_ptr traceStream); + + /// Assign a new ObjectID for given jsi::Pointer. + SynthTrace::ObjectID defObjectID(const jsi::Pointer &p); + /// Get the ObjectID for given jsi::Pointer. + SynthTrace::ObjectID useObjectID(const jsi::Pointer &p) const; + + virtual void flushAndDisableTrace() = 0; + + /// @name jsi::Runtime methods. + /// @{ + + jsi::Value evaluateJavaScript( + const std::shared_ptr &buffer, + const std::string &sourceURL) override; + + void queueMicrotask(const jsi::Function &callback) override; + bool drainMicrotasks(int maxMicrotasksHint = -1) override; + + jsi::Object global() override; + + jsi::Object createObject() override; + jsi::Object createObject(std::shared_ptr ho) override; + + // Note that the NativeState methods do not need to be traced since they + // cannot be observed in JS. + + jsi::BigInt createBigIntFromInt64(int64_t value) override; + jsi::BigInt createBigIntFromUint64(uint64_t value) override; + jsi::String bigintToString(const jsi::BigInt &bigint, int radix) override; + + jsi::String createStringFromAscii(const char *str, size_t length) override; + jsi::String createStringFromUtf8(const uint8_t *utf8, size_t length) override; + std::string utf8(const jsi::PropNameID &) override; + + jsi::PropNameID createPropNameIDFromAscii(const char *str, size_t length) + override; + jsi::PropNameID createPropNameIDFromUtf8(const uint8_t *utf8, size_t length) + override; + std::string utf8(const jsi::String &) override; + + std::string symbolToString(const jsi::Symbol &) override; + + jsi::PropNameID createPropNameIDFromString(const jsi::String &str) override; + jsi::PropNameID createPropNameIDFromSymbol(const jsi::Symbol &sym) override; + + jsi::Value getProperty(const jsi::Object &obj, const jsi::String &name) + override; + jsi::Value getProperty(const jsi::Object &obj, const jsi::PropNameID &name) + override; + + bool hasProperty(const jsi::Object &obj, const jsi::String &name) override; + bool hasProperty(const jsi::Object &obj, const jsi::PropNameID &name) + override; + + void setPropertyValue( + const jsi::Object &obj, + const jsi::String &name, + const jsi::Value &value) override; + void setPropertyValue( + const jsi::Object &obj, + const jsi::PropNameID &name, + const jsi::Value &value) override; + + jsi::Array getPropertyNames(const jsi::Object &o) override; + + jsi::WeakObject createWeakObject(const jsi::Object &o) override; + + jsi::Value lockWeakObject(const jsi::WeakObject &wo) override; + + jsi::Array createArray(size_t length) override; + jsi::ArrayBuffer createArrayBuffer( + std::shared_ptr buffer) override; + + size_t size(const jsi::Array &arr) override; + size_t size(const jsi::ArrayBuffer &buf) override; + + uint8_t *data(const jsi::ArrayBuffer &buf) override; + + jsi::Value getValueAtIndex(const jsi::Array &arr, size_t i) override; + + void setValueAtIndexImpl( + const jsi::Array &arr, + size_t i, + const jsi::Value &value) override; + + jsi::Function createFunctionFromHostFunction( + const jsi::PropNameID &name, + unsigned int paramCount, + jsi::HostFunctionType func) override; + + jsi::Value call( + const jsi::Function &func, + const jsi::Value &jsThis, + const jsi::Value *args, + size_t count) override; + + jsi::Value callAsConstructor( + const jsi::Function &func, + const jsi::Value *args, + size_t count) override; + + void setExternalMemoryPressure(const jsi::Object &obj, size_t amount) + override; + + /// @} + + void addMarker(const std::string &marker); + + SynthTrace &trace() { + return trace_; + } + + const SynthTrace &trace() const { + return trace_; + } + + void replaceNondeterministicFuncs(); + + // This is the number of records recorded as part of the 'preamble' of a synth + // trace. This means all the records after this amount are from the actual + // execution of the trace. + uint32_t getNumPreambleRecordsForTest() const { + assert( + numPreambleRecords_ > 0 && + "Only call this method if the preamble has been executed"); + return numPreambleRecords_; + } + + private: + SynthTrace::TraceValue defTraceValue(const jsi::Value &value) { + return toTraceValue(value, true); + } + SynthTrace::TraceValue useTraceValue(const jsi::Value &value) { + return toTraceValue(value, false); + } + SynthTrace::TraceValue toTraceValue( + const jsi::Value &value, + bool assignNewUID = false); + + std::vector argStringifyer( + const jsi::Value *args, + size_t count, + bool assignNewUID = false); + + SynthTrace::TimeSinceStart getTimeSinceStart() const; + + std::unique_ptr runtime_; + SynthTrace trace_; + std::deque savedFunctions; + const SynthTrace::TimePoint startTime_{std::chrono::steady_clock::now()}; + uint32_t numPreambleRecords_; + + SynthTrace::ObjectID currentUniqueID_{0}; + + /// Map from PointerValue* to ObjectID. Except WeakRef case (see below), we + /// assign a new ObjectID whenever we see a new def of jsi::Pointer Value. + std::unordered_map + uniqueIDs_; + + /// WeakObject's PointerValue* to ObjectID mapping. + /// The key is the PointerValue of the WeakObject at the time of + /// it is created. + /// The value is newly assign ObjectID for that PointerValue. + std::unordered_map + weakRefIDs_; +}; + +// TracingRuntime is *almost* vm independent. This provides the +// vm-specific bits. And, it's not a HermesRuntime, but it holds one. +class TracingHermesRuntime final : public TracingRuntime { + public: + /// This constructor is not intended to be invoked directly. + /// Use makeTracingHermesRuntime instead. + /// + /// \p traceStream the stream to write trace to. + /// \p commitAction is invoked on completion of tracing. + /// Completion can be triggered implicitly by crash (if crash manager is + /// provided) or explicitly by invocation of flush. If the committed trace + /// can be found in a file, the callback returns the file name. Otherwise, + /// the callback returns empty. + /// \p rollbackAction is invoked if the runtime is destructed prior to + /// completion of tracing. It may or may not invoked if completion failed. + TracingHermesRuntime( + std::unique_ptr runtime, + const ::hermes::vm::RuntimeConfig &runtimeConfig, + std::unique_ptr traceStream, + std::function commitAction, + std::function rollbackAction); + + ~TracingHermesRuntime() override; + + void flushAndDisableTrace() override; + + std::string flushAndDisableBridgeTrafficTrace() override; + + jsi::Value evaluateJavaScript( + const std::shared_ptr &buffer, + const std::string &sourceURL) override; + + HermesRuntime &hermesRuntime() { + return static_cast(plain()); + } + + const HermesRuntime &hermesRuntime() const { + return static_cast(plain()); + } + + private: + void crashCallback(int fd); + + const ::hermes::vm::RuntimeConfig conf_; + const std::function commitAction_; + const std::function rollbackAction_; + const llvh::Optional<::hermes::vm::CrashManager::CallbackKey> + crashCallbackKey_; + + bool flushedAndDisabled_{false}; + std::string committedTraceFilename_; +}; + +/// Creates and returns a HermesRuntime that traces JSI interactions. +/// The trace will be written to \p traceScratchPath incrementally. +/// On completion, the file will be renamed to \p traceResultPath, and +/// \p traceCompletionCallback (for post-processing) will be invoked. +/// Completion can be triggered implicitly by crash (if crash manager is +/// provided) or explicitly by invocation of flush. +/// If the runtime is destructed without triggering trace completion, +/// the file at \p traceScratchPath will be deleted. +/// The return value of \p traceCompletionCallback indicates whether the +/// invocation completed successfully. +std::unique_ptr makeTracingHermesRuntime( + std::unique_ptr hermesRuntime, + const ::hermes::vm::RuntimeConfig &runtimeConfig, + const std::string &traceScratchPath, + const std::string &traceResultPath, + std::function traceCompletionCallback); + +/// Creates and returns a HermesRuntime that traces JSI interactions. +/// If \p traceStream is non-null, writes the trace to \p traceStream. +/// The \p forReplay parameter indicates whether the runtime is being used +/// in trace replay. (Its behavior can differ slightly in that case.) +std::unique_ptr makeTracingHermesRuntime( + std::unique_ptr hermesRuntime, + const ::hermes::vm::RuntimeConfig &runtimeConfig, + std::unique_ptr traceStream, + bool forReplay = false); + +} // namespace tracing +} // namespace hermes +} // namespace facebook + +#endif // HERMES_TRACINGRUNTIME_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/CDPAgent.h b/NativeScript/napi/hermes/include_old/hermes/cdp/CDPAgent.h new file mode 100644 index 00000000..e2243259 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/CDPAgent.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_CDPAGENT_H +#define HERMES_CDP_CDPAGENT_H + +#include +#include + +#include +#include +#include +#include + +class CDPAgentTest; + +namespace facebook { +namespace hermes { +namespace cdp { + +using OutboundMessageFunc = std::function; + +class CDPAgentImpl; +class CDPDebugAPI; + +/// Public-facing wrapper for internal CDP state that can be preserved across +/// reloads. +struct HERMES_EXPORT State { + /// Incomplete type that stores the actual state. + struct Private; + + /// Create a new empty wrapper. + State(); + /// Create a new wrapper with the provided \p privateState. + explicit State(std::unique_ptr privateState); + + State(const State &other) = delete; + State &operator=(const State &other) = delete; + State(State &&other) noexcept; + State &operator=(State &&other) noexcept; + ~State(); + + inline operator bool() const { + return privateState_ != nullptr; + } + + /// Get the wrapped state. + inline Private &operator*() { + return *privateState_.get(); + } + + /// Get the wrapped state. + inline Private *operator->() { + return privateState_.get(); + } + + private: + /// Pointer to the actual stored state, hidden from users of this wrapper. + std::unique_ptr privateState_; +}; + +/// An agent for interacting with the provided \p runtime and +/// \p asyncDebuggerAPI via CDP messages in the Debugger, Runtime, Profiler, +/// HeapProfiler domains. +/// The integrator of the agent is expected to manage a queue of tasks to be +/// executed with exclusive access to the runtime (i.e. executed when +/// JavaScript is not running). Tasks to be run are delivered to the integrator +/// via the provided \p enqueueRuntimeTaskCallback, and should be executed in +/// order, at the first opportunity between evaluating JavaScript. +/// The integrator can deliver CDP commands to the agent via the +/// \p handleCommand method. When a CDP response or event is generated, it will +/// be delivered to the integrator via the provided \p messageCallback. +/// Both callbacks may be invoked from arbitrary threads. +class HERMES_EXPORT CDPAgent { + friend class ::CDPAgentTest; + + /// Hide the constructor so users can only construct via static create + /// methods. + CDPAgent( + int32_t executionContextID, + CDPDebugAPI &cdpDebugAPI, + debugger::EnqueueRuntimeTaskFunc enqueueRuntimeTaskCallback, + OutboundMessageFunc messageCallback, + State state, + std::shared_ptr destroyedDomainAgents); + + public: + /// Create a new CDP Agent. This can be done on an arbitrary thread; the + /// runtime will not be accessed during execution of this function. + static std::unique_ptr create( + int32_t executionContextID, + CDPDebugAPI &cdpDebugAPI, + debugger::EnqueueRuntimeTaskFunc enqueueRuntimeTaskCallback, + OutboundMessageFunc messageCallback, + State state = {}); + + /// Destroy the CDP Agent. This can be done on an arbitrary thread. + /// It's expected that the integrator will continue to process any runtime + /// tasks enqueued during destruction. + ~CDPAgent(); + + /// Process a CDP command encoded in \p json. This can be called from + /// arbitrary threads. + void handleCommand(std::string json); + + /// Enable the Runtime domain without processing a CDP command or sending a + /// CDP response. This can be called from arbitrary threads. + void enableRuntimeDomain(); + + /// Enable the Debugger domain without processing a CDP command or sending a + /// CDP response. This can be called from arbitrary threads. + void enableDebuggerDomain(); + + /// Extract state to be persisted across reloads. This can be called from + /// arbitrary threads. + State getState(); + + private: + /// This should be a unique_ptr to provide predictable destruction time lined + /// up with when CDPAgent is destroyed. Do not use shared_ptr. + std::unique_ptr impl_; +}; + +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_CDPAGENT_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/CDPDebugAPI.h b/NativeScript/napi/hermes/include_old/hermes/cdp/CDPDebugAPI.h new file mode 100644 index 00000000..9809ec9a --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/CDPDebugAPI.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_CDPDEBUGAPI_H +#define HERMES_CDP_CDPDEBUGAPI_H + +#include + +#include "ConsoleMessage.h" + +namespace facebook { +namespace hermes { +namespace cdp { + +class CDPAgentImpl; + +/// Storage and interfaces for carrying out a CDP debug session. Contains +/// information and operations that correspond to a single runtime being +/// debugged, independent of any particular CDPAgent. +class HERMES_EXPORT CDPDebugAPI { + public: + /// Create a new CDPDebugAPI instance. The provided runtime must remain valid + /// until the returned CDPDebugAPI is destroyed. + static std::unique_ptr create( + HermesRuntime &runtime, + size_t maxCachedMessages = kMaxCachedConsoleMessages); + ~CDPDebugAPI(); + + /// Gets the runtime originally passed into this instance. + HermesRuntime &runtime() { + return runtime_; + } + + /// Gets the AsyncDebuggerAPI associated with this instance. + debugger::AsyncDebuggerAPI &asyncDebuggerAPI() { + return *asyncDebuggerAPI_; + } + + /// Adds a console message to the current CDPDebugAPI instance, + /// broadcasting it to all current agents, and storing it for + /// future agents (within buffer limitations). This function + /// must only be called from the runtime thread. + void addConsoleMessage(ConsoleMessage message); + + private: + /// Allow CDPAgentImpl (but not integrators) to access + /// consoleMessageStorage_. + friend class CDPAgentImpl; + + CDPDebugAPI(HermesRuntime &runtime, size_t maxCachedMessages); + + HermesRuntime &runtime_; + std::unique_ptr asyncDebuggerAPI_; + ConsoleMessageStorage consoleMessageStorage_; + ConsoleMessageDispatcher consoleMessageDispatcher_; +}; + +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_CDPDEBUGAPI_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/CallbackOStream.h b/NativeScript/napi/hermes/include_old/hermes/cdp/CallbackOStream.h new file mode 100644 index 00000000..b8a4eb3b --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/CallbackOStream.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_CALLBACKOSTREAM_H +#define HERMES_CDP_CALLBACKOSTREAM_H + +#include +#include +#include +#include +#include + +namespace facebook { +namespace hermes { +namespace cdp { + +/// Subclass of \c std::ostream where flushing is implemented through a +/// callback. Writes are collected in a buffer. When filled, the buffer's +/// contents are emptied out and sent to a callback. +struct CallbackOStream : public std::ostream { + /// Signature of callback called to flush buffer contents. Accepts the buffer + /// as a string. Returns a boolean indicating whether flushing succeeded. + /// Callback failure will be translated to stream failure. If the callback + /// throws an exception it will be swallowed and translated into stream + /// failure. + using Fn = std::function; + + /// Construct a new stream. + /// + /// \p sz The size of the buffer -- how large it can get before it must be + /// flushed. Must be non-zero. + /// \p cb The callback function. + CallbackOStream(size_t sz, Fn cb); + + /// This class is neither movable nor copyable. + CallbackOStream(CallbackOStream &&that) = delete; + CallbackOStream &operator=(CallbackOStream &&that) = delete; + CallbackOStream(const CallbackOStream &that) = delete; + CallbackOStream &operator=(const CallbackOStream &that) = delete; + + private: + /// \c std::streambuf sub-class backed by a std::string buffer and + /// implementing overflow by calling a callback. + struct StreamBuf : public std::streambuf { + /// Construct a new streambuf. Parameters are the same as those of + /// \c CallbackOStream . + StreamBuf(size_t sz, Fn cb); + + /// Destruction will flush any remaining buffer contents. + ~StreamBuf() override; + + /// StreamBufs are not copyable, to avoid the flush callback receiving + /// the contents of multiple streams. + StreamBuf(const StreamBuf &) = delete; + StreamBuf &operator=(const StreamBuf &) = delete; + + protected: + /// std::streambuf overrides + int_type overflow(int_type ch) override; + int sync() override; + + private: + /// The size of the backing buffer. Fixed for an instance of the streambuf. + size_t sz_; + + /// The backing buffer that writes will go to until full. + std::unique_ptr buf_; + + /// The function called when buf_ has been filled. + Fn cb_; + + /// Clears the backing buffer. + void reset(); + + /// Clears the backing buffer and returns it contents in a string. + std::string take(); + }; + + StreamBuf sbuf_; +}; + +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_CALLBACKOSTREAM_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/ConsoleMessage.h b/NativeScript/napi/hermes/include_old/hermes/cdp/ConsoleMessage.h new file mode 100644 index 00000000..906dbb9a --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/ConsoleMessage.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_CDPCONSOLEMESSAGESTORAGE_H +#define HERMES_CDP_CDPCONSOLEMESSAGESTORAGE_H + +#include +#include +#include + +#include + +#include + +namespace facebook { +namespace hermes { +namespace cdp { + +/// Controls the max number of message to cached in \p consoleMessageCache_. The +/// value here is chosen to match what Chromium uses in their CDP +/// implementation. +static const int kMaxCachedConsoleMessages = 1000; + +enum class ConsoleAPIType { + kLog, + kDebug, + kInfo, + kError, + kWarning, + kDir, + kDirXML, + kTable, + kTrace, + kStartGroup, + kStartGroupCollapsed, + kEndGroup, + kClear, + kAssert, + kTimeEnd, + kCount +}; + +struct ConsoleMessage { + double timestamp; + ConsoleAPIType type; + std::vector args; + debugger::StackTrace stackTrace; + + ConsoleMessage( + double timestamp, + ConsoleAPIType type, + std::vector args, + debugger::StackTrace stackTrace = {}) + : timestamp(timestamp), + type(type), + args(std::move(args)), + stackTrace(stackTrace) {} +}; + +class ConsoleMessageStorage { + public: + ConsoleMessageStorage(size_t maxCachedMessages = kMaxCachedConsoleMessages); + + void addMessage(ConsoleMessage message); + void clear(); + + const std::deque &messages() const; + size_t discarded() const; + std::optional oldestTimestamp() const; + + private: + /// Maximum number of messages to cache. + size_t maxCachedMessages_; + /// Counts the number of console messages discarded when + /// \p consoleMessageCache_ is full. + size_t numConsoleMessagesDiscardedFromCache_ = 0; + /// Cache for storing console messages. Earlier messages are discarded when + /// the cache is full. The choice to use a std::deque is for fast operations + /// at the beginning and the end, so that adding to the cache and discarding + /// from the cache are fast. + std::deque consoleMessageCache_{}; +}; + +class CDPAgent; + +/// Token that identifies a specific subscription to console messages. +using ConsoleMessageRegistration = uint32_t; + +/// Dispatcher to deliver console messages to all registered subscribers. +/// Everything in this class must be used exclusively from the runtime thread. +class ConsoleMessageDispatcher { + public: + ConsoleMessageDispatcher() {} + ~ConsoleMessageDispatcher() {} + + /// Register a subscriber and return a token that can be used to + /// unregister in the future. Must only be called from the runtime thread. + ConsoleMessageRegistration subscribe( + std::function handler) { + auto token = ++tokenCounter_; + subscribers_[token] = handler; + return token; + } + + /// Unregister a subscriber using the token returned from registration. + /// Must only be called from the runtime thread. + void unsubscribe(ConsoleMessageRegistration token) { + subscribers_.erase(token); + } + + /// Deliver a new console message to each subscriber. Must only be called + /// from the runtime thread. + void deliverMessage(const ConsoleMessage &message) { + for (auto &pair : subscribers_) { + pair.second(message); + } + } + + private: + /// Collection of subscribers, identified by registration token. + std::unordered_map< + ConsoleMessageRegistration, + std::function> + subscribers_; + + /// Counter to generate unique registration tokens. + ConsoleMessageRegistration tokenCounter_ = 0; +}; + +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_CDPCONSOLEMESSAGESTORAGE_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/DebuggerDomainAgent.h b/NativeScript/napi/hermes/include_old/hermes/cdp/DebuggerDomainAgent.h new file mode 100644 index 00000000..b1336e6b --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/DebuggerDomainAgent.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_DEBUGGERDOMAINAGENT_H +#define HERMES_CDP_DEBUGGERDOMAINAGENT_H + +#include +#include + +#include +#include +#include + +#include "DomainAgent.h" +#include "DomainState.h" + +namespace facebook { +namespace hermes { +namespace cdp { + +enum class PausedNotificationReason; + +namespace m = ::facebook::hermes::cdp::message; + +/// Details about a single Hermes breakpoint, implied by a CDP breakpoint. +struct HermesBreakpoint { + debugger::BreakpointID breakpointID; + debugger::ScriptID scriptID; +}; + +/// Type used to store CDP breakpoint identifiers. These IDs are generated by +/// the CDP Handler, so we can constrain them to a specific range. +using CDPBreakpointID = uint32_t; + +/// Description of where breakpoints should be created. +struct CDPBreakpointDescription : public StateValue { + ~CDPBreakpointDescription() override = default; + std::unique_ptr copy() const override { + auto value = std::make_unique(); + value->line = line; + value->column = column; + value->condition = condition; + value->url = url; + return value; + } + + /// Determines whether this breakpoint can be persisted across sessions + bool persistable() const { + // Only persist breakpoints that can apply to future scripts (i.e. + // breakpoints set on a set of files specified by script URL, not + // breakpoints set on an exact, session-specific script ID). + return url.has_value(); + } + + std::optional url; + long long line; + std::optional column; + std::optional condition; +}; + +/// Details of each existing CDP breakpoint, which may correspond to multiple +/// Hermes breakpoints. +struct CDPBreakpoint { + explicit CDPBreakpoint(CDPBreakpointDescription description) + : description(description) {} + + // Description of where the breakpoint should be applied + CDPBreakpointDescription description; + + // Registered breakpoints in Hermes + std::vector hermesBreakpoints; +}; + +struct HermesBreakpointLocation { + debugger::BreakpointID id; + debugger::SourceLocation location; +}; + +/// Handler for the "Debugger" domain of CDP. Accepts events from the runtime, +/// and CDP requests from the debug client belonging to the "Debugger" domain. +/// Produces CDP responses and events belonging to the "Debugger" domain. All +/// methods expect to be invoked with exclusive access to the runtime. +class DebuggerDomainAgent : public DomainAgent { + public: + DebuggerDomainAgent( + int32_t executionContextID, + HermesRuntime &runtime, + debugger::AsyncDebuggerAPI &asyncDebugger, + SynchronizedOutboundCallback messageCallback, + std::shared_ptr objTable_, + DomainState &state); + ~DebuggerDomainAgent(); + + /// Enables the Debugger domain without processing CDP message or sending a + /// CDP response. It will still send CDP notifications if needed. + void enable(); + /// Handles Debugger.enable request + /// @cdp Debugger.enable If domain is already enabled, will return success. + void enable(const m::debugger::EnableRequest &req); + /// Handles Debugger.disable request + /// @cdp Debugger.disable If domain is already disabled, will return success. + void disable(const m::debugger::DisableRequest &req); + + /// Handles Debugger.pause request + void pause(const m::debugger::PauseRequest &req); + /// Handles Debugger.resume request + void resume(const m::debugger::ResumeRequest &req); + + /// Handles Debugger.stepInto request + void stepInto(const m::debugger::StepIntoRequest &req); + /// Handles Debugger.stepOut request + void stepOut(const m::debugger::StepOutRequest &req); + /// Handles Debugger.stepOver request + void stepOver(const m::debugger::StepOverRequest &req); + + /// Handles Debugger.setBlackboxedRanges request + void setBlackboxedRanges(const m::debugger::SetBlackboxedRangesRequest &req); + + /// Handles Debugger.setPauseOnExceptions + void setPauseOnExceptions( + const m::debugger::SetPauseOnExceptionsRequest &req); + + /// Handles Debugger.evaluateOnCallFrame + void evaluateOnCallFrame(const m::debugger::EvaluateOnCallFrameRequest &req); + + /// Debugger.setBreakpoint creates a CDP breakpoint that applies to exactly + /// one script (identified by script ID) that does not survive reloads. + void setBreakpoint(const m::debugger::SetBreakpointRequest &req); + // Debugger.setBreakpointByUrl creates a CDP breakpoint that may apply to + // multiple scripts (identified by URL), and survives reloads. + void setBreakpointByUrl(const m::debugger::SetBreakpointByUrlRequest &req); + /// Handles Debugger.removeBreakpoint + void removeBreakpoint(const m::debugger::RemoveBreakpointRequest &req); + /// Handles Debugger.setBreakpointsActive + /// @cdp Debugger.setBreakpointsActive Allowed even if domain is not enabled. + void setBreakpointsActive( + const m::debugger::SetBreakpointsActiveRequest &req); + + private: + /// Handle an event originating from the runtime. + void handleDebuggerEvent( + HermesRuntime &runtime, + debugger::AsyncDebuggerAPI &asyncDebugger, + debugger::DebuggerEventType event); + + /// Send a Debugger.paused notification to the debug client + void sendPausedNotificationToClient(PausedNotificationReason reason); + /// Send a Debugger.scriptParsed notification to the debug client + void sendScriptParsedNotificationToClient( + const debugger::SourceLocation srcLoc); + + /// Obtain the newly loaded script and send a ScriptParsed notification to the + /// debug client + void processNewLoadedScript(); + + std::pair createCDPBreakpoint( + CDPBreakpointDescription &&description, + std::optional hermesBreakpoint = std::nullopt); + + std::optional createHermesBreakpont( + debugger::ScriptID scriptID, + const CDPBreakpointDescription &description); + + std::optional applyBreakpoint( + CDPBreakpoint &breakpoint, + debugger::ScriptID scriptID); + + bool checkDebuggerEnabled(const m::Request &req); + bool checkDebuggerPaused(const m::Request &req); + + /// Removes any modifications this agent made to Hermes in order to enable + /// debugging + void cleanUp(); + + HermesRuntime &runtime_; + debugger::AsyncDebuggerAPI &asyncDebugger_; + + /// ID for the registered DebuggerEventCallback + debugger::DebuggerEventCallbackID debuggerEventCallbackId_; + + /// Details of each CDP breakpoint that has been created, and not + /// yet destroyed. + std::unordered_map cdpBreakpoints_{}; + + /// CDP breakpoint IDs are assigned by the DebuggerDomainAgent. Keep track of + /// the next available ID. + CDPBreakpointID nextBreakpointID_ = 1; + + DomainState &state_; + + /// Whether the currently installed breakpoints actually take effect. If + /// they're supposed to be inactive, then debugger agent will automatically + /// resume execution when breakpoints are hit. + bool breakpointsActive_ = true; + + /// Whether Debugger.enable was received and wasn't disabled by receiving + /// Debugger.disable + bool enabled_; + + /// Whether to consider the debugger as currently paused. There are some + /// debugger events such as ScriptLoaded where we don't consider the debugger + /// to be paused. + bool paused_; +}; + +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_DEBUGGERDOMAINAGENT_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/DomainAgent.h b/NativeScript/napi/hermes/include_old/hermes/cdp/DomainAgent.h new file mode 100644 index 00000000..6770e829 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/DomainAgent.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_DOMAINAGENT_H +#define HERMES_CDP_DOMAINAGENT_H + +#include +#include + +#include +#include + +#if defined(__clang__) && (!defined(SWIG)) && defined(_LIBCPP_VERSION) && \ + defined(_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS) +#include +#else +#ifndef TSA_GUARDED_BY +#define TSA_GUARDED_BY(x) +#endif +#endif + +namespace facebook { +namespace hermes { +namespace cdp { + +namespace m = ::facebook::hermes::cdp::message; + +/// A wrapper around std::function to make it safe to use from +/// multiple threads. The wrapper implements an invalidate function so that one +/// thread can clean up the underlying std::function in a thread-safe way. +template +class SynchronizedCallback { + public: + SynchronizedCallback(std::function func) + : funcContainer_(std::make_shared(func)) {} + + /// Thread-safe version that calls the underlying std::function. If the + /// underlying std::function is empty, this function is a no-op. + void operator()(Args... args) const { + std::lock_guard lock(funcContainer_->mutex); + if (funcContainer_->func) { + funcContainer_->func(args...); + } + } + + /// Reset the underlying std::function so that future invocations of + /// operator() would just be a no-op. + void invalidate() { + std::lock_guard lock(funcContainer_->mutex); + funcContainer_->func = std::function(); + } + + private: + struct FunctionContainer { + FunctionContainer(std::function func) : func(func) {} + + std::mutex mutex{}; + + /// The actual std::function to be invoked by operator() + std::function func TSA_GUARDED_BY(mutex); + }; + std::shared_ptr funcContainer_; +}; + +using SynchronizedOutboundCallback = SynchronizedCallback; + +class DomainAgent { + protected: + DomainAgent( + int32_t executionContextID, + SynchronizedOutboundCallback messageCallback, + std::shared_ptr objTable) + : executionContextID_(executionContextID), + messageCallback_(messageCallback), + objTable_(objTable) {} + virtual ~DomainAgent() {} + + /// Sends the provided string back to the debug client + void sendToClient(const std::string &str) { + messageCallback_(str); + } + + /// Sends the provided \p Response back to the debug client + void sendResponseToClient(const m::Response &resp) { + sendToClient(resp.toJsonStr()); + } + + /// Sends the provided \p Notification back to the debug client + void sendNotificationToClient(const m::Notification ¬e) { + sendToClient(note.toJsonStr()); + } + + /// Execution context ID associated with the HermesRuntime + int32_t executionContextID_; + + /// Callback function to send CDP response back to the debug client + SynchronizedOutboundCallback messageCallback_; + + std::shared_ptr objTable_; +}; + +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_DOMAINAGENT_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/DomainState.h b/NativeScript/napi/hermes/include_old/hermes/cdp/DomainState.h new file mode 100644 index 00000000..4c21603c --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/DomainState.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_DOMAINSTATE_H +#define HERMES_CDP_DOMAINSTATE_H + +#include +#include +#include +#include +#include + +#if defined(__clang__) && (!defined(SWIG)) && defined(_LIBCPP_VERSION) && \ + defined(_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS) +#include +#else +#ifndef TSA_GUARDED_BY +#define TSA_GUARDED_BY(x) +#endif +#ifndef TSA_REQUIRES +#define TSA_REQUIRES(x) +#endif +#endif + +namespace facebook { +namespace hermes { +namespace cdp { + +/// Base class for data to be stored in DomainState. +struct StateValue { + public: + virtual ~StateValue() = default; + virtual std::unique_ptr copy() const = 0; +}; + +/// StateValue that can be used as a dictionary. Used as the main storage value +/// of DomainState so that modifications can be based on keys of the dictionary +/// hierarchy. +struct DictionaryStateValue : public StateValue { + ~DictionaryStateValue() override = default; + std::unique_ptr copy() const override; + + std::unordered_map> values; +}; + +using StateModification = + std::pair, std::unique_ptr>; + +/// This class acts as container for saving state that CDP agents need after a +/// reload. Its main purpose is to synchronize the manipulation of state on the +/// runtime thread and when CDPAgent::getState() gets called on arbitrary +/// thread. Functions in this class specifically do not contain callbacks to +/// ensure the mutex locking usage remain simple with no reentrancy to think +/// about. +class DomainState { + public: + DomainState(); + explicit DomainState(std::unique_ptr dict); + + /// TSA doesn't get applied to constructors, so delete the normal mechanism. + /// There is a separate copy() function instead. + DomainState(const DomainState &) = delete; + DomainState &operator=(const DomainState &) = delete; + + /// Deep copy of the data and make a new instance. Used by + /// CDPAgent::getState() to get the state in a thread-safe manner. + std::unique_ptr copy(); + + /// This function allows the caller to access values in the saved state. This + /// obtains a copy of the data so that no further synchronization is required + /// after calling this function. This function is expected to only be called a + /// few times after reload, so it isn't used frequently. All entries in the + /// \p paths vector are expected to be pointing to DictionaryStateValue(s) + /// except the last entry, which is a key to any StateValue. + /// \return a copy of the StateValue stored at \p paths, nullptr if no value + /// exists at paths + std::unique_ptr getCopy(std::vector paths); + + /// This class is the only way for callers to manipulate the DomainState. It + /// is a scope-based commit where the modifications get saved upon the class's + /// destruction. The class must not be saved elsewhere and outlive the + /// DomainState where it came from. The intent is to nudge the caller to batch + /// modifications and commit the changes in one go. Because we make a copy of + /// the state with copy(), we want state changes to be atomic. Caller can + /// still break things up into multiple transactions, but the hope is that + /// this nudges them to think about modifications as one atomic unit. + class Transaction { + public: + explicit Transaction(DomainState &state); + ~Transaction(); + + /// Adds a value to the container. All entries in the \p paths vector are + /// expected to be pointing to DictionaryStateValue(s) except the last + /// entry, which is a key to any StateValue. + void add(std::vector paths, const StateValue &value); + + /// Removes a value from the container. All entries in the \p paths vector + /// are expected to be pointing to DictionaryStateValue(s) except the last + /// entry, which is a key to any StateValue. + void remove(std::vector paths); + + private: + friend DomainState; + + DomainState &state_; + std::vector modifications_{}; + }; + + /// Gets a Transaction for modification. + Transaction transaction(); + + private: + /// Helper function for traversing the dictionary hierarchy. + DictionaryStateValue *getDict( + const std::vector &paths, + bool createMissingDict) TSA_REQUIRES(mutex_); + + /// Save modifications to \p dict_. + void commitTransaction(Transaction &transaction); + + std::mutex mutex_{}; + + /// The actual value container. TSA doesn't work if this is just a direct + /// value on the class, so using an unique_ptr. + std::unique_ptr dict_ TSA_GUARDED_BY(mutex_){}; +}; + +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_DOMAINSTATE_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/HeapProfilerDomainAgent.h b/NativeScript/napi/hermes/include_old/hermes/cdp/HeapProfilerDomainAgent.h new file mode 100644 index 00000000..227214bc --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/HeapProfilerDomainAgent.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_HEAPPROFILERDOMAINAGENT_H +#define HERMES_CDP_HEAPPROFILERDOMAINAGENT_H + +#include + +#include "DomainAgent.h" + +namespace facebook { +namespace hermes { +namespace cdp { + +/// Handler for the "HeapProfiler" domain of CDP. All methods expect to be +/// invoked with exclusive access to the runtime. +class HeapProfilerDomainAgent : public DomainAgent { + public: + HeapProfilerDomainAgent( + int32_t executionContextID, + HermesRuntime &runtime, + SynchronizedOutboundCallback messageCallback, + std::shared_ptr objTable); + ~HeapProfilerDomainAgent(); + + /// Handles HeapProfiler.takeHeapSnapshot request + void takeHeapSnapshot(const m::heapProfiler::TakeHeapSnapshotRequest &req); + + /// Handle HeapProfiler.getObjectByHeapObjectId + void getObjectByHeapObjectId( + const m::heapProfiler::GetObjectByHeapObjectIdRequest &req); + + /// Handle HeapProfiler.getObjectByHeapObjectId + void getHeapObjectId(const m::heapProfiler::GetHeapObjectIdRequest &req); + + /// Handle HeapProfiler.collectGarbage + void collectGarbage(const m::heapProfiler::CollectGarbageRequest &req); + + /// Handle HeapProfiler.startTrackingHeapObjects + void startTrackingHeapObjects( + const m::heapProfiler::StartTrackingHeapObjectsRequest &req); + + /// Handle HeapProfiler.stopTrackingHeapObjects + void stopTrackingHeapObjects( + const m::heapProfiler::StopTrackingHeapObjectsRequest &req); + + /// Handle HeapProfiler.startSampling + void startSampling(const m::heapProfiler::StartSamplingRequest &req); + + /// Handle HeapProfiler.stopSampling + void stopSampling(const m::heapProfiler::StopSamplingRequest &req); + + private: + void sendSnapshot(int reqId, bool reportProgress, bool captureNumericValue); + + HermesRuntime &runtime_; + + /// Flag indicating whether this agent is registered to receive heap object + /// tracking callbacks. + bool trackingHeapObjectStackTraces_ = false; + + /// Flag indicating whether this agent is currently running a heap sampling + /// session. + bool samplingHeap_ = false; +}; + +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_HEAPPROFILERDOMAINAGENT_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/JSONValueInterfaces.h b/NativeScript/napi/hermes/include_old/hermes/cdp/JSONValueInterfaces.h new file mode 100644 index 00000000..23a12ba8 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/JSONValueInterfaces.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_JSONVALUEINTERFACES_H +#define HERMES_CDP_JSONVALUEINTERFACES_H + +#include +#include + +#include + +namespace facebook { +namespace hermes { +namespace cdp { +using namespace ::hermes::parser; + +/// Convert a string to a JSONValue. Will return nullopt if parsing is not +/// successful. +std::optional parseStr( + const std::string &str, + JSONFactory &factory); + +/// Convert a string to a JSON object. Will return nullopt if parsing is not +/// successful, or the resulting JSON value is not an object. +std::optional parseStrAsJsonObj( + const std::string &str, + JSONFactory &factory); + +/// Convert a JSONValue to a string. +std::string jsonValToStr(const JSONValue *v); + +/// Check if two JSONValues are equal. +bool jsonValsEQ(const JSONValue *A, const JSONValue *B); + +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_JSONVALUEINTERFACES_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/MessageConverters.h b/NativeScript/napi/hermes/include_old/hermes/cdp/MessageConverters.h new file mode 100644 index 00000000..7397bd1d --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/MessageConverters.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_MESSAGECONVERTERS_H +#define HERMES_CDP_MESSAGECONVERTERS_H + +#include +#include +#include + +#include +#include +#include + +namespace facebook { +namespace hermes { +namespace cdp { +namespace message { + +template +void setChromeLocation( + T &chromeLoc, + const facebook::hermes::debugger::SourceLocation &hermesLoc) { + if (hermesLoc.line != facebook::hermes::debugger::kInvalidLocation) { + chromeLoc.lineNumber = hermesLoc.line - 1; + } + + if (hermesLoc.column != facebook::hermes::debugger::kInvalidLocation) { + chromeLoc.columnNumber = hermesLoc.column - 1; + } +} + +/// ErrorCode magic numbers match JSC's (see InspectorBackendDispatcher.cpp) +enum class ErrorCode { + ParseError = -32700, + InvalidRequest = -32600, + MethodNotFound = -32601, + InvalidParams = -32602, + InternalError = -32603, + ServerError = -32000 +}; + +ErrorResponse +makeErrorResponse(int id, ErrorCode code, const std::string &message); + +OkResponse makeOkResponse(int id); + +namespace debugger { + +Location makeLocation(const facebook::hermes::debugger::SourceLocation &loc); + +} // namespace debugger + +namespace runtime { + +CallFrame makeCallFrame(const facebook::hermes::debugger::CallFrameInfo &info); + +std::vector makeCallFrames( + const facebook::hermes::debugger::StackTrace &stackTrace); + +} // namespace runtime + +namespace heapProfiler { + +std::unique_ptr makeSamplingHeapProfile( + const std::string &value); + +} // namespace heapProfiler + +namespace profiler { + +std::unique_ptr makeProfile(const std::string &value); + +} // namespace profiler + +} // namespace message +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_MESSAGECONVERTERS_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/MessageInterfaces.h b/NativeScript/napi/hermes/include_old/hermes/cdp/MessageInterfaces.h new file mode 100644 index 00000000..f19418f5 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/MessageInterfaces.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_MESSAGEINTERFACES_H +#define HERMES_CDP_MESSAGEINTERFACES_H + +#include +#include +#include +#include +#include + +#include +#include + +namespace facebook { +namespace hermes { +namespace cdp { +namespace message { +using namespace ::hermes::parser; + +struct RequestHandler; + +/// Serializable is an interface for objects that can be serialized to and from +/// JSON. +struct Serializable { + virtual ~Serializable() = default; + virtual JSONValue *toJsonVal(JSONFactory &factory) const = 0; + + std::string toJsonStr() const; +}; + +/// Requests are sent from the debugger to the target. +struct Request : public Serializable { + using ParseResult = std::variant, std::string>; + static std::unique_ptr fromJson(const std::string &str); + + Request() = default; + explicit Request(std::string method) : method(method) {} + + // accept dispatches to the appropriate handler method in RequestHandler based + // on the type of the request. + virtual void accept(RequestHandler &handler) const = 0; + + long long id = 0; + std::string method; +}; + +/// Responses are sent from the target to the debugger in response to a Request. +struct Response : public Serializable { + Response() = default; + + std::optional id = std::nullopt; +}; + +/// Notifications are sent from the target to the debugger. This is used to +/// notify the debugger about events that occur in the target, e.g. stopping +/// at a breakpoint. +struct Notification : public Serializable { + Notification() = default; + explicit Notification(std::string method) : method(method) {} + + std::string method; +}; + +} // namespace message +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_MESSAGEINTERFACES_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/MessageTypes.h b/NativeScript/napi/hermes/include_old/hermes/cdp/MessageTypes.h new file mode 100644 index 00000000..fcc86c32 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/MessageTypes.h @@ -0,0 +1,1262 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. +// @generated SignedSource<> + +#pragma once + +#include +#include + +#include +#include + +namespace facebook { +namespace hermes { +namespace cdp { +namespace message { + +template +void deleter(T *p); +using JSONBlob = std::string; +struct UnknownRequest; + +namespace debugger { +using BreakpointId = std::string; +struct BreakpointResolvedNotification; +struct CallFrame; +using CallFrameId = std::string; +struct DisableRequest; +struct EnableRequest; +struct EvaluateOnCallFrameRequest; +struct EvaluateOnCallFrameResponse; +struct Location; +struct PauseRequest; +struct PausedNotification; +struct RemoveBreakpointRequest; +struct ResumeRequest; +struct ResumedNotification; +struct Scope; +struct ScriptParsedNotification; +struct ScriptPosition; +struct SetBlackboxedRangesRequest; +struct SetBreakpointByUrlRequest; +struct SetBreakpointByUrlResponse; +struct SetBreakpointRequest; +struct SetBreakpointResponse; +struct SetBreakpointsActiveRequest; +struct SetInstrumentationBreakpointRequest; +struct SetInstrumentationBreakpointResponse; +struct SetPauseOnExceptionsRequest; +struct StepIntoRequest; +struct StepOutRequest; +struct StepOverRequest; +} // namespace debugger + +namespace runtime { +struct CallArgument; +struct CallFrame; +struct CallFunctionOnRequest; +struct CallFunctionOnResponse; +struct CompileScriptRequest; +struct CompileScriptResponse; +struct ConsoleAPICalledNotification; +struct CustomPreview; +struct DisableRequest; +struct DiscardConsoleEntriesRequest; +struct EnableRequest; +struct EntryPreview; +struct EvaluateRequest; +struct EvaluateResponse; +struct ExceptionDetails; +struct ExecutionContextCreatedNotification; +struct ExecutionContextDescription; +using ExecutionContextId = long long; +struct GetHeapUsageRequest; +struct GetHeapUsageResponse; +struct GetPropertiesRequest; +struct GetPropertiesResponse; +struct GlobalLexicalScopeNamesRequest; +struct GlobalLexicalScopeNamesResponse; +struct InspectRequestedNotification; +struct InternalPropertyDescriptor; +struct ObjectPreview; +struct PropertyDescriptor; +struct PropertyPreview; +struct ReleaseObjectGroupRequest; +struct ReleaseObjectRequest; +struct RemoteObject; +using RemoteObjectId = std::string; +struct RunIfWaitingForDebuggerRequest; +using ScriptId = std::string; +struct StackTrace; +using Timestamp = double; +using UnserializableValue = std::string; +} // namespace runtime + +namespace heapProfiler { +struct AddHeapSnapshotChunkNotification; +struct CollectGarbageRequest; +struct GetHeapObjectIdRequest; +struct GetHeapObjectIdResponse; +struct GetObjectByHeapObjectIdRequest; +struct GetObjectByHeapObjectIdResponse; +using HeapSnapshotObjectId = std::string; +struct HeapStatsUpdateNotification; +struct LastSeenObjectIdNotification; +struct ReportHeapSnapshotProgressNotification; +struct SamplingHeapProfile; +struct SamplingHeapProfileNode; +struct SamplingHeapProfileSample; +struct StartSamplingRequest; +struct StartTrackingHeapObjectsRequest; +struct StopSamplingRequest; +struct StopSamplingResponse; +struct StopTrackingHeapObjectsRequest; +struct TakeHeapSnapshotRequest; +} // namespace heapProfiler + +namespace profiler { +struct PositionTickInfo; +struct Profile; +struct ProfileNode; +struct StartRequest; +struct StopRequest; +struct StopResponse; +} // namespace profiler + +/// RequestHandler handles requests via the visitor pattern. +struct RequestHandler { + virtual ~RequestHandler() = default; + + virtual void handle(const UnknownRequest &req) = 0; + virtual void handle(const debugger::DisableRequest &req) = 0; + virtual void handle(const debugger::EnableRequest &req) = 0; + virtual void handle(const debugger::EvaluateOnCallFrameRequest &req) = 0; + virtual void handle(const debugger::PauseRequest &req) = 0; + virtual void handle(const debugger::RemoveBreakpointRequest &req) = 0; + virtual void handle(const debugger::ResumeRequest &req) = 0; + virtual void handle(const debugger::SetBlackboxedRangesRequest &req) = 0; + virtual void handle(const debugger::SetBreakpointRequest &req) = 0; + virtual void handle(const debugger::SetBreakpointByUrlRequest &req) = 0; + virtual void handle(const debugger::SetBreakpointsActiveRequest &req) = 0; + virtual void handle( + const debugger::SetInstrumentationBreakpointRequest &req) = 0; + virtual void handle(const debugger::SetPauseOnExceptionsRequest &req) = 0; + virtual void handle(const debugger::StepIntoRequest &req) = 0; + virtual void handle(const debugger::StepOutRequest &req) = 0; + virtual void handle(const debugger::StepOverRequest &req) = 0; + virtual void handle(const heapProfiler::CollectGarbageRequest &req) = 0; + virtual void handle(const heapProfiler::GetHeapObjectIdRequest &req) = 0; + virtual void handle( + const heapProfiler::GetObjectByHeapObjectIdRequest &req) = 0; + virtual void handle(const heapProfiler::StartSamplingRequest &req) = 0; + virtual void handle( + const heapProfiler::StartTrackingHeapObjectsRequest &req) = 0; + virtual void handle(const heapProfiler::StopSamplingRequest &req) = 0; + virtual void handle( + const heapProfiler::StopTrackingHeapObjectsRequest &req) = 0; + virtual void handle(const heapProfiler::TakeHeapSnapshotRequest &req) = 0; + virtual void handle(const profiler::StartRequest &req) = 0; + virtual void handle(const profiler::StopRequest &req) = 0; + virtual void handle(const runtime::CallFunctionOnRequest &req) = 0; + virtual void handle(const runtime::CompileScriptRequest &req) = 0; + virtual void handle(const runtime::DisableRequest &req) = 0; + virtual void handle(const runtime::DiscardConsoleEntriesRequest &req) = 0; + virtual void handle(const runtime::EnableRequest &req) = 0; + virtual void handle(const runtime::EvaluateRequest &req) = 0; + virtual void handle(const runtime::GetHeapUsageRequest &req) = 0; + virtual void handle(const runtime::GetPropertiesRequest &req) = 0; + virtual void handle(const runtime::GlobalLexicalScopeNamesRequest &req) = 0; + virtual void handle(const runtime::ReleaseObjectRequest &req) = 0; + virtual void handle(const runtime::ReleaseObjectGroupRequest &req) = 0; + virtual void handle(const runtime::RunIfWaitingForDebuggerRequest &req) = 0; +}; + +/// NoopRequestHandler can be subclassed to only handle some requests. +struct NoopRequestHandler : public RequestHandler { + void handle(const UnknownRequest &req) override {} + void handle(const debugger::DisableRequest &req) override {} + void handle(const debugger::EnableRequest &req) override {} + void handle(const debugger::EvaluateOnCallFrameRequest &req) override {} + void handle(const debugger::PauseRequest &req) override {} + void handle(const debugger::RemoveBreakpointRequest &req) override {} + void handle(const debugger::ResumeRequest &req) override {} + void handle(const debugger::SetBlackboxedRangesRequest &req) override {} + void handle(const debugger::SetBreakpointRequest &req) override {} + void handle(const debugger::SetBreakpointByUrlRequest &req) override {} + void handle(const debugger::SetBreakpointsActiveRequest &req) override {} + void handle( + const debugger::SetInstrumentationBreakpointRequest &req) override {} + void handle(const debugger::SetPauseOnExceptionsRequest &req) override {} + void handle(const debugger::StepIntoRequest &req) override {} + void handle(const debugger::StepOutRequest &req) override {} + void handle(const debugger::StepOverRequest &req) override {} + void handle(const heapProfiler::CollectGarbageRequest &req) override {} + void handle(const heapProfiler::GetHeapObjectIdRequest &req) override {} + void handle( + const heapProfiler::GetObjectByHeapObjectIdRequest &req) override {} + void handle(const heapProfiler::StartSamplingRequest &req) override {} + void handle( + const heapProfiler::StartTrackingHeapObjectsRequest &req) override {} + void handle(const heapProfiler::StopSamplingRequest &req) override {} + void handle( + const heapProfiler::StopTrackingHeapObjectsRequest &req) override {} + void handle(const heapProfiler::TakeHeapSnapshotRequest &req) override {} + void handle(const profiler::StartRequest &req) override {} + void handle(const profiler::StopRequest &req) override {} + void handle(const runtime::CallFunctionOnRequest &req) override {} + void handle(const runtime::CompileScriptRequest &req) override {} + void handle(const runtime::DisableRequest &req) override {} + void handle(const runtime::DiscardConsoleEntriesRequest &req) override {} + void handle(const runtime::EnableRequest &req) override {} + void handle(const runtime::EvaluateRequest &req) override {} + void handle(const runtime::GetHeapUsageRequest &req) override {} + void handle(const runtime::GetPropertiesRequest &req) override {} + void handle(const runtime::GlobalLexicalScopeNamesRequest &req) override {} + void handle(const runtime::ReleaseObjectRequest &req) override {} + void handle(const runtime::ReleaseObjectGroupRequest &req) override {} + void handle(const runtime::RunIfWaitingForDebuggerRequest &req) override {} +}; + +/// Types +struct debugger::Location : public Serializable { + Location() = default; + Location(Location &&) = default; + Location(const Location &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + Location &operator=(const Location &) = delete; + Location &operator=(Location &&) = default; + + runtime::ScriptId scriptId{}; + long long lineNumber{}; + std::optional columnNumber; +}; + +struct runtime::PropertyPreview : public Serializable { + PropertyPreview() = default; + PropertyPreview(PropertyPreview &&) = default; + PropertyPreview(const PropertyPreview &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + PropertyPreview &operator=(const PropertyPreview &) = delete; + PropertyPreview &operator=(PropertyPreview &&) = default; + + std::string name; + std::string type; + std::optional value; + std::unique_ptr< + runtime::ObjectPreview, + std::function> + valuePreview{nullptr, deleter}; + std::optional subtype; +}; + +struct runtime::EntryPreview : public Serializable { + EntryPreview() = default; + EntryPreview(EntryPreview &&) = default; + EntryPreview(const EntryPreview &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + EntryPreview &operator=(const EntryPreview &) = delete; + EntryPreview &operator=(EntryPreview &&) = default; + + std::unique_ptr< + runtime::ObjectPreview, + std::function> + key{nullptr, deleter}; + std::unique_ptr< + runtime::ObjectPreview, + std::function> + value{nullptr, deleter}; +}; + +struct runtime::ObjectPreview : public Serializable { + ObjectPreview() = default; + ObjectPreview(ObjectPreview &&) = default; + ObjectPreview(const ObjectPreview &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + ObjectPreview &operator=(const ObjectPreview &) = delete; + ObjectPreview &operator=(ObjectPreview &&) = default; + + std::string type; + std::optional subtype; + std::optional description; + bool overflow{}; + std::vector properties; + std::optional> entries; +}; + +struct runtime::CustomPreview : public Serializable { + CustomPreview() = default; + CustomPreview(CustomPreview &&) = default; + CustomPreview(const CustomPreview &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + CustomPreview &operator=(const CustomPreview &) = delete; + CustomPreview &operator=(CustomPreview &&) = default; + + std::string header; + std::optional bodyGetterId; +}; + +struct runtime::RemoteObject : public Serializable { + RemoteObject() = default; + RemoteObject(RemoteObject &&) = default; + RemoteObject(const RemoteObject &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + RemoteObject &operator=(const RemoteObject &) = delete; + RemoteObject &operator=(RemoteObject &&) = default; + + std::string type; + std::optional subtype; + std::optional className; + std::optional value; + std::optional unserializableValue; + std::optional description; + std::optional objectId; + std::optional preview; + std::optional customPreview; +}; + +struct runtime::CallFrame : public Serializable { + CallFrame() = default; + CallFrame(CallFrame &&) = default; + CallFrame(const CallFrame &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + CallFrame &operator=(const CallFrame &) = delete; + CallFrame &operator=(CallFrame &&) = default; + + std::string functionName; + runtime::ScriptId scriptId{}; + std::string url; + long long lineNumber{}; + long long columnNumber{}; +}; + +struct runtime::StackTrace : public Serializable { + StackTrace() = default; + StackTrace(StackTrace &&) = default; + StackTrace(const StackTrace &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + StackTrace &operator=(const StackTrace &) = delete; + StackTrace &operator=(StackTrace &&) = default; + + std::optional description; + std::vector callFrames; + std::unique_ptr parent; +}; + +struct runtime::ExceptionDetails : public Serializable { + ExceptionDetails() = default; + ExceptionDetails(ExceptionDetails &&) = default; + ExceptionDetails(const ExceptionDetails &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + ExceptionDetails &operator=(const ExceptionDetails &) = delete; + ExceptionDetails &operator=(ExceptionDetails &&) = default; + + long long exceptionId{}; + std::string text; + long long lineNumber{}; + long long columnNumber{}; + std::optional scriptId; + std::optional url; + std::optional stackTrace; + std::optional exception; + std::optional executionContextId; +}; + +struct debugger::Scope : public Serializable { + Scope() = default; + Scope(Scope &&) = default; + Scope(const Scope &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + Scope &operator=(const Scope &) = delete; + Scope &operator=(Scope &&) = default; + + std::string type; + runtime::RemoteObject object{}; + std::optional name; + std::optional startLocation; + std::optional endLocation; +}; + +struct debugger::CallFrame : public Serializable { + CallFrame() = default; + CallFrame(CallFrame &&) = default; + CallFrame(const CallFrame &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + CallFrame &operator=(const CallFrame &) = delete; + CallFrame &operator=(CallFrame &&) = default; + + debugger::CallFrameId callFrameId{}; + std::string functionName; + std::optional functionLocation; + debugger::Location location{}; + std::string url; + std::vector scopeChain; + runtime::RemoteObject thisObj{}; + std::optional returnValue; +}; + +struct debugger::ScriptPosition : public Serializable { + ScriptPosition() = default; + ScriptPosition(ScriptPosition &&) = default; + ScriptPosition(const ScriptPosition &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + ScriptPosition &operator=(const ScriptPosition &) = delete; + ScriptPosition &operator=(ScriptPosition &&) = default; + + long long lineNumber{}; + long long columnNumber{}; +}; + +struct heapProfiler::SamplingHeapProfileNode : public Serializable { + SamplingHeapProfileNode() = default; + SamplingHeapProfileNode(SamplingHeapProfileNode &&) = default; + SamplingHeapProfileNode(const SamplingHeapProfileNode &) = delete; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + SamplingHeapProfileNode &operator=(const SamplingHeapProfileNode &) = delete; + SamplingHeapProfileNode &operator=(SamplingHeapProfileNode &&) = default; + + runtime::CallFrame callFrame{}; + double selfSize{}; + long long id{}; + std::vector children; +}; + +struct heapProfiler::SamplingHeapProfileSample : public Serializable { + SamplingHeapProfileSample() = default; + SamplingHeapProfileSample(SamplingHeapProfileSample &&) = default; + SamplingHeapProfileSample(const SamplingHeapProfileSample &) = delete; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + SamplingHeapProfileSample &operator=(const SamplingHeapProfileSample &) = + delete; + SamplingHeapProfileSample &operator=(SamplingHeapProfileSample &&) = default; + + double size{}; + long long nodeId{}; + double ordinal{}; +}; + +struct heapProfiler::SamplingHeapProfile : public Serializable { + SamplingHeapProfile() = default; + SamplingHeapProfile(SamplingHeapProfile &&) = default; + SamplingHeapProfile(const SamplingHeapProfile &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + SamplingHeapProfile &operator=(const SamplingHeapProfile &) = delete; + SamplingHeapProfile &operator=(SamplingHeapProfile &&) = default; + + heapProfiler::SamplingHeapProfileNode head{}; + std::vector samples; +}; + +struct profiler::PositionTickInfo : public Serializable { + PositionTickInfo() = default; + PositionTickInfo(PositionTickInfo &&) = default; + PositionTickInfo(const PositionTickInfo &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + PositionTickInfo &operator=(const PositionTickInfo &) = delete; + PositionTickInfo &operator=(PositionTickInfo &&) = default; + + long long line{}; + long long ticks{}; +}; + +struct profiler::ProfileNode : public Serializable { + ProfileNode() = default; + ProfileNode(ProfileNode &&) = default; + ProfileNode(const ProfileNode &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + ProfileNode &operator=(const ProfileNode &) = delete; + ProfileNode &operator=(ProfileNode &&) = default; + + long long id{}; + runtime::CallFrame callFrame{}; + std::optional hitCount; + std::optional> children; + std::optional deoptReason; + std::optional> positionTicks; +}; + +struct profiler::Profile : public Serializable { + Profile() = default; + Profile(Profile &&) = default; + Profile(const Profile &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + Profile &operator=(const Profile &) = delete; + Profile &operator=(Profile &&) = default; + + std::vector nodes; + double startTime{}; + double endTime{}; + std::optional> samples; + std::optional> timeDeltas; +}; + +struct runtime::CallArgument : public Serializable { + CallArgument() = default; + CallArgument(CallArgument &&) = default; + CallArgument(const CallArgument &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + CallArgument &operator=(const CallArgument &) = delete; + CallArgument &operator=(CallArgument &&) = default; + + std::optional value; + std::optional unserializableValue; + std::optional objectId; +}; + +struct runtime::ExecutionContextDescription : public Serializable { + ExecutionContextDescription() = default; + ExecutionContextDescription(ExecutionContextDescription &&) = default; + ExecutionContextDescription(const ExecutionContextDescription &) = delete; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + ExecutionContextDescription &operator=(const ExecutionContextDescription &) = + delete; + ExecutionContextDescription &operator=(ExecutionContextDescription &&) = + default; + + runtime::ExecutionContextId id{}; + std::string origin; + std::string name; + std::optional auxData; +}; + +struct runtime::PropertyDescriptor : public Serializable { + PropertyDescriptor() = default; + PropertyDescriptor(PropertyDescriptor &&) = default; + PropertyDescriptor(const PropertyDescriptor &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + PropertyDescriptor &operator=(const PropertyDescriptor &) = delete; + PropertyDescriptor &operator=(PropertyDescriptor &&) = default; + + std::string name; + std::optional value; + std::optional writable; + std::optional get; + std::optional set; + bool configurable{}; + bool enumerable{}; + std::optional wasThrown; + std::optional isOwn; + std::optional symbol; +}; + +struct runtime::InternalPropertyDescriptor : public Serializable { + InternalPropertyDescriptor() = default; + InternalPropertyDescriptor(InternalPropertyDescriptor &&) = default; + InternalPropertyDescriptor(const InternalPropertyDescriptor &) = delete; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + InternalPropertyDescriptor &operator=(const InternalPropertyDescriptor &) = + delete; + InternalPropertyDescriptor &operator=(InternalPropertyDescriptor &&) = + default; + + std::string name; + std::optional value; +}; + +/// Requests +struct UnknownRequest : public Request { + UnknownRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional params; +}; + +struct debugger::DisableRequest : public Request { + DisableRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct debugger::EnableRequest : public Request { + EnableRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct debugger::EvaluateOnCallFrameRequest : public Request { + EvaluateOnCallFrameRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + debugger::CallFrameId callFrameId{}; + std::string expression; + std::optional objectGroup; + std::optional includeCommandLineAPI; + std::optional silent; + std::optional returnByValue; + std::optional generatePreview; + std::optional throwOnSideEffect; +}; + +struct debugger::PauseRequest : public Request { + PauseRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct debugger::RemoveBreakpointRequest : public Request { + RemoveBreakpointRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + debugger::BreakpointId breakpointId{}; +}; + +struct debugger::ResumeRequest : public Request { + ResumeRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional terminateOnResume; +}; + +struct debugger::SetBlackboxedRangesRequest : public Request { + SetBlackboxedRangesRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + runtime::ScriptId scriptId{}; + std::vector positions; +}; + +struct debugger::SetBreakpointRequest : public Request { + SetBreakpointRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + debugger::Location location{}; + std::optional condition; +}; + +struct debugger::SetBreakpointByUrlRequest : public Request { + SetBreakpointByUrlRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + long long lineNumber{}; + std::optional url; + std::optional urlRegex; + std::optional scriptHash; + std::optional columnNumber; + std::optional condition; +}; + +struct debugger::SetBreakpointsActiveRequest : public Request { + SetBreakpointsActiveRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + bool active{}; +}; + +struct debugger::SetInstrumentationBreakpointRequest : public Request { + SetInstrumentationBreakpointRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::string instrumentation; +}; + +struct debugger::SetPauseOnExceptionsRequest : public Request { + SetPauseOnExceptionsRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::string state; +}; + +struct debugger::StepIntoRequest : public Request { + StepIntoRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct debugger::StepOutRequest : public Request { + StepOutRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct debugger::StepOverRequest : public Request { + StepOverRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct heapProfiler::CollectGarbageRequest : public Request { + CollectGarbageRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct heapProfiler::GetHeapObjectIdRequest : public Request { + GetHeapObjectIdRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + runtime::RemoteObjectId objectId{}; +}; + +struct heapProfiler::GetObjectByHeapObjectIdRequest : public Request { + GetObjectByHeapObjectIdRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + heapProfiler::HeapSnapshotObjectId objectId{}; + std::optional objectGroup; +}; + +struct heapProfiler::StartSamplingRequest : public Request { + StartSamplingRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional samplingInterval; + std::optional includeObjectsCollectedByMajorGC; + std::optional includeObjectsCollectedByMinorGC; +}; + +struct heapProfiler::StartTrackingHeapObjectsRequest : public Request { + StartTrackingHeapObjectsRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional trackAllocations; +}; + +struct heapProfiler::StopSamplingRequest : public Request { + StopSamplingRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct heapProfiler::StopTrackingHeapObjectsRequest : public Request { + StopTrackingHeapObjectsRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional reportProgress; + std::optional treatGlobalObjectsAsRoots; + std::optional captureNumericValue; +}; + +struct heapProfiler::TakeHeapSnapshotRequest : public Request { + TakeHeapSnapshotRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional reportProgress; + std::optional treatGlobalObjectsAsRoots; + std::optional captureNumericValue; +}; + +struct profiler::StartRequest : public Request { + StartRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct profiler::StopRequest : public Request { + StopRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct runtime::CallFunctionOnRequest : public Request { + CallFunctionOnRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::string functionDeclaration; + std::optional objectId; + std::optional> arguments; + std::optional silent; + std::optional returnByValue; + std::optional generatePreview; + std::optional userGesture; + std::optional awaitPromise; + std::optional executionContextId; + std::optional objectGroup; +}; + +struct runtime::CompileScriptRequest : public Request { + CompileScriptRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::string expression; + std::string sourceURL; + bool persistScript{}; + std::optional executionContextId; +}; + +struct runtime::DisableRequest : public Request { + DisableRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct runtime::DiscardConsoleEntriesRequest : public Request { + DiscardConsoleEntriesRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct runtime::EnableRequest : public Request { + EnableRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct runtime::EvaluateRequest : public Request { + EvaluateRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::string expression; + std::optional objectGroup; + std::optional includeCommandLineAPI; + std::optional silent; + std::optional contextId; + std::optional returnByValue; + std::optional generatePreview; + std::optional userGesture; + std::optional awaitPromise; +}; + +struct runtime::GetHeapUsageRequest : public Request { + GetHeapUsageRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct runtime::GetPropertiesRequest : public Request { + GetPropertiesRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + runtime::RemoteObjectId objectId{}; + std::optional ownProperties; + std::optional accessorPropertiesOnly; + std::optional generatePreview; +}; + +struct runtime::GlobalLexicalScopeNamesRequest : public Request { + GlobalLexicalScopeNamesRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional executionContextId; +}; + +struct runtime::ReleaseObjectRequest : public Request { + ReleaseObjectRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + runtime::RemoteObjectId objectId{}; +}; + +struct runtime::ReleaseObjectGroupRequest : public Request { + ReleaseObjectGroupRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::string objectGroup; +}; + +struct runtime::RunIfWaitingForDebuggerRequest : public Request { + RunIfWaitingForDebuggerRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +/// Responses +struct ErrorResponse : public Response { + ErrorResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + long long code; + std::string message; + std::optional data; +}; + +struct OkResponse : public Response { + OkResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; +}; + +struct debugger::EvaluateOnCallFrameResponse : public Response { + EvaluateOnCallFrameResponse() = default; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + runtime::RemoteObject result{}; + std::optional exceptionDetails; +}; + +struct debugger::SetBreakpointResponse : public Response { + SetBreakpointResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + debugger::BreakpointId breakpointId{}; + debugger::Location actualLocation{}; +}; + +struct debugger::SetBreakpointByUrlResponse : public Response { + SetBreakpointByUrlResponse() = default; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + debugger::BreakpointId breakpointId{}; + std::vector locations; +}; + +struct debugger::SetInstrumentationBreakpointResponse : public Response { + SetInstrumentationBreakpointResponse() = default; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + debugger::BreakpointId breakpointId{}; +}; + +struct heapProfiler::GetHeapObjectIdResponse : public Response { + GetHeapObjectIdResponse() = default; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + heapProfiler::HeapSnapshotObjectId heapSnapshotObjectId{}; +}; + +struct heapProfiler::GetObjectByHeapObjectIdResponse : public Response { + GetObjectByHeapObjectIdResponse() = default; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + runtime::RemoteObject result{}; +}; + +struct heapProfiler::StopSamplingResponse : public Response { + StopSamplingResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + heapProfiler::SamplingHeapProfile profile{}; +}; + +struct profiler::StopResponse : public Response { + StopResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + profiler::Profile profile{}; +}; + +struct runtime::CallFunctionOnResponse : public Response { + CallFunctionOnResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + runtime::RemoteObject result{}; + std::optional exceptionDetails; +}; + +struct runtime::CompileScriptResponse : public Response { + CompileScriptResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::optional scriptId; + std::optional exceptionDetails; +}; + +struct runtime::EvaluateResponse : public Response { + EvaluateResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + runtime::RemoteObject result{}; + std::optional exceptionDetails; +}; + +struct runtime::GetHeapUsageResponse : public Response { + GetHeapUsageResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + double usedSize{}; + double totalSize{}; +}; + +struct runtime::GetPropertiesResponse : public Response { + GetPropertiesResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::vector result; + std::optional> + internalProperties; + std::optional exceptionDetails; +}; + +struct runtime::GlobalLexicalScopeNamesResponse : public Response { + GlobalLexicalScopeNamesResponse() = default; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::vector names; +}; + +/// Notifications +struct debugger::BreakpointResolvedNotification : public Notification { + BreakpointResolvedNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + debugger::BreakpointId breakpointId{}; + debugger::Location location{}; +}; + +struct debugger::PausedNotification : public Notification { + PausedNotification(); + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::vector callFrames; + std::string reason; + std::optional data; + std::optional> hitBreakpoints; + std::optional asyncStackTrace; +}; + +struct debugger::ResumedNotification : public Notification { + ResumedNotification(); + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; +}; + +struct debugger::ScriptParsedNotification : public Notification { + ScriptParsedNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + runtime::ScriptId scriptId{}; + std::string url; + long long startLine{}; + long long startColumn{}; + long long endLine{}; + long long endColumn{}; + runtime::ExecutionContextId executionContextId{}; + std::string hash; + std::optional executionContextAuxData; + std::optional sourceMapURL; + std::optional hasSourceURL; + std::optional isModule; + std::optional length; +}; + +struct heapProfiler::AddHeapSnapshotChunkNotification : public Notification { + AddHeapSnapshotChunkNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::string chunk; +}; + +struct heapProfiler::HeapStatsUpdateNotification : public Notification { + HeapStatsUpdateNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::vector statsUpdate; +}; + +struct heapProfiler::LastSeenObjectIdNotification : public Notification { + LastSeenObjectIdNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + long long lastSeenObjectId{}; + double timestamp{}; +}; + +struct heapProfiler::ReportHeapSnapshotProgressNotification + : public Notification { + ReportHeapSnapshotProgressNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + long long done{}; + long long total{}; + std::optional finished; +}; + +struct runtime::ConsoleAPICalledNotification : public Notification { + ConsoleAPICalledNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::string type; + std::vector args; + runtime::ExecutionContextId executionContextId{}; + runtime::Timestamp timestamp{}; + std::optional stackTrace; +}; + +struct runtime::ExecutionContextCreatedNotification : public Notification { + ExecutionContextCreatedNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + runtime::ExecutionContextDescription context{}; +}; + +struct runtime::InspectRequestedNotification : public Notification { + InspectRequestedNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + runtime::RemoteObject object{}; + JSONBlob hints; + std::optional executionContextId; +}; + +} // namespace message +} // namespace cdp +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/MessageTypesInlines.h b/NativeScript/napi/hermes/include_old/hermes/cdp/MessageTypesInlines.h new file mode 100644 index 00000000..fe765f93 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/MessageTypesInlines.h @@ -0,0 +1,316 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_MESSAGETYPESINLINES_H +#define HERMES_CDP_MESSAGETYPESINLINES_H + +#include +#include +#include + +#include +#include +#include + +namespace facebook { +namespace hermes { +namespace cdp { +namespace message { + +template +using optional = std::optional; + +template +struct is_vector : std::false_type {}; + +template +struct is_vector> : std::true_type {}; + +/// valueFromJson + +/// Convert JSONValue to a Serializable type. +template +typename std:: + enable_if::value, std::unique_ptr>::type + valueFromJson(const JSONValue *v) { + auto res = llvh::dyn_cast_or_null(v); + if (!res) { + return nullptr; + } + return T::tryMake(res); +} + +/// Convert JSONValue to a bool. +template +typename std::enable_if::value, std::unique_ptr>::type +valueFromJson(const JSONValue *v) { + auto res = llvh::dyn_cast_or_null(v); + if (!res) { + return nullptr; + } + return std::make_unique(res->getValue()); +} + +/// Convert JSONValue to a long long. +template +typename std::enable_if::value, std::unique_ptr>:: + type + valueFromJson(const JSONValue *v) { + auto res = llvh::dyn_cast_or_null(v); + if (!res) { + return nullptr; + } + return std::make_unique(res->getValue()); +} + +/// Convert JSONValue to a double. +template +typename std::enable_if::value, std::unique_ptr>:: + type + valueFromJson(const JSONValue *v) { + auto res = llvh::dyn_cast_or_null(v); + if (!res) { + return nullptr; + } + return std::make_unique(res->getValue()); +} + +/// Convert JSONValue to a string. +template +typename std:: + enable_if::value, std::unique_ptr>::type + valueFromJson(const JSONValue *v) { + auto res = llvh::dyn_cast_or_null(v); + if (!res) { + return nullptr; + } + return std::make_unique(res->c_str()); +} + +/// Convert JSONValue to a vector. +template +typename std::enable_if::value, std::unique_ptr>::type +valueFromJson(const JSONValue *items) { + auto *arr = llvh::dyn_cast(items); + std::unique_ptr result = std::make_unique(); + result->reserve(arr->size()); + for (const auto &item : *arr) { + auto itemResult = valueFromJson(item); + if (!itemResult) { + return nullptr; + } + result->push_back(std::move(*itemResult)); + } + return result; +} + +/// Convert JSONValue to a JSONObject. +template +typename std:: + enable_if::value, std::unique_ptr>::type + valueFromJson(JSONValue *v) { + auto *res = llvh::dyn_cast_or_null(v); + if (!res) { + return nullptr; + } + return std::make_unique(res); +} + +/// Pass through JSONValues. +template +typename std:: + enable_if::value, std::unique_ptr>::type + valueFromJson(JSONValue *v) { + return std::make_unique(v); +} + +/// assign(lhs, obj, key) is a wrapper for: +/// +/// lhs = obj[key] +/// +/// It mainly exists so that we can choose the right version of valueFromJson +/// based on the type of lhs. + +template +bool assign(T &lhs, const JSONObject *obj, const U &key) { + JSONValue *v = obj->get(key); + if (v == nullptr) { + return false; + } + auto convertResult = valueFromJson(v); + if (convertResult) { + lhs = std::move(*convertResult); + return true; + } + return false; +} + +template +bool assign(optional &lhs, const JSONObject *obj, const U &key) { + JSONValue *v = obj->get(key); + if (v != nullptr) { + auto convertResult = valueFromJson(v); + if (convertResult) { + lhs = std::move(*convertResult); + return true; + } + return false; + } else { + lhs.reset(); + return true; + } +} + +template +bool assign(std::unique_ptr &lhs, const JSONObject *obj, const U &key) { + JSONValue *v = obj->get(key); + if (v != nullptr) { + auto convertResult = valueFromJson(v); + if (convertResult) { + lhs = std::move(convertResult); + return true; + } + return false; + } else { + lhs.reset(); + return true; + } +} + +template +bool assign( + std::unique_ptr> &lhs, + const JSONObject *obj, + const U &key) { + JSONValue *v = obj->get(key); + if (v != nullptr) { + auto convertResult = valueFromJson(v); + if (convertResult) { + lhs = std::move(convertResult); + return true; + } + return false; + } else { + lhs.reset(); + return true; + } +} + +/// valueToJson + +inline JSONValue *valueToJson(const Serializable &value, JSONFactory &factory) { + return value.toJsonVal(factory); +} + +// Convert a bool to JSONValue. +inline JSONValue *valueToJson(bool b, JSONFactory &factory) { + return factory.getBoolean(b); +} + +// Convert a long long to JSONValue. +inline JSONValue *valueToJson(long long num, JSONFactory &factory) { + return factory.getNumber(num); +} + +// Convert a double to JSONValue. +inline JSONValue *valueToJson(double num, JSONFactory &factory) { + return factory.getNumber(num); +} + +// Convert a string to JSONValue. +inline JSONValue *valueToJson(const std::string &str, JSONFactory &factory) { + return factory.getString(str); +} + +// Convert a vector to JSONValue. +template +JSONValue *valueToJson(const std::vector &items, JSONFactory &factory) { + llvh::SmallVector storage; + for (const auto &item : items) { + storage.push_back(valueToJson(item, factory)); + } + return factory.newArray(storage.size(), storage.begin(), storage.end()); +} + +// Cast a JSONObject to JSONValue. +inline JSONValue *valueToJson(JSONObject *obj, JSONFactory &factory) { + return llvh::cast(obj); +} + +// Pass through JSONValues. +inline JSONValue *valueToJson(JSONValue *v, JSONFactory &factory) { + return v; +} + +/// put(obj, key, value) is meant to be a wrapper for: +/// obj[key] = valueToJson(value); +/// However, JSONObjects are immutable, so we represent a 'put' operation as +/// pushing a new element onto a vector of JSONFactory::Props. + +using Properties = llvh::SmallVectorImpl; + +template +void put( + Properties &props, + const std::string &key, + const V &value, + JSONFactory &factory) { + JSONString *jsStr = factory.getString(key); + JSONValue *jsVal = valueToJson(value, factory); + props.push_back({jsStr, jsVal}); +} + +template +void put( + Properties &props, + const std::string &key, + const optional &optValue, + JSONFactory &factory) { + if (optValue.has_value()) { + JSONString *jsStr = factory.getString(key); + JSONValue *jsVal = valueToJson(optValue.value(), factory); + props.push_back({jsStr, jsVal}); + } +} + +template +void put( + Properties &props, + const std::string &key, + const std::unique_ptr &ptr, + JSONFactory &factory) { + if (ptr.get()) { + JSONString *jsStr = factory.getString(key); + JSONValue *jsVal = valueToJson(*ptr, factory); + props.push_back({jsStr, jsVal}); + } +} + +template +void put( + Properties &props, + const std::string &key, + const std::unique_ptr> &ptr, + JSONFactory &factory) { + if (ptr.get()) { + JSONString *jsStr = factory.getString(key); + JSONValue *jsVal = valueToJson(*ptr, factory); + props.push_back({jsStr, jsVal}); + } +} + +template +void deleter(T *p) { + delete p; +} + +} // namespace message +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_MESSAGETYPESINLINES_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/ProfilerDomainAgent.h b/NativeScript/napi/hermes/include_old/hermes/cdp/ProfilerDomainAgent.h new file mode 100644 index 00000000..6c62b9c8 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/ProfilerDomainAgent.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_PROFILERDOMAINAGENT_H +#define HERMES_CDP_PROFILERDOMAINAGENT_H + +#include +#include + +#include "DomainAgent.h" + +namespace facebook { +namespace hermes { +namespace cdp { + +/// Handler for the "Profiler" domain of CDP. All methods expect to be invoked +/// with exclusive access to the runtime. +class ProfilerDomainAgent : public DomainAgent { + public: + ProfilerDomainAgent( + int32_t executionContextID, + HermesRuntime &runtime, + SynchronizedOutboundCallback messageCallback, + std::shared_ptr objTable); + ~ProfilerDomainAgent() = default; + + void start(const m::profiler::StartRequest &req); + void stop(const m::profiler::StopRequest &req); + + private: + HermesRuntime &runtime_; +}; + +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_PROFILERDOMAINAGENT_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/RemoteObjectConverters.h b/NativeScript/napi/hermes/include_old/hermes/cdp/RemoteObjectConverters.h new file mode 100644 index 00000000..ae688884 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/RemoteObjectConverters.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_REMOTEOBJECTCONVERTERS_H +#define HERMES_CDP_REMOTEOBJECTCONVERTERS_H + +#include +#include +#include +#include + +namespace facebook { +namespace hermes { +namespace cdp { + +struct ObjectSerializationOptions { + bool returnByValue = false; + bool generatePreview = false; +}; + +namespace message { + +namespace debugger { + +CallFrame makeCallFrame( + uint32_t callFrameIndex, + const facebook::hermes::debugger::CallFrameInfo &callFrameInfo, + const facebook::hermes::debugger::LexicalInfo &lexicalInfo, + cdp::RemoteObjectsTable &objTable, + jsi::Runtime &runtime, + const facebook::hermes::debugger::ProgramState &state); + +std::vector makeCallFrames( + const facebook::hermes::debugger::ProgramState &state, + cdp::RemoteObjectsTable &objTable, + jsi::Runtime &runtime); + +} // namespace debugger + +namespace runtime { + +RemoteObject makeRemoteObject( + facebook::jsi::Runtime &runtime, + const facebook::jsi::Value &value, + cdp::RemoteObjectsTable &objTable, + const std::string &objectGroup, + const cdp::ObjectSerializationOptions &serializationOptions); + +RemoteObject makeRemoteObjectForError( + facebook::jsi::Runtime &runtime, + const facebook::jsi::Value &value, + cdp::RemoteObjectsTable &objTable, + const std::string &objectGroup); + +ExceptionDetails makeExceptionDetails( + jsi::Runtime &runtime, + const jsi::JSError &error, + cdp::RemoteObjectsTable &objTable, + const std::string &objectGroup); + +ExceptionDetails makeExceptionDetails(const jsi::JSIException &err); + +ExceptionDetails makeExceptionDetails( + facebook::jsi::Runtime &runtime, + const facebook::hermes::debugger::EvalResult &result, + cdp::RemoteObjectsTable &objTable, + const std::string &objectGroup); + +} // namespace runtime + +} // namespace message +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_REMOTEOBJECTCONVERTERS_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/RemoteObjectsTable.h b/NativeScript/napi/hermes/include_old/hermes/cdp/RemoteObjectsTable.h new file mode 100644 index 00000000..1b8fff5a --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/RemoteObjectsTable.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_REMOTEOBJECTSTABLE_H +#define HERMES_CDP_REMOTEOBJECTSTABLE_H + +#include +#include +#include +#include + +#include + +namespace facebook { +namespace hermes { +namespace cdp { + +/// Well-known object group names + +/** + * Objects created as a result of the Debugger.paused notification (e.g. scope + * objects) are placed in the "backtrace" object group. This object group is + * cleared when the VM resumes. + */ +extern const char *BacktraceObjectGroup; + +/** + * Objects that are created as a result of a console evaluation are placed in + * the "console" object group. This object group is cleared when the client + * clears the console. + */ +extern const char *ConsoleObjectGroup; + +/** + * RemoteObjectsTable manages the mapping of string object ids to scope metadata + * or actual JSI objects. The debugger vends these ids to the client so that the + * client can perform operations on the ids (e.g. enumerate properties on the + * object backed by the id). See Runtime.RemoteObjectId in the CDT docs for + * more details. + * + * Note that object handles are not ref-counted. Suppose an object foo is mapped + * to object id "objId" and is also in object group "objGroup". Then *either* of + * `releaseObject("objId")` or `releaseObjectGroup("objGroup")` will remove foo + * from the table. This matches the behavior of object groups in CDT. + */ +class RemoteObjectsTable { + public: + RemoteObjectsTable(); + ~RemoteObjectsTable(); + + RemoteObjectsTable(const RemoteObjectsTable &) = delete; + RemoteObjectsTable &operator=(const RemoteObjectsTable &) = delete; + + /** + * addScope adds the provided (frameIndex, scopeIndex) mapping to the table. + * If objectGroup is non-empty, then the scope object is also added to that + * object group for releasing via releaseObjectGroup. Returns an object id. + */ + std::string addScope( + std::pair frameAndScopeIndex, + const std::string &objectGroup); + + /** + * addValue adds the JSI value to the table. If objectGroup is non-empty, then + * the scope object is also added to that object group for releasing via + * releaseObjectGroup. Returns an object id. + */ + std::string addValue( + ::facebook::jsi::Value value, + const std::string &objectGroup); + + /// /param objId The object ID. + /// /return true if object ID represents a scope in the scope chain of a call + /// frame. + bool isScopeId(const std::string &objId) const; + + /** + * Retrieves the (frameIndex, scopeIndex) associated with this object id, or + * nullptr if no mapping exists. The pointer stays valid as long as you only + * call const methods on this class. + */ + const std::pair *getScope(const std::string &objId) const; + + /** + * Retrieves the JSI value associated with this object id, or nullptr if no + * mapping exists. The pointer stays valid as long as you only call const + * methods on this class. + */ + const ::facebook::jsi::Value *getValue(const std::string &objId) const; + + /** + * Retrieves the object group that this object id is in, or empty string if it + * isn't in an object group. The returned pointer is only guaranteed to be + * valid until the next call to this class. + */ + std::string getObjectGroup(const std::string &objId) const; + + /** + * Removes the scope or JSI value backed by the provided object ID from the + * table. \return true if the object was removed, false if it was not found. + */ + bool releaseObject(const std::string &objId); + + /** + * Removes all objects that are part of the provided object group from the + * table. + */ + void releaseObjectGroup(const std::string &objectGroup); + + private: + bool releaseObject(int64_t id); + + int64_t scopeId_ = -1; + int64_t valueId_ = 1; + + std::unordered_map> scopes_; + std::unordered_map values_; + std::unordered_map idToGroup_; + std::unordered_map> groupToIds_; +}; + +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_REMOTEOBJECTSTABLE_H diff --git a/NativeScript/napi/hermes/include_old/hermes/cdp/RuntimeDomainAgent.h b/NativeScript/napi/hermes/include_old/hermes/cdp/RuntimeDomainAgent.h new file mode 100644 index 00000000..9c8142aa --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/cdp/RuntimeDomainAgent.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_CDP_RUNTIMEDOMAINAGENT_H +#define HERMES_CDP_RUNTIMEDOMAINAGENT_H + +#include + +#include "CDPDebugAPI.h" +#include "DomainAgent.h" +#include "RemoteObjectConverters.h" + +namespace facebook { +namespace hermes { +namespace cdp { + +namespace m = ::facebook::hermes::cdp::message; + +/// Handler for the "Runtime" domain of CDP. Accepts CDP requests belonging to +/// the "Runtime" domain from the debug client. Produces CDP responses and +/// events belonging to the "Runtime" domain. All methods expect to be invoked +/// with exclusive access to the runtime. +class RuntimeDomainAgent : public DomainAgent { + public: + RuntimeDomainAgent( + int32_t executionContextID, + HermesRuntime &runtime, + debugger::AsyncDebuggerAPI &asyncDebuggerAPI, + SynchronizedOutboundCallback messageCallback, + std::shared_ptr objTable, + ConsoleMessageStorage &consoleMessageStorage, + ConsoleMessageDispatcher &consoleMessageDispatcher); + ~RuntimeDomainAgent(); + + /// Enables the Runtime domain without processing CDP message or sending a CDP + /// response. It will still send CDP notifications if needed. + void enable(); + /// Handles Runtime.enable request + /// @cdp Runtime.enable If domain is already enabled, will return success. + void enable(const m::runtime::EnableRequest &req); + /// @cdp Runtime.discardConsoleEntries + void discardConsoleEntries( + const m::runtime::DiscardConsoleEntriesRequest &req); + /// Handles Runtime.disable request + /// @cdp Runtime.disable If domain is already disabled, will return success. + void disable(const m::runtime::DisableRequest &req); + /// Handles Runtime.getHeapUsage request + /// @cdp Runtime.getHeapUsage Allowed even if domain is not enabled. + void getHeapUsage(const m::runtime::GetHeapUsageRequest &req); + /// Handles Runtime.globalLexicalScopeNames request + /// @cdp Runtime.globalLexicalScopeNames Allowed even if domain is not + /// enabled. + void globalLexicalScopeNames( + const m::runtime::GlobalLexicalScopeNamesRequest &req); + /// Handles Runtime.compileScript request + /// @cdp Runtime.compileScript Not allowed if domain is not enabled. + void compileScript(const m::runtime::CompileScriptRequest &req); + /// Handles Runtime.getProperties request + /// @cdp Runtime.getProperties Allowed even if domain is not enabled. + void getProperties(const m::runtime::GetPropertiesRequest &req); + /// Handles Runtime.evaluate request + /// @cdp Runtime.evaluate Allowed even if domain is not enabled. + void evaluate(const m::runtime::EvaluateRequest &req); + /// Handles Runtime.callFunctionOn request + /// @cdp Runtime.callFunctionOn Allowed even if domain is not enabled. + void callFunctionOn(const m::runtime::CallFunctionOnRequest &req); + /// Dispatches a Runtime.consoleAPICalled notification + void consoleAPICalled(const ConsoleMessage &message, bool isBuffered); + /// Handles Runtime.releaseObject request + /// @cdp Runtime.releaseObject Allowed even if domain is not enabled. + void releaseObject(const m::runtime::ReleaseObjectRequest &req); + /// Handles Runtime.releaseObjectGroup request + /// @cdp Runtime.releaseObjectGroup Allowed even if domain is not enabled. + void releaseObjectGroup(const m::runtime::ReleaseObjectGroupRequest &req); + + private: + struct Helpers { + jsi::Function objectGetOwnPropertySymbols; + jsi::Function objectGetOwnPropertyNames; + jsi::Function objectGetOwnPropertyDescriptor; + jsi::Function objectGetPrototypeOf; + + explicit Helpers(jsi::Runtime &runtime); + }; + + bool checkRuntimeEnabled(const m::Request &req); + + /// Ensure the provided \p executionContextId matches the one + /// indicated via the constructor. Returns true if they match. + /// Sends an error message with the specified \p commandId + /// and returns false otherwise. + bool validateExecutionContextId( + m::runtime::ExecutionContextId executionContextId, + long long commandId); + + std::optional> makePropsFromScope( + std::pair frameAndScopeIndex, + const std::string &objectGroup, + const debugger::ProgramState &state, + const ObjectSerializationOptions &serializationOptions); + std::vector makePropsFromValue( + const jsi::Value &value, + const std::string &objectGroup, + bool onlyOwnProperties, + bool accessorPropertiesOnly, + const ObjectSerializationOptions &serializationOptions); + std::vector + makeInternalPropsFromValue( + const jsi::Value &value, + const std::string &objectGroup, + const ObjectSerializationOptions &serializationOptions); + + HermesRuntime &runtime_; + debugger::AsyncDebuggerAPI &asyncDebuggerAPI_; + ConsoleMessageStorage &consoleMessageStorage_; + ConsoleMessageDispatcher &consoleMessageDispatcher_; + + /// Whether Runtime.enable was received and wasn't disabled by receiving + /// Runtime.disable + bool enabled_; + + // preparedScripts_ stores user-entered scripts that have been prepared for + // execution, and may be invoked by a later command. + std::vector> preparedScripts_; + + /// Console message subscription token, used to unsubscribe during shutdown. + ConsoleMessageRegistration consoleMessageRegistration_; + + /// Cached helper JS functions used by agent methods. + const Helpers helpers_; +}; + +} // namespace cdp +} // namespace hermes +} // namespace facebook + +#endif // HERMES_CDP_RUNTIMEDOMAINAGENT_H diff --git a/NativeScript/napi/hermes/include_old/hermes/hermes.h b/NativeScript/napi/hermes/include_old/hermes/hermes.h new file mode 100644 index 00000000..0d6d70fc --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/hermes.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_HERMES_H +#define HERMES_HERMES_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "js_native_api.h" + +struct HermesTestHelper; + +namespace hermes { + namespace vm { + class GCExecTrace; + class Runtime; + } // namespace vm +} // namespace hermes + +namespace facebook { + namespace jsi { + + class ThreadSafeRuntime; + + } + + namespace hermes { + + namespace debugger { + class Debugger; + } + + class HermesRuntimeImpl; + +/// Represents a Hermes JS runtime. + class HERMES_EXPORT HermesRuntime : public jsi::Runtime { + public: + + napi_status createNapiEnv(napi_env *env); + + static bool isHermesBytecode(const uint8_t *data, size_t len); + // Returns the supported bytecode version. + static uint32_t getBytecodeVersion(); + // (EXPERIMENTAL) Issues madvise calls for portions of the given + // bytecode file that will likely be used when loading the bytecode + // file and running its global function. + static void prefetchHermesBytecode(const uint8_t *data, size_t len); + // Returns whether the data is valid HBC with more extensive checks than + // isHermesBytecode and returns why it isn't in errorMessage (if nonnull) + // if not. + static bool hermesBytecodeSanityCheck( + const uint8_t *data, + size_t len, + std::string *errorMessage = nullptr); + static void setFatalHandler(void (*handler)(const std::string &)); + + // Assuming that \p data is valid HBC bytecode data, returns a pointer to the + // first element of the epilogue, data append to the end of the bytecode + // stream. Return pair contain ptr to data and header. + static std::pair getBytecodeEpilogue( + const uint8_t *data, + size_t len); + + /// Enable sampling profiler. + /// Starts a separate thread that polls VM state with \p meanHzFreq frequency. + /// Any subsequent call to \c enableSamplingProfiler() is ignored until + /// next call to \c disableSamplingProfiler() + static void enableSamplingProfiler(double meanHzFreq = 100); + + /// Disable the sampling profiler + static void disableSamplingProfiler(); + + /// Dump sampled stack trace to the given file name. + static void dumpSampledTraceToFile(const std::string &fileName); + + /// Dump sampled stack trace to the given stream. + static void dumpSampledTraceToStream(std::ostream &stream); + + /// Serialize the sampled stack to the format expected by DevTools' + /// Profiler.stop return type. + void sampledTraceToStreamInDevToolsFormat(std::ostream &stream); + + /// Return the executed JavaScript function info. + /// This information holds the segmentID, Virtualoffset and sourceURL. + /// This information is needed specifically to be able to symbolicate non-CJS + /// bundles correctly. This API will be simplified later to simply return a + /// segmentID and virtualOffset, when we are able to only support CJS bundles. + static std::unordered_map> + getExecutedFunctions(); + + /// \return whether code coverage profiler is enabled or not. + static bool isCodeCoverageProfilerEnabled(); + + /// Enable code coverage profiler. + static void enableCodeCoverageProfiler(); + + /// Disable code coverage profiler. + static void disableCodeCoverageProfiler(); + + // The base class declares most of the interesting methods. This + // just declares new methods which are specific to HermesRuntime. + // The actual implementations of the pure virtual methods are + // provided by a class internal to the .cpp file, which is created + // by the factory. + + /// Load a new segment into the Runtime. + /// The \param context must be a valid RequireContext retrieved from JS + /// using `require.context`. + void loadSegment( + std::unique_ptr buffer, + const jsi::Value &context); + + /// Gets a guaranteed unique id for an Object (or, respectively, String + /// or PropNameId), which is assigned at allocation time and is + /// static throughout that object's (or string's, or PropNameID's) + /// lifetime. + uint64_t getUniqueID(const jsi::Object &o) const; + uint64_t getUniqueID(const jsi::BigInt &s) const; + uint64_t getUniqueID(const jsi::String &s) const; + uint64_t getUniqueID(const jsi::PropNameID &pni) const; + uint64_t getUniqueID(const jsi::Symbol &sym) const; + + /// Same as the other \c getUniqueID, except it can return 0 for some values. + /// 0 means there is no ID associated with the value. + uint64_t getUniqueID(const jsi::Value &val) const; + + /// From an ID retrieved from \p getUniqueID, go back to the object. + /// NOTE: This is much slower in general than the reverse operation, and takes + /// up more memory. Don't use this unless it's absolutely necessary. + /// \return a jsi::Object if a matching object is found, else returns null. + jsi::Value getObjectForID(uint64_t id); + + /// Get a structure representing the execution history (currently just of + /// GC, but will be generalized as necessary), to aid in debugging + /// non-deterministic execution. + const ::hermes::vm::GCExecTrace &getGCExecTrace() const; + + /// Get IO tracking (aka HBC page access) info as a JSON string. + /// See hermes::vm::Runtime::getIOTrackingInfoJSON() for conditions + /// needed for there to be useful output. + std::string getIOTrackingInfoJSON(); + +#ifdef HERMESVM_PROFILER_BB + /// Write the trace to the given stream. + void dumpBasicBlockProfileTrace(std::ostream &os) const; +#endif + +#ifdef HERMESVM_PROFILER_OPCODE + /// Write the opcode stats to the given stream. + void dumpOpcodeStats(std::ostream &os) const; +#endif + + /// \return a reference to the Debugger for this Runtime. + debugger::Debugger &getDebugger(); + +#ifdef HERMES_ENABLE_DEBUGGER + + struct DebugFlags { + // Looking for the .lazy flag? It's no longer necessary. + // Source is evaluated lazily by default. See + // RuntimeConfig::CompilationMode. + }; + + /// Evaluate the given code in an unoptimized form, + /// used for debugging. + void debugJavaScript( + const std::string &src, + const std::string &sourceURL, + const DebugFlags &debugFlags); +#endif + + /// Register this runtime and thread for sampling profiler. Before using the + /// runtime on another thread, invoke this function again from the new thread + /// to make the sampling profiler target the new thread (and forget the old + /// thread). + void registerForProfiling(); + /// Unregister this runtime for sampling profiler. + void unregisterForProfiling(); + + /// Define methods to interrupt JS execution and set time limits. + /// All JS compiled to bytecode via prepareJS, or evaluateJS, will support + /// interruption and time limit monitoring if the runtime is configured with + /// AsyncBreakCheckInEval. If JS prepared in other ways is executed, care must + /// be taken to ensure that it is compiled in a mode that supports it (i.e., + /// the emitted code contains async break checks). + + /// Asynchronously terminates the current execution. This can be called on + /// any thread. + void asyncTriggerTimeout(); + + /// Register this runtime for execution time limit monitoring, with a time + /// limit of \p timeoutInMs milliseconds. + /// See compilation notes above. + void watchTimeLimit(uint32_t timeoutInMs); + /// Unregister this runtime for execution time limit monitoring. + void unwatchTimeLimit(); + + /// Same as \c evaluate JavaScript but with a source map, which will be + /// applied to exception traces and debug information. + /// + /// This is an experimental Hermes-specific API. In the future it may be + /// renamed, moved or combined with another API, but the provided + /// functionality will continue to be available in some form. + jsi::Value evaluateJavaScriptWithSourceMap( + const std::shared_ptr &buffer, + const std::shared_ptr &sourceMapBuf, + const std::string &sourceURL); + + /// Returns the underlying low level Hermes VM runtime instance. + /// This function is considered unsafe and unstable. + /// Direct use of a vm::Runtime should be avoided as the lower level APIs are + /// unsafe and they can change without notice. + ::hermes::vm::Runtime *getVMRuntimeUnsafe() const; + + private: + // Only HermesRuntimeImpl can subclass this. + HermesRuntime() = default; + friend class HermesRuntimeImpl; + + friend struct ::HermesTestHelper; + size_t rootsListLengthForTests() const; + + // Do not add any members here. This ensures that there are no + // object size inconsistencies. All data should be in the impl + // class in the .cpp file. + }; + +/// Return a RuntimeConfig that is more suited for running untrusted JS than +/// the default config. Disables some language features and may trade off some +/// performance for security. +/// +/// Can serve as a starting point with tweaks to re-enable needed features: +/// auto conf = hardenedHermesRuntimeConfig().rebuild(); +/// conf.withArrayBuffer(true); +/// ... +/// auto runtime = makeHermesRuntime(conf.build()); + HERMES_EXPORT ::hermes::vm::RuntimeConfig hardenedHermesRuntimeConfig(); + + HERMES_EXPORT std::unique_ptr makeHermesRuntime( + const ::hermes::vm::RuntimeConfig &runtimeConfig = + ::hermes::vm::RuntimeConfig()); + HERMES_EXPORT std::unique_ptr + makeThreadSafeHermesRuntime( + const ::hermes::vm::RuntimeConfig &runtimeConfig = + ::hermes::vm::RuntimeConfig()); + } // namespace hermes +} // namespace facebook + +#endif \ No newline at end of file diff --git a/NativeScript/napi/hermes/include/hermes/hermes_api.h b/NativeScript/napi/hermes/include_old/hermes/hermes_api.h similarity index 100% rename from NativeScript/napi/hermes/include/hermes/hermes_api.h rename to NativeScript/napi/hermes/include_old/hermes/hermes_api.h diff --git a/NativeScript/napi/hermes/include_old/hermes/hermes_tracing.h b/NativeScript/napi/hermes/include_old/hermes/hermes_tracing.h new file mode 100644 index 00000000..470e82d9 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/hermes_tracing.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#ifndef HERMES_HERMES_TRACING_H +#define HERMES_HERMES_TRACING_H + +#include + +namespace llvh { +class raw_ostream; +} // namespace llvh + +namespace facebook { +namespace hermes { + +/// Creates and returns a tracing runtime if \p runtimeConfig.SynthTraceMode is +/// either SynthTraceMode::Tracing or SynthTraceMode::TracingAndReplaying. +/// Otherwise, returns the passed \n hermesRuntime as is. +/// The trace will be written to \p traceScratchPath incrementally. +/// On completion, the file will be renamed to \p traceResultPath, and +/// \p traceCompletionCallback (for post-processing) will be invoked. +/// Completion can be triggered implicitly by crash (if crash manager is +/// provided) or explicitly by invocation of flush. +/// If the runtime is destructed without triggering trace completion, +/// the file at \p traceScratchPath will be deleted. +/// The return value of \p traceCompletionCallback indicates whether the +/// invocation completed successfully. If \p traceCompletionCallback is null, it +/// also assumes as if the callback is successful. +std::unique_ptr makeTracingHermesRuntime( + std::unique_ptr hermesRuntime, + const ::hermes::vm::RuntimeConfig &runtimeConfig, + const std::string &traceScratchPath, + const std::string &traceResultPath, + std::function traceCompletionCallback); + +/// Creates and returns a tracing runtime that wrapps the passed +/// \p hermesRuntime. This API is mainly for Synth Trace replay (and tracing), +/// and for testing. +/// \p traceStream the stream to write trace to. +/// \p forReplay indicates whether the runtime is being used in trace replay and +/// tracing. +std::unique_ptr makeTracingHermesRuntime( + std::unique_ptr hermesRuntime, + const ::hermes::vm::RuntimeConfig &runtimeConfig, + std::unique_ptr traceStream, + bool forReplay = false); + +} // namespace hermes +} // namespace facebook + +#endif diff --git a/NativeScript/napi/hermes/include_old/hermes/inspector/RuntimeAdapter.h b/NativeScript/napi/hermes/include_old/hermes/inspector/RuntimeAdapter.h new file mode 100644 index 00000000..64396f2c --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/inspector/RuntimeAdapter.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include + +#ifndef INSPECTOR_EXPORT +#ifdef _MSC_VER +#ifdef CREATE_SHARED_LIBRARY +#define INSPECTOR_EXPORT __declspec(dllexport) +#else +#define INSPECTOR_EXPORT +#endif // CREATE_SHARED_LIBRARY +#else // _MSC_VER +#define INSPECTOR_EXPORT __attribute__((visibility("default"))) +#endif // _MSC_VER +#endif // !defined(INSPECTOR_EXPORT) + +namespace facebook { +namespace hermes { +namespace inspector_modern { + +/** + * RuntimeAdapter encapsulates a HermesRuntime object. The underlying Hermes + * runtime object should stay alive for at least as long as the RuntimeAdapter + * is alive. + */ +class INSPECTOR_EXPORT RuntimeAdapter { + public: + virtual ~RuntimeAdapter() = 0; + + /// getRuntime should return the runtime encapsulated by this adapter. The + /// CDP Handler will only invoke this function from the runtime thread. + virtual HermesRuntime &getRuntime() = 0; + + /// \p tickleJs is a method that subclasses can choose to override to make + /// the inspector more responsive. If overridden, it should call the + /// \p __tickleJs JavaScript function. Calling JavaScript functions must be + /// done on the runtime thread, and \p tickleJs() may be invoked from an + /// arbitrary thread. Thus, the call to \p __tickleJs should occur with + /// appropriate locking (e.g. via a thread-safe runtime instance, or by + /// enqueuing the call on to a dedicated JS thread). + /// + /// This makes the inspector more responsive because it gives the inspector + /// the ability to force the process to enter the Hermes interpreter loop + /// soon. This is important because the inspector can only do a number of + /// important operations (like manipulating breakpoints) within the context of + /// a Hermes interperter loop. + /// + /// The default implementation does nothing. + virtual void tickleJs(); +}; + +/** + * SharedRuntimeAdapter is a simple implementation of RuntimeAdapter that + * uses shared_ptr to hold on to the runtime. It's generally only used in tests, + * since it does not implement tickleJs. + */ +class INSPECTOR_EXPORT SharedRuntimeAdapter : public RuntimeAdapter { + public: + SharedRuntimeAdapter(std::shared_ptr runtime); + ~SharedRuntimeAdapter() override; + + HermesRuntime &getRuntime() override; + + private: + std::shared_ptr runtime_; +}; + +} // namespace inspector_modern +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/CDPHandler.h b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/CDPHandler.h new file mode 100644 index 00000000..01fe26eb --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/CDPHandler.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// using include guards instead of #pragma once due to compile issues +// with MSVC and BUCK +#ifndef HERMES_INSPECTOR_CDPHANDLER_H +#define HERMES_INSPECTOR_CDPHANDLER_H + +#include +#include +#include +#include + +#include +#include + +namespace facebook { +namespace hermes { +namespace inspector_modern { +namespace chrome { + +using CDPMessageCallbackFunction = std::function; +using OnUnregisterFunction = std::function; + +class CDPHandlerImpl; + +struct State; + +/// Utility struct to configure the initial state of the CDP session. +struct INSPECTOR_EXPORT CDPHandlerSessionConfig { + bool isRuntimeDomainEnabled{false}; +}; + +/// Configuration for the execution context managed by the CDPHandler. +struct INSPECTOR_EXPORT CDPHandlerExecutionContextDescription { + int32_t id{}; + std::string origin; + std::string name; + std::optional auxData; + bool shouldSendNotifications{}; +}; + +/// CDPHandler processes CDP messages between the client and the debugger. +/// It performs no networking or connection logic itself. +/// The CDP Handler is invoked from multiple threads. The locking strategy is +/// to acquire the lock at each entry point into the class, and hold it until +/// the entry function has returned. In practice, these functions fall into 2 +/// categories: public functions invoked by the creator of this instance, and +/// callbacks invoked by the runtime to report events. +/// Once the lock is held, most members are safe to use from any thread, with +/// the notable exception of the runtime (and debugger retrieved from the +/// runtime). Most runtime methods must only be invoked when running on the +/// runtime thread, which occurs in the CDP Handler constructor/destructor, and +/// callbacks from the runtime thread (e.g. host functions, instrumentation +/// callbacks, and pause callback). +class INSPECTOR_EXPORT CDPHandler { + /// Hide the constructor so users can only construct via static create + /// methods. + CDPHandler( + std::unique_ptr adapter, + const std::string &title, + bool waitForDebugger, + bool processConsoleAPI, + std::shared_ptr state, + const CDPHandlerSessionConfig &sessionConfig, + std::optional + executionContextDescription); + + public: + /// Creating a CDPHandler enables the debugger on the provided runtime. This + /// should generally called before you start running any JS in the runtime. + /// This should also be called on the runtime thread, as methods are invoked + /// on the given \p adapter. + static std::shared_ptr create( + std::unique_ptr adapter, + bool waitForDebugger = false, + bool processConsoleAPI = true, + std::shared_ptr state = nullptr, + const CDPHandlerSessionConfig &sessionConfig = {}, + std::optional + executionContextDescription = std::nullopt); + /// Temporarily kept to allow React Native build to still work + static std::shared_ptr create( + std::unique_ptr adapter, + const std::string &title, + bool waitForDebugger = false, + bool processConsoleAPI = true, + std::shared_ptr state = nullptr, + const CDPHandlerSessionConfig &sessionConfig = {}, + std::optional + executionContextDescription = std::nullopt); + ~CDPHandler(); + + /// getTitle returns the name of the friendly name of the runtime that's shown + /// to users in the CDP frontend (e.g. Chrome DevTools). + std::string getTitle() const; + + /// Provide a callback to receive replies and notifications from the debugger, + /// and optionally provide a function to be called during + /// unregisterCallbacks(). + /// \param msgCallback Function to receive replies and notifications from the + /// debugger + /// \param onDisconnect Function that will be invoked upon calling + /// unregisterCallbacks + /// \return true if there wasn't a previously registered callback + bool registerCallbacks( + CDPMessageCallbackFunction msgCallback, + OnUnregisterFunction onUnregister); + + /// Unregister any previously registered callbacks. + /// \return true if there were previously registered callbacks + bool unregisterCallbacks(); + + /// Process a JSON-encoded Chrome DevTools Protocol request. + void handle(std::string str); + + /// Extract state to be persisted across reloads. + std::unique_ptr getState(); + + private: + std::shared_ptr impl_; + const std::string title_; +}; + +/// Public-facing wrapper for internal CDP state that can be preserved across +/// reloads. +struct INSPECTOR_EXPORT State { + /// Incomplete type that stores the actual state. + struct Private; + + /// Create a new wrapper with the provided \p privateState. + explicit State(std::unique_ptr privateState); + ~State(); + + /// Get the wrapped state. + Private &get() { + return *privateState_.get(); + } + + private: + /// Pointer to the actual stored state, hidden from users of this wrapper. + std::unique_ptr privateState_; +}; + +} // namespace chrome +} // namespace inspector_modern +} // namespace hermes +} // namespace facebook + +#endif // HERMES_INSPECTOR_CDPHandler_H diff --git a/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/CallbackOStream.h b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/CallbackOStream.h new file mode 100644 index 00000000..a9831555 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/CallbackOStream.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace facebook { +namespace hermes { +namespace inspector_modern { +namespace chrome { + +/// Subclass of \c std::ostream where flushing is implemented through a +/// callback. Writes are collected in a buffer. When filled, the buffer's +/// contents are emptied out and sent to a callback. +struct CallbackOStream : public std::ostream { + /// Signature of callback called to flush buffer contents. Accepts the buffer + /// as a string. Returns a boolean indicating whether flushing succeeded. + /// Callback failure will be translated to stream failure. If the callback + /// throws an exception it will be swallowed and translated into stream + /// failure. + using Fn = std::function; + + /// Construct a new stream. + /// + /// \p sz The size of the buffer -- how large it can get before it must be + /// flushed. Must be non-zero. + /// \p cb The callback function. + CallbackOStream(size_t sz, Fn cb); + + /// This class is neither movable nor copyable. + CallbackOStream(CallbackOStream &&that) = delete; + CallbackOStream &operator=(CallbackOStream &&that) = delete; + CallbackOStream(const CallbackOStream &that) = delete; + CallbackOStream &operator=(const CallbackOStream &that) = delete; + + private: + /// \c std::streambuf sub-class backed by a std::string buffer and + /// implementing overflow by calling a callback. + struct StreamBuf : public std::streambuf { + /// Construct a new streambuf. Parameters are the same as those of + /// \c CallbackOStream . + StreamBuf(size_t sz, Fn cb); + + /// Destruction will flush any remaining buffer contents. + ~StreamBuf() override; + + /// StreamBufs are not copyable, to avoid the flush callback receiving + /// the contents of multiple streams. + StreamBuf(const StreamBuf &) = delete; + StreamBuf &operator=(const StreamBuf &) = delete; + + protected: + /// std::streambuf overrides + int_type overflow(int_type ch) override; + int sync() override; + + private: + /// The size of the backing buffer. Fixed for an instance of the streambuf. + size_t sz_; + + /// The backing buffer that writes will go to until full. + std::unique_ptr buf_; + + /// The function called when buf_ has been filled. + Fn cb_; + + /// Clears the backing buffer. + void reset(); + + /// Clears the backing buffer and returns it contents in a string. + std::string take(); + }; + + StreamBuf sbuf_; +}; + +} // namespace chrome +} // namespace inspector_modern +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/JSONValueInterfaces.h b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/JSONValueInterfaces.h new file mode 100644 index 00000000..26331381 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/JSONValueInterfaces.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +#include + +namespace facebook { +namespace hermes { +namespace inspector_modern { +namespace chrome { +using namespace ::hermes::parser; + +/// Convert a string to a JSONValue. Will return nullopt if parsing is not +/// successful. +std::optional parseStr( + const std::string &str, + JSONFactory &factory); + +/// Convert a string to a JSON object. Will return nullopt if parsing is not +/// successful, or the resulting JSON value is not an object. +std::optional parseStrAsJsonObj( + const std::string &str, + JSONFactory &factory); + +/// Convert a JSONValue to a string. +std::string jsonValToStr(const JSONValue *v); + +/// Check if two JSONValues are equal. +bool jsonValsEQ(const JSONValue *A, const JSONValue *B); + +}; // namespace chrome +}; // namespace inspector_modern +}; // namespace hermes +}; // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/MessageConverters.h b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/MessageConverters.h new file mode 100644 index 00000000..fd26c9ed --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/MessageConverters.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace facebook { +namespace hermes { +namespace inspector_modern { +namespace chrome { +namespace message { + +template +void setChromeLocation( + T &chromeLoc, + const facebook::hermes::debugger::SourceLocation &hermesLoc) { + if (hermesLoc.line != facebook::hermes::debugger::kInvalidLocation) { + chromeLoc.lineNumber = hermesLoc.line - 1; + } + + if (hermesLoc.column != facebook::hermes::debugger::kInvalidLocation) { + chromeLoc.columnNumber = hermesLoc.column - 1; + } +} + +/// ErrorCode magic numbers match JSC's (see InspectorBackendDispatcher.cpp) +enum class ErrorCode { + ParseError = -32700, + InvalidRequest = -32600, + MethodNotFound = -32601, + InvalidParams = -32602, + InternalError = -32603, + ServerError = -32000 +}; + +ErrorResponse +makeErrorResponse(int id, ErrorCode code, const std::string &message); + +OkResponse makeOkResponse(int id); + +namespace debugger { + +Location makeLocation(const facebook::hermes::debugger::SourceLocation &loc); + +} // namespace debugger + +namespace runtime { + +CallFrame makeCallFrame(const facebook::hermes::debugger::CallFrameInfo &info); + +std::vector makeCallFrames( + const facebook::hermes::debugger::StackTrace &stackTrace); + +ExceptionDetails makeExceptionDetails( + const facebook::hermes::debugger::ExceptionDetails &details); + +} // namespace runtime + +namespace heapProfiler { + +std::unique_ptr makeSamplingHeapProfile( + const std::string &value); + +} // namespace heapProfiler + +namespace profiler { + +std::unique_ptr makeProfile(const std::string &value); + +} // namespace profiler + +} // namespace message +} // namespace chrome +} // namespace inspector_modern +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/MessageInterfaces.h b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/MessageInterfaces.h new file mode 100644 index 00000000..01e369e2 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/MessageInterfaces.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace facebook { +namespace hermes { +namespace inspector_modern { +namespace chrome { +namespace message { +using namespace ::hermes::parser; + +struct RequestHandler; + +/// Serializable is an interface for objects that can be serialized to and from +/// JSON. +struct Serializable { + virtual ~Serializable() = default; + virtual JSONValue *toJsonVal(JSONFactory &factory) const = 0; + + std::string toJsonStr() const; +}; + +/// Requests are sent from the debugger to the target. +struct Request : public Serializable { + using ParseResult = std::variant, std::string>; + static std::unique_ptr fromJson(const std::string &str); + + Request() = default; + explicit Request(std::string method) : method(method) {} + + // accept dispatches to the appropriate handler method in RequestHandler based + // on the type of the request. + virtual void accept(RequestHandler &handler) const = 0; + + long long id = 0; + std::string method; +}; + +/// Responses are sent from the target to the debugger in response to a Request. +struct Response : public Serializable { + Response() = default; + + long long id = 0; +}; + +/// Notifications are sent from the target to the debugger. This is used to +/// notify the debugger about events that occur in the target, e.g. stopping +/// at a breakpoint. +struct Notification : public Serializable { + Notification() = default; + explicit Notification(std::string method) : method(method) {} + + std::string method; +}; + +} // namespace message +} // namespace chrome +} // namespace inspector_modern +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/MessageTypes.h b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/MessageTypes.h new file mode 100644 index 00000000..e039758f --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/MessageTypes.h @@ -0,0 +1,1183 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. +// @generated SignedSource<<3ebea508f76e06269045891097f89eb5>> + +#pragma once + +#include +#include + +#include +#include + +namespace facebook { +namespace hermes { +namespace inspector_modern { +namespace chrome { +namespace message { + +template +void deleter(T *p); +using JSONBlob = std::string; +struct UnknownRequest; + +namespace debugger { +using BreakpointId = std::string; +struct BreakpointResolvedNotification; +struct CallFrame; +using CallFrameId = std::string; +struct DisableRequest; +struct EnableRequest; +struct EvaluateOnCallFrameRequest; +struct EvaluateOnCallFrameResponse; +struct Location; +struct PauseRequest; +struct PausedNotification; +struct RemoveBreakpointRequest; +struct ResumeRequest; +struct ResumedNotification; +struct Scope; +struct ScriptParsedNotification; +struct SetBreakpointByUrlRequest; +struct SetBreakpointByUrlResponse; +struct SetBreakpointRequest; +struct SetBreakpointResponse; +struct SetBreakpointsActiveRequest; +struct SetInstrumentationBreakpointRequest; +struct SetInstrumentationBreakpointResponse; +struct SetPauseOnExceptionsRequest; +struct StepIntoRequest; +struct StepOutRequest; +struct StepOverRequest; +} // namespace debugger + +namespace runtime { +struct CallArgument; +struct CallFrame; +struct CallFunctionOnRequest; +struct CallFunctionOnResponse; +struct CompileScriptRequest; +struct CompileScriptResponse; +struct ConsoleAPICalledNotification; +struct CustomPreview; +struct DisableRequest; +struct EnableRequest; +struct EntryPreview; +struct EvaluateRequest; +struct EvaluateResponse; +struct ExceptionDetails; +struct ExecutionContextCreatedNotification; +struct ExecutionContextDescription; +using ExecutionContextId = long long; +struct GetHeapUsageRequest; +struct GetHeapUsageResponse; +struct GetPropertiesRequest; +struct GetPropertiesResponse; +struct GlobalLexicalScopeNamesRequest; +struct GlobalLexicalScopeNamesResponse; +struct InternalPropertyDescriptor; +struct ObjectPreview; +struct PropertyDescriptor; +struct PropertyPreview; +struct RemoteObject; +using RemoteObjectId = std::string; +struct RunIfWaitingForDebuggerRequest; +using ScriptId = std::string; +struct StackTrace; +using Timestamp = double; +using UnserializableValue = std::string; +} // namespace runtime + +namespace heapProfiler { +struct AddHeapSnapshotChunkNotification; +struct CollectGarbageRequest; +struct GetHeapObjectIdRequest; +struct GetHeapObjectIdResponse; +struct GetObjectByHeapObjectIdRequest; +struct GetObjectByHeapObjectIdResponse; +using HeapSnapshotObjectId = std::string; +struct HeapStatsUpdateNotification; +struct LastSeenObjectIdNotification; +struct ReportHeapSnapshotProgressNotification; +struct SamplingHeapProfile; +struct SamplingHeapProfileNode; +struct SamplingHeapProfileSample; +struct StartSamplingRequest; +struct StartTrackingHeapObjectsRequest; +struct StopSamplingRequest; +struct StopSamplingResponse; +struct StopTrackingHeapObjectsRequest; +struct TakeHeapSnapshotRequest; +} // namespace heapProfiler + +namespace profiler { +struct PositionTickInfo; +struct Profile; +struct ProfileNode; +struct StartRequest; +struct StopRequest; +struct StopResponse; +} // namespace profiler + +/// RequestHandler handles requests via the visitor pattern. +struct RequestHandler { + virtual ~RequestHandler() = default; + + virtual void handle(const UnknownRequest &req) = 0; + virtual void handle(const debugger::DisableRequest &req) = 0; + virtual void handle(const debugger::EnableRequest &req) = 0; + virtual void handle(const debugger::EvaluateOnCallFrameRequest &req) = 0; + virtual void handle(const debugger::PauseRequest &req) = 0; + virtual void handle(const debugger::RemoveBreakpointRequest &req) = 0; + virtual void handle(const debugger::ResumeRequest &req) = 0; + virtual void handle(const debugger::SetBreakpointRequest &req) = 0; + virtual void handle(const debugger::SetBreakpointByUrlRequest &req) = 0; + virtual void handle(const debugger::SetBreakpointsActiveRequest &req) = 0; + virtual void handle( + const debugger::SetInstrumentationBreakpointRequest &req) = 0; + virtual void handle(const debugger::SetPauseOnExceptionsRequest &req) = 0; + virtual void handle(const debugger::StepIntoRequest &req) = 0; + virtual void handle(const debugger::StepOutRequest &req) = 0; + virtual void handle(const debugger::StepOverRequest &req) = 0; + virtual void handle(const heapProfiler::CollectGarbageRequest &req) = 0; + virtual void handle(const heapProfiler::GetHeapObjectIdRequest &req) = 0; + virtual void handle( + const heapProfiler::GetObjectByHeapObjectIdRequest &req) = 0; + virtual void handle(const heapProfiler::StartSamplingRequest &req) = 0; + virtual void handle( + const heapProfiler::StartTrackingHeapObjectsRequest &req) = 0; + virtual void handle(const heapProfiler::StopSamplingRequest &req) = 0; + virtual void handle( + const heapProfiler::StopTrackingHeapObjectsRequest &req) = 0; + virtual void handle(const heapProfiler::TakeHeapSnapshotRequest &req) = 0; + virtual void handle(const profiler::StartRequest &req) = 0; + virtual void handle(const profiler::StopRequest &req) = 0; + virtual void handle(const runtime::CallFunctionOnRequest &req) = 0; + virtual void handle(const runtime::CompileScriptRequest &req) = 0; + virtual void handle(const runtime::DisableRequest &req) = 0; + virtual void handle(const runtime::EnableRequest &req) = 0; + virtual void handle(const runtime::EvaluateRequest &req) = 0; + virtual void handle(const runtime::GetHeapUsageRequest &req) = 0; + virtual void handle(const runtime::GetPropertiesRequest &req) = 0; + virtual void handle(const runtime::GlobalLexicalScopeNamesRequest &req) = 0; + virtual void handle(const runtime::RunIfWaitingForDebuggerRequest &req) = 0; +}; + +/// NoopRequestHandler can be subclassed to only handle some requests. +struct NoopRequestHandler : public RequestHandler { + void handle(const UnknownRequest &req) override {} + void handle(const debugger::DisableRequest &req) override {} + void handle(const debugger::EnableRequest &req) override {} + void handle(const debugger::EvaluateOnCallFrameRequest &req) override {} + void handle(const debugger::PauseRequest &req) override {} + void handle(const debugger::RemoveBreakpointRequest &req) override {} + void handle(const debugger::ResumeRequest &req) override {} + void handle(const debugger::SetBreakpointRequest &req) override {} + void handle(const debugger::SetBreakpointByUrlRequest &req) override {} + void handle(const debugger::SetBreakpointsActiveRequest &req) override {} + void handle( + const debugger::SetInstrumentationBreakpointRequest &req) override {} + void handle(const debugger::SetPauseOnExceptionsRequest &req) override {} + void handle(const debugger::StepIntoRequest &req) override {} + void handle(const debugger::StepOutRequest &req) override {} + void handle(const debugger::StepOverRequest &req) override {} + void handle(const heapProfiler::CollectGarbageRequest &req) override {} + void handle(const heapProfiler::GetHeapObjectIdRequest &req) override {} + void handle( + const heapProfiler::GetObjectByHeapObjectIdRequest &req) override {} + void handle(const heapProfiler::StartSamplingRequest &req) override {} + void handle( + const heapProfiler::StartTrackingHeapObjectsRequest &req) override {} + void handle(const heapProfiler::StopSamplingRequest &req) override {} + void handle( + const heapProfiler::StopTrackingHeapObjectsRequest &req) override {} + void handle(const heapProfiler::TakeHeapSnapshotRequest &req) override {} + void handle(const profiler::StartRequest &req) override {} + void handle(const profiler::StopRequest &req) override {} + void handle(const runtime::CallFunctionOnRequest &req) override {} + void handle(const runtime::CompileScriptRequest &req) override {} + void handle(const runtime::DisableRequest &req) override {} + void handle(const runtime::EnableRequest &req) override {} + void handle(const runtime::EvaluateRequest &req) override {} + void handle(const runtime::GetHeapUsageRequest &req) override {} + void handle(const runtime::GetPropertiesRequest &req) override {} + void handle(const runtime::GlobalLexicalScopeNamesRequest &req) override {} + void handle(const runtime::RunIfWaitingForDebuggerRequest &req) override {} +}; + +/// Types +struct debugger::Location : public Serializable { + Location() = default; + Location(Location &&) = default; + Location(const Location &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + Location &operator=(const Location &) = delete; + Location &operator=(Location &&) = default; + + runtime::ScriptId scriptId{}; + long long lineNumber{}; + std::optional columnNumber; +}; + +struct runtime::PropertyPreview : public Serializable { + PropertyPreview() = default; + PropertyPreview(PropertyPreview &&) = default; + PropertyPreview(const PropertyPreview &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + PropertyPreview &operator=(const PropertyPreview &) = delete; + PropertyPreview &operator=(PropertyPreview &&) = default; + + std::string name; + std::string type; + std::optional value; + std::unique_ptr< + runtime::ObjectPreview, + std::function> + valuePreview{nullptr, deleter}; + std::optional subtype; +}; + +struct runtime::EntryPreview : public Serializable { + EntryPreview() = default; + EntryPreview(EntryPreview &&) = default; + EntryPreview(const EntryPreview &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + EntryPreview &operator=(const EntryPreview &) = delete; + EntryPreview &operator=(EntryPreview &&) = default; + + std::unique_ptr< + runtime::ObjectPreview, + std::function> + key{nullptr, deleter}; + std::unique_ptr< + runtime::ObjectPreview, + std::function> + value{nullptr, deleter}; +}; + +struct runtime::ObjectPreview : public Serializable { + ObjectPreview() = default; + ObjectPreview(ObjectPreview &&) = default; + ObjectPreview(const ObjectPreview &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + ObjectPreview &operator=(const ObjectPreview &) = delete; + ObjectPreview &operator=(ObjectPreview &&) = default; + + std::string type; + std::optional subtype; + std::optional description; + bool overflow{}; + std::vector properties; + std::optional> entries; +}; + +struct runtime::CustomPreview : public Serializable { + CustomPreview() = default; + CustomPreview(CustomPreview &&) = default; + CustomPreview(const CustomPreview &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + CustomPreview &operator=(const CustomPreview &) = delete; + CustomPreview &operator=(CustomPreview &&) = default; + + std::string header; + std::optional bodyGetterId; +}; + +struct runtime::RemoteObject : public Serializable { + RemoteObject() = default; + RemoteObject(RemoteObject &&) = default; + RemoteObject(const RemoteObject &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + RemoteObject &operator=(const RemoteObject &) = delete; + RemoteObject &operator=(RemoteObject &&) = default; + + std::string type; + std::optional subtype; + std::optional className; + std::optional value; + std::optional unserializableValue; + std::optional description; + std::optional objectId; + std::optional preview; + std::optional customPreview; +}; + +struct runtime::CallFrame : public Serializable { + CallFrame() = default; + CallFrame(CallFrame &&) = default; + CallFrame(const CallFrame &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + CallFrame &operator=(const CallFrame &) = delete; + CallFrame &operator=(CallFrame &&) = default; + + std::string functionName; + runtime::ScriptId scriptId{}; + std::string url; + long long lineNumber{}; + long long columnNumber{}; +}; + +struct runtime::StackTrace : public Serializable { + StackTrace() = default; + StackTrace(StackTrace &&) = default; + StackTrace(const StackTrace &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + StackTrace &operator=(const StackTrace &) = delete; + StackTrace &operator=(StackTrace &&) = default; + + std::optional description; + std::vector callFrames; + std::unique_ptr parent; +}; + +struct runtime::ExceptionDetails : public Serializable { + ExceptionDetails() = default; + ExceptionDetails(ExceptionDetails &&) = default; + ExceptionDetails(const ExceptionDetails &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + ExceptionDetails &operator=(const ExceptionDetails &) = delete; + ExceptionDetails &operator=(ExceptionDetails &&) = default; + + long long exceptionId{}; + std::string text; + long long lineNumber{}; + long long columnNumber{}; + std::optional scriptId; + std::optional url; + std::optional stackTrace; + std::optional exception; + std::optional executionContextId; +}; + +struct debugger::Scope : public Serializable { + Scope() = default; + Scope(Scope &&) = default; + Scope(const Scope &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + Scope &operator=(const Scope &) = delete; + Scope &operator=(Scope &&) = default; + + std::string type; + runtime::RemoteObject object{}; + std::optional name; + std::optional startLocation; + std::optional endLocation; +}; + +struct debugger::CallFrame : public Serializable { + CallFrame() = default; + CallFrame(CallFrame &&) = default; + CallFrame(const CallFrame &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + CallFrame &operator=(const CallFrame &) = delete; + CallFrame &operator=(CallFrame &&) = default; + + debugger::CallFrameId callFrameId{}; + std::string functionName; + std::optional functionLocation; + debugger::Location location{}; + std::string url; + std::vector scopeChain; + runtime::RemoteObject thisObj{}; + std::optional returnValue; +}; + +struct heapProfiler::SamplingHeapProfileNode : public Serializable { + SamplingHeapProfileNode() = default; + SamplingHeapProfileNode(SamplingHeapProfileNode &&) = default; + SamplingHeapProfileNode(const SamplingHeapProfileNode &) = delete; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + SamplingHeapProfileNode &operator=(const SamplingHeapProfileNode &) = delete; + SamplingHeapProfileNode &operator=(SamplingHeapProfileNode &&) = default; + + runtime::CallFrame callFrame{}; + double selfSize{}; + long long id{}; + std::vector children; +}; + +struct heapProfiler::SamplingHeapProfileSample : public Serializable { + SamplingHeapProfileSample() = default; + SamplingHeapProfileSample(SamplingHeapProfileSample &&) = default; + SamplingHeapProfileSample(const SamplingHeapProfileSample &) = delete; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + SamplingHeapProfileSample &operator=(const SamplingHeapProfileSample &) = + delete; + SamplingHeapProfileSample &operator=(SamplingHeapProfileSample &&) = default; + + double size{}; + long long nodeId{}; + double ordinal{}; +}; + +struct heapProfiler::SamplingHeapProfile : public Serializable { + SamplingHeapProfile() = default; + SamplingHeapProfile(SamplingHeapProfile &&) = default; + SamplingHeapProfile(const SamplingHeapProfile &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + SamplingHeapProfile &operator=(const SamplingHeapProfile &) = delete; + SamplingHeapProfile &operator=(SamplingHeapProfile &&) = default; + + heapProfiler::SamplingHeapProfileNode head{}; + std::vector samples; +}; + +struct profiler::PositionTickInfo : public Serializable { + PositionTickInfo() = default; + PositionTickInfo(PositionTickInfo &&) = default; + PositionTickInfo(const PositionTickInfo &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + PositionTickInfo &operator=(const PositionTickInfo &) = delete; + PositionTickInfo &operator=(PositionTickInfo &&) = default; + + long long line{}; + long long ticks{}; +}; + +struct profiler::ProfileNode : public Serializable { + ProfileNode() = default; + ProfileNode(ProfileNode &&) = default; + ProfileNode(const ProfileNode &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + ProfileNode &operator=(const ProfileNode &) = delete; + ProfileNode &operator=(ProfileNode &&) = default; + + long long id{}; + runtime::CallFrame callFrame{}; + std::optional hitCount; + std::optional> children; + std::optional deoptReason; + std::optional> positionTicks; +}; + +struct profiler::Profile : public Serializable { + Profile() = default; + Profile(Profile &&) = default; + Profile(const Profile &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + Profile &operator=(const Profile &) = delete; + Profile &operator=(Profile &&) = default; + + std::vector nodes; + double startTime{}; + double endTime{}; + std::optional> samples; + std::optional> timeDeltas; +}; + +struct runtime::CallArgument : public Serializable { + CallArgument() = default; + CallArgument(CallArgument &&) = default; + CallArgument(const CallArgument &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + CallArgument &operator=(const CallArgument &) = delete; + CallArgument &operator=(CallArgument &&) = default; + + std::optional value; + std::optional unserializableValue; + std::optional objectId; +}; + +struct runtime::ExecutionContextDescription : public Serializable { + ExecutionContextDescription() = default; + ExecutionContextDescription(ExecutionContextDescription &&) = default; + ExecutionContextDescription(const ExecutionContextDescription &) = delete; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + ExecutionContextDescription &operator=(const ExecutionContextDescription &) = + delete; + ExecutionContextDescription &operator=(ExecutionContextDescription &&) = + default; + + runtime::ExecutionContextId id{}; + std::string origin; + std::string name; + std::optional auxData; +}; + +struct runtime::PropertyDescriptor : public Serializable { + PropertyDescriptor() = default; + PropertyDescriptor(PropertyDescriptor &&) = default; + PropertyDescriptor(const PropertyDescriptor &) = delete; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + PropertyDescriptor &operator=(const PropertyDescriptor &) = delete; + PropertyDescriptor &operator=(PropertyDescriptor &&) = default; + + std::string name; + std::optional value; + std::optional writable; + std::optional get; + std::optional set; + bool configurable{}; + bool enumerable{}; + std::optional wasThrown; + std::optional isOwn; + std::optional symbol; +}; + +struct runtime::InternalPropertyDescriptor : public Serializable { + InternalPropertyDescriptor() = default; + InternalPropertyDescriptor(InternalPropertyDescriptor &&) = default; + InternalPropertyDescriptor(const InternalPropertyDescriptor &) = delete; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + InternalPropertyDescriptor &operator=(const InternalPropertyDescriptor &) = + delete; + InternalPropertyDescriptor &operator=(InternalPropertyDescriptor &&) = + default; + + std::string name; + std::optional value; +}; + +/// Requests +struct UnknownRequest : public Request { + UnknownRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional params; +}; + +struct debugger::DisableRequest : public Request { + DisableRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct debugger::EnableRequest : public Request { + EnableRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct debugger::EvaluateOnCallFrameRequest : public Request { + EvaluateOnCallFrameRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + debugger::CallFrameId callFrameId{}; + std::string expression; + std::optional objectGroup; + std::optional includeCommandLineAPI; + std::optional silent; + std::optional returnByValue; + std::optional generatePreview; + std::optional throwOnSideEffect; +}; + +struct debugger::PauseRequest : public Request { + PauseRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct debugger::RemoveBreakpointRequest : public Request { + RemoveBreakpointRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + debugger::BreakpointId breakpointId{}; +}; + +struct debugger::ResumeRequest : public Request { + ResumeRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional terminateOnResume; +}; + +struct debugger::SetBreakpointRequest : public Request { + SetBreakpointRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + debugger::Location location{}; + std::optional condition; +}; + +struct debugger::SetBreakpointByUrlRequest : public Request { + SetBreakpointByUrlRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + long long lineNumber{}; + std::optional url; + std::optional urlRegex; + std::optional scriptHash; + std::optional columnNumber; + std::optional condition; +}; + +struct debugger::SetBreakpointsActiveRequest : public Request { + SetBreakpointsActiveRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + bool active{}; +}; + +struct debugger::SetInstrumentationBreakpointRequest : public Request { + SetInstrumentationBreakpointRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::string instrumentation; +}; + +struct debugger::SetPauseOnExceptionsRequest : public Request { + SetPauseOnExceptionsRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::string state; +}; + +struct debugger::StepIntoRequest : public Request { + StepIntoRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct debugger::StepOutRequest : public Request { + StepOutRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct debugger::StepOverRequest : public Request { + StepOverRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct heapProfiler::CollectGarbageRequest : public Request { + CollectGarbageRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct heapProfiler::GetHeapObjectIdRequest : public Request { + GetHeapObjectIdRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + runtime::RemoteObjectId objectId{}; +}; + +struct heapProfiler::GetObjectByHeapObjectIdRequest : public Request { + GetObjectByHeapObjectIdRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + heapProfiler::HeapSnapshotObjectId objectId{}; + std::optional objectGroup; +}; + +struct heapProfiler::StartSamplingRequest : public Request { + StartSamplingRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional samplingInterval; + std::optional includeObjectsCollectedByMajorGC; + std::optional includeObjectsCollectedByMinorGC; +}; + +struct heapProfiler::StartTrackingHeapObjectsRequest : public Request { + StartTrackingHeapObjectsRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional trackAllocations; +}; + +struct heapProfiler::StopSamplingRequest : public Request { + StopSamplingRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct heapProfiler::StopTrackingHeapObjectsRequest : public Request { + StopTrackingHeapObjectsRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional reportProgress; + std::optional treatGlobalObjectsAsRoots; + std::optional captureNumericValue; +}; + +struct heapProfiler::TakeHeapSnapshotRequest : public Request { + TakeHeapSnapshotRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional reportProgress; + std::optional treatGlobalObjectsAsRoots; + std::optional captureNumericValue; +}; + +struct profiler::StartRequest : public Request { + StartRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct profiler::StopRequest : public Request { + StopRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct runtime::CallFunctionOnRequest : public Request { + CallFunctionOnRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::string functionDeclaration; + std::optional objectId; + std::optional> arguments; + std::optional silent; + std::optional returnByValue; + std::optional generatePreview; + std::optional userGesture; + std::optional awaitPromise; + std::optional executionContextId; + std::optional objectGroup; +}; + +struct runtime::CompileScriptRequest : public Request { + CompileScriptRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::string expression; + std::string sourceURL; + bool persistScript{}; + std::optional executionContextId; +}; + +struct runtime::DisableRequest : public Request { + DisableRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct runtime::EnableRequest : public Request { + EnableRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct runtime::EvaluateRequest : public Request { + EvaluateRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::string expression; + std::optional objectGroup; + std::optional includeCommandLineAPI; + std::optional silent; + std::optional contextId; + std::optional returnByValue; + std::optional generatePreview; + std::optional userGesture; + std::optional awaitPromise; +}; + +struct runtime::GetHeapUsageRequest : public Request { + GetHeapUsageRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +struct runtime::GetPropertiesRequest : public Request { + GetPropertiesRequest(); + static std::unique_ptr tryMake(const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + runtime::RemoteObjectId objectId{}; + std::optional ownProperties; + std::optional generatePreview; +}; + +struct runtime::GlobalLexicalScopeNamesRequest : public Request { + GlobalLexicalScopeNamesRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; + + std::optional executionContextId; +}; + +struct runtime::RunIfWaitingForDebuggerRequest : public Request { + RunIfWaitingForDebuggerRequest(); + static std::unique_ptr tryMake( + const JSONObject *obj); + + JSONValue *toJsonVal(JSONFactory &factory) const override; + void accept(RequestHandler &handler) const override; +}; + +/// Responses +struct ErrorResponse : public Response { + ErrorResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + long long code; + std::string message; + std::optional data; +}; + +struct OkResponse : public Response { + OkResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; +}; + +struct debugger::EvaluateOnCallFrameResponse : public Response { + EvaluateOnCallFrameResponse() = default; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + runtime::RemoteObject result{}; + std::optional exceptionDetails; +}; + +struct debugger::SetBreakpointResponse : public Response { + SetBreakpointResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + debugger::BreakpointId breakpointId{}; + debugger::Location actualLocation{}; +}; + +struct debugger::SetBreakpointByUrlResponse : public Response { + SetBreakpointByUrlResponse() = default; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + debugger::BreakpointId breakpointId{}; + std::vector locations; +}; + +struct debugger::SetInstrumentationBreakpointResponse : public Response { + SetInstrumentationBreakpointResponse() = default; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + debugger::BreakpointId breakpointId{}; +}; + +struct heapProfiler::GetHeapObjectIdResponse : public Response { + GetHeapObjectIdResponse() = default; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + heapProfiler::HeapSnapshotObjectId heapSnapshotObjectId{}; +}; + +struct heapProfiler::GetObjectByHeapObjectIdResponse : public Response { + GetObjectByHeapObjectIdResponse() = default; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + runtime::RemoteObject result{}; +}; + +struct heapProfiler::StopSamplingResponse : public Response { + StopSamplingResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + heapProfiler::SamplingHeapProfile profile{}; +}; + +struct profiler::StopResponse : public Response { + StopResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + profiler::Profile profile{}; +}; + +struct runtime::CallFunctionOnResponse : public Response { + CallFunctionOnResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + runtime::RemoteObject result{}; + std::optional exceptionDetails; +}; + +struct runtime::CompileScriptResponse : public Response { + CompileScriptResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::optional scriptId; + std::optional exceptionDetails; +}; + +struct runtime::EvaluateResponse : public Response { + EvaluateResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + runtime::RemoteObject result{}; + std::optional exceptionDetails; +}; + +struct runtime::GetHeapUsageResponse : public Response { + GetHeapUsageResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + double usedSize{}; + double totalSize{}; +}; + +struct runtime::GetPropertiesResponse : public Response { + GetPropertiesResponse() = default; + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::vector result; + std::optional> + internalProperties; + std::optional exceptionDetails; +}; + +struct runtime::GlobalLexicalScopeNamesResponse : public Response { + GlobalLexicalScopeNamesResponse() = default; + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::vector names; +}; + +/// Notifications +struct debugger::BreakpointResolvedNotification : public Notification { + BreakpointResolvedNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + debugger::BreakpointId breakpointId{}; + debugger::Location location{}; +}; + +struct debugger::PausedNotification : public Notification { + PausedNotification(); + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::vector callFrames; + std::string reason; + std::optional data; + std::optional> hitBreakpoints; + std::optional asyncStackTrace; +}; + +struct debugger::ResumedNotification : public Notification { + ResumedNotification(); + static std::unique_ptr tryMake(const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; +}; + +struct debugger::ScriptParsedNotification : public Notification { + ScriptParsedNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + runtime::ScriptId scriptId{}; + std::string url; + long long startLine{}; + long long startColumn{}; + long long endLine{}; + long long endColumn{}; + runtime::ExecutionContextId executionContextId{}; + std::string hash; + std::optional executionContextAuxData; + std::optional sourceMapURL; + std::optional hasSourceURL; + std::optional isModule; + std::optional length; +}; + +struct heapProfiler::AddHeapSnapshotChunkNotification : public Notification { + AddHeapSnapshotChunkNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::string chunk; +}; + +struct heapProfiler::HeapStatsUpdateNotification : public Notification { + HeapStatsUpdateNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::vector statsUpdate; +}; + +struct heapProfiler::LastSeenObjectIdNotification : public Notification { + LastSeenObjectIdNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + long long lastSeenObjectId{}; + double timestamp{}; +}; + +struct heapProfiler::ReportHeapSnapshotProgressNotification + : public Notification { + ReportHeapSnapshotProgressNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + long long done{}; + long long total{}; + std::optional finished; +}; + +struct runtime::ConsoleAPICalledNotification : public Notification { + ConsoleAPICalledNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + std::string type; + std::vector args; + runtime::ExecutionContextId executionContextId{}; + runtime::Timestamp timestamp{}; + std::optional stackTrace; +}; + +struct runtime::ExecutionContextCreatedNotification : public Notification { + ExecutionContextCreatedNotification(); + static std::unique_ptr tryMake( + const JSONObject *obj); + JSONValue *toJsonVal(JSONFactory &factory) const override; + + runtime::ExecutionContextDescription context{}; +}; + +} // namespace message +} // namespace chrome +} // namespace inspector_modern +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/MessageTypesInlines.h b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/MessageTypesInlines.h new file mode 100644 index 00000000..49a4995d --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/MessageTypesInlines.h @@ -0,0 +1,315 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace facebook { +namespace hermes { +namespace inspector_modern { +namespace chrome { +namespace message { + +template +using optional = std::optional; + +template +struct is_vector : std::false_type {}; + +template +struct is_vector> : std::true_type {}; + +/// valueFromJson + +/// Convert JSONValue to a Serializable type. +template +typename std:: + enable_if::value, std::unique_ptr>::type + valueFromJson(const JSONValue *v) { + auto res = llvh::dyn_cast_or_null(v); + if (!res) { + return nullptr; + } + return T::tryMake(res); +} + +/// Convert JSONValue to a bool. +template +typename std::enable_if::value, std::unique_ptr>::type +valueFromJson(const JSONValue *v) { + auto res = llvh::dyn_cast_or_null(v); + if (!res) { + return nullptr; + } + return std::make_unique(res->getValue()); +} + +/// Convert JSONValue to a long long. +template +typename std::enable_if::value, std::unique_ptr>:: + type + valueFromJson(const JSONValue *v) { + auto res = llvh::dyn_cast_or_null(v); + if (!res) { + return nullptr; + } + return std::make_unique(res->getValue()); +} + +/// Convert JSONValue to a double. +template +typename std::enable_if::value, std::unique_ptr>:: + type + valueFromJson(const JSONValue *v) { + auto res = llvh::dyn_cast_or_null(v); + if (!res) { + return nullptr; + } + return std::make_unique(res->getValue()); +} + +/// Convert JSONValue to a string. +template +typename std:: + enable_if::value, std::unique_ptr>::type + valueFromJson(const JSONValue *v) { + auto res = llvh::dyn_cast_or_null(v); + if (!res) { + return nullptr; + } + return std::make_unique(res->c_str()); +} + +/// Convert JSONValue to a vector. +template +typename std::enable_if::value, std::unique_ptr>::type +valueFromJson(const JSONValue *items) { + auto *arr = llvh::dyn_cast(items); + std::unique_ptr result = std::make_unique(); + result->reserve(arr->size()); + for (const auto &item : *arr) { + auto itemResult = valueFromJson(item); + if (!itemResult) { + return nullptr; + } + result->push_back(std::move(*itemResult)); + } + return result; +} + +/// Convert JSONValue to a JSONObject. +template +typename std:: + enable_if::value, std::unique_ptr>::type + valueFromJson(JSONValue *v) { + auto *res = llvh::dyn_cast_or_null(v); + if (!res) { + return nullptr; + } + return std::make_unique(res); +} + +/// Pass through JSONValues. +template +typename std:: + enable_if::value, std::unique_ptr>::type + valueFromJson(JSONValue *v) { + return std::make_unique(v); +} + +/// assign(lhs, obj, key) is a wrapper for: +/// +/// lhs = obj[key] +/// +/// It mainly exists so that we can choose the right version of valueFromJson +/// based on the type of lhs. + +template +bool assign(T &lhs, const JSONObject *obj, const U &key) { + JSONValue *v = obj->get(key); + if (v == nullptr) { + return false; + } + auto convertResult = valueFromJson(v); + if (convertResult) { + lhs = std::move(*convertResult); + return true; + } + return false; +} + +template +bool assign(optional &lhs, const JSONObject *obj, const U &key) { + JSONValue *v = obj->get(key); + if (v != nullptr) { + auto convertResult = valueFromJson(v); + if (convertResult) { + lhs = std::move(*convertResult); + return true; + } + return false; + } else { + lhs.reset(); + return true; + } +} + +template +bool assign(std::unique_ptr &lhs, const JSONObject *obj, const U &key) { + JSONValue *v = obj->get(key); + if (v != nullptr) { + auto convertResult = valueFromJson(v); + if (convertResult) { + lhs = std::move(convertResult); + return true; + } + return false; + } else { + lhs.reset(); + return true; + } +} + +template +bool assign( + std::unique_ptr> &lhs, + const JSONObject *obj, + const U &key) { + JSONValue *v = obj->get(key); + if (v != nullptr) { + auto convertResult = valueFromJson(v); + if (convertResult) { + lhs = std::move(convertResult); + return true; + } + return false; + } else { + lhs.reset(); + return true; + } +} + +/// valueToJson + +inline JSONValue *valueToJson(const Serializable &value, JSONFactory &factory) { + return value.toJsonVal(factory); +} + +// Convert a bool to JSONValue. +inline JSONValue *valueToJson(bool b, JSONFactory &factory) { + return factory.getBoolean(b); +} + +// Convert a long long to JSONValue. +inline JSONValue *valueToJson(long long num, JSONFactory &factory) { + return factory.getNumber(num); +} + +// Convert a double to JSONValue. +inline JSONValue *valueToJson(double num, JSONFactory &factory) { + return factory.getNumber(num); +} + +// Convert a string to JSONValue. +inline JSONValue *valueToJson(const std::string &str, JSONFactory &factory) { + return factory.getString(str); +} + +// Convert a vector to JSONValue. +template +JSONValue *valueToJson(const std::vector &items, JSONFactory &factory) { + llvh::SmallVector storage; + for (const auto &item : items) { + storage.push_back(valueToJson(item, factory)); + } + return factory.newArray(storage.size(), storage.begin(), storage.end()); +} + +// Cast a JSONObject to JSONValue. +inline JSONValue *valueToJson(JSONObject *obj, JSONFactory &factory) { + return llvh::cast(obj); +} + +// Pass through JSONValues. +inline JSONValue *valueToJson(JSONValue *v, JSONFactory &factory) { + return v; +} + +/// put(obj, key, value) is meant to be a wrapper for: +/// obj[key] = valueToJson(value); +/// However, JSONObjects are immutable, so we represent a 'put' operation as +/// pushing a new element onto a vector of JSONFactory::Props. + +using Properties = llvh::SmallVectorImpl; + +template +void put( + Properties &props, + const std::string &key, + const V &value, + JSONFactory &factory) { + JSONString *jsStr = factory.getString(key); + JSONValue *jsVal = valueToJson(value, factory); + props.push_back({jsStr, jsVal}); +} + +template +void put( + Properties &props, + const std::string &key, + const optional &optValue, + JSONFactory &factory) { + if (optValue.has_value()) { + JSONString *jsStr = factory.getString(key); + JSONValue *jsVal = valueToJson(optValue.value(), factory); + props.push_back({jsStr, jsVal}); + } +} + +template +void put( + Properties &props, + const std::string &key, + const std::unique_ptr &ptr, + JSONFactory &factory) { + if (ptr.get()) { + JSONString *jsStr = factory.getString(key); + JSONValue *jsVal = valueToJson(*ptr, factory); + props.push_back({jsStr, jsVal}); + } +} + +template +void put( + Properties &props, + const std::string &key, + const std::unique_ptr> &ptr, + JSONFactory &factory) { + if (ptr.get()) { + JSONString *jsStr = factory.getString(key); + JSONValue *jsVal = valueToJson(*ptr, factory); + props.push_back({jsStr, jsVal}); + } +} + +template +void deleter(T *p) { + delete p; +} + +} // namespace message +} // namespace chrome +} // namespace inspector_modern +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/RemoteObjectConverters.h b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/RemoteObjectConverters.h new file mode 100644 index 00000000..89355dc3 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/RemoteObjectConverters.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include + +namespace facebook { +namespace hermes { +namespace inspector_modern { +namespace chrome { +namespace message { + +namespace debugger { + +CallFrame makeCallFrame( + uint32_t callFrameIndex, + const facebook::hermes::debugger::CallFrameInfo &callFrameInfo, + const facebook::hermes::debugger::LexicalInfo &lexicalInfo, + facebook::hermes::inspector_modern::chrome::RemoteObjectsTable &objTable, + jsi::Runtime &runtime, + const facebook::hermes::debugger::ProgramState &state); + +std::vector makeCallFrames( + const facebook::hermes::debugger::ProgramState &state, + facebook::hermes::inspector_modern::chrome::RemoteObjectsTable &objTable, + jsi::Runtime &runtime); + +} // namespace debugger + +namespace runtime { + +RemoteObject makeRemoteObject( + facebook::jsi::Runtime &runtime, + const facebook::jsi::Value &value, + facebook::hermes::inspector_modern::chrome::RemoteObjectsTable &objTable, + const std::string &objectGroup, + bool byValue = false, + bool generatePreview = false); + +} // namespace runtime + +} // namespace message +} // namespace chrome +} // namespace inspector_modern +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/RemoteObjectsTable.h b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/RemoteObjectsTable.h new file mode 100644 index 00000000..d7a3370f --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/RemoteObjectsTable.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include + +#include + +namespace facebook { +namespace hermes { +namespace inspector_modern { +namespace chrome { + +/// Well-known object group names + +/** + * Objects created as a result of the Debugger.paused notification (e.g. scope + * objects) are placed in the "backtrace" object group. This object group is + * cleared when the VM resumes. + */ +extern const char *BacktraceObjectGroup; + +/** + * Objects that are created as a result of a console evaluation are placed in + * the "console" object group. This object group is cleared when the client + * clears the console. + */ +extern const char *ConsoleObjectGroup; + +/** + * RemoteObjectsTable manages the mapping of string object ids to scope metadata + * or actual JSI objects. The debugger vends these ids to the client so that the + * client can perform operations on the ids (e.g. enumerate properties on the + * object backed by the id). See Runtime.RemoteObjectId in the CDT docs for + * more details. + * + * Note that object handles are not ref-counted. Suppose an object foo is mapped + * to object id "objId" and is also in object group "objGroup". Then *either* of + * `releaseObject("objId")` or `releaseObjectGroup("objGroup")` will remove foo + * from the table. This matches the behavior of object groups in CDT. + */ +class RemoteObjectsTable { + public: + RemoteObjectsTable(); + ~RemoteObjectsTable(); + + RemoteObjectsTable(const RemoteObjectsTable &) = delete; + RemoteObjectsTable &operator=(const RemoteObjectsTable &) = delete; + + /** + * addScope adds the provided (frameIndex, scopeIndex) mapping to the table. + * If objectGroup is non-empty, then the scope object is also added to that + * object group for releasing via releaseObjectGroup. Returns an object id. + */ + std::string addScope( + std::pair frameAndScopeIndex, + const std::string &objectGroup); + + /** + * addValue adds the JSI value to the table. If objectGroup is non-empty, then + * the scope object is also added to that object group for releasing via + * releaseObjectGroup. Returns an object id. + */ + std::string addValue( + ::facebook::jsi::Value value, + const std::string &objectGroup); + + /** + * Retrieves the (frameIndex, scopeIndex) associated with this object id, or + * nullptr if no mapping exists. The pointer stays valid as long as you only + * call const methods on this class. + */ + const std::pair *getScope(const std::string &objId) const; + + /** + * Retrieves the JSI value associated with this object id, or nullptr if no + * mapping exists. The pointer stays valid as long as you only call const + * methods on this class. + */ + const ::facebook::jsi::Value *getValue(const std::string &objId) const; + + /** + * Retrieves the object group that this object id is in, or empty string if it + * isn't in an object group. The returned pointer is only guaranteed to be + * valid until the next call to this class. + */ + std::string getObjectGroup(const std::string &objId) const; + + /** + * Removes the scope or JSI value backed by the provided object ID from the + * table. + */ + void releaseObject(const std::string &objId); + + /** + * Removes all objects that are part of the provided object group from the + * table. + */ + void releaseObjectGroup(const std::string &objectGroup); + + private: + void releaseObject(int64_t id); + + int64_t scopeId_ = -1; + int64_t valueId_ = 1; + + std::unordered_map> scopes_; + std::unordered_map values_; + std::unordered_map idToGroup_; + std::unordered_map> groupToIds_; +}; + +} // namespace chrome +} // namespace inspector_modern +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/tests/AsyncHermesRuntime.h b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/tests/AsyncHermesRuntime.h new file mode 100644 index 00000000..aaaf9cd0 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/tests/AsyncHermesRuntime.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace facebook { +namespace hermes { +namespace inspector_modern { +namespace chrome { + +/// URL assigned to scripts being executed in the absense of a caller-specified +/// URL. +constexpr auto kDefaultUrl = "url"; + +/** + * AsyncHermesRuntime is a helper class that runs JS scripts in a Hermes VM on + * a separate thread. This is useful for tests that want to test running JS + * in a multithreaded environment. + */ +class AsyncHermesRuntime { + public: + // Create a runtime. If veryLazy, configure the runtime to use completely + // lazy compilation. + AsyncHermesRuntime(bool veryLazy = false); + ~AsyncHermesRuntime(); + + std::shared_ptr runtime() { + return runtime_; + } + + /** + * stop sets the stop flag on this instance. JS scripts can get the current + * value of the stop flag by calling the global shouldStop() function. + */ + void stop(); + + /** + * start unsets the stop flag on this instance. JS scripts can get the current + * value of the stop flag by calling the global shouldStop() function. + */ + void start(); + + /** + * hasStoredValue returns whether or not a value has been stored yet + */ + bool hasStoredValue(); + + /** + * awaitStoredValue is a helper for getStoredValue that returns the value + * synchronously rather than in a future. + */ + jsi::Value awaitStoredValue( + std::chrono::milliseconds timeout = std::chrono::milliseconds(2500)); + + /** + * tickleJsAsync evaluates '__tickleJs()' in the underlying Hermes runtime on + * a separate thread. + */ + void tickleJsAsync(); + + /** + * executeScriptAsync evaluates JS in the underlying Hermes runtime on a + * separate thread. + * + * This method should be called at most once during the lifetime of an + * AsyncHermesRuntime instance. + */ + void executeScriptAsync( + const std::string &str, + const std::string &url = kDefaultUrl, + facebook::hermes::HermesRuntime::DebugFlags flags = + facebook::hermes::HermesRuntime::DebugFlags{}); + + /** + * executeScriptSync evaluates JS in the underlying Hermes runtime on a + * separate thread. It will block the caller until execution completes. If + * this takes longer than \p timeout, an exception will be thrown. + */ + void executeScriptSync( + const std::string &script, + const std::string &url = kDefaultUrl, + facebook::hermes::HermesRuntime::DebugFlags flags = + facebook::hermes::HermesRuntime::DebugFlags{}, + std::chrono::milliseconds timeout = std::chrono::milliseconds(2500)); + + /// Evaluates the given bytecode in the underlying Hermes runtime on a + /// separate thread. + /// \param bytecode Bytecode compiled with compileJS() API + /// \param url Corresponding source URL + void evaluateBytecodeAsync( + const std::string &bytecode, + const std::string &url = "url"); + + /** + * wait blocks until all previous executeScriptAsync calls finish. + */ + void wait( + std::chrono::milliseconds timeout = std::chrono::milliseconds(2500)); + + /** + * returns the number of thrown exceptions. + */ + size_t getNumberOfExceptions(); + + /** + * returns the message of the last thrown exception. + */ + std::string getLastThrownExceptionMessage(); + + /** + * registers the runtime for profiling in the executor thread. + */ + void registerForProfilingInExecutor(); + + /** + * unregisters the runtime for profiling in the executor thread. + */ + void unregisterForProfilingInExecutor(); + + private: + jsi::Value shouldStop( + jsi::Runtime &runtime, + const jsi::Value &thisVal, + const jsi::Value *args, + size_t count); + + jsi::Value storeValue( + jsi::Runtime &runtime, + const jsi::Value &thisVal, + const jsi::Value *args, + size_t count); + + std::shared_ptr runtime_; + std::unique_ptr<::hermes::SerialExecutor> executor_; + std::atomic stopFlag_{}; + std::promise storedValue_; + bool hasStoredValue_{false}; + std::vector thrownExceptions_; +}; + +/// RAII-style class dealing with sampling profiler registration in tests. This +/// is especially important in tests -- if any test failure is caused by an +/// uncaught exception, stack unwinding will destroy a VM registered for +/// profiling in a thread that's not the one where registration happened, which +/// will lead to a hermes fatal error. Using this RAII class ensure that the +/// proper test failure cause is reported. +struct SamplingProfilerRAII { + explicit SamplingProfilerRAII(AsyncHermesRuntime &rt) : runtime_(rt) { + runtime_.registerForProfilingInExecutor(); + } + + ~SamplingProfilerRAII() { + runtime_.unregisterForProfilingInExecutor(); + } + + AsyncHermesRuntime &runtime_; +}; +} // namespace chrome +} // namespace inspector_modern +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/tests/SyncConnection.h b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/tests/SyncConnection.h new file mode 100644 index 00000000..d9ecc509 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/tests/SyncConnection.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +#include "AsyncHermesRuntime.h" + +namespace facebook { +namespace hermes { +namespace inspector_modern { +namespace chrome { + +class ExecutorRuntimeAdapter + : public facebook::hermes::inspector_modern::RuntimeAdapter { + public: + explicit ExecutorRuntimeAdapter(AsyncHermesRuntime &runtime) + : runtime_(runtime) {} + + virtual ~ExecutorRuntimeAdapter() override = default; + + HermesRuntime &getRuntime() override { + return *runtime_.runtime(); + } + + void tickleJs() override; + + private: + AsyncHermesRuntime &runtime_; +}; + +/** + * SyncConnection provides a synchronous interface over Connection that is + * useful in tests. + */ +class SyncConnection { + public: + explicit SyncConnection( + AsyncHermesRuntime &runtime, + bool waitForDebugger = false); + ~SyncConnection(); + + /// sends a message to the debugger + void send(const std::string &str); + + /// waits for the next message of either kind (response or notification) + /// from the debugger. returns the message. throws on timeout. + std::string waitForMessage( + std::chrono::milliseconds timeout = std::chrono::milliseconds(2500)); + + bool registerCallbacks(); + bool unregisterCallbacks(); + + /// \return True if onUnregister was called in a previous unregisterCallbacks + /// call. A registerCallbacks call will reset the status. + bool onUnregisterWasCalled(); + + private: + /// This function is given to the CDPHandler to receive replies in the form of + /// CDP messages + void onReply(const std::string &message); + + /// This function is given to the CDPHandler to be invoked upon + /// unregisterCallbacks call + void onUnregister(); + + std::shared_ptr cdpHandler_; + + bool onUnregisterCalled_ = false; + + std::mutex mutex_; + std::condition_variable hasMessage_; + std::queue messages_; +}; + +} // namespace chrome +} // namespace inspector_modern +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/tests/TestHelpers.h b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/tests/TestHelpers.h new file mode 100644 index 00000000..2f0e0399 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/hermes/inspector/chrome/tests/TestHelpers.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include +#include +#include + +namespace facebook { +namespace hermes { +namespace inspector_modern { +namespace chrome { + +using namespace ::hermes::parser; + +inline JSONValue *mustParseStr(const std::string &str, JSONFactory &factory) { + std::optional v = parseStr(str, factory); + EXPECT_TRUE(v.has_value()); + return v.value(); +} + +inline JSONObject *mustParseStrAsJsonObj( + const std::string &str, + JSONFactory &factory) { + std::optional obj = parseStrAsJsonObj(str, factory); + EXPECT_TRUE(obj.has_value()); + return obj.value(); +} + +template +T mustMake(const JSONObject *obj) { + std::unique_ptr instance = T::tryMake(obj); + EXPECT_TRUE(instance != nullptr); + return std::move(*instance); +} + +namespace message { + +inline std::unique_ptr mustGetRequestFromJson(const std::string &str) { + std::unique_ptr req = Request::fromJson(str); + EXPECT_TRUE(req != nullptr); + return req; +} + +} // namespace message + +} // namespace chrome +} // namespace inspector_modern +} // namespace hermes +} // namespace facebook diff --git a/NativeScript/napi/hermes/include/hermes/synthtest/tests/TestFunctions.h b/NativeScript/napi/hermes/include_old/hermes/synthtest/tests/TestFunctions.h similarity index 100% rename from NativeScript/napi/hermes/include/hermes/synthtest/tests/TestFunctions.h rename to NativeScript/napi/hermes/include_old/hermes/synthtest/tests/TestFunctions.h diff --git a/NativeScript/napi/hermes/include_old/jsi/JSIDynamic.h b/NativeScript/napi/hermes/include_old/jsi/JSIDynamic.h new file mode 100644 index 00000000..a96cc281 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/jsi/JSIDynamic.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace jsi { + +facebook::jsi::Value valueFromDynamic( + facebook::jsi::Runtime& runtime, + const folly::dynamic& dyn); + +folly::dynamic dynamicFromValue( + facebook::jsi::Runtime& runtime, + const facebook::jsi::Value& value, + std::function filterObjectKeys = nullptr); + +} // namespace jsi +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/jsi/decorator.h b/NativeScript/napi/hermes/include_old/jsi/decorator.h new file mode 100644 index 00000000..c0d3cc6d --- /dev/null +++ b/NativeScript/napi/hermes/include_old/jsi/decorator.h @@ -0,0 +1,901 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include + +// This file contains objects to help API users create their own +// runtime adapters, i.e. if you want to compose runtimes to add your +// own behavior. + +namespace facebook { +namespace jsi { + +// Use this to wrap host functions. It will pass the member runtime as +// the first arg to the callback. The first argument to the ctor +// should be the decorated runtime, not the plain one. +class DecoratedHostFunction { + public: + DecoratedHostFunction(Runtime& drt, HostFunctionType plainHF) + : drt_(drt), plainHF_(std::move(plainHF)) {} + + Runtime& decoratedRuntime() { + return drt_; + } + + Value + operator()(Runtime&, const Value& thisVal, const Value* args, size_t count) { + return plainHF_(decoratedRuntime(), thisVal, args, count); + } + + private: + template + friend class RuntimeDecorator; + + Runtime& drt_; + HostFunctionType plainHF_; +}; + +// From the perspective of the caller, a plain HostObject is passed to +// the decorated Runtime, and the HostObject methods expect to get +// passed that Runtime. But the plain Runtime will pass itself to its +// callback, so we need a helper here which curries the decorated +// Runtime, and calls the plain HostObject with it. +// +// If the concrete RuntimeDecorator derives DecoratedHostObject, it +// should call the base class get() and set() to invoke the plain +// HostObject functionality. The Runtime& it passes does not matter, +// as it is not used. +class DecoratedHostObject : public HostObject { + public: + DecoratedHostObject(Runtime& drt, std::shared_ptr plainHO) + : drt_(drt), plainHO_(plainHO) {} + + // The derived class methods can call this to get a reference to the + // decorated runtime, since the rt passed to the callback will be + // the plain runtime. + Runtime& decoratedRuntime() { + return drt_; + } + + Value get(Runtime&, const PropNameID& name) override { + return plainHO_->get(decoratedRuntime(), name); + } + + void set(Runtime&, const PropNameID& name, const Value& value) override { + plainHO_->set(decoratedRuntime(), name, value); + } + + std::vector getPropertyNames(Runtime&) override { + return plainHO_->getPropertyNames(decoratedRuntime()); + } + + private: + template + friend class RuntimeDecorator; + + Runtime& drt_; + std::shared_ptr plainHO_; +}; + +/// C++ variant on a standard Decorator pattern, using template +/// parameters. The \c Plain template parameter type is the +/// undecorated Runtime type. You can usually use \c Runtime here, +/// but if you know the concrete type ahead of time and it's final, +/// the compiler can devirtualize calls to the decorated +/// implementation. The \c Base template parameter type will be used +/// as the base class of the decorated type. Here, too, you can +/// usually use \c Runtime, but if you want the decorated type to +/// implement a derived class of Runtime, you can specify that here. +/// For an example, see threadsafe.h. +template +class RuntimeDecorator : public Base, private jsi::Instrumentation { + public: + Plain& plain() { + static_assert( + std::is_base_of::value, + "RuntimeDecorator's Plain type must derive from jsi::Runtime"); + static_assert( + std::is_base_of::value, + "RuntimeDecorator's Base type must derive from jsi::Runtime"); + return plain_; + } + const Plain& plain() const { + return plain_; + } + + Value evaluateJavaScript( + const std::shared_ptr& buffer, + const std::string& sourceURL) override { + return plain().evaluateJavaScript(buffer, sourceURL); + } + std::shared_ptr prepareJavaScript( + const std::shared_ptr& buffer, + std::string sourceURL) override { + return plain().prepareJavaScript(buffer, std::move(sourceURL)); + } + Value evaluatePreparedJavaScript( + const std::shared_ptr& js) override { + return plain().evaluatePreparedJavaScript(js); + } + void queueMicrotask(const jsi::Function& callback) override { + return plain().queueMicrotask(callback); + } + bool drainMicrotasks(int maxMicrotasksHint) override { + return plain().drainMicrotasks(maxMicrotasksHint); + } + Object global() override { + return plain().global(); + } + std::string description() override { + return plain().description(); + }; + bool isInspectable() override { + return plain().isInspectable(); + }; + Instrumentation& instrumentation() override { + return *this; + } + + protected: + // plain is generally going to be a reference to an object managed + // by a derived class. We cache it here so this class can be + // concrete, and avoid making virtual calls to find the plain + // Runtime. Note that the ctor and dtor do not access through the + // reference, so passing a reference to an object before its + // lifetime has started is ok. + RuntimeDecorator(Plain& plain) : plain_(plain) {} + + Runtime::PointerValue* cloneSymbol(const Runtime::PointerValue* pv) override { + return plain_.cloneSymbol(pv); + }; + Runtime::PointerValue* cloneBigInt(const Runtime::PointerValue* pv) override { + return plain_.cloneBigInt(pv); + }; + Runtime::PointerValue* cloneString(const Runtime::PointerValue* pv) override { + return plain_.cloneString(pv); + }; + Runtime::PointerValue* cloneObject(const Runtime::PointerValue* pv) override { + return plain_.cloneObject(pv); + }; + Runtime::PointerValue* clonePropNameID( + const Runtime::PointerValue* pv) override { + return plain_.clonePropNameID(pv); + }; + + PropNameID createPropNameIDFromAscii(const char* str, size_t length) + override { + return plain_.createPropNameIDFromAscii(str, length); + }; + PropNameID createPropNameIDFromUtf8(const uint8_t* utf8, size_t length) + override { + return plain_.createPropNameIDFromUtf8(utf8, length); + }; + PropNameID createPropNameIDFromString(const String& str) override { + return plain_.createPropNameIDFromString(str); + }; + PropNameID createPropNameIDFromSymbol(const Symbol& sym) override { + return plain_.createPropNameIDFromSymbol(sym); + }; + std::string utf8(const PropNameID& id) override { + return plain_.utf8(id); + }; + bool compare(const PropNameID& a, const PropNameID& b) override { + return plain_.compare(a, b); + }; + + std::string symbolToString(const Symbol& sym) override { + return plain_.symbolToString(sym); + } + + BigInt createBigIntFromInt64(int64_t value) override { + return plain_.createBigIntFromInt64(value); + } + BigInt createBigIntFromUint64(uint64_t value) override { + return plain_.createBigIntFromUint64(value); + } + bool bigintIsInt64(const BigInt& b) override { + return plain_.bigintIsInt64(b); + } + bool bigintIsUint64(const BigInt& b) override { + return plain_.bigintIsUint64(b); + } + uint64_t truncate(const BigInt& b) override { + return plain_.truncate(b); + } + String bigintToString(const BigInt& bigint, int radix) override { + return plain_.bigintToString(bigint, radix); + } + + String createStringFromAscii(const char* str, size_t length) override { + return plain_.createStringFromAscii(str, length); + }; + String createStringFromUtf8(const uint8_t* utf8, size_t length) override { + return plain_.createStringFromUtf8(utf8, length); + }; + std::string utf8(const String& s) override { + return plain_.utf8(s); + } + + std::u16string utf16(const String& str) override { + return plain_.utf16(str); + } + std::u16string utf16(const PropNameID& sym) override { + return plain_.utf16(sym); + } + + Object createObject() override { + return plain_.createObject(); + }; + + Object createObject(std::shared_ptr ho) override { + return plain_.createObject( + std::make_shared(*this, std::move(ho))); + }; + std::shared_ptr getHostObject(const jsi::Object& o) override { + std::shared_ptr dho = plain_.getHostObject(o); + return static_cast(*dho).plainHO_; + }; + +// HostFunctionType& getHostFunction(const jsi::Function& f) override { +// HostFunctionType& dhf = plain_.getHostFunction(f); +// // This will fail if a cpp file including this header is not compiled +// // with RTTI. +// return dhf.target()->plainHF_; +// }; + + bool hasNativeState(const Object& o) override { + return plain_.hasNativeState(o); + } + std::shared_ptr getNativeState(const Object& o) override { + return plain_.getNativeState(o); + } + void setNativeState(const Object& o, std::shared_ptr state) + override { + plain_.setNativeState(o, state); + } + + void setExternalMemoryPressure(const Object& obj, size_t amt) override { + plain_.setExternalMemoryPressure(obj, amt); + } + + Value getProperty(const Object& o, const PropNameID& name) override { + return plain_.getProperty(o, name); + }; + Value getProperty(const Object& o, const String& name) override { + return plain_.getProperty(o, name); + }; + bool hasProperty(const Object& o, const PropNameID& name) override { + return plain_.hasProperty(o, name); + }; + bool hasProperty(const Object& o, const String& name) override { + return plain_.hasProperty(o, name); + }; + void setPropertyValue( + const Object& o, + const PropNameID& name, + const Value& value) override { + plain_.setPropertyValue(o, name, value); + }; + void setPropertyValue(const Object& o, const String& name, const Value& value) + override { + plain_.setPropertyValue(o, name, value); + }; + + bool isArray(const Object& o) const override { + return plain_.isArray(o); + }; + bool isArrayBuffer(const Object& o) const override { + return plain_.isArrayBuffer(o); + }; + bool isFunction(const Object& o) const override { + return plain_.isFunction(o); + }; + bool isHostObject(const jsi::Object& o) const override { + return plain_.isHostObject(o); + }; + bool isHostFunction(const jsi::Function& f) const override { + return plain_.isHostFunction(f); + }; + Array getPropertyNames(const Object& o) override { + return plain_.getPropertyNames(o); + }; + + WeakObject createWeakObject(const Object& o) override { + return plain_.createWeakObject(o); + }; + Value lockWeakObject(const WeakObject& wo) override { + return plain_.lockWeakObject(wo); + }; + + Array createArray(size_t length) override { + return plain_.createArray(length); + }; + ArrayBuffer createArrayBuffer( + std::shared_ptr buffer) override { + return plain_.createArrayBuffer(std::move(buffer)); + }; + size_t size(const Array& a) override { + return plain_.size(a); + }; + size_t size(const ArrayBuffer& ab) override { + return plain_.size(ab); + }; + uint8_t* data(const ArrayBuffer& ab) override { + return plain_.data(ab); + }; + Value getValueAtIndex(const Array& a, size_t i) override { + return plain_.getValueAtIndex(a, i); + }; + void setValueAtIndexImpl(const Array& a, size_t i, const Value& value) + override { + plain_.setValueAtIndexImpl(a, i, value); + }; + + Function createFunctionFromHostFunction( + const PropNameID& name, + unsigned int paramCount, + HostFunctionType func) override { + return plain_.createFunctionFromHostFunction( + name, paramCount, DecoratedHostFunction(*this, std::move(func))); + }; + Value call( + const Function& f, + const Value& jsThis, + const Value* args, + size_t count) override { + return plain_.call(f, jsThis, args, count); + }; + Value callAsConstructor(const Function& f, const Value* args, size_t count) + override { + return plain_.callAsConstructor(f, args, count); + }; + + // Private data for managing scopes. + Runtime::ScopeState* pushScope() override { + return plain_.pushScope(); + } + void popScope(Runtime::ScopeState* ss) override { + plain_.popScope(ss); + } + + bool strictEquals(const Symbol& a, const Symbol& b) const override { + return plain_.strictEquals(a, b); + }; + bool strictEquals(const BigInt& a, const BigInt& b) const override { + return plain_.strictEquals(a, b); + }; + bool strictEquals(const String& a, const String& b) const override { + return plain_.strictEquals(a, b); + }; + bool strictEquals(const Object& a, const Object& b) const override { + return plain_.strictEquals(a, b); + }; + + bool instanceOf(const Object& o, const Function& f) override { + return plain_.instanceOf(o, f); + }; + + // jsi::Instrumentation methods + + std::string getRecordedGCStats() override { + return plain().instrumentation().getRecordedGCStats(); + } + + std::unordered_map getHeapInfo( + bool includeExpensive) override { + return plain().instrumentation().getHeapInfo(includeExpensive); + } + + void collectGarbage(std::string cause) override { + plain().instrumentation().collectGarbage(std::move(cause)); + } + + void startTrackingHeapObjectStackTraces( + std::function)> callback) override { + plain().instrumentation().startTrackingHeapObjectStackTraces( + std::move(callback)); + } + + void stopTrackingHeapObjectStackTraces() override { + plain().instrumentation().stopTrackingHeapObjectStackTraces(); + } + + void startHeapSampling(size_t samplingInterval) override { + plain().instrumentation().startHeapSampling(samplingInterval); + } + + void stopHeapSampling(std::ostream& os) override { + plain().instrumentation().stopHeapSampling(os); + } + + void createSnapshotToFile( + const std::string& path, + const HeapSnapshotOptions& options) override { + plain().instrumentation().createSnapshotToFile(path, options); + } + + void createSnapshotToStream( + std::ostream& os, + const HeapSnapshotOptions& options) override { + plain().instrumentation().createSnapshotToStream(os, options); + } + + std::string flushAndDisableBridgeTrafficTrace() override { + return const_cast(plain()) + .instrumentation() + .flushAndDisableBridgeTrafficTrace(); + } + + void writeBasicBlockProfileTraceToFile( + const std::string& fileName) const override { + const_cast(plain()) + .instrumentation() + .writeBasicBlockProfileTraceToFile(fileName); + } + + /// Dump external profiler symbols to the given file name. + void dumpProfilerSymbolsToFile(const std::string& fileName) const override { + const_cast(plain()).instrumentation().dumpProfilerSymbolsToFile( + fileName); + } + + private: + Plain& plain_; +}; + +namespace detail { + +// This metaprogramming allows the With type's methods to be +// optional. + +template +struct BeforeCaller { + static void before(T&) {} +}; + +template +struct AfterCaller { + static void after(T&) {} +}; + +// decltype((void)&...) is either SFINAE, or void. +// So, if SFINAE does not happen for T, then this specialization exists +// for BeforeCaller, and always applies. If not, only the +// default above exists, and that is used instead. +template +struct BeforeCaller { + static void before(T& t) { + t.before(); + } +}; + +template +struct AfterCaller { + static void after(T& t) { + t.after(); + } +}; + +// It's possible to use multiple decorators by nesting +// WithRuntimeDecorator<...>, but this specialization allows use of +// std::tuple of decorator classes instead. See testlib.cpp for an +// example. +template +struct BeforeCaller> { + static void before(std::tuple& tuple) { + all_before<0, T...>(tuple); + } + + private: + template + static void all_before(std::tuple& tuple) { + detail::BeforeCaller::before(std::get(tuple)); + all_before(tuple); + } + + template + static void all_before(std::tuple&) {} +}; + +template +struct AfterCaller> { + static void after(std::tuple& tuple) { + all_after<0, T...>(tuple); + } + + private: + template + static void all_after(std::tuple& tuple) { + all_after(tuple); + detail::AfterCaller::after(std::get(tuple)); + } + + template + static void all_after(std::tuple&) {} +}; + +} // namespace detail + +// A decorator which implements an around idiom. A With instance is +// RAII constructed before each call to the undecorated class; the +// ctor is passed a single argument of type WithArg&. Plain and Base +// are used as in the base class. +template +class WithRuntimeDecorator : public RuntimeDecorator { + public: + using RD = RuntimeDecorator; + + // The reference arguments to the ctor are stored, but not used by + // the ctor, and there is no ctor, so they can be passed members of + // the derived class. + WithRuntimeDecorator(Plain& plain, With& with) : RD(plain), with_(with) {} + + Value evaluateJavaScript( + const std::shared_ptr& buffer, + const std::string& sourceURL) override { + Around around{with_}; + return RD::evaluateJavaScript(buffer, sourceURL); + } + std::shared_ptr prepareJavaScript( + const std::shared_ptr& buffer, + std::string sourceURL) override { + Around around{with_}; + return RD::prepareJavaScript(buffer, std::move(sourceURL)); + } + Value evaluatePreparedJavaScript( + const std::shared_ptr& js) override { + Around around{with_}; + return RD::evaluatePreparedJavaScript(js); + } + void queueMicrotask(const Function& callback) override { + Around around{with_}; + RD::queueMicrotask(callback); + } + bool drainMicrotasks(int maxMicrotasksHint) override { + Around around{with_}; + return RD::drainMicrotasks(maxMicrotasksHint); + } + Object global() override { + Around around{with_}; + return RD::global(); + } + std::string description() override { + Around around{with_}; + return RD::description(); + }; + bool isInspectable() override { + Around around{with_}; + return RD::isInspectable(); + }; + + // The jsi:: prefix is necessary because MSVC compiler complains C2247: + // Instrumentation is not accessible because RuntimeDecorator uses private + // to inherit from Instrumentation. + // TODO(T40821815) Consider removing this workaround when updating MSVC + jsi::Instrumentation& instrumentation() override { + Around around{with_}; + return RD::instrumentation(); + } + + protected: + Runtime::PointerValue* cloneSymbol(const Runtime::PointerValue* pv) override { + Around around{with_}; + return RD::cloneSymbol(pv); + }; + Runtime::PointerValue* cloneBigInt(const Runtime::PointerValue* pv) override { + Around around{with_}; + return RD::cloneBigInt(pv); + }; + Runtime::PointerValue* cloneString(const Runtime::PointerValue* pv) override { + Around around{with_}; + return RD::cloneString(pv); + }; + Runtime::PointerValue* cloneObject(const Runtime::PointerValue* pv) override { + Around around{with_}; + return RD::cloneObject(pv); + }; + Runtime::PointerValue* clonePropNameID( + const Runtime::PointerValue* pv) override { + Around around{with_}; + return RD::clonePropNameID(pv); + }; + + PropNameID createPropNameIDFromAscii(const char* str, size_t length) + override { + Around around{with_}; + return RD::createPropNameIDFromAscii(str, length); + }; + PropNameID createPropNameIDFromUtf8(const uint8_t* utf8, size_t length) + override { + Around around{with_}; + return RD::createPropNameIDFromUtf8(utf8, length); + }; + PropNameID createPropNameIDFromString(const String& str) override { + Around around{with_}; + return RD::createPropNameIDFromString(str); + }; + PropNameID createPropNameIDFromSymbol(const Symbol& sym) override { + Around around{with_}; + return RD::createPropNameIDFromSymbol(sym); + }; + std::string utf8(const PropNameID& id) override { + Around around{with_}; + return RD::utf8(id); + }; + bool compare(const PropNameID& a, const PropNameID& b) override { + Around around{with_}; + return RD::compare(a, b); + }; + + std::string symbolToString(const Symbol& sym) override { + Around around{with_}; + return RD::symbolToString(sym); + }; + + BigInt createBigIntFromInt64(int64_t i) override { + Around around{with_}; + return RD::createBigIntFromInt64(i); + }; + BigInt createBigIntFromUint64(uint64_t i) override { + Around around{with_}; + return RD::createBigIntFromUint64(i); + }; + bool bigintIsInt64(const BigInt& bi) override { + Around around{with_}; + return RD::bigintIsInt64(bi); + }; + bool bigintIsUint64(const BigInt& bi) override { + Around around{with_}; + return RD::bigintIsUint64(bi); + }; + uint64_t truncate(const BigInt& bi) override { + Around around{with_}; + return RD::truncate(bi); + }; + String bigintToString(const BigInt& bi, int i) override { + Around around{with_}; + return RD::bigintToString(bi, i); + }; + + String createStringFromAscii(const char* str, size_t length) override { + Around around{with_}; + return RD::createStringFromAscii(str, length); + }; + String createStringFromUtf8(const uint8_t* utf8, size_t length) override { + Around around{with_}; + return RD::createStringFromUtf8(utf8, length); + }; + std::string utf8(const String& s) override { + Around around{with_}; + return RD::utf8(s); + } + + std::u16string utf16(const String& str) override { + Around around{with_}; + return RD::utf16(str); + } + std::u16string utf16(const PropNameID& sym) override { + Around around{with_}; + return RD::utf16(sym); + } + + Value createValueFromJsonUtf8(const uint8_t* json, size_t length) override { + Around around{with_}; + return RD::createValueFromJsonUtf8(json, length); + }; + + Object createObject() override { + Around around{with_}; + return RD::createObject(); + }; + Object createObject(std::shared_ptr ho) override { + Around around{with_}; + return RD::createObject(std::move(ho)); + }; + std::shared_ptr getHostObject(const jsi::Object& o) override { + Around around{with_}; + return RD::getHostObject(o); + }; + HostFunctionType& getHostFunction(const jsi::Function& f) override { + Around around{with_}; + return RD::getHostFunction(f); + }; + + bool hasNativeState(const Object& o) override { + Around around{with_}; + return RD::hasNativeState(o); + }; + std::shared_ptr getNativeState(const Object& o) override { + Around around{with_}; + return RD::getNativeState(o); + }; + void setNativeState(const Object& o, std::shared_ptr state) + override { + Around around{with_}; + RD::setNativeState(o, state); + }; + + Value getProperty(const Object& o, const PropNameID& name) override { + Around around{with_}; + return RD::getProperty(o, name); + }; + Value getProperty(const Object& o, const String& name) override { + Around around{with_}; + return RD::getProperty(o, name); + }; + bool hasProperty(const Object& o, const PropNameID& name) override { + Around around{with_}; + return RD::hasProperty(o, name); + }; + bool hasProperty(const Object& o, const String& name) override { + Around around{with_}; + return RD::hasProperty(o, name); + }; + void setPropertyValue( + const Object& o, + const PropNameID& name, + const Value& value) override { + Around around{with_}; + RD::setPropertyValue(o, name, value); + }; + void setPropertyValue(const Object& o, const String& name, const Value& value) + override { + Around around{with_}; + RD::setPropertyValue(o, name, value); + }; + + bool isArray(const Object& o) const override { + Around around{with_}; + return RD::isArray(o); + }; + bool isArrayBuffer(const Object& o) const override { + Around around{with_}; + return RD::isArrayBuffer(o); + }; + bool isFunction(const Object& o) const override { + Around around{with_}; + return RD::isFunction(o); + }; + bool isHostObject(const jsi::Object& o) const override { + Around around{with_}; + return RD::isHostObject(o); + }; + bool isHostFunction(const jsi::Function& f) const override { + Around around{with_}; + return RD::isHostFunction(f); + }; + Array getPropertyNames(const Object& o) override { + Around around{with_}; + return RD::getPropertyNames(o); + }; + + WeakObject createWeakObject(const Object& o) override { + Around around{with_}; + return RD::createWeakObject(o); + }; + Value lockWeakObject(const WeakObject& wo) override { + Around around{with_}; + return RD::lockWeakObject(wo); + }; + + Array createArray(size_t length) override { + Around around{with_}; + return RD::createArray(length); + }; + ArrayBuffer createArrayBuffer( + std::shared_ptr buffer) override { + return RD::createArrayBuffer(std::move(buffer)); + }; + size_t size(const Array& a) override { + Around around{with_}; + return RD::size(a); + }; + size_t size(const ArrayBuffer& ab) override { + Around around{with_}; + return RD::size(ab); + }; + uint8_t* data(const ArrayBuffer& ab) override { + Around around{with_}; + return RD::data(ab); + }; + Value getValueAtIndex(const Array& a, size_t i) override { + Around around{with_}; + return RD::getValueAtIndex(a, i); + }; + void setValueAtIndexImpl(const Array& a, size_t i, const Value& value) + override { + Around around{with_}; + RD::setValueAtIndexImpl(a, i, value); + }; + + Function createFunctionFromHostFunction( + const PropNameID& name, + unsigned int paramCount, + HostFunctionType func) override { + Around around{with_}; + return RD::createFunctionFromHostFunction( + name, paramCount, std::move(func)); + }; + Value call( + const Function& f, + const Value& jsThis, + const Value* args, + size_t count) override { + Around around{with_}; + return RD::call(f, jsThis, args, count); + }; + Value callAsConstructor(const Function& f, const Value* args, size_t count) + override { + Around around{with_}; + return RD::callAsConstructor(f, args, count); + }; + + // Private data for managing scopes. + Runtime::ScopeState* pushScope() override { + Around around{with_}; + return RD::pushScope(); + } + void popScope(Runtime::ScopeState* ss) override { + Around around{with_}; + RD::popScope(ss); + } + + bool strictEquals(const Symbol& a, const Symbol& b) const override { + Around around{with_}; + return RD::strictEquals(a, b); + }; + bool strictEquals(const BigInt& a, const BigInt& b) const override { + Around around{with_}; + return RD::strictEquals(a, b); + }; + + bool strictEquals(const String& a, const String& b) const override { + Around around{with_}; + return RD::strictEquals(a, b); + }; + bool strictEquals(const Object& a, const Object& b) const override { + Around around{with_}; + return RD::strictEquals(a, b); + }; + + bool instanceOf(const Object& o, const Function& f) override { + Around around{with_}; + return RD::instanceOf(o, f); + }; + + void setExternalMemoryPressure(const jsi::Object& obj, size_t amount) + override { + Around around{with_}; + RD::setExternalMemoryPressure(obj, amount); + }; + + private: + // Wrap an RAII type around With& to guarantee after always happens. + struct Around { + Around(With& with) : with_(with) { + detail::BeforeCaller::before(with_); + } + ~Around() { + detail::AfterCaller::after(with_); + } + + With& with_; + }; + + With& with_; +}; + +} // namespace jsi +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/jsi/instrumentation.h b/NativeScript/napi/hermes/include_old/jsi/instrumentation.h new file mode 100644 index 00000000..726858cc --- /dev/null +++ b/NativeScript/napi/hermes/include_old/jsi/instrumentation.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace facebook { +namespace jsi { + +/// Methods for starting and collecting instrumentation, an \c Instrumentation +/// instance is associated with a particular \c Runtime instance, which it +/// controls the instrumentation of. +/// None of these functions should return newly created jsi values, nor should +/// it modify the values of any jsi values in the heap (although GCs are fine). +class JSI_EXPORT Instrumentation { + public: + /// Additional options controlling what to include when capturing a heap + /// snapshot. + struct HeapSnapshotOptions { + bool captureNumericValue{false}; + }; + + virtual ~Instrumentation() = default; + + /// Returns GC statistics as a JSON-encoded string, with an object containing + /// "type" and "version" fields outermost. "type" is a string, unique to a + /// particular implementation of \c jsi::Instrumentation, and "version" is a + /// number to indicate any revision to that implementation and its output + /// format. + /// + /// \pre This call can only be made on the instrumentation instance of a + /// runtime initialised to collect GC statistics. + /// + /// \post All cumulative measurements mentioned in the output are accumulated + /// across the entire lifetime of the Runtime. + /// + /// \return the GC statistics collected so far, as a JSON-encoded string. + virtual std::string getRecordedGCStats() = 0; + + /// Request statistics about the current state of the runtime's heap. This + /// function can be called at any time, and should produce information that is + /// correct at the instant it is called (i.e, not stale). + /// + /// \return a map from a string key to a number associated with that + /// statistic. + virtual std::unordered_map getHeapInfo( + bool includeExpensive) = 0; + + /// Perform a full garbage collection. + /// \param cause The cause of this collection, as it should be reported in + /// logs. + virtual void collectGarbage(std::string cause) = 0; + + /// A HeapStatsUpdate is a tuple of the fragment index, the number of objects + /// in that fragment, and the number of bytes used by those objects. + /// A "fragment" is a view of all objects allocated within a time slice. + using HeapStatsUpdate = std::tuple; + + /// Start capturing JS stack-traces for all JS heap allocated objects. These + /// can be accessed via \c ::createSnapshotToFile(). + /// \param fragmentCallback If present, invoke this callback every so often + /// with the most recently seen object ID, and a list of fragments that have + /// been updated. This callback will be invoked on the same thread that the + /// runtime is using. + virtual void startTrackingHeapObjectStackTraces( + std::function stats)> fragmentCallback) = 0; + + /// Stop capture JS stack-traces for JS heap allocated objects. + virtual void stopTrackingHeapObjectStackTraces() = 0; + + /// Start a heap sampling profiler that will sample heap allocations, and the + /// stack trace they were allocated at. Reports a summary of which functions + /// allocated the most. + /// \param samplingInterval The number of bytes allocated to wait between + /// samples. This will be used as the expected value of a poisson + /// distribution. + virtual void startHeapSampling(size_t samplingInterval) = 0; + + /// Turns off the heap sampling profiler previously enabled via + /// \c startHeapSampling. Writes the output of the sampling heap profiler to + /// \p os. The output is a JSON formatted string. + virtual void stopHeapSampling(std::ostream& os) = 0; + + /// Captures the heap to a file + /// + /// \param path to save the heap capture. + /// \param options additional options for what to capture. + virtual void createSnapshotToFile( + const std::string& path, + const HeapSnapshotOptions& options = {false}) = 0; + + /// Captures the heap to an output stream + /// + /// \param os output stream to write to. + /// \param options additional options for what to capture. + virtual void createSnapshotToStream( + std::ostream& os, + const HeapSnapshotOptions& options = {false}) = 0; + + /// If the runtime has been created to trace to a temp file, flush + /// any unwritten parts of the trace of bridge traffic to the file, + /// and return the name of the file. Otherwise, return the empty string. + /// Tracing is disabled after this call. + virtual std::string flushAndDisableBridgeTrafficTrace() = 0; + + /// Write basic block profile trace to the given file name. + virtual void writeBasicBlockProfileTraceToFile( + const std::string& fileName) const = 0; + + /// Dump external profiler symbols to the given file name. + virtual void dumpProfilerSymbolsToFile(const std::string& fileName) const = 0; +}; + +} // namespace jsi +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/jsi/jsi-inl.h b/NativeScript/napi/hermes/include_old/jsi/jsi-inl.h new file mode 100644 index 00000000..111a4702 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/jsi/jsi-inl.h @@ -0,0 +1,356 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +namespace facebook { +namespace jsi { +namespace detail { + +inline Value toValue(Runtime&, std::nullptr_t) { + return Value::null(); +} +inline Value toValue(Runtime&, bool b) { + return Value(b); +} +inline Value toValue(Runtime&, double d) { + return Value(d); +} +inline Value toValue(Runtime&, float f) { + return Value(static_cast(f)); +} +inline Value toValue(Runtime&, int i) { + return Value(i); +} +inline Value toValue(Runtime& runtime, const char* str) { + return String::createFromAscii(runtime, str); +} +inline Value toValue(Runtime& runtime, const std::string& str) { + return String::createFromUtf8(runtime, str); +} +template +inline Value toValue(Runtime& runtime, const T& other) { + static_assert( + std::is_base_of::value, + "This type cannot be converted to Value"); + return Value(runtime, other); +} +inline Value toValue(Runtime& runtime, const Value& value) { + return Value(runtime, value); +} +inline Value&& toValue(Runtime&, Value&& value) { + return std::move(value); +} + +inline PropNameID toPropNameID(Runtime& runtime, const char* name) { + return PropNameID::forAscii(runtime, name); +} +inline PropNameID toPropNameID(Runtime& runtime, const std::string& name) { + return PropNameID::forUtf8(runtime, name); +} +inline PropNameID&& toPropNameID(Runtime&, PropNameID&& name) { + return std::move(name); +} + +/// Helper to throw while still compiling with exceptions turned off. +template +[[noreturn]] inline void throwOrDie(Args&&... args) { + std::rethrow_exception( + std::make_exception_ptr(E{std::forward(args)...})); +} + +} // namespace detail + +template +inline T Runtime::make(Runtime::PointerValue* pv) { + return T(pv); +} + +inline Runtime::PointerValue* Runtime::getPointerValue(jsi::Pointer& pointer) { + return pointer.ptr_; +} + +inline const Runtime::PointerValue* Runtime::getPointerValue( + const jsi::Pointer& pointer) { + return pointer.ptr_; +} + +inline const Runtime::PointerValue* Runtime::getPointerValue( + const jsi::Value& value) { + return value.data_.pointer.ptr_; +} + +inline Value Object::getProperty(Runtime& runtime, const char* name) const { + return getProperty(runtime, String::createFromAscii(runtime, name)); +} + +inline Value Object::getProperty(Runtime& runtime, const String& name) const { + return runtime.getProperty(*this, name); +} + +inline Value Object::getProperty(Runtime& runtime, const PropNameID& name) + const { + return runtime.getProperty(*this, name); +} + +inline bool Object::hasProperty(Runtime& runtime, const char* name) const { + return hasProperty(runtime, String::createFromAscii(runtime, name)); +} + +inline bool Object::hasProperty(Runtime& runtime, const String& name) const { + return runtime.hasProperty(*this, name); +} + +inline bool Object::hasProperty(Runtime& runtime, const PropNameID& name) + const { + return runtime.hasProperty(*this, name); +} + +template +void Object::setProperty(Runtime& runtime, const char* name, T&& value) const { + setProperty( + runtime, String::createFromAscii(runtime, name), std::forward(value)); +} + +template +void Object::setProperty(Runtime& runtime, const String& name, T&& value) + const { + setPropertyValue( + runtime, name, detail::toValue(runtime, std::forward(value))); +} + +template +void Object::setProperty(Runtime& runtime, const PropNameID& name, T&& value) + const { + setPropertyValue( + runtime, name, detail::toValue(runtime, std::forward(value))); +} + +inline Array Object::getArray(Runtime& runtime) const& { + assert(runtime.isArray(*this)); + (void)runtime; // when assert is disabled we need to mark this as used + return Array(runtime.cloneObject(ptr_)); +} + +inline Array Object::getArray(Runtime& runtime) && { + assert(runtime.isArray(*this)); + (void)runtime; // when assert is disabled we need to mark this as used + Runtime::PointerValue* value = ptr_; + ptr_ = nullptr; + return Array(value); +} + +inline ArrayBuffer Object::getArrayBuffer(Runtime& runtime) const& { + assert(runtime.isArrayBuffer(*this)); + (void)runtime; // when assert is disabled we need to mark this as used + return ArrayBuffer(runtime.cloneObject(ptr_)); +} + +inline ArrayBuffer Object::getArrayBuffer(Runtime& runtime) && { + assert(runtime.isArrayBuffer(*this)); + (void)runtime; // when assert is disabled we need to mark this as used + Runtime::PointerValue* value = ptr_; + ptr_ = nullptr; + return ArrayBuffer(value); +} + +inline Function Object::getFunction(Runtime& runtime) const& { + assert(runtime.isFunction(*this)); + return Function(runtime.cloneObject(ptr_)); +} + +inline Function Object::getFunction(Runtime& runtime) && { + assert(runtime.isFunction(*this)); + (void)runtime; // when assert is disabled we need to mark this as used + Runtime::PointerValue* value = ptr_; + ptr_ = nullptr; + return Function(value); +} + +template +inline bool Object::isHostObject(Runtime& runtime) const { + return runtime.isHostObject(*this) && + std::dynamic_pointer_cast(runtime.getHostObject(*this)); +} + +template <> +inline bool Object::isHostObject(Runtime& runtime) const { + return runtime.isHostObject(*this); +} + +template +inline std::shared_ptr Object::getHostObject(Runtime& runtime) const { + assert(isHostObject(runtime)); + return std::static_pointer_cast(runtime.getHostObject(*this)); +} + +template +inline std::shared_ptr Object::asHostObject(Runtime& runtime) const { + if (!isHostObject(runtime)) { + detail::throwOrDie( + "Object is not a HostObject of desired type"); + } + return std::static_pointer_cast(runtime.getHostObject(*this)); +} + +template <> +inline std::shared_ptr Object::getHostObject( + Runtime& runtime) const { + assert(runtime.isHostObject(*this)); + return runtime.getHostObject(*this); +} + +template +inline bool Object::hasNativeState(Runtime& runtime) const { + return runtime.hasNativeState(*this) && + std::dynamic_pointer_cast(runtime.getNativeState(*this)); +} + +template <> +inline bool Object::hasNativeState(Runtime& runtime) const { + return runtime.hasNativeState(*this); +} + +template +inline std::shared_ptr Object::getNativeState(Runtime& runtime) const { + assert(hasNativeState(runtime)); + return std::static_pointer_cast(runtime.getNativeState(*this)); +} + +inline void Object::setNativeState( + Runtime& runtime, + std::shared_ptr state) const { + runtime.setNativeState(*this, state); +} + +inline void Object::setExternalMemoryPressure(Runtime& runtime, size_t amt) + const { + runtime.setExternalMemoryPressure(*this, amt); +} + +inline Array Object::getPropertyNames(Runtime& runtime) const { + return runtime.getPropertyNames(*this); +} + +inline Value WeakObject::lock(Runtime& runtime) const { + return runtime.lockWeakObject(*this); +} + +template +void Array::setValueAtIndex(Runtime& runtime, size_t i, T&& value) const { + setValueAtIndexImpl( + runtime, i, detail::toValue(runtime, std::forward(value))); +} + +inline Value Array::getValueAtIndex(Runtime& runtime, size_t i) const { + return runtime.getValueAtIndex(*this, i); +} + +inline Function Function::createFromHostFunction( + Runtime& runtime, + const jsi::PropNameID& name, + unsigned int paramCount, + jsi::HostFunctionType func) { + return runtime.createFunctionFromHostFunction( + name, paramCount, std::move(func)); +} + +inline Value Function::call(Runtime& runtime, const Value* args, size_t count) + const { + return runtime.call(*this, Value::undefined(), args, count); +} + +inline Value Function::call(Runtime& runtime, std::initializer_list args) + const { + return call(runtime, args.begin(), args.size()); +} + +template +inline Value Function::call(Runtime& runtime, Args&&... args) const { + // A more awesome version of this would be able to create raw values + // which can be used directly without wrapping and unwrapping, but + // this will do for now. + return call(runtime, {detail::toValue(runtime, std::forward(args))...}); +} + +inline Value Function::callWithThis( + Runtime& runtime, + const Object& jsThis, + const Value* args, + size_t count) const { + return runtime.call(*this, Value(runtime, jsThis), args, count); +} + +inline Value Function::callWithThis( + Runtime& runtime, + const Object& jsThis, + std::initializer_list args) const { + return callWithThis(runtime, jsThis, args.begin(), args.size()); +} + +template +inline Value Function::callWithThis( + Runtime& runtime, + const Object& jsThis, + Args&&... args) const { + // A more awesome version of this would be able to create raw values + // which can be used directly without wrapping and unwrapping, but + // this will do for now. + return callWithThis( + runtime, jsThis, {detail::toValue(runtime, std::forward(args))...}); +} + +template +inline Array Array::createWithElements(Runtime& runtime, Args&&... args) { + return createWithElements( + runtime, {detail::toValue(runtime, std::forward(args))...}); +} + +template +inline std::vector PropNameID::names( + Runtime& runtime, + Args&&... args) { + return names({detail::toPropNameID(runtime, std::forward(args))...}); +} + +template +inline std::vector PropNameID::names( + PropNameID (&&propertyNames)[N]) { + std::vector result; + result.reserve(N); + for (auto& name : propertyNames) { + result.push_back(std::move(name)); + } + return result; +} + +inline Value Function::callAsConstructor( + Runtime& runtime, + const Value* args, + size_t count) const { + return runtime.callAsConstructor(*this, args, count); +} + +inline Value Function::callAsConstructor( + Runtime& runtime, + std::initializer_list args) const { + return callAsConstructor(runtime, args.begin(), args.size()); +} + +template +inline Value Function::callAsConstructor(Runtime& runtime, Args&&... args) + const { + return callAsConstructor( + runtime, {detail::toValue(runtime, std::forward(args))...}); +} + +String BigInt::toString(Runtime& runtime, int radix) const { + return runtime.bigintToString(*this, radix); +} + +} // namespace jsi +} // namespace facebook diff --git a/NativeScript/napi/hermes/include_old/jsi/jsi.h b/NativeScript/napi/hermes/include_old/jsi/jsi.h new file mode 100644 index 00000000..be48bb82 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/jsi/jsi.h @@ -0,0 +1,1549 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#ifndef JSI_EXPORT +#ifdef _MSC_VER +#ifdef CREATE_SHARED_LIBRARY +#define JSI_EXPORT __declspec(dllexport) +#else +#define JSI_EXPORT +#endif // CREATE_SHARED_LIBRARY +#else // _MSC_VER +#define JSI_EXPORT __attribute__((visibility("default"))) +#endif // _MSC_VER +#endif // !defined(JSI_EXPORT) + +class FBJSRuntime; +namespace facebook { +namespace jsi { + +/// Base class for buffers of data or bytecode that need to be passed to the +/// runtime. The buffer is expected to be fully immutable, so the result of +/// size(), data(), and the contents of the pointer returned by data() must not +/// change after construction. +class JSI_EXPORT Buffer { + public: + virtual ~Buffer(); + virtual size_t size() const = 0; + virtual const uint8_t* data() const = 0; +}; + +class JSI_EXPORT StringBuffer : public Buffer { + public: + StringBuffer(std::string s) : s_(std::move(s)) {} + size_t size() const override { + return s_.size(); + } + const uint8_t* data() const override { + return reinterpret_cast(s_.data()); + } + + private: + std::string s_; +}; + +/// Base class for buffers of data that need to be passed to the runtime. The +/// result of size() and data() must not change after construction. However, the +/// region pointed to by data() may be modified by the user or the runtime. The +/// user must ensure that access to the contents of the buffer is properly +/// synchronised. +class JSI_EXPORT MutableBuffer { + public: + virtual ~MutableBuffer(); + virtual size_t size() const = 0; + virtual uint8_t* data() = 0; +}; + +/// PreparedJavaScript is a base class representing JavaScript which is in a +/// form optimized for execution, in a runtime-specific way. Construct one via +/// jsi::Runtime::prepareJavaScript(). +/// ** This is an experimental API that is subject to change. ** +class JSI_EXPORT PreparedJavaScript { + protected: + PreparedJavaScript() = default; + + public: + virtual ~PreparedJavaScript() = 0; +}; + +class Runtime; +class Pointer; +class PropNameID; +class Symbol; +class BigInt; +class String; +class Object; +class WeakObject; +class Array; +class ArrayBuffer; +class Function; +class Value; +class Instrumentation; +class Scope; +class JSIException; +class JSError; + +/// A function which has this type can be registered as a function +/// callable from JavaScript using Function::createFromHostFunction(). +/// When the function is called, args will point to the arguments, and +/// count will indicate how many arguments are passed. The function +/// can return a Value to the caller, or throw an exception. If a C++ +/// exception is thrown, a JS Error will be created and thrown into +/// JS; if the C++ exception extends std::exception, the Error's +/// message will be whatever what() returns. Note that it is undefined whether +/// HostFunctions may or may not be called in strict mode; that is `thisVal` +/// can be any value - it will not necessarily be coerced to an object or +/// or set to the global object. +using HostFunctionType = std::function< + Value(Runtime& rt, const Value& thisVal, const Value* args, size_t count)>; + +/// An object which implements this interface can be registered as an +/// Object with the JS runtime. +class JSI_EXPORT HostObject { + public: + // The C++ object's dtor will be called when the GC finalizes this + // object. (This may be as late as when the Runtime is shut down.) + // You have no control over which thread it is called on. This will + // be called from inside the GC, so it is unsafe to do any VM + // operations which require a Runtime&. Derived classes' dtors + // should also avoid doing anything expensive. Calling the dtor on + // a jsi object is explicitly ok. If you want to do JS operations, + // or any nontrivial work, you should add it to a work queue, and + // manage it externally. + virtual ~HostObject(); + + // When JS wants a property with a given name from the HostObject, + // it will call this method. If it throws an exception, the call + // will throw a JS \c Error object. By default this returns undefined. + // \return the value for the property. + virtual Value get(Runtime&, const PropNameID& name); + + // When JS wants to set a property with a given name on the HostObject, + // it will call this method. If it throws an exception, the call will + // throw a JS \c Error object. By default this throws a type error exception + // mimicking the behavior of a frozen object in strict mode. + virtual void set(Runtime&, const PropNameID& name, const Value& value); + + // When JS wants a list of property names for the HostObject, it will + // call this method. If it throws an exception, the call will throw a + // JS \c Error object. The default implementation returns empty vector. + virtual std::vector getPropertyNames(Runtime& rt); +}; + +/// Native state (and destructor) that can be attached to any JS object +/// using setNativeState. +class JSI_EXPORT NativeState { + public: + virtual ~NativeState(); +}; + +/// Represents a JS runtime. Movable, but not copyable. Note that +/// this object may not be thread-aware, but cannot be used safely from +/// multiple threads at once. The application is responsible for +/// ensuring that it is used safely. This could mean using the +/// Runtime from a single thread, using a mutex, doing all work on a +/// serial queue, etc. This restriction applies to the methods of +/// this class, and any method in the API which take a Runtime& as an +/// argument. Destructors (all but ~Scope), operators, or other methods +/// which do not take Runtime& as an argument are safe to call from any +/// thread, but it is still forbidden to make write operations on a single +/// instance of any class from more than one thread. In addition, to +/// make shutdown safe, destruction of objects associated with the Runtime +/// must be destroyed before the Runtime is destroyed, or from the +/// destructor of a managed HostObject or HostFunction. Informally, this +/// means that the main source of unsafe behavior is to hold a jsi object +/// in a non-Runtime-managed object, and not clean it up before the Runtime +/// is shut down. If your lifecycle is such that avoiding this is hard, +/// you will probably need to do use your own locks. +class JSI_EXPORT Runtime { + public: + virtual ~Runtime(); + + /// Evaluates the given JavaScript \c buffer. \c sourceURL is used + /// to annotate the stack trace if there is an exception. The + /// contents may be utf8-encoded JS source code, or binary bytecode + /// whose format is specific to the implementation. If the input + /// format is unknown, or evaluation causes an error, a JSIException + /// will be thrown. + /// Note this function should ONLY be used when there isn't another means + /// through the JSI API. For example, it will be much slower to use this to + /// call a global function than using the JSI APIs to read the function + /// property from the global object and then calling it explicitly. + virtual Value evaluateJavaScript( + const std::shared_ptr& buffer, + const std::string& sourceURL) = 0; + + /// Prepares to evaluate the given JavaScript \c buffer by processing it into + /// a form optimized for execution. This may include pre-parsing, compiling, + /// etc. If the input is invalid (for example, cannot be parsed), a + /// JSIException will be thrown. The resulting object is tied to the + /// particular concrete type of Runtime from which it was created. It may be + /// used (via evaluatePreparedJavaScript) in any Runtime of the same concrete + /// type. + /// The PreparedJavaScript object may be passed to multiple VM instances, so + /// they can all share and benefit from the prepared script. + /// As with evaluateJavaScript(), using JavaScript code should be avoided + /// when the JSI API is sufficient. + virtual std::shared_ptr prepareJavaScript( + const std::shared_ptr& buffer, + std::string sourceURL) = 0; + + /// Evaluates a PreparedJavaScript. If evaluation causes an error, a + /// JSIException will be thrown. + /// As with evaluateJavaScript(), using JavaScript code should be avoided + /// when the JSI API is sufficient. + virtual Value evaluatePreparedJavaScript( + const std::shared_ptr& js) = 0; + + /// Queues a microtask in the JavaScript VM internal Microtask (a.k.a. Job in + /// ECMA262) queue, to be executed when the host drains microtasks in + /// its event loop implementation. + /// + /// \param callback a function to be executed as a microtask. + virtual void queueMicrotask(const jsi::Function& callback) = 0; + + /// Drain the JavaScript VM internal Microtask (a.k.a. Job in ECMA262) queue. + /// + /// \param maxMicrotasksHint a hint to tell an implementation that it should + /// make a best effort not execute more than the given number. It's default + /// to -1 for infinity (unbounded execution). + /// \return true if the queue is drained or false if there is more work to do. + /// + /// When there were exceptions thrown from the execution of microtasks, + /// implementations shall discard the exceptional jobs. An implementation may + /// \throw a \c JSError object to signal the hosts to handle. In that case, an + /// implementation may or may not suspend the draining. + /// + /// Hosts may call this function again to resume the draining if it was + /// suspended due to either exceptions or the \p maxMicrotasksHint bound. + /// E.g. a host may repetitively invoke this function until the queue is + /// drained to implement the "microtask checkpoint" defined in WHATWG HTML + /// event loop: https://html.spec.whatwg.org/C#perform-a-microtask-checkpoint. + /// + /// Note that error propagation is only a concern if a host needs to implement + /// `queueMicrotask`, a recent API that allows enqueueing arbitrary functions + /// (hence may throw) as microtasks. Exceptions from ECMA-262 Promise Jobs are + /// handled internally to VMs and are never propagated to hosts. + /// + /// This API offers some queue management to hosts at its best effort due to + /// different behaviors and limitations imposed by different VMs and APIs. By + /// the time this is written, An implementation may swallow exceptions (JSC), + /// may not pause (V8), and may not support bounded executions. + virtual bool drainMicrotasks(int maxMicrotasksHint = -1) = 0; + + /// \return the global object + virtual Object global() = 0; + + /// \return a short printable description of the instance. It should + /// at least include some human-readable indication of the runtime + /// implementation. This should only be used by logging, debugging, + /// and other developer-facing callers. + virtual std::string description() = 0; + + /// \return whether or not the underlying runtime supports debugging via the + /// Chrome remote debugging protocol. + /// + /// NOTE: the API for determining whether a runtime is debuggable and + /// registering a runtime with the debugger is still in flux, so please don't + /// use this API unless you know what you're doing. + virtual bool isInspectable() = 0; + + /// \return an interface to extract metrics from this \c Runtime. The default + /// implementation of this function returns an \c Instrumentation instance + /// which returns no metrics. + virtual Instrumentation& instrumentation(); + + protected: + friend class Pointer; + friend class PropNameID; + friend class Symbol; + friend class BigInt; + friend class String; + friend class Object; + friend class WeakObject; + friend class Array; + friend class ArrayBuffer; + friend class Function; + friend class Value; + friend class Scope; + friend class JSError; + + // Potential optimization: avoid the cloneFoo() virtual dispatch, + // and instead just fix the number of fields, and copy them, since + // in practice they are trivially copyable. Sufficient use of + // rvalue arguments/methods would also reduce the number of clones. + + struct PointerValue { + virtual void invalidate() noexcept = 0; + + protected: + virtual ~PointerValue() = default; + }; + + virtual PointerValue* cloneSymbol(const Runtime::PointerValue* pv) = 0; + virtual PointerValue* cloneBigInt(const Runtime::PointerValue* pv) = 0; + virtual PointerValue* cloneString(const Runtime::PointerValue* pv) = 0; + virtual PointerValue* cloneObject(const Runtime::PointerValue* pv) = 0; + virtual PointerValue* clonePropNameID(const Runtime::PointerValue* pv) = 0; + + virtual PropNameID createPropNameIDFromAscii( + const char* str, + size_t length) = 0; + virtual PropNameID createPropNameIDFromUtf8( + const uint8_t* utf8, + size_t length) = 0; + virtual PropNameID createPropNameIDFromString(const String& str) = 0; + virtual PropNameID createPropNameIDFromSymbol(const Symbol& sym) = 0; + virtual std::string utf8(const PropNameID&) = 0; + virtual bool compare(const PropNameID&, const PropNameID&) = 0; + + virtual std::string symbolToString(const Symbol&) = 0; + + virtual BigInt createBigIntFromInt64(int64_t) = 0; + virtual BigInt createBigIntFromUint64(uint64_t) = 0; + virtual bool bigintIsInt64(const BigInt&) = 0; + virtual bool bigintIsUint64(const BigInt&) = 0; + virtual uint64_t truncate(const BigInt&) = 0; + virtual String bigintToString(const BigInt&, int) = 0; + + virtual String createStringFromAscii(const char* str, size_t length) = 0; + virtual String createStringFromUtf8(const uint8_t* utf8, size_t length) = 0; + virtual std::string utf8(const String&) = 0; + + // \return a \c Value created from a utf8-encoded JSON string. The default + // implementation creates a \c String and invokes JSON.parse. + virtual Value createValueFromJsonUtf8(const uint8_t* json, size_t length); + + virtual Object createObject() = 0; + virtual Object createObject(std::shared_ptr ho) = 0; + virtual std::shared_ptr getHostObject(const jsi::Object&) = 0; + virtual HostFunctionType& getHostFunction(const jsi::Function&) = 0; + + virtual bool hasNativeState(const jsi::Object&) = 0; + virtual std::shared_ptr getNativeState(const jsi::Object&) = 0; + virtual void setNativeState( + const jsi::Object&, + std::shared_ptr state) = 0; + + virtual Value getProperty(const Object&, const PropNameID& name) = 0; + virtual Value getProperty(const Object&, const String& name) = 0; + virtual bool hasProperty(const Object&, const PropNameID& name) = 0; + virtual bool hasProperty(const Object&, const String& name) = 0; + virtual void setPropertyValue( + const Object&, + const PropNameID& name, + const Value& value) = 0; + virtual void + setPropertyValue(const Object&, const String& name, const Value& value) = 0; + + virtual bool isArray(const Object&) const = 0; + virtual bool isArrayBuffer(const Object&) const = 0; + virtual bool isFunction(const Object&) const = 0; + virtual bool isHostObject(const jsi::Object&) const = 0; + virtual bool isHostFunction(const jsi::Function&) const = 0; + virtual Array getPropertyNames(const Object&) = 0; + + virtual WeakObject createWeakObject(const Object&) = 0; + virtual Value lockWeakObject(const WeakObject&) = 0; + + virtual Array createArray(size_t length) = 0; + virtual ArrayBuffer createArrayBuffer( + std::shared_ptr buffer) = 0; + virtual size_t size(const Array&) = 0; + virtual size_t size(const ArrayBuffer&) = 0; + virtual uint8_t* data(const ArrayBuffer&) = 0; + virtual Value getValueAtIndex(const Array&, size_t i) = 0; + virtual void + setValueAtIndexImpl(const Array&, size_t i, const Value& value) = 0; + + virtual Function createFunctionFromHostFunction( + const PropNameID& name, + unsigned int paramCount, + HostFunctionType func) = 0; + virtual Value call( + const Function&, + const Value& jsThis, + const Value* args, + size_t count) = 0; + virtual Value + callAsConstructor(const Function&, const Value* args, size_t count) = 0; + + // Private data for managing scopes. + struct ScopeState; + virtual ScopeState* pushScope(); + virtual void popScope(ScopeState*); + + virtual bool strictEquals(const Symbol& a, const Symbol& b) const = 0; + virtual bool strictEquals(const BigInt& a, const BigInt& b) const = 0; + virtual bool strictEquals(const String& a, const String& b) const = 0; + virtual bool strictEquals(const Object& a, const Object& b) const = 0; + + virtual bool instanceOf(const Object& o, const Function& f) = 0; + + /// See Object::setExternalMemoryPressure. + virtual void setExternalMemoryPressure( + const jsi::Object& obj, + size_t amount) = 0; + + virtual std::u16string utf16(const String& str); + virtual std::u16string utf16(const PropNameID& sym); + + // These exist so derived classes can access the private parts of + // Value, Symbol, String, and Object, which are all friends of Runtime. + template + static T make(PointerValue* pv); + static PointerValue* getPointerValue(Pointer& pointer); + static const PointerValue* getPointerValue(const Pointer& pointer); + static const PointerValue* getPointerValue(const Value& value); + + friend class ::FBJSRuntime; + template + friend class RuntimeDecorator; +}; + +// Base class for pointer-storing types. +class JSI_EXPORT Pointer { + protected: + explicit Pointer(Pointer&& other) noexcept : ptr_(other.ptr_) { + other.ptr_ = nullptr; + } + + ~Pointer() { + if (ptr_) { + ptr_->invalidate(); + } + } + + Pointer& operator=(Pointer&& other) noexcept; + + friend class Runtime; + friend class Value; + + explicit Pointer(Runtime::PointerValue* ptr) : ptr_(ptr) {} + + typename Runtime::PointerValue* ptr_; +}; + +/// Represents something that can be a JS property key. Movable, not copyable. +class JSI_EXPORT PropNameID : public Pointer { + public: + using Pointer::Pointer; + + PropNameID(Runtime& runtime, const PropNameID& other) + : Pointer(runtime.clonePropNameID(other.ptr_)) {} + + PropNameID(PropNameID&& other) = default; + PropNameID& operator=(PropNameID&& other) = default; + + /// Create a JS property name id from ascii values. The data is + /// copied. + static PropNameID forAscii(Runtime& runtime, const char* str, size_t length) { + return runtime.createPropNameIDFromAscii(str, length); + } + + /// Create a property name id from a nul-terminated C ascii name. The data is + /// copied. + static PropNameID forAscii(Runtime& runtime, const char* str) { + return forAscii(runtime, str, strlen(str)); + } + + /// Create a PropNameID from a C++ string. The string is copied. + static PropNameID forAscii(Runtime& runtime, const std::string& str) { + return forAscii(runtime, str.c_str(), str.size()); + } + + /// Create a PropNameID from utf8 values. The data is copied. + /// Results are undefined if \p utf8 contains invalid code points. + static PropNameID + forUtf8(Runtime& runtime, const uint8_t* utf8, size_t length) { + return runtime.createPropNameIDFromUtf8(utf8, length); + } + + /// Create a PropNameID from utf8-encoded octets stored in a + /// std::string. The string data is transformed and copied. + /// Results are undefined if \p utf8 contains invalid code points. + static PropNameID forUtf8(Runtime& runtime, const std::string& utf8) { + return runtime.createPropNameIDFromUtf8( + reinterpret_cast(utf8.data()), utf8.size()); + } + + /// Create a PropNameID from a JS string. + static PropNameID forString(Runtime& runtime, const jsi::String& str) { + return runtime.createPropNameIDFromString(str); + } + + /// Create a PropNameID from a JS symbol. + static PropNameID forSymbol(Runtime& runtime, const jsi::Symbol& sym) { + return runtime.createPropNameIDFromSymbol(sym); + } + + // Creates a vector of PropNameIDs constructed from given arguments. + template + static std::vector names(Runtime& runtime, Args&&... args); + + // Creates a vector of given PropNameIDs. + template + static std::vector names(PropNameID (&&propertyNames)[N]); + + /// Copies the data in a PropNameID as utf8 into a C++ string. + std::string utf8(Runtime& runtime) const { + return runtime.utf8(*this); + } + + /// Copies the data in a PropNameID as utf16 into a C++ string. + std::u16string utf16(Runtime& runtime) const { + return runtime.utf16(*this); + } + + static bool compare( + Runtime& runtime, + const jsi::PropNameID& a, + const jsi::PropNameID& b) { + return runtime.compare(a, b); + } + + friend class Runtime; + friend class Value; +}; + +/// Represents a JS Symbol (es6). Movable, not copyable. +/// TODO T40778724: this is a limited implementation sufficient for +/// the debugger not to crash when a Symbol is a property in an Object +/// or element in an array. Complete support for creating will come +/// later. +class JSI_EXPORT Symbol : public Pointer { + public: + using Pointer::Pointer; + + Symbol(Symbol&& other) = default; + Symbol& operator=(Symbol&& other) = default; + + /// \return whether a and b refer to the same symbol. + static bool strictEquals(Runtime& runtime, const Symbol& a, const Symbol& b) { + return runtime.strictEquals(a, b); + } + + /// Converts a Symbol into a C++ string as JS .toString would. The output + /// will look like \c Symbol(description) . + std::string toString(Runtime& runtime) const { + return runtime.symbolToString(*this); + } + + friend class Runtime; + friend class Value; +}; + +/// Represents a JS BigInt. Movable, not copyable. +class JSI_EXPORT BigInt : public Pointer { + public: + using Pointer::Pointer; + + BigInt(BigInt&& other) = default; + BigInt& operator=(BigInt&& other) = default; + + /// Create a BigInt representing the signed 64-bit \p value. + static BigInt fromInt64(Runtime& runtime, int64_t value) { + return runtime.createBigIntFromInt64(value); + } + + /// Create a BigInt representing the unsigned 64-bit \p value. + static BigInt fromUint64(Runtime& runtime, uint64_t value) { + return runtime.createBigIntFromUint64(value); + } + + /// \return whether a === b. + static bool strictEquals(Runtime& runtime, const BigInt& a, const BigInt& b) { + return runtime.strictEquals(a, b); + } + + /// \returns This bigint truncated to a signed 64-bit integer. + int64_t getInt64(Runtime& runtime) const { + return runtime.truncate(*this); + } + + /// \returns Whether this bigint can be losslessly converted to int64_t. + bool isInt64(Runtime& runtime) const { + return runtime.bigintIsInt64(*this); + } + + /// \returns This bigint truncated to a signed 64-bit integer. Throws a + /// JSIException if the truncation is lossy. + int64_t asInt64(Runtime& runtime) const; + + /// \returns This bigint truncated to an unsigned 64-bit integer. + uint64_t getUint64(Runtime& runtime) const { + return runtime.truncate(*this); + } + + /// \returns Whether this bigint can be losslessly converted to uint64_t. + bool isUint64(Runtime& runtime) const { + return runtime.bigintIsUint64(*this); + } + + /// \returns This bigint truncated to an unsigned 64-bit integer. Throws a + /// JSIException if the truncation is lossy. + uint64_t asUint64(Runtime& runtime) const; + + /// \returns this BigInt converted to a String in base \p radix. Throws a + /// JSIException if radix is not in the [2, 36] range. + inline String toString(Runtime& runtime, int radix = 10) const; + + friend class Runtime; + friend class Value; +}; + +/// Represents a JS String. Movable, not copyable. +class JSI_EXPORT String : public Pointer { + public: + using Pointer::Pointer; + + String(String&& other) = default; + String& operator=(String&& other) = default; + + /// Create a JS string from ascii values. The string data is + /// copied. + static String + createFromAscii(Runtime& runtime, const char* str, size_t length) { + return runtime.createStringFromAscii(str, length); + } + + /// Create a JS string from a nul-terminated C ascii string. The + /// string data is copied. + static String createFromAscii(Runtime& runtime, const char* str) { + return createFromAscii(runtime, str, strlen(str)); + } + + /// Create a JS string from a C++ string. The string data is + /// copied. + static String createFromAscii(Runtime& runtime, const std::string& str) { + return createFromAscii(runtime, str.c_str(), str.size()); + } + + /// Create a JS string from utf8-encoded octets. The string data is + /// transformed and copied. Results are undefined if \p utf8 contains invalid + /// code points. + static String + createFromUtf8(Runtime& runtime, const uint8_t* utf8, size_t length) { + return runtime.createStringFromUtf8(utf8, length); + } + + /// Create a JS string from utf8-encoded octets stored in a + /// std::string. The string data is transformed and copied. Results are + /// undefined if \p utf8 contains invalid code points. + static String createFromUtf8(Runtime& runtime, const std::string& utf8) { + return runtime.createStringFromUtf8( + reinterpret_cast(utf8.data()), utf8.length()); + } + + /// \return whether a and b contain the same characters. + static bool strictEquals(Runtime& runtime, const String& a, const String& b) { + return runtime.strictEquals(a, b); + } + + /// Copies the data in a JS string as utf8 into a C++ string. + std::string utf8(Runtime& runtime) const { + return runtime.utf8(*this); + } + + /// Copies the data in a JS string as utf16 into a C++ string. + std::u16string utf16(Runtime& runtime) const { + return runtime.utf16(*this); + } + + friend class Runtime; + friend class Value; +}; + +class Array; +class Function; + +/// Represents a JS Object. Movable, not copyable. +class JSI_EXPORT Object : public Pointer { + public: + using Pointer::Pointer; + + Object(Object&& other) = default; + Object& operator=(Object&& other) = default; + + /// Creates a new Object instance, like '{}' in JS. + Object(Runtime& runtime) : Object(runtime.createObject()) {} + + static Object createFromHostObject( + Runtime& runtime, + std::shared_ptr ho) { + return runtime.createObject(ho); + } + + /// \return whether this and \c obj are the same JSObject or not. + static bool strictEquals(Runtime& runtime, const Object& a, const Object& b) { + return runtime.strictEquals(a, b); + } + + /// \return the result of `this instanceOf ctor` in JS. + bool instanceOf(Runtime& rt, const Function& ctor) const { + return rt.instanceOf(*this, ctor); + } + + /// \return the property of the object with the given ascii name. + /// If the name isn't a property on the object, returns the + /// undefined value. + Value getProperty(Runtime& runtime, const char* name) const; + + /// \return the property of the object with the String name. + /// If the name isn't a property on the object, returns the + /// undefined value. + Value getProperty(Runtime& runtime, const String& name) const; + + /// \return the property of the object with the given JS PropNameID + /// name. If the name isn't a property on the object, returns the + /// undefined value. + Value getProperty(Runtime& runtime, const PropNameID& name) const; + + /// \return true if and only if the object has a property with the + /// given ascii name. + bool hasProperty(Runtime& runtime, const char* name) const; + + /// \return true if and only if the object has a property with the + /// given String name. + bool hasProperty(Runtime& runtime, const String& name) const; + + /// \return true if and only if the object has a property with the + /// given PropNameID name. + bool hasProperty(Runtime& runtime, const PropNameID& name) const; + + /// Sets the property value from a Value or anything which can be + /// used to make one: nullptr_t, bool, double, int, const char*, + /// String, or Object. + template + void setProperty(Runtime& runtime, const char* name, T&& value) const; + + /// Sets the property value from a Value or anything which can be + /// used to make one: nullptr_t, bool, double, int, const char*, + /// String, or Object. + template + void setProperty(Runtime& runtime, const String& name, T&& value) const; + + /// Sets the property value from a Value or anything which can be + /// used to make one: nullptr_t, bool, double, int, const char*, + /// String, or Object. + template + void setProperty(Runtime& runtime, const PropNameID& name, T&& value) const; + + /// \return true iff JS \c Array.isArray() would return \c true. If + /// so, then \c getArray() will succeed. + bool isArray(Runtime& runtime) const { + return runtime.isArray(*this); + } + + /// \return true iff the Object is an ArrayBuffer. If so, then \c + /// getArrayBuffer() will succeed. + bool isArrayBuffer(Runtime& runtime) const { + return runtime.isArrayBuffer(*this); + } + + /// \return true iff the Object is callable. If so, then \c + /// getFunction will succeed. + bool isFunction(Runtime& runtime) const { + return runtime.isFunction(*this); + } + + /// \return true iff the Object was initialized with \c createFromHostObject + /// and the HostObject passed is of type \c T. If returns \c true then + /// \c getHostObject will succeed. + template + bool isHostObject(Runtime& runtime) const; + + /// \return an Array instance which refers to the same underlying + /// object. If \c isArray() would return false, this will assert. + Array getArray(Runtime& runtime) const&; + + /// \return an Array instance which refers to the same underlying + /// object. If \c isArray() would return false, this will assert. + Array getArray(Runtime& runtime) &&; + + /// \return an Array instance which refers to the same underlying + /// object. If \c isArray() would return false, this will throw + /// JSIException. + Array asArray(Runtime& runtime) const&; + + /// \return an Array instance which refers to the same underlying + /// object. If \c isArray() would return false, this will throw + /// JSIException. + Array asArray(Runtime& runtime) &&; + + /// \return an ArrayBuffer instance which refers to the same underlying + /// object. If \c isArrayBuffer() would return false, this will assert. + ArrayBuffer getArrayBuffer(Runtime& runtime) const&; + + /// \return an ArrayBuffer instance which refers to the same underlying + /// object. If \c isArrayBuffer() would return false, this will assert. + ArrayBuffer getArrayBuffer(Runtime& runtime) &&; + + /// \return a Function instance which refers to the same underlying + /// object. If \c isFunction() would return false, this will assert. + Function getFunction(Runtime& runtime) const&; + + /// \return a Function instance which refers to the same underlying + /// object. If \c isFunction() would return false, this will assert. + Function getFunction(Runtime& runtime) &&; + + /// \return a Function instance which refers to the same underlying + /// object. If \c isFunction() would return false, this will throw + /// JSIException. + Function asFunction(Runtime& runtime) const&; + + /// \return a Function instance which refers to the same underlying + /// object. If \c isFunction() would return false, this will throw + /// JSIException. + Function asFunction(Runtime& runtime) &&; + + /// \return a shared_ptr which refers to the same underlying + /// \c HostObject that was used to create this object. If \c isHostObject + /// is false, this will assert. Note that this does a type check and will + /// assert if the underlying HostObject isn't of type \c T + template + std::shared_ptr getHostObject(Runtime& runtime) const; + + /// \return a shared_ptr which refers to the same underlying + /// \c HostObject that was used to create this object. If \c isHostObject + /// is false, this will throw. + template + std::shared_ptr asHostObject(Runtime& runtime) const; + + /// \return whether this object has native state of type T previously set by + /// \c setNativeState. + template + bool hasNativeState(Runtime& runtime) const; + + /// \return a shared_ptr to the state previously set by \c setNativeState. + /// If \c hasNativeState is false, this will assert. Note that this does a + /// type check and will assert if the native state isn't of type \c T + template + std::shared_ptr getNativeState(Runtime& runtime) const; + + /// Set the internal native state property of this object, overwriting any old + /// value. Creates a new shared_ptr to the object managed by \p state, which + /// will live until the value at this property becomes unreachable. + /// + /// Throws a type error if this object is a proxy or host object. + void setNativeState(Runtime& runtime, std::shared_ptr state) + const; + + /// \return same as \c getProperty(name).asObject(), except with + /// a better exception message. + Object getPropertyAsObject(Runtime& runtime, const char* name) const; + + /// \return similar to \c + /// getProperty(name).getObject().getFunction(), except it will + /// throw JSIException instead of asserting if the property is + /// not an object, or the object is not callable. + Function getPropertyAsFunction(Runtime& runtime, const char* name) const; + + /// \return an Array consisting of all enumerable property names in + /// the object and its prototype chain. All values in the return + /// will be isString(). (This is probably not optimal, but it + /// works. I only need it in one place.) + Array getPropertyNames(Runtime& runtime) const; + + /// Inform the runtime that there is additional memory associated with a given + /// JavaScript object that is not visible to the GC. This can be used if an + /// object is known to retain some native memory, and may be used to guide + /// decisions about when to run garbage collection. + /// This method may be invoked multiple times on an object, and subsequent + /// calls will overwrite any previously set value. Once the object is garbage + /// collected, the associated external memory will be considered freed and may + /// no longer factor into GC decisions. + void setExternalMemoryPressure(Runtime& runtime, size_t amt) const; + + protected: + void setPropertyValue( + Runtime& runtime, + const String& name, + const Value& value) const { + return runtime.setPropertyValue(*this, name, value); + } + + void setPropertyValue( + Runtime& runtime, + const PropNameID& name, + const Value& value) const { + return runtime.setPropertyValue(*this, name, value); + } + + friend class Runtime; + friend class Value; +}; + +/// Represents a weak reference to a JS Object. If the only reference +/// to an Object are these, the object is eligible for GC. Method +/// names are inspired by C++ weak_ptr. Movable, not copyable. +class JSI_EXPORT WeakObject : public Pointer { + public: + using Pointer::Pointer; + + WeakObject(WeakObject&& other) = default; + WeakObject& operator=(WeakObject&& other) = default; + + /// Create a WeakObject from an Object. + WeakObject(Runtime& runtime, const Object& o) + : WeakObject(runtime.createWeakObject(o)) {} + + /// \return a Value representing the underlying Object if it is still valid; + /// otherwise returns \c undefined. Note that this method has nothing to do + /// with threads or concurrency. The name is based on std::weak_ptr::lock() + /// which serves a similar purpose. + Value lock(Runtime& runtime) const; + + friend class Runtime; +}; + +/// Represents a JS Object which can be efficiently used as an array +/// with integral indices. +class JSI_EXPORT Array : public Object { + public: + Array(Array&&) = default; + /// Creates a new Array instance, with \c length undefined elements. + Array(Runtime& runtime, size_t length) : Array(runtime.createArray(length)) {} + + Array& operator=(Array&&) = default; + + /// \return the size of the Array, according to its length property. + /// (C++ naming convention) + size_t size(Runtime& runtime) const { + return runtime.size(*this); + } + + /// \return the size of the Array, according to its length property. + /// (JS naming convention) + size_t length(Runtime& runtime) const { + return size(runtime); + } + + /// \return the property of the array at index \c i. If there is no + /// such property, returns the undefined value. If \c i is out of + /// range [ 0..\c length ] throws a JSIException. + Value getValueAtIndex(Runtime& runtime, size_t i) const; + + /// Sets the property of the array at index \c i. The argument + /// value behaves as with Object::setProperty(). If \c i is out of + /// range [ 0..\c length ] throws a JSIException. + template + void setValueAtIndex(Runtime& runtime, size_t i, T&& value) const; + + /// There is no current API for changing the size of an array once + /// created. We'll probably need that eventually. + + /// Creates a new Array instance from provided values + template + static Array createWithElements(Runtime&, Args&&... args); + + /// Creates a new Array instance from initializer list. + static Array createWithElements( + Runtime& runtime, + std::initializer_list elements); + + private: + friend class Object; + friend class Value; + friend class Runtime; + + void setValueAtIndexImpl(Runtime& runtime, size_t i, const Value& value) + const { + return runtime.setValueAtIndexImpl(*this, i, value); + } + + Array(Runtime::PointerValue* value) : Object(value) {} +}; + +/// Represents a JSArrayBuffer +class JSI_EXPORT ArrayBuffer : public Object { + public: + ArrayBuffer(ArrayBuffer&&) = default; + ArrayBuffer& operator=(ArrayBuffer&&) = default; + + ArrayBuffer(Runtime& runtime, std::shared_ptr buffer) + : ArrayBuffer(runtime.createArrayBuffer(std::move(buffer))) {} + + /// \return the size of the ArrayBuffer storage. This is not affected by + /// overriding the byteLength property. + /// (C++ naming convention) + size_t size(Runtime& runtime) const { + return runtime.size(*this); + } + + size_t length(Runtime& runtime) const { + return runtime.size(*this); + } + + uint8_t* data(Runtime& runtime) const { + return runtime.data(*this); + } + + private: + friend class Object; + friend class Value; + friend class Runtime; + + ArrayBuffer(Runtime::PointerValue* value) : Object(value) {} +}; + +/// Represents a JS Object which is guaranteed to be Callable. +class JSI_EXPORT Function : public Object { + public: + Function(Function&&) = default; + Function& operator=(Function&&) = default; + + /// Create a function which, when invoked, calls C++ code. If the + /// function throws an exception, a JS Error will be created and + /// thrown. + /// \param name the name property for the function. + /// \param paramCount the length property for the function, which + /// may not be the number of arguments the function is passed. + /// \note The std::function's dtor will be called when the GC finalizes this + /// function. As with HostObject, this may be as late as when the Runtime is + /// shut down, and may occur on an arbitrary thread. If the function contains + /// any captured values, you are responsible for ensuring that their + /// destructors are safe to call on any thread. + static Function createFromHostFunction( + Runtime& runtime, + const jsi::PropNameID& name, + unsigned int paramCount, + jsi::HostFunctionType func); + + /// Calls the function with \c count \c args. The \c this value of the JS + /// function will not be set by the C++ caller, similar to calling + /// Function.prototype.apply(undefined, args) in JS. + /// \b Note: as with Function.prototype.apply, \c this may not always be + /// \c undefined in the function itself. If the function is non-strict, + /// \c this will be set to the global object. + Value call(Runtime& runtime, const Value* args, size_t count) const; + + /// Calls the function with a \c std::initializer_list of Value + /// arguments. The \c this value of the JS function will not be set by the + /// C++ caller, similar to calling Function.prototype.apply(undefined, args) + /// in JS. + /// \b Note: as with Function.prototype.apply, \c this may not always be + /// \c undefined in the function itself. If the function is non-strict, + /// \c this will be set to the global object. + Value call(Runtime& runtime, std::initializer_list args) const; + + /// Calls the function with any number of arguments similarly to + /// Object::setProperty(). The \c this value of the JS function will not be + /// set by the C++ caller, similar to calling + /// Function.prototype.call(undefined, ...args) in JS. + /// \b Note: as with Function.prototype.call, \c this may not always be + /// \c undefined in the function itself. If the function is non-strict, + /// \c this will be set to the global object. + template + Value call(Runtime& runtime, Args&&... args) const; + + /// Calls the function with \c count \c args and \c jsThis value passed + /// as the \c this value. + Value callWithThis( + Runtime& Runtime, + const Object& jsThis, + const Value* args, + size_t count) const; + + /// Calls the function with a \c std::initializer_list of Value + /// arguments and \c jsThis passed as the \c this value. + Value callWithThis( + Runtime& runtime, + const Object& jsThis, + std::initializer_list args) const; + + /// Calls the function with any number of arguments similarly to + /// Object::setProperty(), and with \c jsThis passed as the \c this value. + template + Value callWithThis(Runtime& runtime, const Object& jsThis, Args&&... args) + const; + + /// Calls the function as a constructor with \c count \c args. Equivalent + /// to calling `new Func` where `Func` is the js function reqresented by + /// this. + Value callAsConstructor(Runtime& runtime, const Value* args, size_t count) + const; + + /// Same as above `callAsConstructor`, except use an initializer_list to + /// supply the arguments. + Value callAsConstructor(Runtime& runtime, std::initializer_list args) + const; + + /// Same as above `callAsConstructor`, but automatically converts/wraps + /// any argument with a jsi Value. + template + Value callAsConstructor(Runtime& runtime, Args&&... args) const; + + /// Returns whether this was created with Function::createFromHostFunction. + /// If true then you can use getHostFunction to get the underlying + /// HostFunctionType. + bool isHostFunction(Runtime& runtime) const { + return runtime.isHostFunction(*this); + } + + /// Returns the underlying HostFunctionType iff isHostFunction returns true + /// and asserts otherwise. You can use this to use std::function<>::target + /// to get the object that was passed to create the HostFunctionType. + /// + /// Note: The reference returned is borrowed from the JS object underlying + /// \c this, and thus only lasts as long as the object underlying + /// \c this does. + HostFunctionType& getHostFunction(Runtime& runtime) const { + assert(isHostFunction(runtime)); + return runtime.getHostFunction(*this); + } + + private: + friend class Object; + friend class Value; + friend class Runtime; + + Function(Runtime::PointerValue* value) : Object(value) {} +}; + +/// Represents any JS Value (undefined, null, boolean, number, symbol, +/// string, or object). Movable, or explicitly copyable (has no copy +/// ctor). +class JSI_EXPORT Value { + public: + /// Default ctor creates an \c undefined JS value. + Value() noexcept : Value(UndefinedKind) {} + + /// Creates a \c null JS value. + /* implicit */ Value(std::nullptr_t) : kind_(NullKind) {} + + /// Creates a boolean JS value. + /* implicit */ Value(bool b) : Value(BooleanKind) { + data_.boolean = b; + } + + /// Creates a number JS value. + /* implicit */ Value(double d) : Value(NumberKind) { + data_.number = d; + } + + /// Creates a number JS value. + /* implicit */ Value(int i) : Value(NumberKind) { + data_.number = i; + } + + /// Moves a Symbol, String, or Object rvalue into a new JS value. + template < + typename T, + typename = std::enable_if_t< + std::is_base_of::value || + std::is_base_of::value || + std::is_base_of::value || + std::is_base_of::value>> + /* implicit */ Value(T&& other) : Value(kindOf(other)) { + new (&data_.pointer) T(std::move(other)); + } + + /// Value("foo") will treat foo as a bool. This makes doing that a + /// compile error. + template + Value(const char*) { + static_assert( + !std::is_same::value, + "Value cannot be constructed directly from const char*"); + } + + Value(Value&& other) noexcept; + + /// Copies a Symbol lvalue into a new JS value. + Value(Runtime& runtime, const Symbol& sym) : Value(SymbolKind) { + new (&data_.pointer) Symbol(runtime.cloneSymbol(sym.ptr_)); + } + + /// Copies a BigInt lvalue into a new JS value. + Value(Runtime& runtime, const BigInt& bigint) : Value(BigIntKind) { + new (&data_.pointer) BigInt(runtime.cloneBigInt(bigint.ptr_)); + } + + /// Copies a String lvalue into a new JS value. + Value(Runtime& runtime, const String& str) : Value(StringKind) { + new (&data_.pointer) String(runtime.cloneString(str.ptr_)); + } + + /// Copies a Object lvalue into a new JS value. + Value(Runtime& runtime, const Object& obj) : Value(ObjectKind) { + new (&data_.pointer) Object(runtime.cloneObject(obj.ptr_)); + } + + /// Creates a JS value from another Value lvalue. + Value(Runtime& runtime, const Value& value); + + /// Value(rt, "foo") will treat foo as a bool. This makes doing + /// that a compile error. + template + Value(Runtime&, const char*) { + static_assert( + !std::is_same::value, + "Value cannot be constructed directly from const char*"); + } + + ~Value(); + // \return the undefined \c Value. + static Value undefined() { + return Value(); + } + + // \return the null \c Value. + static Value null() { + return Value(nullptr); + } + + // \return a \c Value created from a utf8-encoded JSON string. + static Value + createFromJsonUtf8(Runtime& runtime, const uint8_t* json, size_t length) { + return runtime.createValueFromJsonUtf8(json, length); + } + + /// \return according to the Strict Equality Comparison algorithm, see: + /// https://262.ecma-international.org/11.0/#sec-strict-equality-comparison + static bool strictEquals(Runtime& runtime, const Value& a, const Value& b); + + Value& operator=(Value&& other) noexcept { + this->~Value(); + new (this) Value(std::move(other)); + return *this; + } + + bool isUndefined() const { + return kind_ == UndefinedKind; + } + + bool isNull() const { + return kind_ == NullKind; + } + + bool isBool() const { + return kind_ == BooleanKind; + } + + bool isNumber() const { + return kind_ == NumberKind; + } + + bool isString() const { + return kind_ == StringKind; + } + + bool isBigInt() const { + return kind_ == BigIntKind; + } + + bool isSymbol() const { + return kind_ == SymbolKind; + } + + bool isObject() const { + return kind_ == ObjectKind; + } + + /// \return the boolean value, or asserts if not a boolean. + bool getBool() const { + assert(isBool()); + return data_.boolean; + } + + /// \return the boolean value, or throws JSIException if not a + /// boolean. + bool asBool() const; + + /// \return the number value, or asserts if not a number. + double getNumber() const { + assert(isNumber()); + return data_.number; + } + + /// \return the number value, or throws JSIException if not a + /// number. + double asNumber() const; + + /// \return the Symbol value, or asserts if not a symbol. + Symbol getSymbol(Runtime& runtime) const& { + assert(isSymbol()); + return Symbol(runtime.cloneSymbol(data_.pointer.ptr_)); + } + + /// \return the Symbol value, or asserts if not a symbol. + /// Can be used on rvalue references to avoid cloning more symbols. + Symbol getSymbol(Runtime&) && { + assert(isSymbol()); + auto ptr = data_.pointer.ptr_; + data_.pointer.ptr_ = nullptr; + return static_cast(ptr); + } + + /// \return the Symbol value, or throws JSIException if not a + /// symbol + Symbol asSymbol(Runtime& runtime) const&; + Symbol asSymbol(Runtime& runtime) &&; + + /// \return the BigInt value, or asserts if not a bigint. + BigInt getBigInt(Runtime& runtime) const& { + assert(isBigInt()); + return BigInt(runtime.cloneBigInt(data_.pointer.ptr_)); + } + + /// \return the BigInt value, or asserts if not a bigint. + /// Can be used on rvalue references to avoid cloning more bigints. + BigInt getBigInt(Runtime&) && { + assert(isBigInt()); + auto ptr = data_.pointer.ptr_; + data_.pointer.ptr_ = nullptr; + return static_cast(ptr); + } + + /// \return the BigInt value, or throws JSIException if not a + /// bigint + BigInt asBigInt(Runtime& runtime) const&; + BigInt asBigInt(Runtime& runtime) &&; + + /// \return the String value, or asserts if not a string. + String getString(Runtime& runtime) const& { + assert(isString()); + return String(runtime.cloneString(data_.pointer.ptr_)); + } + + /// \return the String value, or asserts if not a string. + /// Can be used on rvalue references to avoid cloning more strings. + String getString(Runtime&) && { + assert(isString()); + auto ptr = data_.pointer.ptr_; + data_.pointer.ptr_ = nullptr; + return static_cast(ptr); + } + + /// \return the String value, or throws JSIException if not a + /// string. + String asString(Runtime& runtime) const&; + String asString(Runtime& runtime) &&; + + /// \return the Object value, or asserts if not an object. + Object getObject(Runtime& runtime) const& { + assert(isObject()); + return Object(runtime.cloneObject(data_.pointer.ptr_)); + } + + /// \return the Object value, or asserts if not an object. + /// Can be used on rvalue references to avoid cloning more objects. + Object getObject(Runtime&) && { + assert(isObject()); + auto ptr = data_.pointer.ptr_; + data_.pointer.ptr_ = nullptr; + return static_cast(ptr); + } + + /// \return the Object value, or throws JSIException if not an + /// object. + Object asObject(Runtime& runtime) const&; + Object asObject(Runtime& runtime) &&; + + // \return a String like JS .toString() would do. + String toString(Runtime& runtime) const; + + private: + friend class Runtime; + + enum ValueKind { + UndefinedKind, + NullKind, + BooleanKind, + NumberKind, + SymbolKind, + BigIntKind, + StringKind, + ObjectKind, + PointerKind = SymbolKind, + }; + + union Data { + // Value's ctor and dtor will manage the lifecycle of the contained Data. + Data() { + static_assert( + sizeof(Data) == sizeof(uint64_t), + "Value data should fit in a 64-bit register"); + } + ~Data() {} + + // scalars + bool boolean; + double number; + // pointers + Pointer pointer; // Symbol, String, Object, Array, Function + }; + + Value(ValueKind kind) : kind_(kind) {} + + constexpr static ValueKind kindOf(const Symbol&) { + return SymbolKind; + } + constexpr static ValueKind kindOf(const BigInt&) { + return BigIntKind; + } + constexpr static ValueKind kindOf(const String&) { + return StringKind; + } + constexpr static ValueKind kindOf(const Object&) { + return ObjectKind; + } + + ValueKind kind_; + Data data_; + + // In the future: Value becomes NaN-boxed. See T40538354. +}; + +/// Not movable and not copyable RAII marker advising the underlying +/// JavaScript VM to track resources allocated since creation until +/// destruction so that they can be recycled eagerly when the Scope +/// goes out of scope instead of floating in the air until the next +/// garbage collection or any other delayed release occurs. +/// +/// This API should be treated only as advice, implementations can +/// choose to ignore the fact that Scopes are created or destroyed. +/// +/// This class is an exception to the rule allowing destructors to be +/// called without proper synchronization (see Runtime documentation). +/// The whole point of this class is to enable all sorts of clean ups +/// when the destructor is called and this proper synchronization is +/// required at that time. +/// +/// Instances of this class are intended to be created as automatic stack +/// variables in which case destructor calls don't require any additional +/// locking, provided that the lock (if any) is managed with RAII helpers. +class JSI_EXPORT Scope { + public: + explicit Scope(Runtime& rt) : rt_(rt), prv_(rt.pushScope()) {} + ~Scope() { + rt_.popScope(prv_); + } + + Scope(const Scope&) = delete; + Scope(Scope&&) = delete; + + Scope& operator=(const Scope&) = delete; + Scope& operator=(Scope&&) = delete; + + template + static auto callInNewScope(Runtime& rt, F f) -> decltype(f()) { + Scope s(rt); + return f(); + } + + private: + Runtime& rt_; + Runtime::ScopeState* prv_; +}; + +/// Base class for jsi exceptions +class JSI_EXPORT JSIException : public std::exception { + protected: + JSIException() {} + JSIException(std::string what) : what_(std::move(what)) {} + + public: + JSIException(const JSIException&) = default; + + virtual const char* what() const noexcept override { + return what_.c_str(); + } + + virtual ~JSIException() override; + + protected: + std::string what_; +}; + +/// This exception will be thrown by API functions on errors not related to +/// JavaScript execution. +class JSI_EXPORT JSINativeException : public JSIException { + public: + JSINativeException(std::string what) : JSIException(std::move(what)) {} + + JSINativeException(const JSINativeException&) = default; + + virtual ~JSINativeException(); +}; + +/// This exception will be thrown by API functions whenever a JS +/// operation causes an exception as described by the spec, or as +/// otherwise described. +class JSI_EXPORT JSError : public JSIException { + public: + /// Creates a JSError referring to provided \c value + JSError(Runtime& r, Value&& value); + + /// Creates a JSError referring to new \c Error instance capturing current + /// JavaScript stack. The error message property is set to given \c message. + JSError(Runtime& rt, std::string message); + + /// Creates a JSError referring to new \c Error instance capturing current + /// JavaScript stack. The error message property is set to given \c message. + JSError(Runtime& rt, const char* message) + : JSError(rt, std::string(message)) {} + + /// Creates a JSError referring to a JavaScript Object having message and + /// stack properties set to provided values. + JSError(Runtime& rt, std::string message, std::string stack); + + /// Creates a JSError referring to provided value and what string + /// set to provided message. This argument order is a bit weird, + /// but necessary to avoid ambiguity with the above. + JSError(std::string what, Runtime& rt, Value&& value); + + /// Creates a JSError referring to the provided value, message and stack. This + /// constructor does not take a Runtime parameter, and therefore cannot result + /// in recursively invoking the JSError constructor. + JSError(Value&& value, std::string message, std::string stack); + + JSError(const JSError&) = default; + + virtual ~JSError(); + + const std::string& getStack() const { + return stack_; + } + + const std::string& getMessage() const { + return message_; + } + + const jsi::Value& value() const { + assert(value_); + return *value_; + } + + private: + // This initializes the value_ member and does some other + // validation, so it must be called by every branch through the + // constructors. + void setValue(Runtime& rt, Value&& value); + + // This needs to be on the heap, because throw requires the object + // be copyable, and Value is not. + std::shared_ptr value_; + std::string message_; + std::string stack_; +}; + +} // namespace jsi +} // namespace facebook + +#include diff --git a/NativeScript/napi/hermes/include_old/jsi/jsilib.h b/NativeScript/napi/hermes/include_old/jsi/jsilib.h new file mode 100644 index 00000000..c94de89f --- /dev/null +++ b/NativeScript/napi/hermes/include_old/jsi/jsilib.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +namespace facebook { +namespace jsi { + +class FileBuffer : public Buffer { + public: + FileBuffer(const std::string& path); + ~FileBuffer() override; + + size_t size() const override { + return size_; + } + + const uint8_t* data() const override { + return data_; + } + + private: + size_t size_; + uint8_t* data_; +}; + +// A trivial implementation of PreparedJavaScript that simply stores the source +// buffer and URL. +class SourceJavaScriptPreparation final : public jsi::PreparedJavaScript, + public jsi::Buffer { + std::shared_ptr buf_; + std::string sourceURL_; + + public: + SourceJavaScriptPreparation( + std::shared_ptr buf, + std::string sourceURL) + : buf_(std::move(buf)), sourceURL_(std::move(sourceURL)) {} + + const std::string& sourceURL() const { + return sourceURL_; + } + + size_t size() const override { + return buf_->size(); + } + const uint8_t* data() const override { + return buf_->data(); + } +}; + +} // namespace jsi +} // namespace facebook diff --git a/NativeScript/napi/hermes/include/jsi/test/testlib.h b/NativeScript/napi/hermes/include_old/jsi/test/testlib.h similarity index 100% rename from NativeScript/napi/hermes/include/jsi/test/testlib.h rename to NativeScript/napi/hermes/include_old/jsi/test/testlib.h diff --git a/NativeScript/napi/hermes/include_old/jsi/threadsafe.h b/NativeScript/napi/hermes/include_old/jsi/threadsafe.h new file mode 100644 index 00000000..cb10a335 --- /dev/null +++ b/NativeScript/napi/hermes/include_old/jsi/threadsafe.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include + +namespace facebook { +namespace jsi { + +class ThreadSafeRuntime : public Runtime { + public: + virtual void lock() const = 0; + virtual void unlock() const = 0; + virtual Runtime& getUnsafeRuntime() = 0; +}; + +namespace detail { + +template +struct WithLock { + L lock; + WithLock(R& r) : lock(r) {} + void before() { + lock.lock(); + } + void after() { + lock.unlock(); + } +}; + +// The actual implementation of a given ThreadSafeRuntime. It's parameterized +// by: +// +// - R: The actual Runtime type that this wraps +// - L: A lock type that has three members: +// - L(R& r) // ctor +// - void lock() +// - void unlock() +template +class ThreadSafeRuntimeImpl final + : public WithRuntimeDecorator, R, ThreadSafeRuntime> { + public: + template + ThreadSafeRuntimeImpl(Args&&... args) + : WithRuntimeDecorator, R, ThreadSafeRuntime>( + unsafe_, + lock_), + unsafe_(std::forward(args)...), + lock_(unsafe_) {} + + R& getUnsafeRuntime() override { + return WithRuntimeDecorator, R, ThreadSafeRuntime>::plain(); + } + + void lock() const override { + lock_.before(); + } + + void unlock() const override { + lock_.after(); + } + + private: + R unsafe_; + mutable WithLock lock_; +}; + +} // namespace detail + +} // namespace jsi +} // namespace facebook diff --git a/NativeScript/napi/hermes/js_native_api.h b/NativeScript/napi/hermes/js_native_api.h new file mode 100644 index 00000000..9e7073cf --- /dev/null +++ b/NativeScript/napi/hermes/js_native_api.h @@ -0,0 +1,600 @@ +#ifndef SRC_JS_NATIVE_API_H_ +#define SRC_JS_NATIVE_API_H_ + +// This file needs to be compatible with C compilers. +#include // NOLINT(modernize-deprecated-headers) +#include // NOLINT(modernize-deprecated-headers) + +// Use INT_MAX, this should only be consumed by the pre-processor anyway. +#define NAPI_VERSION_EXPERIMENTAL 2147483647 +#ifndef NAPI_VERSION +// The baseline version for N-API. +// The NAPI_VERSION controls which version will be used by default when +// compilling a native addon. If the addon developer specifically wants to use +// functions available in a new version of N-API that is not yet ported in all +// LTS versions, they can set NAPI_VERSION knowing that they have specifically +// depended on that version. +#define NAPI_VERSION 8 +#endif + +#include "js_native_api_types.h" + +// If you need __declspec(dllimport), either include instead, or +// define NAPI_EXTERN as __declspec(dllimport) on the compiler's command line. +#ifndef NAPI_EXTERN +#ifdef _WIN32 +#define NAPI_EXTERN __declspec(dllexport) +#elif defined(__wasm__) +#define NAPI_EXTERN \ + __attribute__((visibility("default"))) \ + __attribute__((__import_module__("napi"))) +#else +#define NAPI_EXTERN __attribute__((visibility("default"))) +#endif +#endif + +#define NAPI_AUTO_LENGTH SIZE_MAX + +#ifdef __cplusplus +#define EXTERN_C_START extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_START +#define EXTERN_C_END +#endif + +EXTERN_C_START + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_last_error_info( + node_api_basic_env env, const napi_extended_error_info** result); + +// Getters for defined singletons +NAPI_EXTERN napi_status NAPI_CDECL napi_get_undefined(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_null(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_global(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_boolean(napi_env env, + bool value, + napi_value* result); + +// Methods to create Primitive types/Objects +NAPI_EXTERN napi_status NAPI_CDECL napi_create_object(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_array(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_array_with_length(napi_env env, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_double(napi_env env, + double value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_int32(napi_env env, + int32_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_uint32(napi_env env, + uint32_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_int64(napi_env env, + int64_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_latin1( + napi_env env, const char* str, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf8(napi_env env, + const char* str, + size_t length, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf16(napi_env env, + const char16_t* str, + size_t length, + napi_value* result); +#if NAPI_VERSION >= 10 +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_external_string_latin1( + napi_env env, + char* str, + size_t length, + node_api_basic_finalize finalize_callback, + void* finalize_hint, + napi_value* result, + bool* copied); +NAPI_EXTERN napi_status NAPI_CDECL +node_api_create_external_string_utf16(napi_env env, + char16_t* str, + size_t length, + node_api_basic_finalize finalize_callback, + void* finalize_hint, + napi_value* result, + bool* copied); + +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_latin1( + napi_env env, const char* str, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf8( + napi_env env, const char* str, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf16( + napi_env env, const char16_t* str, size_t length, napi_value* result); +#endif // NAPI_VERSION >= 10 + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_symbol(napi_env env, + napi_value description, + napi_value* result); +#if NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL +node_api_symbol_for(napi_env env, + const char* utf8description, + size_t length, + napi_value* result); +#endif // NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL napi_create_function(napi_env env, + const char* utf8name, + size_t length, + napi_callback cb, + void* data, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_type_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_range_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +#if NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_syntax_error( + napi_env env, napi_value code, napi_value msg, napi_value* result); +#endif // NAPI_VERSION >= 9 + +// Methods to get the native napi_value from Primitive type +NAPI_EXTERN napi_status NAPI_CDECL napi_typeof(napi_env env, + napi_value value, + napi_valuetype* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_double(napi_env env, + napi_value value, + double* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int32(napi_env env, + napi_value value, + int32_t* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_uint32(napi_env env, + napi_value value, + uint32_t* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int64(napi_env env, + napi_value value, + int64_t* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bool(napi_env env, + napi_value value, + bool* result); + +// Copies LATIN-1 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_latin1( + napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result); + +// Copies UTF-8 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_utf8( + napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result); + +// Copies UTF-16 encoded bytes from a string into a buffer. +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_string_utf16(napi_env env, + napi_value value, + char16_t* buf, + size_t bufsize, + size_t* result); + +// Methods to coerce values +// These APIs may execute user scripts +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_bool(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_number(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_object(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_string(napi_env env, + napi_value value, + napi_value* result); + +// Methods to work with Objects +NAPI_EXTERN napi_status NAPI_CDECL napi_get_prototype(napi_env env, + napi_value object, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_property_names(napi_env env, + napi_value object, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_set_property(napi_env env, + napi_value object, + napi_value key, + napi_value value); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_property(napi_env env, + napi_value object, + napi_value key, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_own_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_set_named_property(napi_env env, + napi_value object, + const char* utf8name, + napi_value value); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_named_property(napi_env env, + napi_value object, + const char* utf8name, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_named_property(napi_env env, + napi_value object, + const char* utf8name, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_set_element(napi_env env, + napi_value object, + uint32_t index, + napi_value value); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_element(napi_env env, + napi_value object, + uint32_t index, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_element(napi_env env, + napi_value object, + uint32_t index, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_element(napi_env env, + napi_value object, + uint32_t index, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_define_properties(napi_env env, + napi_value object, + size_t property_count, + const napi_property_descriptor* properties); + +// Methods to work with Arrays +NAPI_EXTERN napi_status NAPI_CDECL napi_is_array(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_array_length(napi_env env, + napi_value value, + uint32_t* result); + +// Methods to compare values +NAPI_EXTERN napi_status NAPI_CDECL napi_strict_equals(napi_env env, + napi_value lhs, + napi_value rhs, + bool* result); + +// Methods to work with Functions +NAPI_EXTERN napi_status NAPI_CDECL napi_call_function(napi_env env, + napi_value recv, + napi_value func, + size_t argc, + const napi_value* argv, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_new_instance(napi_env env, + napi_value constructor, + size_t argc, + const napi_value* argv, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_instanceof(napi_env env, + napi_value object, + napi_value constructor, + bool* result); + +// Methods to work with napi_callbacks + +// Gets all callback info in a single call. (Ugly, but faster.) +NAPI_EXTERN napi_status NAPI_CDECL napi_get_cb_info( + napi_env env, // [in] Node-API environment handle + napi_callback_info cbinfo, // [in] Opaque callback-info handle + size_t* argc, // [in-out] Specifies the size of the provided argv array + // and receives the actual count of args. + napi_value* argv, // [out] Array of values + napi_value* this_arg, // [out] Receives the JS 'this' arg for the call + void** data); // [out] Receives the data pointer for the callback. + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_new_target( + napi_env env, napi_callback_info cbinfo, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_define_class(napi_env env, + const char* utf8name, + size_t length, + napi_callback constructor, + void* data, + size_t property_count, + const napi_property_descriptor* properties, + napi_value* result); + +// Methods to work with external data objects +NAPI_EXTERN napi_status NAPI_CDECL +napi_wrap(napi_env env, + napi_value js_object, + void* native_object, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_ref* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_unwrap(napi_env env, + napi_value js_object, + void** result); +NAPI_EXTERN napi_status NAPI_CDECL napi_remove_wrap(napi_env env, + napi_value js_object, + void** result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_external(napi_env env, + void* data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_external(napi_env env, + napi_value value, + void** result); + +// Methods to control object lifespan + +// Set initial_refcount to 0 for a weak reference, >0 for a strong reference. +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_reference(napi_env env, + napi_value value, + uint32_t initial_refcount, + napi_ref* result); + +// Deletes a reference. The referenced value is released, and may +// be GC'd unless there are other references to it. +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_reference(napi_env env, + napi_ref ref); + +// Increments the reference count, optionally returning the resulting count. +// After this call the reference will be a strong reference because its +// refcount is >0, and the referenced object is effectively "pinned". +// Calling this when the refcount is 0 and the object is unavailable +// results in an error. +NAPI_EXTERN napi_status NAPI_CDECL napi_reference_ref(napi_env env, + napi_ref ref, + uint32_t* result); + +// Decrements the reference count, optionally returning the resulting count. +// If the result is 0 the reference is now weak and the object may be GC'd +// at any time if there are no other references. Calling this when the +// refcount is already 0 results in an error. +NAPI_EXTERN napi_status NAPI_CDECL napi_reference_unref(napi_env env, + napi_ref ref, + uint32_t* result); + +// Attempts to get a referenced value. If the reference is weak, +// the value might no longer be available, in that case the call +// is still successful but the result is NULL. +NAPI_EXTERN napi_status NAPI_CDECL napi_get_reference_value(napi_env env, + napi_ref ref, + napi_value* result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_open_handle_scope(napi_env env, napi_handle_scope* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_close_handle_scope(napi_env env, napi_handle_scope scope); +NAPI_EXTERN napi_status NAPI_CDECL napi_open_escapable_handle_scope( + napi_env env, napi_escapable_handle_scope* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_close_escapable_handle_scope( + napi_env env, napi_escapable_handle_scope scope); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_escape_handle(napi_env env, + napi_escapable_handle_scope scope, + napi_value escapee, + napi_value* result); + +// Methods to support error handling +NAPI_EXTERN napi_status NAPI_CDECL napi_throw(napi_env env, napi_value error); +NAPI_EXTERN napi_status NAPI_CDECL napi_throw_error(napi_env env, + const char* code, + const char* msg); +NAPI_EXTERN napi_status NAPI_CDECL napi_throw_type_error(napi_env env, + const char* code, + const char* msg); +NAPI_EXTERN napi_status NAPI_CDECL napi_throw_range_error(napi_env env, + const char* code, + const char* msg); +#if NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL node_api_throw_syntax_error(napi_env env, + const char* code, + const char* msg); +#endif // NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL napi_is_error(napi_env env, + napi_value value, + bool* result); + +// Methods to support catching exceptions +NAPI_EXTERN napi_status NAPI_CDECL napi_is_exception_pending(napi_env env, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_and_clear_last_exception(napi_env env, napi_value* result); + +// Methods to work with array buffers and typed arrays +NAPI_EXTERN napi_status NAPI_CDECL napi_is_arraybuffer(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_arraybuffer(napi_env env, + size_t byte_length, + void** data, + napi_value* result); +#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_external_arraybuffer(napi_env env, + void* external_data, + size_t byte_length, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED +NAPI_EXTERN napi_status NAPI_CDECL napi_get_arraybuffer_info( + napi_env env, napi_value arraybuffer, void** data, size_t* byte_length); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_typedarray(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_typedarray(napi_env env, + napi_typedarray_type type, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_typedarray_info(napi_env env, + napi_value typedarray, + napi_typedarray_type* type, + size_t* length, + void** data, + napi_value* arraybuffer, + size_t* byte_offset); + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_dataview(napi_env env, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_dataview(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_dataview_info(napi_env env, + napi_value dataview, + size_t* bytelength, + void** data, + napi_value* arraybuffer, + size_t* byte_offset); + +// version management +NAPI_EXTERN napi_status NAPI_CDECL napi_get_version(node_api_basic_env env, + uint32_t* result); + +// Promises +NAPI_EXTERN napi_status NAPI_CDECL napi_create_promise(napi_env env, + napi_deferred* deferred, + napi_value* promise); +NAPI_EXTERN napi_status NAPI_CDECL napi_resolve_deferred(napi_env env, + napi_deferred deferred, + napi_value resolution); +NAPI_EXTERN napi_status NAPI_CDECL napi_reject_deferred(napi_env env, + napi_deferred deferred, + napi_value rejection); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_promise(napi_env env, + napi_value value, + bool* is_promise); + +// Running a script +NAPI_EXTERN napi_status NAPI_CDECL napi_run_script(napi_env env, + napi_value script, + napi_value* result); + +// Memory management +NAPI_EXTERN napi_status NAPI_CDECL napi_adjust_external_memory( + node_api_basic_env env, int64_t change_in_bytes, int64_t* adjusted_value); + +#if NAPI_VERSION >= 5 + +// Dates +NAPI_EXTERN napi_status NAPI_CDECL napi_create_date(napi_env env, + double time, + napi_value* result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_is_date(napi_env env, + napi_value value, + bool* is_date); + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_date_value(napi_env env, + napi_value value, + double* result); + +// Add finalizer for pointer +NAPI_EXTERN napi_status NAPI_CDECL +napi_add_finalizer(napi_env env, + napi_value js_object, + void* finalize_data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_ref* result); + +#endif // NAPI_VERSION >= 5 + +#if NAPI_VERSION >= 6 + +// BigInt +NAPI_EXTERN napi_status NAPI_CDECL napi_create_bigint_int64(napi_env env, + int64_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_bigint_uint64(napi_env env, uint64_t value, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_bigint_words(napi_env env, + int sign_bit, + size_t word_count, + const uint64_t* words, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_int64(napi_env env, + napi_value value, + int64_t* result, + bool* lossless); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_uint64( + napi_env env, napi_value value, uint64_t* result, bool* lossless); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_value_bigint_words(napi_env env, + napi_value value, + int* sign_bit, + size_t* word_count, + uint64_t* words); + +// Object +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_all_property_names(napi_env env, + napi_value object, + napi_key_collection_mode key_mode, + napi_key_filter key_filter, + napi_key_conversion key_conversion, + napi_value* result); + +// Instance data +NAPI_EXTERN napi_status NAPI_CDECL +napi_set_instance_data(node_api_basic_env env, + void* data, + napi_finalize finalize_cb, + void* finalize_hint); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_instance_data(node_api_basic_env env, void** data); +#endif // NAPI_VERSION >= 6 + +#if NAPI_VERSION >= 7 +// ArrayBuffer detaching +NAPI_EXTERN napi_status NAPI_CDECL +napi_detach_arraybuffer(napi_env env, napi_value arraybuffer); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_is_detached_arraybuffer(napi_env env, napi_value value, bool* result); +#endif // NAPI_VERSION >= 7 + +#if NAPI_VERSION >= 8 +// Type tagging +NAPI_EXTERN napi_status NAPI_CDECL napi_type_tag_object( + napi_env env, napi_value value, const napi_type_tag* type_tag); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_check_object_type_tag(napi_env env, + napi_value value, + const napi_type_tag* type_tag, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_object_freeze(napi_env env, + napi_value object); +NAPI_EXTERN napi_status NAPI_CDECL napi_object_seal(napi_env env, + napi_value object); +#endif // NAPI_VERSION >= 8 + +EXTERN_C_END + +#endif // SRC_JS_NATIVE_API_H_ diff --git a/NativeScript/napi/hermes/js_native_api_types.h b/NativeScript/napi/hermes/js_native_api_types.h new file mode 100644 index 00000000..7853a8d7 --- /dev/null +++ b/NativeScript/napi/hermes/js_native_api_types.h @@ -0,0 +1,195 @@ +#ifndef SRC_JS_NATIVE_API_TYPES_H_ +#define SRC_JS_NATIVE_API_TYPES_H_ + +// This file needs to be compatible with C compilers. +// This is a public include file, and these includes have essentially +// became part of it's API. +#include // NOLINT(modernize-deprecated-headers) +#include // NOLINT(modernize-deprecated-headers) + +#if !defined __cplusplus || (defined(_MSC_VER) && _MSC_VER < 1900) +typedef uint16_t char16_t; +#endif + +#ifndef NAPI_CDECL +#ifdef _WIN32 +#define NAPI_CDECL __cdecl +#else +#define NAPI_CDECL +#endif +#endif + +// JSVM API types are all opaque pointers for ABI stability +// typedef undefined structs instead of void* for compile time type safety +typedef struct napi_env__* napi_env; + +// We need to mark APIs which can be called during garbage collection (GC), +// meaning that they do not affect the state of the JS engine, and can +// therefore be called synchronously from a finalizer that itself runs +// synchronously during GC. Such APIs can receive either a `napi_env` or a +// `node_api_basic_env` as their first parameter, because we should be able to +// also call them during normal, non-garbage-collecting operations, whereas +// APIs that affect the state of the JS engine can only receive a `napi_env` as +// their first parameter, because we must not call them during GC. In lieu of +// inheritance, we use the properties of the const qualifier to accomplish +// this, because both a const and a non-const value can be passed to an API +// expecting a const value, but only a non-const value can be passed to an API +// expecting a non-const value. +// +// In conjunction with appropriate CFLAGS to warn us if we're passing a const +// (basic) environment into an API that expects a non-const environment, and +// the definition of basic finalizer function pointer types below, which +// receive a basic environment as their first parameter, and can thus only call +// basic APIs (unless the user explicitly casts the environment), we achieve +// the ability to ensure at compile time that we do not call APIs that affect +// the state of the JS engine from a synchronous (basic) finalizer. +typedef struct napi_env__* node_api_nogc_env; +typedef node_api_nogc_env node_api_basic_env; + +typedef struct napi_value__* napi_value; +typedef struct napi_ref__* napi_ref; +typedef struct napi_handle_scope__* napi_handle_scope; +typedef struct napi_escapable_handle_scope__* napi_escapable_handle_scope; +typedef struct napi_callback_info__* napi_callback_info; +typedef struct napi_deferred__* napi_deferred; + +typedef enum { + napi_default = 0, + napi_writable = 1 << 0, + napi_enumerable = 1 << 1, + napi_configurable = 1 << 2, + + // Used with napi_define_class to distinguish static properties + // from instance properties. Ignored by napi_define_properties. + napi_static = 1 << 10, + +#if NAPI_VERSION >= 8 + // Default for class methods. + napi_default_method = napi_writable | napi_configurable, + + // Default for object properties, like in JS obj[prop]. + napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable, +#endif // NAPI_VERSION >= 8 +} napi_property_attributes; + +typedef enum { + // ES6 types (corresponds to typeof) + napi_undefined, + napi_null, + napi_boolean, + napi_number, + napi_string, + napi_symbol, + napi_object, + napi_function, + napi_external, + napi_bigint, +} napi_valuetype; + +typedef enum { + napi_int8_array, + napi_uint8_array, + napi_uint8_clamped_array, + napi_int16_array, + napi_uint16_array, + napi_int32_array, + napi_uint32_array, + napi_float32_array, + napi_float64_array, + napi_bigint64_array, + napi_biguint64_array, +} napi_typedarray_type; + +typedef enum { + napi_ok, + napi_invalid_arg, + napi_object_expected, + napi_string_expected, + napi_name_expected, + napi_function_expected, + napi_number_expected, + napi_boolean_expected, + napi_array_expected, + napi_generic_failure, + napi_pending_exception, + napi_cancelled, + napi_escape_called_twice, + napi_handle_scope_mismatch, + napi_callback_scope_mismatch, + napi_queue_full, + napi_closing, + napi_bigint_expected, + napi_date_expected, + napi_arraybuffer_expected, + napi_detachable_arraybuffer_expected, + napi_would_deadlock, // unused + napi_no_external_buffers_allowed, + napi_cannot_run_js, +} napi_status; +// Note: when adding a new enum value to `napi_status`, please also update +// * `const int last_status` in the definition of `napi_get_last_error_info()' +// in file js_native_api_v8.cc. +// * `const char* error_messages[]` in file js_native_api_v8.cc with a brief +// message explaining the error. +// * the definition of `napi_status` in doc/api/n-api.md to reflect the newly +// added value(s). + +typedef napi_value(NAPI_CDECL* napi_callback)(napi_env env, + napi_callback_info info); +typedef void(NAPI_CDECL* napi_finalize)(napi_env env, + void* finalize_data, + void* finalize_hint); + +typedef napi_finalize node_api_nogc_finalize; +typedef node_api_nogc_finalize node_api_basic_finalize; + +typedef struct { + // One of utf8name or name should be NULL. + const char* utf8name; + napi_value name; + + napi_callback method; + napi_callback getter; + napi_callback setter; + napi_value value; + + napi_property_attributes attributes; + void* data; +} napi_property_descriptor; + +typedef struct { + const char* error_message; + void* engine_reserved; + uint32_t engine_error_code; + napi_status error_code; +} napi_extended_error_info; + +#if NAPI_VERSION >= 6 +typedef enum { + napi_key_include_prototypes, + napi_key_own_only +} napi_key_collection_mode; + +typedef enum { + napi_key_all_properties = 0, + napi_key_writable = 1, + napi_key_enumerable = 1 << 1, + napi_key_configurable = 1 << 2, + napi_key_skip_strings = 1 << 3, + napi_key_skip_symbols = 1 << 4 +} napi_key_filter; + +typedef enum { + napi_key_keep_numbers, + napi_key_numbers_to_strings +} napi_key_conversion; +#endif // NAPI_VERSION >= 6 + +#if NAPI_VERSION >= 8 +typedef struct { + uint64_t lower; + uint64_t upper; +} napi_type_tag; +#endif // NAPI_VERSION >= 8 + +#endif // SRC_JS_NATIVE_API_TYPES_H_ diff --git a/NativeScript/napi/hermes/jsr.cpp b/NativeScript/napi/hermes/jsr.cpp index 715b74a7..c29a120b 100644 --- a/NativeScript/napi/hermes/jsr.cpp +++ b/NativeScript/napi/hermes/jsr.cpp @@ -4,10 +4,6 @@ using namespace facebook::jsi; std::unordered_map JSR::env_to_jsr_cache; -typedef struct napi_runtime__ { - JSR *hermes; -} napi_runtime__; - JSR::JSR() { hermes::vm::RuntimeConfig config = hermes::vm::RuntimeConfig::Builder().withMicrotaskQueue(true).withES6Class( @@ -58,7 +54,7 @@ napi_status js_unlock_env(napi_env env) { napi_status js_create_napi_env(napi_env *env, napi_runtime runtime) { if (env == nullptr) return napi_invalid_arg; - runtime->hermes->rt->createNapiEnv(env); + *env = (napi_env)runtime->hermes->rt->createNodeApiEnv(9); JSR::env_to_jsr_cache.insert(std::make_pair(*env, runtime->hermes)); return napi_ok; } diff --git a/NativeScript/napi/hermes/jsr.h b/NativeScript/napi/hermes/jsr.h index 3a29c915..c388331f 100644 --- a/NativeScript/napi/hermes/jsr.h +++ b/NativeScript/napi/hermes/jsr.h @@ -6,7 +6,6 @@ #define TEST_APP_JSR_H #include "hermes/hermes.h" -#include "hermes/hermes_api.h" #include "jsi/threadsafe.h" #include "jsr_common.h" @@ -28,6 +27,10 @@ class JSR { static std::unordered_map env_to_jsr_cache; }; +typedef struct napi_runtime__ { + JSR *hermes; +} napi_runtime__; + class NapiScope { public: explicit NapiScope(napi_env env, bool openHandle = true) diff --git a/NativeScript/napi/hermes/node_api.h b/NativeScript/napi/hermes/node_api.h new file mode 100644 index 00000000..4ebfbd46 --- /dev/null +++ b/NativeScript/napi/hermes/node_api.h @@ -0,0 +1,270 @@ +#ifndef SRC_NODE_API_H_ +#define SRC_NODE_API_H_ + +#if defined(BUILDING_NODE_EXTENSION) && !defined(NAPI_EXTERN) +#ifdef _WIN32 +// Building native addon against node +#define NAPI_EXTERN __declspec(dllimport) +#elif defined(__wasm__) +#define NAPI_EXTERN __attribute__((__import_module__("napi"))) +#endif +#endif +#include "js_native_api.h" +#include "node_api_types.h" + +struct uv_loop_s; // Forward declaration. + +#ifdef _WIN32 +#define NAPI_MODULE_EXPORT __declspec(dllexport) +#else +#ifdef __EMSCRIPTEN__ +#define NAPI_MODULE_EXPORT \ + __attribute__((visibility("default"))) __attribute__((used)) +#else +#define NAPI_MODULE_EXPORT __attribute__((visibility("default"))) +#endif +#endif + +#if defined(__GNUC__) +#define NAPI_NO_RETURN __attribute__((noreturn)) +#elif defined(_WIN32) +#define NAPI_NO_RETURN __declspec(noreturn) +#else +#define NAPI_NO_RETURN +#endif + +typedef napi_value(NAPI_CDECL* napi_addon_register_func)(napi_env env, + napi_value exports); +typedef int32_t(NAPI_CDECL* node_api_addon_get_api_version_func)(void); + +// Used by deprecated registration method napi_module_register. +typedef struct napi_module { + int nm_version; + unsigned int nm_flags; + const char* nm_filename; + napi_addon_register_func nm_register_func; + const char* nm_modname; + void* nm_priv; + void* reserved[4]; +} napi_module; + +#define NAPI_MODULE_VERSION 1 + +#define NAPI_MODULE_INITIALIZER_X(base, version) \ + NAPI_MODULE_INITIALIZER_X_HELPER(base, version) +#define NAPI_MODULE_INITIALIZER_X_HELPER(base, version) base##version + +#ifdef __wasm__ +#define NAPI_MODULE_INITIALIZER_BASE napi_register_wasm_v +#else +#define NAPI_MODULE_INITIALIZER_BASE napi_register_module_v +#endif + +#define NODE_API_MODULE_GET_API_VERSION_BASE node_api_module_get_api_version_v + +#define NAPI_MODULE_INITIALIZER \ + NAPI_MODULE_INITIALIZER_X(NAPI_MODULE_INITIALIZER_BASE, NAPI_MODULE_VERSION) + +#define NODE_API_MODULE_GET_API_VERSION \ + NAPI_MODULE_INITIALIZER_X(NODE_API_MODULE_GET_API_VERSION_BASE, \ + NAPI_MODULE_VERSION) + +#define NAPI_MODULE_INIT() \ + EXTERN_C_START \ + NAPI_MODULE_EXPORT int32_t NODE_API_MODULE_GET_API_VERSION(void) { \ + return NAPI_VERSION; \ + } \ + NAPI_MODULE_EXPORT napi_value NAPI_MODULE_INITIALIZER(napi_env env, \ + napi_value exports); \ + EXTERN_C_END \ + napi_value NAPI_MODULE_INITIALIZER(napi_env env, napi_value exports) + +#define NAPI_MODULE(modname, regfunc) \ + NAPI_MODULE_INIT() { \ + return regfunc(env, exports); \ + } + +// Deprecated. Use NAPI_MODULE. +#define NAPI_MODULE_X(modname, regfunc, priv, flags) \ + NAPI_MODULE(modname, regfunc) + +EXTERN_C_START + +// Deprecated. Replaced by symbol-based registration defined by NAPI_MODULE +// and NAPI_MODULE_INIT macros. +NAPI_EXTERN void NAPI_CDECL napi_module_register(napi_module* mod); + +NAPI_EXTERN NAPI_NO_RETURN void NAPI_CDECL +napi_fatal_error(const char* location, + size_t location_len, + const char* message, + size_t message_len); + +// Methods for custom handling of async operations +NAPI_EXTERN napi_status NAPI_CDECL +napi_async_init(napi_env env, + napi_value async_resource, + napi_value async_resource_name, + napi_async_context* result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_async_destroy(napi_env env, napi_async_context async_context); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_make_callback(napi_env env, + napi_async_context async_context, + napi_value recv, + napi_value func, + size_t argc, + const napi_value* argv, + napi_value* result); + +// Methods to provide node::Buffer functionality with napi types +NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer(napi_env env, + size_t length, + void** data, + napi_value* result); +#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_external_buffer(napi_env env, + size_t length, + void* data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED + +#if NAPI_VERSION >= 10 + +NAPI_EXTERN napi_status NAPI_CDECL +node_api_create_buffer_from_arraybuffer(napi_env env, + napi_value arraybuffer, + size_t byte_offset, + size_t byte_length, + napi_value* result); +#endif // NAPI_VERSION >= 10 + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer_copy(napi_env env, + size_t length, + const void* data, + void** result_data, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_buffer(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_buffer_info(napi_env env, + napi_value value, + void** data, + size_t* length); + +// Methods to manage simple async operations +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_async_work(napi_env env, + napi_value async_resource, + napi_value async_resource_name, + napi_async_execute_callback execute, + napi_async_complete_callback complete, + void* data, + napi_async_work* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_async_work(napi_env env, + napi_async_work work); +NAPI_EXTERN napi_status NAPI_CDECL napi_queue_async_work(node_api_basic_env env, + napi_async_work work); +NAPI_EXTERN napi_status NAPI_CDECL +napi_cancel_async_work(node_api_basic_env env, napi_async_work work); + +// version management +NAPI_EXTERN napi_status NAPI_CDECL napi_get_node_version( + node_api_basic_env env, const napi_node_version** version); + +#if NAPI_VERSION >= 2 + +// Return the current libuv event loop for a given environment +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_uv_event_loop(node_api_basic_env env, struct uv_loop_s** loop); + +#endif // NAPI_VERSION >= 2 + +#if NAPI_VERSION >= 3 + +NAPI_EXTERN napi_status NAPI_CDECL napi_fatal_exception(napi_env env, + napi_value err); + +NAPI_EXTERN napi_status NAPI_CDECL napi_add_env_cleanup_hook( + node_api_basic_env env, napi_cleanup_hook fun, void* arg); + +NAPI_EXTERN napi_status NAPI_CDECL napi_remove_env_cleanup_hook( + node_api_basic_env env, napi_cleanup_hook fun, void* arg); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_open_callback_scope(napi_env env, + napi_value resource_object, + napi_async_context context, + napi_callback_scope* result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_close_callback_scope(napi_env env, napi_callback_scope scope); + +#endif // NAPI_VERSION >= 3 + +#if NAPI_VERSION >= 4 + +// Calling into JS from other threads +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_threadsafe_function(napi_env env, + napi_value func, + napi_value async_resource, + napi_value async_resource_name, + size_t max_queue_size, + size_t initial_thread_count, + void* thread_finalize_data, + napi_finalize thread_finalize_cb, + void* context, + napi_threadsafe_function_call_js call_js_cb, + napi_threadsafe_function* result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_threadsafe_function_context( + napi_threadsafe_function func, void** result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_call_threadsafe_function(napi_threadsafe_function func, + void* data, + napi_threadsafe_function_call_mode is_blocking); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_acquire_threadsafe_function(napi_threadsafe_function func); + +NAPI_EXTERN napi_status NAPI_CDECL napi_release_threadsafe_function( + napi_threadsafe_function func, napi_threadsafe_function_release_mode mode); + +NAPI_EXTERN napi_status NAPI_CDECL napi_unref_threadsafe_function( + node_api_basic_env env, napi_threadsafe_function func); + +NAPI_EXTERN napi_status NAPI_CDECL napi_ref_threadsafe_function( + node_api_basic_env env, napi_threadsafe_function func); + +#endif // NAPI_VERSION >= 4 + +#if NAPI_VERSION >= 8 + +NAPI_EXTERN napi_status NAPI_CDECL +napi_add_async_cleanup_hook(node_api_basic_env env, + napi_async_cleanup_hook hook, + void* arg, + napi_async_cleanup_hook_handle* remove_handle); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_remove_async_cleanup_hook(napi_async_cleanup_hook_handle remove_handle); + +#endif // NAPI_VERSION >= 8 + +#if NAPI_VERSION >= 9 + +NAPI_EXTERN napi_status NAPI_CDECL +node_api_get_module_file_name(node_api_basic_env env, const char** result); + +#endif // NAPI_VERSION >= 9 + +EXTERN_C_END + +#endif // SRC_NODE_API_H_ diff --git a/NativeScript/napi/hermes/node_api_types.h b/NativeScript/napi/hermes/node_api_types.h new file mode 100644 index 00000000..9c2f03f4 --- /dev/null +++ b/NativeScript/napi/hermes/node_api_types.h @@ -0,0 +1,52 @@ +#ifndef SRC_NODE_API_TYPES_H_ +#define SRC_NODE_API_TYPES_H_ + +#include "js_native_api_types.h" + +typedef struct napi_callback_scope__* napi_callback_scope; +typedef struct napi_async_context__* napi_async_context; +typedef struct napi_async_work__* napi_async_work; + +#if NAPI_VERSION >= 3 +typedef void(NAPI_CDECL* napi_cleanup_hook)(void* arg); +#endif // NAPI_VERSION >= 3 + +#if NAPI_VERSION >= 4 +typedef struct napi_threadsafe_function__* napi_threadsafe_function; +#endif // NAPI_VERSION >= 4 + +#if NAPI_VERSION >= 4 +typedef enum { + napi_tsfn_release, + napi_tsfn_abort +} napi_threadsafe_function_release_mode; + +typedef enum { + napi_tsfn_nonblocking, + napi_tsfn_blocking +} napi_threadsafe_function_call_mode; +#endif // NAPI_VERSION >= 4 + +typedef void(NAPI_CDECL* napi_async_execute_callback)(napi_env env, void* data); +typedef void(NAPI_CDECL* napi_async_complete_callback)(napi_env env, + napi_status status, + void* data); +#if NAPI_VERSION >= 4 +typedef void(NAPI_CDECL* napi_threadsafe_function_call_js)( + napi_env env, napi_value js_callback, void* context, void* data); +#endif // NAPI_VERSION >= 4 + +typedef struct { + uint32_t major; + uint32_t minor; + uint32_t patch; + const char* release; +} napi_node_version; + +#if NAPI_VERSION >= 8 +typedef struct napi_async_cleanup_hook_handle__* napi_async_cleanup_hook_handle; +typedef void(NAPI_CDECL* napi_async_cleanup_hook)( + napi_async_cleanup_hook_handle handle, void* data); +#endif // NAPI_VERSION >= 8 + +#endif // SRC_NODE_API_TYPES_H_ diff --git a/NativeScript/napi/v8/include/inspector/Debugger.h b/NativeScript/napi/v8/include/inspector/Debugger.h new file mode 100644 index 00000000..d984c6a4 --- /dev/null +++ b/NativeScript/napi/v8/include/inspector/Debugger.h @@ -0,0 +1,59 @@ +// This file is generated by Exported_h.template. + +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_inspector_protocol_Debugger_api_h +#define v8_inspector_protocol_Debugger_api_h + +#include "v8-inspector.h" + +namespace v8_inspector { +namespace protocol { + +#ifndef v8_inspector_protocol_exported_api_h +#define v8_inspector_protocol_exported_api_h +class V8_EXPORT Exported { +public: + virtual void AppendSerialized(std::vector* out) const = 0; + + virtual ~Exported() { } +}; +#endif // !defined(v8_inspector_protocol_exported_api_h) + +namespace Debugger { +namespace API { + +// ------------- Enums. + +namespace Paused { +namespace ReasonEnum { +V8_EXPORT extern const char* Ambiguous; +V8_EXPORT extern const char* Assert; +V8_EXPORT extern const char* CSPViolation; +V8_EXPORT extern const char* DebugCommand; +V8_EXPORT extern const char* DOM; +V8_EXPORT extern const char* EventListener; +V8_EXPORT extern const char* Exception; +V8_EXPORT extern const char* Instrumentation; +V8_EXPORT extern const char* OOM; +V8_EXPORT extern const char* Other; +V8_EXPORT extern const char* PromiseRejection; +V8_EXPORT extern const char* XHR; +} // ReasonEnum +} // Paused + +// ------------- Types. + +class V8_EXPORT SearchMatch : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +} // namespace API +} // namespace Debugger +} // namespace v8_inspector +} // namespace protocol + +#endif // !defined(v8_inspector_protocol_Debugger_api_h) diff --git a/NativeScript/napi/v8/include/inspector/Runtime.h b/NativeScript/napi/v8/include/inspector/Runtime.h new file mode 100644 index 00000000..f9d515ba --- /dev/null +++ b/NativeScript/napi/v8/include/inspector/Runtime.h @@ -0,0 +1,52 @@ +// This file is generated by Exported_h.template. + +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_inspector_protocol_Runtime_api_h +#define v8_inspector_protocol_Runtime_api_h + +#include "v8-inspector.h" + +namespace v8_inspector { +namespace protocol { + +#ifndef v8_inspector_protocol_exported_api_h +#define v8_inspector_protocol_exported_api_h +class V8_EXPORT Exported { +public: + virtual void AppendSerialized(std::vector* out) const = 0; + + virtual ~Exported() { } +}; +#endif // !defined(v8_inspector_protocol_exported_api_h) + +namespace Runtime { +namespace API { + +// ------------- Enums. + +// ------------- Types. + +class V8_EXPORT RemoteObject : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +class V8_EXPORT StackTrace : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +class V8_EXPORT StackTraceId : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +} // namespace API +} // namespace Runtime +} // namespace v8_inspector +} // namespace protocol + +#endif // !defined(v8_inspector_protocol_Runtime_api_h) diff --git a/NativeScript/napi/v8/include/inspector/Schema.h b/NativeScript/napi/v8/include/inspector/Schema.h new file mode 100644 index 00000000..03a76fa9 --- /dev/null +++ b/NativeScript/napi/v8/include/inspector/Schema.h @@ -0,0 +1,42 @@ +// This file is generated by Exported_h.template. + +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_inspector_protocol_Schema_api_h +#define v8_inspector_protocol_Schema_api_h + +#include "v8-inspector.h" + +namespace v8_inspector { +namespace protocol { + +#ifndef v8_inspector_protocol_exported_api_h +#define v8_inspector_protocol_exported_api_h +class V8_EXPORT Exported { +public: + virtual void AppendSerialized(std::vector* out) const = 0; + + virtual ~Exported() { } +}; +#endif // !defined(v8_inspector_protocol_exported_api_h) + +namespace Schema { +namespace API { + +// ------------- Enums. + +// ------------- Types. + +class V8_EXPORT Domain : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +} // namespace API +} // namespace Schema +} // namespace v8_inspector +} // namespace protocol + +#endif // !defined(v8_inspector_protocol_Schema_api_h) diff --git a/NativeScript/napi/v8/include_old/APIDesign.md b/NativeScript/napi/v8/include_old/APIDesign.md new file mode 100644 index 00000000..fe42c8ed --- /dev/null +++ b/NativeScript/napi/v8/include_old/APIDesign.md @@ -0,0 +1,72 @@ +# The V8 public C++ API + +# Overview + +The V8 public C++ API aims to support four use cases: + +1. Enable applications that embed V8 (called the embedder) to configure and run + one or more instances of V8. +2. Expose ECMAScript-like capabilities to the embedder. +3. Enable the embedder to interact with ECMAScript by exposing API objects. +4. Provide access to the V8 debugger (inspector). + +# Configuring and running an instance of V8 + +V8 requires access to certain OS-level primitives such as the ability to +schedule work on threads, or allocate memory. + +The embedder can define how to access those primitives via the v8::Platform +interface. While V8 bundles a basic implementation, embedders are highly +encouraged to implement v8::Platform themselves. + +Currently, the v8::ArrayBuffer::Allocator is passed to the v8::Isolate factory +method, however, conceptually it should also be part of the v8::Platform since +all instances of V8 should share one allocator. + +Once the v8::Platform is configured, an v8::Isolate can be created. All +further interactions with V8 should explicitly reference the v8::Isolate they +refer to. All API methods should eventually take an v8::Isolate parameter. + +When a given instance of V8 is no longer needed, it can be destroyed by +disposing the respective v8::Isolate. If the embedder wishes to free all memory +associated with the v8::Isolate, it has to first clear all global handles +associated with that v8::Isolate. + +# ECMAScript-like capabilities + +In general, the C++ API shouldn't enable capabilities that aren't available to +scripts running in V8. Experience has shown that it's not possible to maintain +such API methods in the long term. However, capabilities also available to +scripts, i.e., ones that are defined in the ECMAScript standard are there to +stay, and we can safely expose them to embedders. + +The C++ API should also be pleasant to use, and not require learning new +paradigms. Similarly to how the API exposed to scripts aims to provide good +ergonomics, we should aim to provide a reasonable developer experience for this +API surface. + +ECMAScript makes heavy use of exceptions, however, V8's C++ code doesn't use +C++ exceptions. Therefore, all API methods that can throw exceptions should +indicate so by returning a v8::Maybe<> or v8::MaybeLocal<> result, +and by taking a v8::Local<v8::Context> parameter that indicates in which +context a possible exception should be thrown. + +# API objects + +V8 allows embedders to define special objects that expose additional +capabilities and APIs to scripts. The most prominent example is exposing the +HTML DOM in Blink. Other examples are e.g. node.js. It is less clear what kind +of capabilities we want to expose via this API surface. As a rule of thumb, we +want to expose operations as defined in the WebIDL and HTML spec: we +assume that those requirements are somewhat stable, and that they are a +superset of the requirements of other embedders including node.js. + +Ideally, the API surfaces defined in those specs hook into the ECMAScript spec +which in turn guarantees long-term stability of the API. + +# The V8 inspector + +All debugging capabilities of V8 should be exposed via the inspector protocol. +The exception to this are profiling features exposed via v8-profiler.h. +Changes to the inspector protocol need to ensure backwards compatibility and +commitment to maintain. diff --git a/NativeScript/napi/v8/include_old/DEPS b/NativeScript/napi/v8/include_old/DEPS new file mode 100644 index 00000000..21ce3d96 --- /dev/null +++ b/NativeScript/napi/v8/include_old/DEPS @@ -0,0 +1,10 @@ +include_rules = [ + # v8-inspector-protocol.h depends on generated files under include/inspector. + "+inspector", + "+cppgc/common.h", + # Used by v8-cppgc.h to bridge to cppgc. + "+cppgc/custom-space.h", + "+cppgc/heap-statistics.h", + "+cppgc/internal/write-barrier.h", + "+cppgc/visitor.h", +] diff --git a/NativeScript/napi/v8/include_old/DIR_METADATA b/NativeScript/napi/v8/include_old/DIR_METADATA new file mode 100644 index 00000000..a27ea1b5 --- /dev/null +++ b/NativeScript/napi/v8/include_old/DIR_METADATA @@ -0,0 +1,11 @@ +# Metadata information for this directory. +# +# For more information on DIR_METADATA files, see: +# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# +# For the schema of this file, see Metadata message: +# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto + +monorail { + component: "Blink>JavaScript>API" +} \ No newline at end of file diff --git a/NativeScript/napi/v8/include_old/OWNERS b/NativeScript/napi/v8/include_old/OWNERS new file mode 100644 index 00000000..535040c5 --- /dev/null +++ b/NativeScript/napi/v8/include_old/OWNERS @@ -0,0 +1,23 @@ +adamk@chromium.org +cbruni@chromium.org +leszeks@chromium.org +mlippautz@chromium.org +verwaest@chromium.org +yangguo@chromium.org + +per-file *DEPS=file:../COMMON_OWNERS +per-file v8-internal.h=file:../COMMON_OWNERS + +per-file v8-debug.h=file:../src/debug/OWNERS + +per-file js_protocol.pdl=file:../src/inspector/OWNERS +per-file v8-inspector*=file:../src/inspector/OWNERS +per-file v8-inspector*=file:../src/inspector/OWNERS + +# Needed by the auto_tag builder +per-file v8-version.h=v8-ci-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com + +# For branch updates: +per-file v8-version.h=file:../INFRA_OWNERS +per-file v8-version.h=hablich@chromium.org +per-file v8-version.h=vahl@chromium.org diff --git a/NativeScript/napi/v8/include_old/cppgc/DEPS b/NativeScript/napi/v8/include_old/cppgc/DEPS new file mode 100644 index 00000000..2ec7ebbd --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/DEPS @@ -0,0 +1,9 @@ +include_rules = [ + "-include", + "+v8config.h", + "+v8-platform.h", + "+v8-source-location.h", + "+cppgc", + "-src", + "+libplatform/libplatform.h", +] diff --git a/NativeScript/napi/v8/include_old/cppgc/OWNERS b/NativeScript/napi/v8/include_old/cppgc/OWNERS new file mode 100644 index 00000000..6ccabf60 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/OWNERS @@ -0,0 +1,2 @@ +bikineev@chromium.org +omerkatz@chromium.org \ No newline at end of file diff --git a/NativeScript/napi/v8/include_old/cppgc/README.md b/NativeScript/napi/v8/include_old/cppgc/README.md new file mode 100644 index 00000000..d825ea5b --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/README.md @@ -0,0 +1,135 @@ +# Oilpan: C++ Garbage Collection + +Oilpan is an open-source garbage collection library for C++ that can be used stand-alone or in collaboration with V8's JavaScript garbage collector. +Oilpan implements mark-and-sweep garbage collection (GC) with limited compaction (for a subset of objects). + +**Key properties** + +- Trace-based garbage collection; +- Incremental and concurrent marking; +- Incremental and concurrent sweeping; +- Precise on-heap memory layout; +- Conservative on-stack memory layout; +- Allows for collection with and without considering stack; +- Non-incremental and non-concurrent compaction for selected spaces; + +See the [Hello World](https://chromium.googlesource.com/v8/v8/+/main/samples/cppgc/hello-world.cc) example on how to get started using Oilpan to manage C++ code. + +Oilpan follows V8's project organization, see e.g. on how we accept [contributions](https://v8.dev/docs/contribute) and [provide a stable API](https://v8.dev/docs/api). + +## Threading model + +Oilpan features thread-local garbage collection and assumes heaps are not shared among threads. +In other words, objects are accessed and ultimately reclaimed by the garbage collector on the same thread that allocates them. +This allows Oilpan to run garbage collection in parallel with mutators running in other threads. + +References to objects belonging to another thread's heap are modeled using cross-thread roots. +This is even true for on-heap to on-heap references. + +Oilpan heaps may generally not be accessed from different threads unless otherwise noted. + +## Heap partitioning + +Oilpan's heaps are partitioned into spaces. +The space for an object is chosen depending on a number of criteria, e.g.: + +- Objects over 64KiB are allocated in a large object space +- Objects can be assigned to a dedicated custom space. + Custom spaces can also be marked as compactable. +- Other objects are allocated in one of the normal page spaces bucketed depending on their size. + +## Precise and conservative garbage collection + +Oilpan supports two kinds of GCs: + +1. **Conservative GC.** +A GC is called conservative when it is executed while the regular native stack is not empty. +In this case, the native stack might contain references to objects in Oilpan's heap, which should be kept alive. +The GC scans the native stack and treats the pointers discovered via the native stack as part of the root set. +This kind of GC is considered imprecise because values on stack other than references may accidentally appear as references to on-heap object, which means these objects will be kept alive despite being in practice unreachable from the application as an actual reference. + +2. **Precise GC.** +A precise GC is triggered at the end of an event loop, which is controlled by an embedder via a platform. +At this point, it is guaranteed that there are no on-stack references pointing to Oilpan's heap. +This means there is no risk of confusing other value types with references. +Oilpan has precise knowledge of on-heap object layouts, and so it knows exactly where pointers lie in memory. +Oilpan can just start marking from the regular root set and collect all garbage precisely. + +## Atomic, incremental and concurrent garbage collection + +Oilpan has three modes of operation: + +1. **Atomic GC.** +The entire GC cycle, including all its phases (e.g. see [Marking](#Marking-phase) and [Sweeping](#Sweeping-phase)), are executed back to back in a single pause. +This mode of operation is also known as Stop-The-World (STW) garbage collection. +It results in the most jank (due to a single long pause), but is overall the most efficient (e.g. no need for write barriers). + +2. **Incremental GC.** +Garbage collection work is split up into multiple steps which are interleaved with the mutator, i.e. user code chunked into tasks. +Each step is a small chunk of work that is executed either as dedicated tasks between mutator tasks or, as needed, during mutator tasks. +Using incremental GC introduces the need for write barriers that record changes to the object graph so that a consistent state is observed and no objects are accidentally considered dead and reclaimed. +The incremental steps are followed by a smaller atomic pause to finalize garbage collection. +The smaller pause times, due to smaller chunks of work, helps with reducing jank. + +3. **Concurrent GC.** +This is the most common type of GC. +It builds on top of incremental GC and offloads much of the garbage collection work away from the mutator thread and on to background threads. +Using concurrent GC allows the mutator thread to spend less time on GC and more on the actual mutator. + +## Marking phase + +The marking phase consists of the following steps: + +1. Mark all objects in the root set. + +2. Mark all objects transitively reachable from the root set by calling `Trace()` methods defined on each object. + +3. Clear out all weak handles to unreachable objects and run weak callbacks. + +The marking phase can be executed atomically in a stop-the-world manner, in which all 3 steps are executed one after the other. + +Alternatively, it can also be executed incrementally/concurrently. +With incremental/concurrent marking, step 1 is executed in a short pause after which the mutator regains control. +Step 2 is repeatedly executed in an interleaved manner with the mutator. +When the GC is ready to finalize, i.e. step 2 is (almost) finished, another short pause is triggered in which step 2 is finished and step 3 is performed. + +To prevent a user-after-free (UAF) issues it is required for Oilpan to know about all edges in the object graph. +This means that all pointers except on-stack pointers must be wrapped with Oilpan's handles (i.e., Persistent<>, Member<>, WeakMember<>). +Raw pointers to on-heap objects create an edge that Oilpan cannot observe and cause UAF issues +Thus, raw pointers shall not be used to reference on-heap objects (except for raw pointers on native stacks). + +## Sweeping phase + +The sweeping phase consists of the following steps: + +1. Invoke pre-finalizers. +At this point, no destructors have been invoked and no memory has been reclaimed. +Pre-finalizers are allowed to access any other on-heap objects, even those that may get destructed. + +2. Sweeping invokes destructors of the dead (unreachable) objects and reclaims memory to be reused by future allocations. + +Assumptions should not be made about the order and the timing of their execution. +There is no guarantee on the order in which the destructors are invoked. +That's why destructors must not access any other on-heap objects (which might have already been destructed). +If some destructor unavoidably needs to access other on-heap objects, it will have to be converted to a pre-finalizer. +The pre-finalizer is allowed to access other on-heap objects. + +The mutator is resumed before all destructors have ran. +For example, imagine a case where X is a client of Y, and Y holds a list of clients. +If the code relies on X's destructor removing X from the list, there is a risk that Y iterates the list and calls some method of X which may touch other on-heap objects. +This causes a use-after-free. +Care must be taken to make sure that X is explicitly removed from the list before the mutator resumes its execution in a way that doesn't rely on X's destructor (e.g. a pre-finalizer). + +Similar to marking, sweeping can be executed in either an atomic stop-the-world manner or incrementally/concurrently. +With incremental/concurrent sweeping, step 2 is interleaved with mutator. +Incremental/concurrent sweeping can be atomically finalized in case it is needed to trigger another GC cycle. +Even with concurrent sweeping, destructors are guaranteed to run on the thread the object has been allocated on to preserve C++ semantics. + +Notes: + +* Weak processing runs only when the holder object of the WeakMember outlives the pointed object. +If the holder object and the pointed object die at the same time, weak processing doesn't run. +It is wrong to write code assuming that the weak processing always runs. + +* Pre-finalizers are heavy because the thread needs to scan all pre-finalizers at each sweeping phase to determine which pre-finalizers should be invoked (the thread needs to invoke pre-finalizers of dead objects). +Adding pre-finalizers to frequently created objects should be avoided. diff --git a/NativeScript/napi/v8/include_old/cppgc/allocation.h b/NativeScript/napi/v8/include_old/cppgc/allocation.h new file mode 100644 index 00000000..69883fb3 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/allocation.h @@ -0,0 +1,310 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_ALLOCATION_H_ +#define INCLUDE_CPPGC_ALLOCATION_H_ + +#include +#include +#include +#include +#include +#include + +#include "cppgc/custom-space.h" +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/gc-info.h" +#include "cppgc/type-traits.h" +#include "v8config.h" // NOLINT(build/include_directory) + +#if defined(__has_attribute) +#if __has_attribute(assume_aligned) +#define CPPGC_DEFAULT_ALIGNED \ + __attribute__((assume_aligned(api_constants::kDefaultAlignment))) +#define CPPGC_DOUBLE_WORD_ALIGNED \ + __attribute__((assume_aligned(2 * api_constants::kDefaultAlignment))) +#endif // __has_attribute(assume_aligned) +#endif // defined(__has_attribute) + +#if !defined(CPPGC_DEFAULT_ALIGNED) +#define CPPGC_DEFAULT_ALIGNED +#endif + +#if !defined(CPPGC_DOUBLE_WORD_ALIGNED) +#define CPPGC_DOUBLE_WORD_ALIGNED +#endif + +namespace cppgc { + +/** + * AllocationHandle is used to allocate garbage-collected objects. + */ +class AllocationHandle; + +namespace internal { + +// Similar to C++17 std::align_val_t; +enum class AlignVal : size_t {}; + +class V8_EXPORT MakeGarbageCollectedTraitInternal { + protected: + static inline void MarkObjectAsFullyConstructed(const void* payload) { + // See api_constants for an explanation of the constants. + std::atomic* atomic_mutable_bitfield = + reinterpret_cast*>( + const_cast(reinterpret_cast( + reinterpret_cast(payload) - + api_constants::kFullyConstructedBitFieldOffsetFromPayload))); + // It's safe to split use load+store here (instead of a read-modify-write + // operation), since it's guaranteed that this 16-bit bitfield is only + // modified by a single thread. This is cheaper in terms of code bloat (on + // ARM) and performance. + uint16_t value = atomic_mutable_bitfield->load(std::memory_order_relaxed); + value |= api_constants::kFullyConstructedBitMask; + atomic_mutable_bitfield->store(value, std::memory_order_release); + } + + // Dispatch based on compile-time information. + // + // Default implementation is for a custom space with >`kDefaultAlignment` byte + // alignment. + template + struct AllocationDispatcher final { + static void* Invoke(AllocationHandle& handle, size_t size) { + static_assert(std::is_base_of::value, + "Custom space must inherit from CustomSpaceBase."); + static_assert( + !CustomSpace::kSupportsCompaction, + "Custom spaces that support compaction do not support allocating " + "objects with non-default (i.e. word-sized) alignment."); + return MakeGarbageCollectedTraitInternal::Allocate( + handle, size, static_cast(alignment), + internal::GCInfoTrait::Index(), CustomSpace::kSpaceIndex); + } + }; + + // Fast path for regular allocations for the default space with + // `kDefaultAlignment` byte alignment. + template + struct AllocationDispatcher + final { + static void* Invoke(AllocationHandle& handle, size_t size) { + return MakeGarbageCollectedTraitInternal::Allocate( + handle, size, internal::GCInfoTrait::Index()); + } + }; + + // Default space with >`kDefaultAlignment` byte alignment. + template + struct AllocationDispatcher final { + static void* Invoke(AllocationHandle& handle, size_t size) { + return MakeGarbageCollectedTraitInternal::Allocate( + handle, size, static_cast(alignment), + internal::GCInfoTrait::Index()); + } + }; + + // Custom space with `kDefaultAlignment` byte alignment. + template + struct AllocationDispatcher + final { + static void* Invoke(AllocationHandle& handle, size_t size) { + static_assert(std::is_base_of::value, + "Custom space must inherit from CustomSpaceBase."); + return MakeGarbageCollectedTraitInternal::Allocate( + handle, size, internal::GCInfoTrait::Index(), + CustomSpace::kSpaceIndex); + } + }; + + private: + static void* CPPGC_DEFAULT_ALIGNED Allocate(cppgc::AllocationHandle&, size_t, + GCInfoIndex); + static void* CPPGC_DOUBLE_WORD_ALIGNED Allocate(cppgc::AllocationHandle&, + size_t, AlignVal, + GCInfoIndex); + static void* CPPGC_DEFAULT_ALIGNED Allocate(cppgc::AllocationHandle&, size_t, + GCInfoIndex, CustomSpaceIndex); + static void* CPPGC_DOUBLE_WORD_ALIGNED Allocate(cppgc::AllocationHandle&, + size_t, AlignVal, GCInfoIndex, + CustomSpaceIndex); + + friend class HeapObjectHeader; +}; + +} // namespace internal + +/** + * Base trait that provides utilities for advancers users that have custom + * allocation needs (e.g., overriding size). It's expected that users override + * MakeGarbageCollectedTrait (see below) and inherit from + * MakeGarbageCollectedTraitBase and make use of the low-level primitives + * offered to allocate and construct an object. + */ +template +class MakeGarbageCollectedTraitBase + : private internal::MakeGarbageCollectedTraitInternal { + private: + static_assert(internal::IsGarbageCollectedType::value, + "T needs to be a garbage collected object"); + static_assert(!IsGarbageCollectedWithMixinTypeV || + sizeof(T) <= + internal::api_constants::kLargeObjectSizeThreshold, + "GarbageCollectedMixin may not be a large object"); + + protected: + /** + * Allocates memory for an object of type T. + * + * \param handle AllocationHandle identifying the heap to allocate the object + * on. + * \param size The size that should be reserved for the object. + * \returns the memory to construct an object of type T on. + */ + V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) { + static_assert( + std::is_base_of::value, + "U of GarbageCollected must be a base of T. Check " + "GarbageCollected base class inheritance."); + static constexpr size_t kWantedAlignment = + alignof(T) < internal::api_constants::kDefaultAlignment + ? internal::api_constants::kDefaultAlignment + : alignof(T); + static_assert( + kWantedAlignment <= internal::api_constants::kMaxSupportedAlignment, + "Requested alignment larger than alignof(std::max_align_t) bytes. " + "Please file a bug to possibly get this restriction lifted."); + return AllocationDispatcher< + typename internal::GCInfoFolding< + T, typename T::ParentMostGarbageCollectedType>::ResultType, + typename SpaceTrait::Space, kWantedAlignment>::Invoke(handle, size); + } + + /** + * Marks an object as fully constructed, resulting in precise handling by the + * garbage collector. + * + * \param payload The base pointer the object is allocated at. + */ + V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) { + internal::MakeGarbageCollectedTraitInternal::MarkObjectAsFullyConstructed( + payload); + } +}; + +/** + * Passed to MakeGarbageCollected to specify how many bytes should be appended + * to the allocated object. + * + * Example: + * \code + * class InlinedArray final : public GarbageCollected { + * public: + * explicit InlinedArray(size_t bytes) : size(bytes), byte_array(this + 1) {} + * void Trace(Visitor*) const {} + + * size_t size; + * char* byte_array; + * }; + * + * auto* inlined_array = MakeGarbageCollectedbyte_array[i]); + * } + * \endcode + */ +struct AdditionalBytes { + constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {} + const size_t value; +}; + +/** + * Default trait class that specifies how to construct an object of type T. + * Advanced users may override how an object is constructed using the utilities + * that are provided through MakeGarbageCollectedTraitBase. + * + * Any trait overriding construction must + * - allocate through `MakeGarbageCollectedTraitBase::Allocate`; + * - mark the object as fully constructed using + * `MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed`; + */ +template +class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase { + public: + template + static T* Call(AllocationHandle& handle, Args&&... args) { + void* memory = + MakeGarbageCollectedTraitBase::Allocate(handle, sizeof(T)); + T* object = ::new (memory) T(std::forward(args)...); + MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed(object); + return object; + } + + template + static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes, + Args&&... args) { + void* memory = MakeGarbageCollectedTraitBase::Allocate( + handle, sizeof(T) + additional_bytes.value); + T* object = ::new (memory) T(std::forward(args)...); + MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed(object); + return object; + } +}; + +/** + * Allows users to specify a post-construction callback for specific types. The + * callback is invoked on the instance of type T right after it has been + * constructed. This can be useful when the callback requires a + * fully-constructed object to be able to dispatch to virtual methods. + */ +template +struct PostConstructionCallbackTrait { + static void Call(T*) {} +}; + +/** + * Constructs a managed object of type T where T transitively inherits from + * GarbageCollected. + * + * \param args List of arguments with which an instance of T will be + * constructed. + * \returns an instance of type T. + */ +template +V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) { + T* object = + MakeGarbageCollectedTrait::Call(handle, std::forward(args)...); + PostConstructionCallbackTrait::Call(object); + return object; +} + +/** + * Constructs a managed object of type T where T transitively inherits from + * GarbageCollected. Created objects will have additional bytes appended to + * it. Allocated memory would suffice for `sizeof(T) + additional_bytes`. + * + * \param additional_bytes Denotes how many bytes to append to T. + * \param args List of arguments with which an instance of T will be + * constructed. + * \returns an instance of type T. + */ +template +V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, + AdditionalBytes additional_bytes, + Args&&... args) { + T* object = MakeGarbageCollectedTrait::Call(handle, additional_bytes, + std::forward(args)...); + PostConstructionCallbackTrait::Call(object); + return object; +} + +} // namespace cppgc + +#undef CPPGC_DEFAULT_ALIGNED +#undef CPPGC_DOUBLE_WORD_ALIGNED + +#endif // INCLUDE_CPPGC_ALLOCATION_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/common.h b/NativeScript/napi/v8/include_old/cppgc/common.h new file mode 100644 index 00000000..96103836 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/common.h @@ -0,0 +1,28 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_COMMON_H_ +#define INCLUDE_CPPGC_COMMON_H_ + +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +/** + * Indicator for the stack state of the embedder. + */ +enum class EmbedderStackState { + /** + * Stack may contain interesting heap pointers. + */ + kMayContainHeapPointers, + /** + * Stack does not contain any interesting heap pointers. + */ + kNoHeapPointers, +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_COMMON_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/cross-thread-persistent.h b/NativeScript/napi/v8/include_old/cppgc/cross-thread-persistent.h new file mode 100644 index 00000000..a5f8bac0 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/cross-thread-persistent.h @@ -0,0 +1,466 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_ +#define INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_ + +#include + +#include "cppgc/internal/persistent-node.h" +#include "cppgc/internal/pointer-policies.h" +#include "cppgc/persistent.h" +#include "cppgc/visitor.h" + +namespace cppgc { +namespace internal { + +// Wrapper around PersistentBase that allows accessing poisoned memory when +// using ASAN. This is needed as the GC of the heap that owns the value +// of a CTP, may clear it (heap termination, weakness) while the object +// holding the CTP may be poisoned as itself may be deemed dead. +class CrossThreadPersistentBase : public PersistentBase { + public: + CrossThreadPersistentBase() = default; + explicit CrossThreadPersistentBase(const void* raw) : PersistentBase(raw) {} + + V8_CLANG_NO_SANITIZE("address") const void* GetValueFromGC() const { + return raw_; + } + + V8_CLANG_NO_SANITIZE("address") + PersistentNode* GetNodeFromGC() const { return node_; } + + V8_CLANG_NO_SANITIZE("address") + void ClearFromGC() const { + raw_ = nullptr; + SetNodeSafe(nullptr); + } + + // GetNodeSafe() can be used for a thread-safe IsValid() check in a + // double-checked locking pattern. See ~BasicCrossThreadPersistent. + PersistentNode* GetNodeSafe() const { + return reinterpret_cast*>(&node_)->load( + std::memory_order_acquire); + } + + // The GC writes using SetNodeSafe() while holding the lock. + V8_CLANG_NO_SANITIZE("address") + void SetNodeSafe(PersistentNode* value) const { +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define V8_IS_ASAN 1 +#endif +#endif + +#ifdef V8_IS_ASAN + __atomic_store(&node_, &value, __ATOMIC_RELEASE); +#else // !V8_IS_ASAN + // Non-ASAN builds can use atomics. This also covers MSVC which does not + // have the __atomic_store intrinsic. + reinterpret_cast*>(&node_)->store( + value, std::memory_order_release); +#endif // !V8_IS_ASAN + +#undef V8_IS_ASAN + } +}; + +template +class BasicCrossThreadPersistent final : public CrossThreadPersistentBase, + public LocationPolicy, + private WeaknessPolicy, + private CheckingPolicy { + public: + using typename WeaknessPolicy::IsStrongPersistent; + using PointeeType = T; + + ~BasicCrossThreadPersistent() { + // This implements fast path for destroying empty/sentinel. + // + // Simplified version of `AssignUnsafe()` to allow calling without a + // complete type `T`. Uses double-checked locking with a simple thread-safe + // check for a valid handle based on a node. + if (GetNodeSafe()) { + PersistentRegionLock guard; + const void* old_value = GetValue(); + // The fast path check (GetNodeSafe()) does not acquire the lock. Recheck + // validity while holding the lock to ensure the reference has not been + // cleared. + if (IsValid(old_value)) { + CrossThreadPersistentRegion& region = + this->GetPersistentRegion(old_value); + region.FreeNode(GetNode()); + SetNode(nullptr); + } else { + CPPGC_DCHECK(!GetNode()); + } + } + // No need to call SetValue() as the handle is not used anymore. This can + // leave behind stale sentinel values but will always destroy the underlying + // node. + } + + BasicCrossThreadPersistent( + const SourceLocation& loc = SourceLocation::Current()) + : LocationPolicy(loc) {} + + BasicCrossThreadPersistent( + std::nullptr_t, const SourceLocation& loc = SourceLocation::Current()) + : LocationPolicy(loc) {} + + BasicCrossThreadPersistent( + SentinelPointer s, const SourceLocation& loc = SourceLocation::Current()) + : CrossThreadPersistentBase(s), LocationPolicy(loc) {} + + BasicCrossThreadPersistent( + T* raw, const SourceLocation& loc = SourceLocation::Current()) + : CrossThreadPersistentBase(raw), LocationPolicy(loc) { + if (!IsValid(raw)) return; + PersistentRegionLock guard; + CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw); + SetNode(region.AllocateNode(this, &TraceAsRoot)); + this->CheckPointer(raw); + } + + class UnsafeCtorTag { + private: + UnsafeCtorTag() = default; + template + friend class BasicCrossThreadPersistent; + }; + + BasicCrossThreadPersistent( + UnsafeCtorTag, T* raw, + const SourceLocation& loc = SourceLocation::Current()) + : CrossThreadPersistentBase(raw), LocationPolicy(loc) { + if (!IsValid(raw)) return; + CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw); + SetNode(region.AllocateNode(this, &TraceAsRoot)); + this->CheckPointer(raw); + } + + BasicCrossThreadPersistent( + T& raw, const SourceLocation& loc = SourceLocation::Current()) + : BasicCrossThreadPersistent(&raw, loc) {} + + template ::value>> + BasicCrossThreadPersistent( + internal::BasicMember + member, + const SourceLocation& loc = SourceLocation::Current()) + : BasicCrossThreadPersistent(member.Get(), loc) {} + + BasicCrossThreadPersistent( + const BasicCrossThreadPersistent& other, + const SourceLocation& loc = SourceLocation::Current()) + : BasicCrossThreadPersistent(loc) { + // Invoke operator=. + *this = other; + } + + // Heterogeneous ctor. + template ::value>> + BasicCrossThreadPersistent( + const BasicCrossThreadPersistent& other, + const SourceLocation& loc = SourceLocation::Current()) + : BasicCrossThreadPersistent(loc) { + *this = other; + } + + BasicCrossThreadPersistent( + BasicCrossThreadPersistent&& other, + const SourceLocation& loc = SourceLocation::Current()) noexcept { + // Invoke operator=. + *this = std::move(other); + } + + BasicCrossThreadPersistent& operator=( + const BasicCrossThreadPersistent& other) { + PersistentRegionLock guard; + AssignSafe(guard, other.Get()); + return *this; + } + + template ::value>> + BasicCrossThreadPersistent& operator=( + const BasicCrossThreadPersistent& other) { + PersistentRegionLock guard; + AssignSafe(guard, other.Get()); + return *this; + } + + BasicCrossThreadPersistent& operator=(BasicCrossThreadPersistent&& other) { + if (this == &other) return *this; + Clear(); + PersistentRegionLock guard; + PersistentBase::operator=(std::move(other)); + LocationPolicy::operator=(std::move(other)); + if (!IsValid(GetValue())) return *this; + GetNode()->UpdateOwner(this); + other.SetValue(nullptr); + other.SetNode(nullptr); + this->CheckPointer(Get()); + return *this; + } + + /** + * Assigns a raw pointer. + * + * Note: **Not thread-safe.** + */ + BasicCrossThreadPersistent& operator=(T* other) { + AssignUnsafe(other); + return *this; + } + + // Assignment from member. + template ::value>> + BasicCrossThreadPersistent& operator=( + internal::BasicMember + member) { + return operator=(member.Get()); + } + + /** + * Assigns a nullptr. + * + * \returns the handle. + */ + BasicCrossThreadPersistent& operator=(std::nullptr_t) { + Clear(); + return *this; + } + + /** + * Assigns the sentinel pointer. + * + * \returns the handle. + */ + BasicCrossThreadPersistent& operator=(SentinelPointer s) { + PersistentRegionLock guard; + AssignSafe(guard, s); + return *this; + } + + /** + * Returns a pointer to the stored object. + * + * Note: **Not thread-safe.** + * + * \returns a pointer to the stored object. + */ + // CFI cast exemption to allow passing SentinelPointer through T* and support + // heterogeneous assignments between different Member and Persistent handles + // based on their actual types. + V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { + return static_cast(const_cast(GetValue())); + } + + /** + * Clears the stored object. + */ + void Clear() { + PersistentRegionLock guard; + AssignSafe(guard, nullptr); + } + + /** + * Returns a pointer to the stored object and releases it. + * + * Note: **Not thread-safe.** + * + * \returns a pointer to the stored object. + */ + T* Release() { + T* result = Get(); + Clear(); + return result; + } + + /** + * Conversio to boolean. + * + * Note: **Not thread-safe.** + * + * \returns true if an actual object has been stored and false otherwise. + */ + explicit operator bool() const { return Get(); } + + /** + * Conversion to object of type T. + * + * Note: **Not thread-safe.** + * + * \returns the object. + */ + operator T*() const { return Get(); } + + /** + * Dereferences the stored object. + * + * Note: **Not thread-safe.** + */ + T* operator->() const { return Get(); } + T& operator*() const { return *Get(); } + + template + BasicCrossThreadPersistent + To() const { + using OtherBasicCrossThreadPersistent = + BasicCrossThreadPersistent; + PersistentRegionLock guard; + return OtherBasicCrossThreadPersistent( + typename OtherBasicCrossThreadPersistent::UnsafeCtorTag(), + static_cast(Get())); + } + + template ::IsStrongPersistent::value>::type> + BasicCrossThreadPersistent + Lock() const { + return BasicCrossThreadPersistent< + U, internal::StrongCrossThreadPersistentPolicy>(*this); + } + + private: + static bool IsValid(const void* ptr) { + return ptr && ptr != kSentinelPointer; + } + + static void TraceAsRoot(RootVisitor& root_visitor, const void* ptr) { + root_visitor.Trace(*static_cast(ptr)); + } + + void AssignUnsafe(T* ptr) { + const void* old_value = GetValue(); + if (IsValid(old_value)) { + PersistentRegionLock guard; + old_value = GetValue(); + // The fast path check (IsValid()) does not acquire the lock. Reload + // the value to ensure the reference has not been cleared. + if (IsValid(old_value)) { + CrossThreadPersistentRegion& region = + this->GetPersistentRegion(old_value); + if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) { + SetValue(ptr); + this->CheckPointer(ptr); + return; + } + region.FreeNode(GetNode()); + SetNode(nullptr); + } else { + CPPGC_DCHECK(!GetNode()); + } + } + SetValue(ptr); + if (!IsValid(ptr)) return; + PersistentRegionLock guard; + SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &TraceAsRoot)); + this->CheckPointer(ptr); + } + + void AssignSafe(PersistentRegionLock&, T* ptr) { + PersistentRegionLock::AssertLocked(); + const void* old_value = GetValue(); + if (IsValid(old_value)) { + CrossThreadPersistentRegion& region = + this->GetPersistentRegion(old_value); + if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) { + SetValue(ptr); + this->CheckPointer(ptr); + return; + } + region.FreeNode(GetNode()); + SetNode(nullptr); + } + SetValue(ptr); + if (!IsValid(ptr)) return; + SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &TraceAsRoot)); + this->CheckPointer(ptr); + } + + void ClearFromGC() const { + if (IsValid(GetValueFromGC())) { + WeaknessPolicy::GetPersistentRegion(GetValueFromGC()) + .FreeNode(GetNodeFromGC()); + CrossThreadPersistentBase::ClearFromGC(); + } + } + + // See Get() for details. + V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") + T* GetFromGC() const { + return static_cast(const_cast(GetValueFromGC())); + } + + friend class internal::RootVisitor; +}; + +template +struct IsWeak< + BasicCrossThreadPersistent> + : std::true_type {}; + +} // namespace internal + +namespace subtle { + +/** + * **DO NOT USE: Has known caveats, see below.** + * + * CrossThreadPersistent allows retaining objects from threads other than the + * thread the owning heap is operating on. + * + * Known caveats: + * - Does not protect the heap owning an object from terminating. + * - Reaching transitively through the graph is unsupported as objects may be + * moved concurrently on the thread owning the object. + */ +template +using CrossThreadPersistent = internal::BasicCrossThreadPersistent< + T, internal::StrongCrossThreadPersistentPolicy>; + +/** + * **DO NOT USE: Has known caveats, see below.** + * + * CrossThreadPersistent allows weakly retaining objects from threads other than + * the thread the owning heap is operating on. + * + * Known caveats: + * - Does not protect the heap owning an object from terminating. + * - Reaching transitively through the graph is unsupported as objects may be + * moved concurrently on the thread owning the object. + */ +template +using WeakCrossThreadPersistent = internal::BasicCrossThreadPersistent< + T, internal::WeakCrossThreadPersistentPolicy>; + +} // namespace subtle +} // namespace cppgc + +#endif // INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/custom-space.h b/NativeScript/napi/v8/include_old/cppgc/custom-space.h new file mode 100644 index 00000000..757c4fde --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/custom-space.h @@ -0,0 +1,97 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_CUSTOM_SPACE_H_ +#define INCLUDE_CPPGC_CUSTOM_SPACE_H_ + +#include + +namespace cppgc { + +/** + * Index identifying a custom space. + */ +struct CustomSpaceIndex { + constexpr CustomSpaceIndex(size_t value) : value(value) {} // NOLINT + size_t value; +}; + +/** + * Top-level base class for custom spaces. Users must inherit from CustomSpace + * below. + */ +class CustomSpaceBase { + public: + virtual ~CustomSpaceBase() = default; + virtual CustomSpaceIndex GetCustomSpaceIndex() const = 0; + virtual bool IsCompactable() const = 0; +}; + +/** + * Base class custom spaces should directly inherit from. The class inheriting + * from `CustomSpace` must define `kSpaceIndex` as unique space index. These + * indices need for form a sequence starting at 0. + * + * Example: + * \code + * class CustomSpace1 : public CustomSpace { + * public: + * static constexpr CustomSpaceIndex kSpaceIndex = 0; + * }; + * class CustomSpace2 : public CustomSpace { + * public: + * static constexpr CustomSpaceIndex kSpaceIndex = 1; + * }; + * \endcode + */ +template +class CustomSpace : public CustomSpaceBase { + public: + /** + * Compaction is only supported on spaces that manually manage slots + * recording. + */ + static constexpr bool kSupportsCompaction = false; + + CustomSpaceIndex GetCustomSpaceIndex() const final { + return ConcreteCustomSpace::kSpaceIndex; + } + bool IsCompactable() const final { + return ConcreteCustomSpace::kSupportsCompaction; + } +}; + +/** + * User-overridable trait that allows pinning types to custom spaces. + */ +template +struct SpaceTrait { + using Space = void; +}; + +namespace internal { + +template +struct IsAllocatedOnCompactableSpaceImpl { + static constexpr bool value = CustomSpace::kSupportsCompaction; +}; + +template <> +struct IsAllocatedOnCompactableSpaceImpl { + // Non-custom spaces are by default not compactable. + static constexpr bool value = false; +}; + +template +struct IsAllocatedOnCompactableSpace { + public: + static constexpr bool value = + IsAllocatedOnCompactableSpaceImpl::Space>::value; +}; + +} // namespace internal + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_CUSTOM_SPACE_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/default-platform.h b/NativeScript/napi/v8/include_old/cppgc/default-platform.h new file mode 100644 index 00000000..a27871cc --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/default-platform.h @@ -0,0 +1,67 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_DEFAULT_PLATFORM_H_ +#define INCLUDE_CPPGC_DEFAULT_PLATFORM_H_ + +#include + +#include "cppgc/platform.h" +#include "libplatform/libplatform.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +/** + * Platform provided by cppgc. Uses V8's DefaultPlatform provided by + * libplatform internally. Exception: `GetForegroundTaskRunner()`, see below. + */ +class V8_EXPORT DefaultPlatform : public Platform { + public: + using IdleTaskSupport = v8::platform::IdleTaskSupport; + explicit DefaultPlatform( + int thread_pool_size = 0, + IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled, + std::unique_ptr tracing_controller = {}) + : v8_platform_(v8::platform::NewDefaultPlatform( + thread_pool_size, idle_task_support, + v8::platform::InProcessStackDumping::kDisabled, + std::move(tracing_controller))) {} + + cppgc::PageAllocator* GetPageAllocator() override { + return v8_platform_->GetPageAllocator(); + } + + double MonotonicallyIncreasingTime() override { + return v8_platform_->MonotonicallyIncreasingTime(); + } + + std::shared_ptr GetForegroundTaskRunner() override { + // V8's default platform creates a new task runner when passed the + // `v8::Isolate` pointer the first time. For non-default platforms this will + // require getting the appropriate task runner. + return v8_platform_->GetForegroundTaskRunner(kNoIsolate); + } + + std::unique_ptr PostJob( + cppgc::TaskPriority priority, + std::unique_ptr job_task) override { + return v8_platform_->PostJob(priority, std::move(job_task)); + } + + TracingController* GetTracingController() override { + return v8_platform_->GetTracingController(); + } + + v8::Platform* GetV8Platform() const { return v8_platform_.get(); } + + protected: + static constexpr v8::Isolate* kNoIsolate = nullptr; + + std::unique_ptr v8_platform_; +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_DEFAULT_PLATFORM_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/ephemeron-pair.h b/NativeScript/napi/v8/include_old/cppgc/ephemeron-pair.h new file mode 100644 index 00000000..e16cf1f0 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/ephemeron-pair.h @@ -0,0 +1,30 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_EPHEMERON_PAIR_H_ +#define INCLUDE_CPPGC_EPHEMERON_PAIR_H_ + +#include "cppgc/liveness-broker.h" +#include "cppgc/member.h" + +namespace cppgc { + +/** + * An ephemeron pair is used to conditionally retain an object. + * The `value` will be kept alive only if the `key` is alive. + */ +template +struct EphemeronPair { + EphemeronPair(K* k, V* v) : key(k), value(v) {} + WeakMember key; + Member value; + + void ClearValueIfKeyIsDead(const LivenessBroker& broker) { + if (!broker.IsHeapObjectAlive(key)) value = nullptr; + } +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_EPHEMERON_PAIR_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/explicit-management.h b/NativeScript/napi/v8/include_old/cppgc/explicit-management.h new file mode 100644 index 00000000..0290328d --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/explicit-management.h @@ -0,0 +1,100 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_ +#define INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_ + +#include + +#include "cppgc/allocation.h" +#include "cppgc/internal/logging.h" +#include "cppgc/type-traits.h" + +namespace cppgc { + +class HeapHandle; + +namespace subtle { + +template +void FreeUnreferencedObject(HeapHandle& heap_handle, T& object); +template +bool Resize(T& object, AdditionalBytes additional_bytes); + +} // namespace subtle + +namespace internal { + +class ExplicitManagementImpl final { + private: + V8_EXPORT static void FreeUnreferencedObject(HeapHandle&, void*); + V8_EXPORT static bool Resize(void*, size_t); + + template + friend void subtle::FreeUnreferencedObject(HeapHandle&, T&); + template + friend bool subtle::Resize(T&, AdditionalBytes); +}; +} // namespace internal + +namespace subtle { + +/** + * Informs the garbage collector that `object` can be immediately reclaimed. The + * destructor may not be invoked immediately but only on next garbage + * collection. + * + * It is up to the embedder to guarantee that no other object holds a reference + * to `object` after calling `FreeUnreferencedObject()`. In case such a + * reference exists, it's use results in a use-after-free. + * + * To aid in using the API, `FreeUnreferencedObject()` may be called from + * destructors on objects that would be reclaimed in the same garbage collection + * cycle. + * + * \param heap_handle The corresponding heap. + * \param object Reference to an object that is of type `GarbageCollected` and + * should be immediately reclaimed. + */ +template +void FreeUnreferencedObject(HeapHandle& heap_handle, T& object) { + static_assert(IsGarbageCollectedTypeV, + "Object must be of type GarbageCollected."); + internal::ExplicitManagementImpl::FreeUnreferencedObject(heap_handle, + &object); +} + +/** + * Tries to resize `object` of type `T` with additional bytes on top of + * sizeof(T). Resizing is only useful with trailing inlined storage, see e.g. + * `MakeGarbageCollected(AllocationHandle&, AdditionalBytes)`. + * + * `Resize()` performs growing or shrinking as needed and may skip the operation + * for internal reasons, see return value. + * + * It is up to the embedder to guarantee that in case of shrinking a larger + * object down, the reclaimed area is not used anymore. Any subsequent use + * results in a use-after-free. + * + * The `object` must be live when calling `Resize()`. + * + * \param object Reference to an object that is of type `GarbageCollected` and + * should be resized. + * \param additional_bytes Bytes in addition to sizeof(T) that the object should + * provide. + * \returns true when the operation was successful and the result can be relied + * on, and false otherwise. + */ +template +bool Resize(T& object, AdditionalBytes additional_bytes) { + static_assert(IsGarbageCollectedTypeV, + "Object must be of type GarbageCollected."); + return internal::ExplicitManagementImpl::Resize( + &object, sizeof(T) + additional_bytes.value); +} + +} // namespace subtle +} // namespace cppgc + +#endif // INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/garbage-collected.h b/NativeScript/napi/v8/include_old/cppgc/garbage-collected.h new file mode 100644 index 00000000..6737c8be --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/garbage-collected.h @@ -0,0 +1,106 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_GARBAGE_COLLECTED_H_ +#define INCLUDE_CPPGC_GARBAGE_COLLECTED_H_ + +#include "cppgc/internal/api-constants.h" +#include "cppgc/platform.h" +#include "cppgc/trace-trait.h" +#include "cppgc/type-traits.h" + +namespace cppgc { + +class Visitor; + +/** + * Base class for managed objects. Only descendent types of `GarbageCollected` + * can be constructed using `MakeGarbageCollected()`. Must be inherited from as + * left-most base class. + * + * Types inheriting from GarbageCollected must provide a method of + * signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed + * pointers to the visitor and delegates to garbage-collected base classes. + * The method must be virtual if the type is not directly a child of + * GarbageCollected and marked as final. + * + * \code + * // Example using final class. + * class FinalType final : public GarbageCollected { + * public: + * void Trace(cppgc::Visitor* visitor) const { + * // Dispatch using visitor->Trace(...); + * } + * }; + * + * // Example using non-final base class. + * class NonFinalBase : public GarbageCollected { + * public: + * virtual void Trace(cppgc::Visitor*) const {} + * }; + * + * class FinalChild final : public NonFinalBase { + * public: + * void Trace(cppgc::Visitor* visitor) const final { + * // Dispatch using visitor->Trace(...); + * NonFinalBase::Trace(visitor); + * } + * }; + * \endcode + */ +template +class GarbageCollected { + public: + using IsGarbageCollectedTypeMarker = void; + using ParentMostGarbageCollectedType = T; + + // Must use MakeGarbageCollected. + void* operator new(size_t) = delete; + void* operator new[](size_t) = delete; + // The garbage collector is taking care of reclaiming the object. Also, + // virtual destructor requires an unambiguous, accessible 'operator delete'. + void operator delete(void*) { +#ifdef V8_ENABLE_CHECKS + internal::Fatal( + "Manually deleting a garbage collected object is not allowed"); +#endif // V8_ENABLE_CHECKS + } + void operator delete[](void*) = delete; + + protected: + GarbageCollected() = default; +}; + +/** + * Base class for managed mixin objects. Such objects cannot be constructed + * directly but must be mixed into the inheritance hierarchy of a + * GarbageCollected object. + * + * Types inheriting from GarbageCollectedMixin must override a virtual method + * of signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed + * pointers to the visitor and delegates to base classes. + * + * \code + * class Mixin : public GarbageCollectedMixin { + * public: + * void Trace(cppgc::Visitor* visitor) const override { + * // Dispatch using visitor->Trace(...); + * } + * }; + * \endcode + */ +class GarbageCollectedMixin { + public: + using IsGarbageCollectedMixinTypeMarker = void; + + /** + * This Trace method must be overriden by objects inheriting from + * GarbageCollectedMixin. + */ + virtual void Trace(cppgc::Visitor*) const {} +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_GARBAGE_COLLECTED_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/heap-consistency.h b/NativeScript/napi/v8/include_old/cppgc/heap-consistency.h new file mode 100644 index 00000000..eb7fdaee --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/heap-consistency.h @@ -0,0 +1,309 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_HEAP_CONSISTENCY_H_ +#define INCLUDE_CPPGC_HEAP_CONSISTENCY_H_ + +#include + +#include "cppgc/internal/write-barrier.h" +#include "cppgc/macros.h" +#include "cppgc/member.h" +#include "cppgc/trace-trait.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +class HeapHandle; + +namespace subtle { + +/** + * **DO NOT USE: Use the appropriate managed types.** + * + * Consistency helpers that aid in maintaining a consistent internal state of + * the garbage collector. + */ +class HeapConsistency final { + public: + using WriteBarrierParams = internal::WriteBarrier::Params; + using WriteBarrierType = internal::WriteBarrier::Type; + + /** + * Gets the required write barrier type for a specific write. + * + * \param slot Slot containing the pointer to the object. The slot itself + * must reside in an object that has been allocated using + * `MakeGarbageCollected()`. + * \param value The pointer to the object. May be an interior pointer to an + * interface of the actual object. + * \param params Parameters that may be used for actual write barrier calls. + * Only filled if return value indicates that a write barrier is needed. The + * contents of the `params` are an implementation detail. + * \returns whether a write barrier is needed and which barrier to invoke. + */ + static V8_INLINE WriteBarrierType GetWriteBarrierType( + const void* slot, const void* value, WriteBarrierParams& params) { + return internal::WriteBarrier::GetWriteBarrierType(slot, value, params); + } + + /** + * Gets the required write barrier type for a specific write. This override is + * only used for all the BasicMember types. + * + * \param slot Slot containing the pointer to the object. The slot itself + * must reside in an object that has been allocated using + * `MakeGarbageCollected()`. + * \param value The pointer to the object held via `BasicMember`. + * \param params Parameters that may be used for actual write barrier calls. + * Only filled if return value indicates that a write barrier is needed. The + * contents of the `params` are an implementation detail. + * \returns whether a write barrier is needed and which barrier to invoke. + */ + template + static V8_INLINE WriteBarrierType GetWriteBarrierType( + const internal::BasicMember& value, + WriteBarrierParams& params) { + return internal::WriteBarrier::GetWriteBarrierType( + value.GetRawSlot(), value.GetRawStorage(), params); + } + + /** + * Gets the required write barrier type for a specific write. + * + * \param slot Slot to some part of an object. The object must not necessarily + have been allocated using `MakeGarbageCollected()` but can also live + off-heap or on stack. + * \param params Parameters that may be used for actual write barrier calls. + * Only filled if return value indicates that a write barrier is needed. The + * contents of the `params` are an implementation detail. + * \param callback Callback returning the corresponding heap handle. The + * callback is only invoked if the heap cannot otherwise be figured out. The + * callback must not allocate. + * \returns whether a write barrier is needed and which barrier to invoke. + */ + template + static V8_INLINE WriteBarrierType + GetWriteBarrierType(const void* slot, WriteBarrierParams& params, + HeapHandleCallback callback) { + return internal::WriteBarrier::GetWriteBarrierType(slot, params, callback); + } + + /** + * Gets the required write barrier type for a specific write. + * This version is meant to be used in conjunction with with a marking write + * barrier barrier which doesn't consider the slot. + * + * \param value The pointer to the object. May be an interior pointer to an + * interface of the actual object. + * \param params Parameters that may be used for actual write barrier calls. + * Only filled if return value indicates that a write barrier is needed. The + * contents of the `params` are an implementation detail. + * \returns whether a write barrier is needed and which barrier to invoke. + */ + static V8_INLINE WriteBarrierType + GetWriteBarrierType(const void* value, WriteBarrierParams& params) { + return internal::WriteBarrier::GetWriteBarrierType(value, params); + } + + /** + * Conservative Dijkstra-style write barrier that processes an object if it + * has not yet been processed. + * + * \param params The parameters retrieved from `GetWriteBarrierType()`. + * \param object The pointer to the object. May be an interior pointer to a + * an interface of the actual object. + */ + static V8_INLINE void DijkstraWriteBarrier(const WriteBarrierParams& params, + const void* object) { + internal::WriteBarrier::DijkstraMarkingBarrier(params, object); + } + + /** + * Conservative Dijkstra-style write barrier that processes a range of + * elements if they have not yet been processed. + * + * \param params The parameters retrieved from `GetWriteBarrierType()`. + * \param first_element Pointer to the first element that should be processed. + * The slot itself must reside in an object that has been allocated using + * `MakeGarbageCollected()`. + * \param element_size Size of the element in bytes. + * \param number_of_elements Number of elements that should be processed, + * starting with `first_element`. + * \param trace_callback The trace callback that should be invoked for each + * element if necessary. + */ + static V8_INLINE void DijkstraWriteBarrierRange( + const WriteBarrierParams& params, const void* first_element, + size_t element_size, size_t number_of_elements, + TraceCallback trace_callback) { + internal::WriteBarrier::DijkstraMarkingBarrierRange( + params, first_element, element_size, number_of_elements, + trace_callback); + } + + /** + * Steele-style write barrier that re-processes an object if it has already + * been processed. + * + * \param params The parameters retrieved from `GetWriteBarrierType()`. + * \param object The pointer to the object which must point to an object that + * has been allocated using `MakeGarbageCollected()`. Interior pointers are + * not supported. + */ + static V8_INLINE void SteeleWriteBarrier(const WriteBarrierParams& params, + const void* object) { + internal::WriteBarrier::SteeleMarkingBarrier(params, object); + } + + /** + * Generational barrier for maintaining consistency when running with multiple + * generations. + * + * \param params The parameters retrieved from `GetWriteBarrierType()`. + * \param slot Slot containing the pointer to the object. The slot itself + * must reside in an object that has been allocated using + * `MakeGarbageCollected()`. + */ + static V8_INLINE void GenerationalBarrier(const WriteBarrierParams& params, + const void* slot) { + internal::WriteBarrier::GenerationalBarrier< + internal::WriteBarrier::GenerationalBarrierType::kPreciseSlot>(params, + slot); + } + + /** + * Generational barrier for maintaining consistency when running with multiple + * generations. This version is used when slot contains uncompressed pointer. + * + * \param params The parameters retrieved from `GetWriteBarrierType()`. + * \param slot Uncompressed slot containing the direct pointer to the object. + * The slot itself must reside in an object that has been allocated using + * `MakeGarbageCollected()`. + */ + static V8_INLINE void GenerationalBarrierForUncompressedSlot( + const WriteBarrierParams& params, const void* uncompressed_slot) { + internal::WriteBarrier::GenerationalBarrier< + internal::WriteBarrier::GenerationalBarrierType:: + kPreciseUncompressedSlot>(params, uncompressed_slot); + } + + /** + * Generational barrier for source object that may contain outgoing pointers + * to objects in young generation. + * + * \param params The parameters retrieved from `GetWriteBarrierType()`. + * \param inner_pointer Pointer to the source object. + */ + static V8_INLINE void GenerationalBarrierForSourceObject( + const WriteBarrierParams& params, const void* inner_pointer) { + internal::WriteBarrier::GenerationalBarrier< + internal::WriteBarrier::GenerationalBarrierType::kImpreciseSlot>( + params, inner_pointer); + } + + private: + HeapConsistency() = delete; +}; + +/** + * Disallows garbage collection finalizations. Any garbage collection triggers + * result in a crash when in this scope. + * + * Note that the garbage collector already covers paths that can lead to garbage + * collections, so user code does not require checking + * `IsGarbageCollectionAllowed()` before allocations. + */ +class V8_EXPORT V8_NODISCARD DisallowGarbageCollectionScope final { + CPPGC_STACK_ALLOCATED(); + + public: + /** + * \returns whether garbage collections are currently allowed. + */ + static bool IsGarbageCollectionAllowed(HeapHandle& heap_handle); + + /** + * Enters a disallow garbage collection scope. Must be paired with `Leave()`. + * Prefer a scope instance of `DisallowGarbageCollectionScope`. + * + * \param heap_handle The corresponding heap. + */ + static void Enter(HeapHandle& heap_handle); + + /** + * Leaves a disallow garbage collection scope. Must be paired with `Enter()`. + * Prefer a scope instance of `DisallowGarbageCollectionScope`. + * + * \param heap_handle The corresponding heap. + */ + static void Leave(HeapHandle& heap_handle); + + /** + * Constructs a scoped object that automatically enters and leaves a disallow + * garbage collection scope based on its lifetime. + * + * \param heap_handle The corresponding heap. + */ + explicit DisallowGarbageCollectionScope(HeapHandle& heap_handle); + ~DisallowGarbageCollectionScope(); + + DisallowGarbageCollectionScope(const DisallowGarbageCollectionScope&) = + delete; + DisallowGarbageCollectionScope& operator=( + const DisallowGarbageCollectionScope&) = delete; + + private: + HeapHandle& heap_handle_; +}; + +/** + * Avoids invoking garbage collection finalizations. Already running garbage + * collection phase are unaffected by this scope. + * + * Should only be used temporarily as the scope has an impact on memory usage + * and follow up garbage collections. + */ +class V8_EXPORT V8_NODISCARD NoGarbageCollectionScope final { + CPPGC_STACK_ALLOCATED(); + + public: + /** + * Enters a no garbage collection scope. Must be paired with `Leave()`. Prefer + * a scope instance of `NoGarbageCollectionScope`. + * + * \param heap_handle The corresponding heap. + */ + static void Enter(HeapHandle& heap_handle); + + /** + * Leaves a no garbage collection scope. Must be paired with `Enter()`. Prefer + * a scope instance of `NoGarbageCollectionScope`. + * + * \param heap_handle The corresponding heap. + */ + static void Leave(HeapHandle& heap_handle); + + /** + * Constructs a scoped object that automatically enters and leaves a no + * garbage collection scope based on its lifetime. + * + * \param heap_handle The corresponding heap. + */ + explicit NoGarbageCollectionScope(HeapHandle& heap_handle); + ~NoGarbageCollectionScope(); + + NoGarbageCollectionScope(const NoGarbageCollectionScope&) = delete; + NoGarbageCollectionScope& operator=(const NoGarbageCollectionScope&) = delete; + + private: + HeapHandle& heap_handle_; +}; + +} // namespace subtle +} // namespace cppgc + +#endif // INCLUDE_CPPGC_HEAP_CONSISTENCY_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/heap-handle.h b/NativeScript/napi/v8/include_old/cppgc/heap-handle.h new file mode 100644 index 00000000..0d1d21e6 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/heap-handle.h @@ -0,0 +1,48 @@ +// Copyright 2022 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_HEAP_HANDLE_H_ +#define INCLUDE_CPPGC_HEAP_HANDLE_H_ + +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +namespace internal { +class HeapBase; +class WriteBarrierTypeForCagedHeapPolicy; +class WriteBarrierTypeForNonCagedHeapPolicy; +} // namespace internal + +/** + * Opaque handle used for additional heap APIs. + */ +class HeapHandle { + public: + // Deleted copy ctor to avoid treating the type by value. + HeapHandle(const HeapHandle&) = delete; + HeapHandle& operator=(const HeapHandle&) = delete; + + private: + HeapHandle() = default; + + V8_INLINE bool is_incremental_marking_in_progress() const { + return is_incremental_marking_in_progress_; + } + + V8_INLINE bool is_young_generation_enabled() const { + return is_young_generation_enabled_; + } + + bool is_incremental_marking_in_progress_ = false; + bool is_young_generation_enabled_ = false; + + friend class internal::HeapBase; + friend class internal::WriteBarrierTypeForCagedHeapPolicy; + friend class internal::WriteBarrierTypeForNonCagedHeapPolicy; +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_HEAP_HANDLE_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/heap-state.h b/NativeScript/napi/v8/include_old/cppgc/heap-state.h new file mode 100644 index 00000000..28212589 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/heap-state.h @@ -0,0 +1,82 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_HEAP_STATE_H_ +#define INCLUDE_CPPGC_HEAP_STATE_H_ + +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +class HeapHandle; + +namespace subtle { + +/** + * Helpers to peek into heap-internal state. + */ +class V8_EXPORT HeapState final { + public: + /** + * Returns whether the garbage collector is marking. This API is experimental + * and is expected to be removed in future. + * + * \param heap_handle The corresponding heap. + * \returns true if the garbage collector is currently marking, and false + * otherwise. + */ + static bool IsMarking(const HeapHandle& heap_handle); + + /* + * Returns whether the garbage collector is sweeping. This API is experimental + * and is expected to be removed in future. + * + * \param heap_handle The corresponding heap. + * \returns true if the garbage collector is currently sweeping, and false + * otherwise. + */ + static bool IsSweeping(const HeapHandle& heap_handle); + + /* + * Returns whether the garbage collector is currently sweeping on the thread + * owning this heap. This API allows the caller to determine whether it has + * been called from a destructor of a managed object. This API is experimental + * and may be removed in future. + * + * \param heap_handle The corresponding heap. + * \returns true if the garbage collector is currently sweeping on this + * thread, and false otherwise. + */ + static bool IsSweepingOnOwningThread(const HeapHandle& heap_handle); + + /** + * Returns whether the garbage collector is in the atomic pause, i.e., the + * mutator is stopped from running. This API is experimental and is expected + * to be removed in future. + * + * \param heap_handle The corresponding heap. + * \returns true if the garbage collector is currently in the atomic pause, + * and false otherwise. + */ + static bool IsInAtomicPause(const HeapHandle& heap_handle); + + /** + * Returns whether the last garbage collection was finalized conservatively + * (i.e., with a non-empty stack). This API is experimental and is expected to + * be removed in future. + * + * \param heap_handle The corresponding heap. + * \returns true if the last garbage collection was finalized conservatively, + * and false otherwise. + */ + static bool PreviousGCWasConservative(const HeapHandle& heap_handle); + + private: + HeapState() = delete; +}; + +} // namespace subtle +} // namespace cppgc + +#endif // INCLUDE_CPPGC_HEAP_STATE_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/heap-statistics.h b/NativeScript/napi/v8/include_old/cppgc/heap-statistics.h new file mode 100644 index 00000000..5e389874 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/heap-statistics.h @@ -0,0 +1,120 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_HEAP_STATISTICS_H_ +#define INCLUDE_CPPGC_HEAP_STATISTICS_H_ + +#include +#include +#include +#include + +namespace cppgc { + +/** + * `HeapStatistics` contains memory consumption and utilization statistics for a + * cppgc heap. + */ +struct HeapStatistics final { + /** + * Specifies the detail level of the heap statistics. Brief statistics contain + * only the top-level allocated and used memory statistics for the entire + * heap. Detailed statistics also contain a break down per space and page, as + * well as freelist statistics and object type histograms. Note that used + * memory reported by brief statistics and detailed statistics might differ + * slightly. + */ + enum DetailLevel : uint8_t { + kBrief, + kDetailed, + }; + + /** + * Object statistics for a single type. + */ + struct ObjectStatsEntry { + /** + * Number of allocated bytes. + */ + size_t allocated_bytes; + /** + * Number of allocated objects. + */ + size_t object_count; + }; + + /** + * Page granularity statistics. For each page the statistics record the + * allocated memory size and overall used memory size for the page. + */ + struct PageStatistics { + /** Overall committed amount of memory for the page. */ + size_t committed_size_bytes = 0; + /** Resident amount of memory held by the page. */ + size_t resident_size_bytes = 0; + /** Amount of memory actually used on the page. */ + size_t used_size_bytes = 0; + /** Statistics for object allocated on the page. Filled only when + * NameProvider::SupportsCppClassNamesAsObjectNames() is true. */ + std::vector object_statistics; + }; + + /** + * Statistics of the freelist (used only in non-large object spaces). For + * each bucket in the freelist the statistics record the bucket size, the + * number of freelist entries in the bucket, and the overall allocated memory + * consumed by these freelist entries. + */ + struct FreeListStatistics { + /** bucket sizes in the freelist. */ + std::vector bucket_size; + /** number of freelist entries per bucket. */ + std::vector free_count; + /** memory size consumed by freelist entries per size. */ + std::vector free_size; + }; + + /** + * Space granularity statistics. For each space the statistics record the + * space name, the amount of allocated memory and overall used memory for the + * space. The statistics also contain statistics for each of the space's + * pages, its freelist and the objects allocated on the space. + */ + struct SpaceStatistics { + /** The space name */ + std::string name; + /** Overall committed amount of memory for the heap. */ + size_t committed_size_bytes = 0; + /** Resident amount of memory held by the heap. */ + size_t resident_size_bytes = 0; + /** Amount of memory actually used on the space. */ + size_t used_size_bytes = 0; + /** Statistics for each of the pages in the space. */ + std::vector page_stats; + /** Statistics for the freelist of the space. */ + FreeListStatistics free_list_stats; + }; + + /** Overall committed amount of memory for the heap. */ + size_t committed_size_bytes = 0; + /** Resident amount of memory held by the heap. */ + size_t resident_size_bytes = 0; + /** Amount of memory actually used on the heap. */ + size_t used_size_bytes = 0; + /** Detail level of this HeapStatistics. */ + DetailLevel detail_level; + + /** Statistics for each of the spaces in the heap. Filled only when + * `detail_level` is `DetailLevel::kDetailed`. */ + std::vector space_stats; + + /** + * Vector of `cppgc::GarbageCollected` type names. + */ + std::vector type_names; +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_HEAP_STATISTICS_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/heap.h b/NativeScript/napi/v8/include_old/cppgc/heap.h new file mode 100644 index 00000000..02ee12ea --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/heap.h @@ -0,0 +1,202 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_HEAP_H_ +#define INCLUDE_CPPGC_HEAP_H_ + +#include +#include +#include +#include + +#include "cppgc/common.h" +#include "cppgc/custom-space.h" +#include "cppgc/platform.h" +#include "v8config.h" // NOLINT(build/include_directory) + +/** + * cppgc - A C++ garbage collection library. + */ +namespace cppgc { + +class AllocationHandle; +class HeapHandle; + +/** + * Implementation details of cppgc. Those details are considered internal and + * may change at any point in time without notice. Users should never rely on + * the contents of this namespace. + */ +namespace internal { +class Heap; +} // namespace internal + +class V8_EXPORT Heap { + public: + /** + * Specifies the stack state the embedder is in. + */ + using StackState = EmbedderStackState; + + /** + * Specifies whether conservative stack scanning is supported. + */ + enum class StackSupport : uint8_t { + /** + * Conservative stack scan is supported. + */ + kSupportsConservativeStackScan, + /** + * Conservative stack scan is not supported. Embedders may use this option + * when using custom infrastructure that is unsupported by the library. + */ + kNoConservativeStackScan, + }; + + /** + * Specifies supported marking types. + */ + enum class MarkingType : uint8_t { + /** + * Atomic stop-the-world marking. This option does not require any write + * barriers but is the most intrusive in terms of jank. + */ + kAtomic, + /** + * Incremental marking interleaves marking with the rest of the application + * workload on the same thread. + */ + kIncremental, + /** + * Incremental and concurrent marking. + */ + kIncrementalAndConcurrent + }; + + /** + * Specifies supported sweeping types. + */ + enum class SweepingType : uint8_t { + /** + * Atomic stop-the-world sweeping. All of sweeping is performed at once. + */ + kAtomic, + /** + * Incremental sweeping interleaves sweeping with the rest of the + * application workload on the same thread. + */ + kIncremental, + /** + * Incremental and concurrent sweeping. Sweeping is split and interleaved + * with the rest of the application. + */ + kIncrementalAndConcurrent + }; + + /** + * Constraints for a Heap setup. + */ + struct ResourceConstraints { + /** + * Allows the heap to grow to some initial size in bytes before triggering + * garbage collections. This is useful when it is known that applications + * need a certain minimum heap to run to avoid repeatedly invoking the + * garbage collector when growing the heap. + */ + size_t initial_heap_size_bytes = 0; + }; + + /** + * Options specifying Heap properties (e.g. custom spaces) when initializing a + * heap through `Heap::Create()`. + */ + struct HeapOptions { + /** + * Creates reasonable defaults for instantiating a Heap. + * + * \returns the HeapOptions that can be passed to `Heap::Create()`. + */ + static HeapOptions Default() { return {}; } + + /** + * Custom spaces added to heap are required to have indices forming a + * numbered sequence starting at 0, i.e., their `kSpaceIndex` must + * correspond to the index they reside in the vector. + */ + std::vector> custom_spaces; + + /** + * Specifies whether conservative stack scan is supported. When conservative + * stack scan is not supported, the collector may try to invoke + * garbage collections using non-nestable task, which are guaranteed to have + * no interesting stack, through the provided Platform. If such tasks are + * not supported by the Platform, the embedder must take care of invoking + * the GC through `ForceGarbageCollectionSlow()`. + */ + StackSupport stack_support = StackSupport::kSupportsConservativeStackScan; + + /** + * Specifies which types of marking are supported by the heap. + */ + MarkingType marking_support = MarkingType::kIncrementalAndConcurrent; + + /** + * Specifies which types of sweeping are supported by the heap. + */ + SweepingType sweeping_support = SweepingType::kIncrementalAndConcurrent; + + /** + * Resource constraints specifying various properties that the internal + * GC scheduler follows. + */ + ResourceConstraints resource_constraints; + }; + + /** + * Creates a new heap that can be used for object allocation. + * + * \param platform implemented and provided by the embedder. + * \param options HeapOptions specifying various properties for the Heap. + * \returns a new Heap instance. + */ + static std::unique_ptr Create( + std::shared_ptr platform, + HeapOptions options = HeapOptions::Default()); + + virtual ~Heap() = default; + + /** + * Forces garbage collection. + * + * \param source String specifying the source (or caller) triggering a + * forced garbage collection. + * \param reason String specifying the reason for the forced garbage + * collection. + * \param stack_state The embedder stack state, see StackState. + */ + void ForceGarbageCollectionSlow( + const char* source, const char* reason, + StackState stack_state = StackState::kMayContainHeapPointers); + + /** + * \returns the opaque handle for allocating objects using + * `MakeGarbageCollected()`. + */ + AllocationHandle& GetAllocationHandle(); + + /** + * \returns the opaque heap handle which may be used to refer to this heap in + * other APIs. Valid as long as the underlying `Heap` is alive. + */ + HeapHandle& GetHeapHandle(); + + private: + Heap() = default; + + friend class internal::Heap; +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_HEAP_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/api-constants.h b/NativeScript/napi/v8/include_old/cppgc/internal/api-constants.h new file mode 100644 index 00000000..4e2a637e --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/api-constants.h @@ -0,0 +1,87 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_ +#define INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_ + +#include +#include + +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +// Embedders should not rely on this code! + +// Internal constants to avoid exposing internal types on the API surface. +namespace api_constants { + +constexpr size_t kKB = 1024; +constexpr size_t kMB = kKB * 1024; +constexpr size_t kGB = kMB * 1024; + +// Offset of the uint16_t bitfield from the payload contaning the +// in-construction bit. This is subtracted from the payload pointer to get +// to the right bitfield. +static constexpr size_t kFullyConstructedBitFieldOffsetFromPayload = + 2 * sizeof(uint16_t); +// Mask for in-construction bit. +static constexpr uint16_t kFullyConstructedBitMask = uint16_t{1}; + +static constexpr size_t kPageSize = size_t{1} << 17; + +#if defined(V8_TARGET_ARCH_ARM64) && defined(V8_OS_DARWIN) +constexpr size_t kGuardPageSize = 0; +#else +constexpr size_t kGuardPageSize = 4096; +#endif + +static constexpr size_t kLargeObjectSizeThreshold = kPageSize / 2; + +#if defined(CPPGC_POINTER_COMPRESSION) +#if defined(CPPGC_ENABLE_LARGER_CAGE) +constexpr unsigned kPointerCompressionShift = 3; +#else // !defined(CPPGC_ENABLE_LARGER_CAGE) +constexpr unsigned kPointerCompressionShift = 1; +#endif // !defined(CPPGC_ENABLE_LARGER_CAGE) +#endif // !defined(CPPGC_POINTER_COMPRESSION) + +#if defined(CPPGC_CAGED_HEAP) +#if defined(CPPGC_2GB_CAGE) +constexpr size_t kCagedHeapDefaultReservationSize = + static_cast(2) * kGB; +constexpr size_t kCagedHeapMaxReservationSize = + kCagedHeapDefaultReservationSize; +#else // !defined(CPPGC_2GB_CAGE) +constexpr size_t kCagedHeapDefaultReservationSize = + static_cast(4) * kGB; +#if defined(CPPGC_POINTER_COMPRESSION) +constexpr size_t kCagedHeapMaxReservationSize = + size_t{1} << (31 + kPointerCompressionShift); +#else // !defined(CPPGC_POINTER_COMPRESSION) +constexpr size_t kCagedHeapMaxReservationSize = + kCagedHeapDefaultReservationSize; +#endif // !defined(CPPGC_POINTER_COMPRESSION) +#endif // !defined(CPPGC_2GB_CAGE) +constexpr size_t kCagedHeapReservationAlignment = kCagedHeapMaxReservationSize; +#endif // defined(CPPGC_CAGED_HEAP) + +static constexpr size_t kDefaultAlignment = sizeof(void*); + +// Maximum support alignment for a type as in `alignof(T)`. +static constexpr size_t kMaxSupportedAlignment = 2 * kDefaultAlignment; + +// Granularity of heap allocations. +constexpr size_t kAllocationGranularity = sizeof(void*); + +// Default cacheline size. +constexpr size_t kCachelineSize = 64; + +} // namespace api_constants + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/atomic-entry-flag.h b/NativeScript/napi/v8/include_old/cppgc/internal/atomic-entry-flag.h new file mode 100644 index 00000000..5a7d3b8f --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/atomic-entry-flag.h @@ -0,0 +1,48 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_ +#define INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_ + +#include + +namespace cppgc { +namespace internal { + +// A flag which provides a fast check whether a scope may be entered on the +// current thread, without needing to access thread-local storage or mutex. Can +// have false positives (i.e., spuriously report that it might be entered), so +// it is expected that this will be used in tandem with a precise check that the +// scope is in fact entered on that thread. +// +// Example: +// g_frobnicating_flag.MightBeEntered() && +// ThreadLocalFrobnicator().IsFrobnicating() +// +// Relaxed atomic operations are sufficient, since: +// - all accesses remain atomic +// - each thread must observe its own operations in order +// - no thread ever exits the flag more times than it enters (if used correctly) +// And so if a thread observes zero, it must be because it has observed an equal +// number of exits as entries. +class AtomicEntryFlag final { + public: + void Enter() { entries_.fetch_add(1, std::memory_order_relaxed); } + void Exit() { entries_.fetch_sub(1, std::memory_order_relaxed); } + + // Returns false only if the current thread is not between a call to Enter + // and a call to Exit. Returns true if this thread or another thread may + // currently be in the scope guarded by this flag. + bool MightBeEntered() const { + return entries_.load(std::memory_order_relaxed) != 0; + } + + private: + std::atomic_int entries_{0}; +}; + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/base-page-handle.h b/NativeScript/napi/v8/include_old/cppgc/internal/base-page-handle.h new file mode 100644 index 00000000..9c690755 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/base-page-handle.h @@ -0,0 +1,45 @@ +// Copyright 2022 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_BASE_PAGE_HANDLE_H_ +#define INCLUDE_CPPGC_INTERNAL_BASE_PAGE_HANDLE_H_ + +#include "cppgc/heap-handle.h" +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/logging.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +// The class is needed in the header to allow for fast access to HeapHandle in +// the write barrier. +class BasePageHandle { + public: + static V8_INLINE BasePageHandle* FromPayload(void* payload) { + return reinterpret_cast( + (reinterpret_cast(payload) & + ~(api_constants::kPageSize - 1)) + + api_constants::kGuardPageSize); + } + static V8_INLINE const BasePageHandle* FromPayload(const void* payload) { + return FromPayload(const_cast(payload)); + } + + HeapHandle& heap_handle() { return heap_handle_; } + const HeapHandle& heap_handle() const { return heap_handle_; } + + protected: + explicit BasePageHandle(HeapHandle& heap_handle) : heap_handle_(heap_handle) { + CPPGC_DCHECK(reinterpret_cast(this) % api_constants::kPageSize == + api_constants::kGuardPageSize); + } + + HeapHandle& heap_handle_; +}; + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_BASE_PAGE_HANDLE_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/caged-heap-local-data.h b/NativeScript/napi/v8/include_old/cppgc/internal/caged-heap-local-data.h new file mode 100644 index 00000000..1eb87dfb --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/caged-heap-local-data.h @@ -0,0 +1,121 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_ +#define INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_ + +#include +#include +#include + +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/caged-heap.h" +#include "cppgc/internal/logging.h" +#include "cppgc/platform.h" +#include "v8config.h" // NOLINT(build/include_directory) + +#if __cpp_lib_bitopts +#include +#endif // __cpp_lib_bitopts + +#if defined(CPPGC_CAGED_HEAP) + +namespace cppgc { +namespace internal { + +class HeapBase; +class HeapBaseHandle; + +#if defined(CPPGC_YOUNG_GENERATION) + +// AgeTable is the bytemap needed for the fast generation check in the write +// barrier. AgeTable contains entries that correspond to 4096 bytes memory +// regions (cards). Each entry in the table represents generation of the objects +// that reside on the corresponding card (young, old or mixed). +class V8_EXPORT AgeTable final { + static constexpr size_t kRequiredSize = 1 * api_constants::kMB; + static constexpr size_t kAllocationGranularity = + api_constants::kAllocationGranularity; + + public: + // Represents age of the objects living on a single card. + enum class Age : uint8_t { kOld, kYoung, kMixed }; + // When setting age for a range, consider or ignore ages of the adjacent + // cards. + enum class AdjacentCardsPolicy : uint8_t { kConsider, kIgnore }; + + static constexpr size_t kCardSizeInBytes = + api_constants::kCagedHeapDefaultReservationSize / kRequiredSize; + + static constexpr size_t CalculateAgeTableSizeForHeapSize(size_t heap_size) { + return heap_size / kCardSizeInBytes; + } + + void SetAge(uintptr_t cage_offset, Age age) { + table_[card(cage_offset)] = age; + } + + V8_INLINE Age GetAge(uintptr_t cage_offset) const { + return table_[card(cage_offset)]; + } + + void SetAgeForRange(uintptr_t cage_offset_begin, uintptr_t cage_offset_end, + Age age, AdjacentCardsPolicy adjacent_cards_policy); + + Age GetAgeForRange(uintptr_t cage_offset_begin, + uintptr_t cage_offset_end) const; + + void ResetForTesting(); + + private: + V8_INLINE size_t card(uintptr_t offset) const { + constexpr size_t kGranularityBits = +#if __cpp_lib_bitopts + std::countr_zero(static_cast(kCardSizeInBytes)); +#elif V8_HAS_BUILTIN_CTZ + __builtin_ctz(static_cast(kCardSizeInBytes)); +#else //! V8_HAS_BUILTIN_CTZ + // Hardcode and check with assert. +#if defined(CPPGC_2GB_CAGE) + 11; +#else // !defined(CPPGC_2GB_CAGE) + 12; +#endif // !defined(CPPGC_2GB_CAGE) +#endif // !V8_HAS_BUILTIN_CTZ + static_assert((1 << kGranularityBits) == kCardSizeInBytes); + const size_t entry = offset >> kGranularityBits; + CPPGC_DCHECK(CagedHeapBase::GetAgeTableSize() > entry); + return entry; + } + +#if defined(V8_CC_GNU) + // gcc disallows flexible arrays in otherwise empty classes. + Age table_[0]; +#else // !defined(V8_CC_GNU) + Age table_[]; +#endif // !defined(V8_CC_GNU) +}; + +#endif // CPPGC_YOUNG_GENERATION + +struct CagedHeapLocalData final { + V8_INLINE static CagedHeapLocalData& Get() { + return *reinterpret_cast(CagedHeapBase::GetBase()); + } + + static constexpr size_t CalculateLocalDataSizeForHeapSize(size_t heap_size) { + return AgeTable::CalculateAgeTableSizeForHeapSize(heap_size); + } + +#if defined(CPPGC_YOUNG_GENERATION) + AgeTable age_table; +#endif +}; + +} // namespace internal +} // namespace cppgc + +#endif // defined(CPPGC_CAGED_HEAP) + +#endif // INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/caged-heap.h b/NativeScript/napi/v8/include_old/cppgc/internal/caged-heap.h new file mode 100644 index 00000000..0c987a95 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/caged-heap.h @@ -0,0 +1,68 @@ +// Copyright 2022 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_H_ +#define INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_H_ + +#include +#include + +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/base-page-handle.h" +#include "v8config.h" // NOLINT(build/include_directory) + +#if defined(CPPGC_CAGED_HEAP) + +namespace cppgc { +namespace internal { + +class V8_EXPORT CagedHeapBase { + public: + V8_INLINE static uintptr_t OffsetFromAddress(const void* address) { + return reinterpret_cast(address) & + (api_constants::kCagedHeapReservationAlignment - 1); + } + + V8_INLINE static bool IsWithinCage(const void* address) { + CPPGC_DCHECK(g_heap_base_); + return (reinterpret_cast(address) & + ~(api_constants::kCagedHeapReservationAlignment - 1)) == + g_heap_base_; + } + + V8_INLINE static bool AreWithinCage(const void* addr1, const void* addr2) { +#if defined(CPPGC_2GB_CAGE) + static constexpr size_t kHeapBaseShift = sizeof(uint32_t) * CHAR_BIT - 1; +#else //! defined(CPPGC_2GB_CAGE) +#if defined(CPPGC_POINTER_COMPRESSION) + static constexpr size_t kHeapBaseShift = + 31 + api_constants::kPointerCompressionShift; +#else // !defined(CPPGC_POINTER_COMPRESSION) + static constexpr size_t kHeapBaseShift = sizeof(uint32_t) * CHAR_BIT; +#endif // !defined(CPPGC_POINTER_COMPRESSION) +#endif //! defined(CPPGC_2GB_CAGE) + static_assert((static_cast(1) << kHeapBaseShift) == + api_constants::kCagedHeapMaxReservationSize); + CPPGC_DCHECK(g_heap_base_); + return !(((reinterpret_cast(addr1) ^ g_heap_base_) | + (reinterpret_cast(addr2) ^ g_heap_base_)) >> + kHeapBaseShift); + } + + V8_INLINE static uintptr_t GetBase() { return g_heap_base_; } + V8_INLINE static size_t GetAgeTableSize() { return g_age_table_size_; } + + private: + friend class CagedHeap; + + static uintptr_t g_heap_base_; + static size_t g_age_table_size_; +}; + +} // namespace internal +} // namespace cppgc + +#endif // defined(CPPGC_CAGED_HEAP) + +#endif // INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/compiler-specific.h b/NativeScript/napi/v8/include_old/cppgc/internal/compiler-specific.h new file mode 100644 index 00000000..595b6398 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/compiler-specific.h @@ -0,0 +1,38 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_ +#define INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_ + +namespace cppgc { + +#if defined(__has_attribute) +#define CPPGC_HAS_ATTRIBUTE(FEATURE) __has_attribute(FEATURE) +#else +#define CPPGC_HAS_ATTRIBUTE(FEATURE) 0 +#endif + +#if defined(__has_cpp_attribute) +#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) __has_cpp_attribute(FEATURE) +#else +#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) 0 +#endif + +// [[no_unique_address]] comes in C++20 but supported in clang with -std >= +// c++11. +#if CPPGC_HAS_CPP_ATTRIBUTE(no_unique_address) +#define CPPGC_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else +#define CPPGC_NO_UNIQUE_ADDRESS +#endif + +#if CPPGC_HAS_ATTRIBUTE(unused) +#define CPPGC_UNUSED __attribute__((unused)) +#else +#define CPPGC_UNUSED +#endif + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/finalizer-trait.h b/NativeScript/napi/v8/include_old/cppgc/internal/finalizer-trait.h new file mode 100644 index 00000000..ab49af87 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/finalizer-trait.h @@ -0,0 +1,93 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_ +#define INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_ + +#include + +#include "cppgc/type-traits.h" + +namespace cppgc { +namespace internal { + +using FinalizationCallback = void (*)(void*); + +template +struct HasFinalizeGarbageCollectedObject : std::false_type {}; + +template +struct HasFinalizeGarbageCollectedObject< + T, + std::void_t().FinalizeGarbageCollectedObject())>> + : std::true_type {}; + +// The FinalizerTraitImpl specifies how to finalize objects. +template +struct FinalizerTraitImpl; + +template +struct FinalizerTraitImpl { + private: + // Dispatch to custom FinalizeGarbageCollectedObject(). + struct Custom { + static void Call(void* obj) { + static_cast(obj)->FinalizeGarbageCollectedObject(); + } + }; + + // Dispatch to regular destructor. + struct Destructor { + static void Call(void* obj) { static_cast(obj)->~T(); } + }; + + using FinalizeImpl = + std::conditional_t::value, Custom, + Destructor>; + + public: + static void Finalize(void* obj) { + static_assert(sizeof(T), "T must be fully defined"); + FinalizeImpl::Call(obj); + } +}; + +template +struct FinalizerTraitImpl { + static void Finalize(void* obj) { + static_assert(sizeof(T), "T must be fully defined"); + } +}; + +// The FinalizerTrait is used to determine if a type requires finalization and +// what finalization means. +template +struct FinalizerTrait { + private: + // Object has a finalizer if it has + // - a custom FinalizeGarbageCollectedObject method, or + // - a destructor. + static constexpr bool kNonTrivialFinalizer = + internal::HasFinalizeGarbageCollectedObject::value || + !std::is_trivially_destructible::type>::value; + + static void Finalize(void* obj) { + internal::FinalizerTraitImpl::Finalize(obj); + } + + public: + static constexpr bool HasFinalizer() { return kNonTrivialFinalizer; } + + // The callback used to finalize an object of type T. + static constexpr FinalizationCallback kCallback = + kNonTrivialFinalizer ? Finalize : nullptr; +}; + +template +constexpr FinalizationCallback FinalizerTrait::kCallback; + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/gc-info.h b/NativeScript/napi/v8/include_old/cppgc/internal/gc-info.h new file mode 100644 index 00000000..c8cb99ac --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/gc-info.h @@ -0,0 +1,148 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ +#define INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ + +#include +#include +#include + +#include "cppgc/internal/finalizer-trait.h" +#include "cppgc/internal/logging.h" +#include "cppgc/internal/name-trait.h" +#include "cppgc/trace-trait.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +using GCInfoIndex = uint16_t; + +struct V8_EXPORT EnsureGCInfoIndexTrait final { + // Acquires a new GC info object and updates `registered_index` with the index + // that identifies that new info accordingly. + template + V8_INLINE static GCInfoIndex EnsureIndex( + std::atomic& registered_index) { + return EnsureGCInfoIndexTraitDispatch{}(registered_index); + } + + private: + template ::HasFinalizer(), + bool = NameTrait::HasNonHiddenName()> + struct EnsureGCInfoIndexTraitDispatch; + + static GCInfoIndex V8_PRESERVE_MOST + EnsureGCInfoIndex(std::atomic&, TraceCallback, + FinalizationCallback, NameCallback); + static GCInfoIndex V8_PRESERVE_MOST EnsureGCInfoIndex( + std::atomic&, TraceCallback, FinalizationCallback); + static GCInfoIndex V8_PRESERVE_MOST + EnsureGCInfoIndex(std::atomic&, TraceCallback, NameCallback); + static GCInfoIndex V8_PRESERVE_MOST + EnsureGCInfoIndex(std::atomic&, TraceCallback); +}; + +#define DISPATCH(has_finalizer, has_non_hidden_name, function) \ + template \ + struct EnsureGCInfoIndexTrait::EnsureGCInfoIndexTraitDispatch< \ + T, has_finalizer, has_non_hidden_name> { \ + V8_INLINE GCInfoIndex \ + operator()(std::atomic& registered_index) { \ + return function; \ + } \ + }; + +// ------------------------------------------------------- // +// DISPATCH(has_finalizer, has_non_hidden_name, function) // +// ------------------------------------------------------- // +DISPATCH(true, true, // + EnsureGCInfoIndex(registered_index, // + TraceTrait::Trace, // + FinalizerTrait::kCallback, // + NameTrait::GetName)) // +DISPATCH(true, false, // + EnsureGCInfoIndex(registered_index, // + TraceTrait::Trace, // + FinalizerTrait::kCallback)) // +DISPATCH(false, true, // + EnsureGCInfoIndex(registered_index, // + TraceTrait::Trace, // + NameTrait::GetName)) // +DISPATCH(false, false, // + EnsureGCInfoIndex(registered_index, // + TraceTrait::Trace)) // + +#undef DISPATCH + +// Trait determines how the garbage collector treats objects wrt. to traversing, +// finalization, and naming. +template +struct GCInfoTrait final { + V8_INLINE static GCInfoIndex Index() { + static_assert(sizeof(T), "T must be fully defined"); + static std::atomic + registered_index; // Uses zero initialization. + GCInfoIndex index = registered_index.load(std::memory_order_acquire); + if (V8_UNLIKELY(!index)) { + index = EnsureGCInfoIndexTrait::EnsureIndex(registered_index); + CPPGC_DCHECK(index != 0); + CPPGC_DCHECK(index == registered_index.load(std::memory_order_acquire)); + } + return index; + } + + static constexpr bool CheckCallbacksAreDefined() { + // No USE() macro available. + (void)static_cast(TraceTrait::Trace); + (void)static_cast(FinalizerTrait::kCallback); + (void)static_cast(NameTrait::GetName); + return true; + } +}; + +// Fold types based on finalizer behavior. Note that finalizer characteristics +// align with trace behavior, i.e., destructors are virtual when trace methods +// are and vice versa. +template +struct GCInfoFolding final { + static constexpr bool kHasVirtualDestructorAtBase = + std::has_virtual_destructor::value; + static constexpr bool kBothTypesAreTriviallyDestructible = + std::is_trivially_destructible::value && + std::is_trivially_destructible::value; + static constexpr bool kHasCustomFinalizerDispatchAtBase = + internal::HasFinalizeGarbageCollectedObject< + ParentMostGarbageCollectedType>::value; +#ifdef CPPGC_SUPPORTS_OBJECT_NAMES + static constexpr bool kWantsDetailedObjectNames = true; +#else // !CPPGC_SUPPORTS_OBJECT_NAMES + static constexpr bool kWantsDetailedObjectNames = false; +#endif // !CPPGC_SUPPORTS_OBJECT_NAMES + + // Always true. Forces the compiler to resolve callbacks which ensures that + // both modes don't break without requiring compiling a separate + // configuration. Only a single GCInfo (for `ResultType` below) will actually + // be instantiated but existence (and well-formedness) of all callbacks is + // checked. + static constexpr bool kCheckTypeGuardAlwaysTrue = + GCInfoTrait::CheckCallbacksAreDefined() && + GCInfoTrait::CheckCallbacksAreDefined(); + + // Folding would regress name resolution when deriving names from C++ + // class names as it would just folds a name to the base class name. + using ResultType = + std::conditional_t; +}; + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/logging.h b/NativeScript/napi/v8/include_old/cppgc/internal/logging.h new file mode 100644 index 00000000..3a279fe0 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/logging.h @@ -0,0 +1,50 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_LOGGING_H_ +#define INCLUDE_CPPGC_INTERNAL_LOGGING_H_ + +#include "cppgc/source-location.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +void V8_EXPORT DCheckImpl(const char*, + const SourceLocation& = SourceLocation::Current()); +[[noreturn]] void V8_EXPORT +FatalImpl(const char*, const SourceLocation& = SourceLocation::Current()); + +// Used to ignore -Wunused-variable. +template +struct EatParams {}; + +#if defined(DEBUG) +#define CPPGC_DCHECK_MSG(condition, message) \ + do { \ + if (V8_UNLIKELY(!(condition))) { \ + ::cppgc::internal::DCheckImpl(message); \ + } \ + } while (false) +#else // !defined(DEBUG) +#define CPPGC_DCHECK_MSG(condition, message) \ + (static_cast(::cppgc::internal::EatParams(condition), message)>{})) +#endif // !defined(DEBUG) + +#define CPPGC_DCHECK(condition) CPPGC_DCHECK_MSG(condition, #condition) + +#define CPPGC_CHECK_MSG(condition, message) \ + do { \ + if (V8_UNLIKELY(!(condition))) { \ + ::cppgc::internal::FatalImpl(message); \ + } \ + } while (false) + +#define CPPGC_CHECK(condition) CPPGC_CHECK_MSG(condition, #condition) + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_LOGGING_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/member-storage.h b/NativeScript/napi/v8/include_old/cppgc/internal/member-storage.h new file mode 100644 index 00000000..61b255ba --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/member-storage.h @@ -0,0 +1,256 @@ +// Copyright 2022 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_MEMBER_STORAGE_H_ +#define INCLUDE_CPPGC_INTERNAL_MEMBER_STORAGE_H_ + +#include +#include +#include + +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/logging.h" +#include "cppgc/sentinel-pointer.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +enum class WriteBarrierSlotType { + kCompressed, + kUncompressed, +}; + +#if defined(CPPGC_POINTER_COMPRESSION) + +#if defined(__clang__) +// Attribute const allows the compiler to assume that CageBaseGlobal::g_base_ +// doesn't change (e.g. across calls) and thereby avoid redundant loads. +#define CPPGC_CONST __attribute__((const)) +#define CPPGC_REQUIRE_CONSTANT_INIT \ + __attribute__((require_constant_initialization)) +#else // defined(__clang__) +#define CPPGC_CONST +#define CPPGC_REQUIRE_CONSTANT_INIT +#endif // defined(__clang__) + +class V8_EXPORT CageBaseGlobal final { + public: + V8_INLINE CPPGC_CONST static uintptr_t Get() { + CPPGC_DCHECK(IsBaseConsistent()); + return g_base_.base; + } + + V8_INLINE CPPGC_CONST static bool IsSet() { + CPPGC_DCHECK(IsBaseConsistent()); + return (g_base_.base & ~kLowerHalfWordMask) != 0; + } + + private: + // We keep the lower halfword as ones to speed up decompression. + static constexpr uintptr_t kLowerHalfWordMask = + (api_constants::kCagedHeapReservationAlignment - 1); + + static union alignas(api_constants::kCachelineSize) Base { + uintptr_t base; + char cache_line[api_constants::kCachelineSize]; + } g_base_ CPPGC_REQUIRE_CONSTANT_INIT; + + CageBaseGlobal() = delete; + + V8_INLINE static bool IsBaseConsistent() { + return kLowerHalfWordMask == (g_base_.base & kLowerHalfWordMask); + } + + friend class CageBaseGlobalUpdater; +}; + +#undef CPPGC_REQUIRE_CONSTANT_INIT +#undef CPPGC_CONST + +class V8_TRIVIAL_ABI CompressedPointer final { + public: + using IntegralType = uint32_t; + static constexpr auto kWriteBarrierSlotType = + WriteBarrierSlotType::kCompressed; + + V8_INLINE CompressedPointer() : value_(0u) {} + V8_INLINE explicit CompressedPointer(const void* ptr) + : value_(Compress(ptr)) {} + V8_INLINE explicit CompressedPointer(std::nullptr_t) : value_(0u) {} + V8_INLINE explicit CompressedPointer(SentinelPointer) + : value_(kCompressedSentinel) {} + + V8_INLINE const void* Load() const { return Decompress(value_); } + V8_INLINE const void* LoadAtomic() const { + return Decompress( + reinterpret_cast&>(value_).load( + std::memory_order_relaxed)); + } + + V8_INLINE void Store(const void* ptr) { value_ = Compress(ptr); } + V8_INLINE void StoreAtomic(const void* value) { + reinterpret_cast&>(value_).store( + Compress(value), std::memory_order_relaxed); + } + + V8_INLINE void Clear() { value_ = 0u; } + V8_INLINE bool IsCleared() const { return !value_; } + + V8_INLINE bool IsSentinel() const { return value_ == kCompressedSentinel; } + + V8_INLINE uint32_t GetAsInteger() const { return value_; } + + V8_INLINE friend bool operator==(CompressedPointer a, CompressedPointer b) { + return a.value_ == b.value_; + } + V8_INLINE friend bool operator!=(CompressedPointer a, CompressedPointer b) { + return a.value_ != b.value_; + } + V8_INLINE friend bool operator<(CompressedPointer a, CompressedPointer b) { + return a.value_ < b.value_; + } + V8_INLINE friend bool operator<=(CompressedPointer a, CompressedPointer b) { + return a.value_ <= b.value_; + } + V8_INLINE friend bool operator>(CompressedPointer a, CompressedPointer b) { + return a.value_ > b.value_; + } + V8_INLINE friend bool operator>=(CompressedPointer a, CompressedPointer b) { + return a.value_ >= b.value_; + } + + static V8_INLINE IntegralType Compress(const void* ptr) { + static_assert(SentinelPointer::kSentinelValue == + 1 << api_constants::kPointerCompressionShift, + "The compression scheme relies on the sentinel encoded as 1 " + "<< kPointerCompressionShift"); + static constexpr size_t kGigaCageMask = + ~(api_constants::kCagedHeapReservationAlignment - 1); + static constexpr size_t kPointerCompressionShiftMask = + (1 << api_constants::kPointerCompressionShift) - 1; + + CPPGC_DCHECK(CageBaseGlobal::IsSet()); + const uintptr_t base = CageBaseGlobal::Get(); + CPPGC_DCHECK(!ptr || ptr == kSentinelPointer || + (base & kGigaCageMask) == + (reinterpret_cast(ptr) & kGigaCageMask)); + CPPGC_DCHECK( + (reinterpret_cast(ptr) & kPointerCompressionShiftMask) == 0); + +#if defined(CPPGC_2GB_CAGE) + // Truncate the pointer. + auto compressed = + static_cast(reinterpret_cast(ptr)); +#else // !defined(CPPGC_2GB_CAGE) + const auto uptr = reinterpret_cast(ptr); + // Shift the pointer and truncate. + auto compressed = static_cast( + uptr >> api_constants::kPointerCompressionShift); +#endif // !defined(CPPGC_2GB_CAGE) + // Normal compressed pointers must have the MSB set. + CPPGC_DCHECK((!compressed || compressed == kCompressedSentinel) || + (compressed & (1 << 31))); + return compressed; + } + + static V8_INLINE void* Decompress(IntegralType ptr) { + CPPGC_DCHECK(CageBaseGlobal::IsSet()); + const uintptr_t base = CageBaseGlobal::Get(); + // Treat compressed pointer as signed and cast it to uint64_t, which will + // sign-extend it. +#if defined(CPPGC_2GB_CAGE) + const uint64_t mask = static_cast(static_cast(ptr)); +#else // !defined(CPPGC_2GB_CAGE) + // Then, shift the result. It's important to shift the unsigned + // value, as otherwise it would result in undefined behavior. + const uint64_t mask = static_cast(static_cast(ptr)) + << api_constants::kPointerCompressionShift; +#endif // !defined(CPPGC_2GB_CAGE) + return reinterpret_cast(mask & base); + } + + private: +#if defined(CPPGC_2GB_CAGE) + static constexpr IntegralType kCompressedSentinel = + SentinelPointer::kSentinelValue; +#else // !defined(CPPGC_2GB_CAGE) + static constexpr IntegralType kCompressedSentinel = + SentinelPointer::kSentinelValue >> + api_constants::kPointerCompressionShift; +#endif // !defined(CPPGC_2GB_CAGE) + // All constructors initialize `value_`. Do not add a default value here as it + // results in a non-atomic write on some builds, even when the atomic version + // of the constructor is used. + IntegralType value_; +}; + +#endif // defined(CPPGC_POINTER_COMPRESSION) + +class V8_TRIVIAL_ABI RawPointer final { + public: + using IntegralType = uintptr_t; + static constexpr auto kWriteBarrierSlotType = + WriteBarrierSlotType::kUncompressed; + + V8_INLINE RawPointer() : ptr_(nullptr) {} + V8_INLINE explicit RawPointer(const void* ptr) : ptr_(ptr) {} + + V8_INLINE const void* Load() const { return ptr_; } + V8_INLINE const void* LoadAtomic() const { + return reinterpret_cast&>(ptr_).load( + std::memory_order_relaxed); + } + + V8_INLINE void Store(const void* ptr) { ptr_ = ptr; } + V8_INLINE void StoreAtomic(const void* ptr) { + reinterpret_cast&>(ptr_).store( + ptr, std::memory_order_relaxed); + } + + V8_INLINE void Clear() { ptr_ = nullptr; } + V8_INLINE bool IsCleared() const { return !ptr_; } + + V8_INLINE bool IsSentinel() const { return ptr_ == kSentinelPointer; } + + V8_INLINE uintptr_t GetAsInteger() const { + return reinterpret_cast(ptr_); + } + + V8_INLINE friend bool operator==(RawPointer a, RawPointer b) { + return a.ptr_ == b.ptr_; + } + V8_INLINE friend bool operator!=(RawPointer a, RawPointer b) { + return a.ptr_ != b.ptr_; + } + V8_INLINE friend bool operator<(RawPointer a, RawPointer b) { + return a.ptr_ < b.ptr_; + } + V8_INLINE friend bool operator<=(RawPointer a, RawPointer b) { + return a.ptr_ <= b.ptr_; + } + V8_INLINE friend bool operator>(RawPointer a, RawPointer b) { + return a.ptr_ > b.ptr_; + } + V8_INLINE friend bool operator>=(RawPointer a, RawPointer b) { + return a.ptr_ >= b.ptr_; + } + + private: + // All constructors initialize `ptr_`. Do not add a default value here as it + // results in a non-atomic write on some builds, even when the atomic version + // of the constructor is used. + const void* ptr_; +}; + +#if defined(CPPGC_POINTER_COMPRESSION) +using DefaultMemberStorage = CompressedPointer; +#else // !defined(CPPGC_POINTER_COMPRESSION) +using DefaultMemberStorage = RawPointer; +#endif // !defined(CPPGC_POINTER_COMPRESSION) + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_MEMBER_STORAGE_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/name-trait.h b/NativeScript/napi/v8/include_old/cppgc/internal/name-trait.h new file mode 100644 index 00000000..1d927a9d --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/name-trait.h @@ -0,0 +1,137 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ +#define INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ + +#include +#include +#include + +#include "cppgc/name-provider.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +#if CPPGC_SUPPORTS_OBJECT_NAMES && defined(__clang__) +#define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 1 + +// Provides constexpr c-string storage for a name of fixed |Size| characters. +// Automatically appends terminating 0 byte. +template +struct NameBuffer { + char name[Size + 1]{}; + + static constexpr NameBuffer FromCString(const char* str) { + NameBuffer result; + for (size_t i = 0; i < Size; ++i) result.name[i] = str[i]; + result.name[Size] = 0; + return result; + } +}; + +template +const char* GetTypename() { + static constexpr char kSelfPrefix[] = + "const char *cppgc::internal::GetTypename() [T ="; + static_assert(__builtin_strncmp(__PRETTY_FUNCTION__, kSelfPrefix, + sizeof(kSelfPrefix) - 1) == 0, + "The prefix must match"); + static constexpr const char* kTypenameStart = + __PRETTY_FUNCTION__ + sizeof(kSelfPrefix); + static constexpr size_t kTypenameSize = + __builtin_strlen(__PRETTY_FUNCTION__) - sizeof(kSelfPrefix) - 1; + // NameBuffer is an indirection that is needed to make sure that only a + // substring of __PRETTY_FUNCTION__ gets materialized in the binary. + static constexpr auto buffer = + NameBuffer::FromCString(kTypenameStart); + return buffer.name; +} + +#else +#define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 0 +#endif + +struct HeapObjectName { + const char* value; + bool name_was_hidden; +}; + +enum class HeapObjectNameForUnnamedObject : uint8_t { + kUseClassNameIfSupported, + kUseHiddenName, +}; + +class V8_EXPORT NameTraitBase { + protected: + static HeapObjectName GetNameFromTypeSignature(const char*); +}; + +// Trait that specifies how the garbage collector retrieves the name for a +// given object. +template +class NameTrait final : public NameTraitBase { + public: + static constexpr bool HasNonHiddenName() { +#if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME + return true; +#elif CPPGC_SUPPORTS_OBJECT_NAMES + return true; +#else // !CPPGC_SUPPORTS_OBJECT_NAMES + return std::is_base_of::value; +#endif // !CPPGC_SUPPORTS_OBJECT_NAMES + } + + static HeapObjectName GetName( + const void* obj, HeapObjectNameForUnnamedObject name_retrieval_mode) { + return GetNameFor(static_cast(obj), name_retrieval_mode); + } + + private: + static HeapObjectName GetNameFor(const NameProvider* name_provider, + HeapObjectNameForUnnamedObject) { + // Objects inheriting from `NameProvider` are not considered unnamed as + // users already provided a name for them. + return {name_provider->GetHumanReadableName(), false}; + } + + static HeapObjectName GetNameFor( + const void*, HeapObjectNameForUnnamedObject name_retrieval_mode) { + if (name_retrieval_mode == HeapObjectNameForUnnamedObject::kUseHiddenName) + return {NameProvider::kHiddenName, true}; + +#if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME + return {GetTypename(), false}; +#elif CPPGC_SUPPORTS_OBJECT_NAMES + +#if defined(V8_CC_GNU) +#define PRETTY_FUNCTION_VALUE __PRETTY_FUNCTION__ +#elif defined(V8_CC_MSVC) +#define PRETTY_FUNCTION_VALUE __FUNCSIG__ +#else +#define PRETTY_FUNCTION_VALUE nullptr +#endif + + static const HeapObjectName leaky_name = + GetNameFromTypeSignature(PRETTY_FUNCTION_VALUE); + return leaky_name; + +#undef PRETTY_FUNCTION_VALUE + +#else // !CPPGC_SUPPORTS_OBJECT_NAMES + return {NameProvider::kHiddenName, true}; +#endif // !CPPGC_SUPPORTS_OBJECT_NAMES + } +}; + +using NameCallback = HeapObjectName (*)(const void*, + HeapObjectNameForUnnamedObject); + +} // namespace internal +} // namespace cppgc + +#undef CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME + +#endif // INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/persistent-node.h b/NativeScript/napi/v8/include_old/cppgc/internal/persistent-node.h new file mode 100644 index 00000000..d22692a7 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/persistent-node.h @@ -0,0 +1,214 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ +#define INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ + +#include +#include +#include + +#include "cppgc/internal/logging.h" +#include "cppgc/trace-trait.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +class CrossThreadPersistentRegion; +class FatalOutOfMemoryHandler; +class RootVisitor; + +// PersistentNode represents a variant of two states: +// 1) traceable node with a back pointer to the Persistent object; +// 2) freelist entry. +class PersistentNode final { + public: + PersistentNode() = default; + + PersistentNode(const PersistentNode&) = delete; + PersistentNode& operator=(const PersistentNode&) = delete; + + void InitializeAsUsedNode(void* owner, TraceRootCallback trace) { + CPPGC_DCHECK(trace); + owner_ = owner; + trace_ = trace; + } + + void InitializeAsFreeNode(PersistentNode* next) { + next_ = next; + trace_ = nullptr; + } + + void UpdateOwner(void* owner) { + CPPGC_DCHECK(IsUsed()); + owner_ = owner; + } + + PersistentNode* FreeListNext() const { + CPPGC_DCHECK(!IsUsed()); + return next_; + } + + void Trace(RootVisitor& root_visitor) const { + CPPGC_DCHECK(IsUsed()); + trace_(root_visitor, owner_); + } + + bool IsUsed() const { return trace_; } + + void* owner() const { + CPPGC_DCHECK(IsUsed()); + return owner_; + } + + private: + // PersistentNode acts as a designated union: + // If trace_ != nullptr, owner_ points to the corresponding Persistent handle. + // Otherwise, next_ points to the next freed PersistentNode. + union { + void* owner_ = nullptr; + PersistentNode* next_; + }; + TraceRootCallback trace_ = nullptr; +}; + +class V8_EXPORT PersistentRegionBase { + using PersistentNodeSlots = std::array; + + public: + // Clears Persistent fields to avoid stale pointers after heap teardown. + ~PersistentRegionBase(); + + PersistentRegionBase(const PersistentRegionBase&) = delete; + PersistentRegionBase& operator=(const PersistentRegionBase&) = delete; + + void Iterate(RootVisitor&); + + size_t NodesInUse() const; + + void ClearAllUsedNodes(); + + protected: + explicit PersistentRegionBase(const FatalOutOfMemoryHandler& oom_handler); + + PersistentNode* TryAllocateNodeFromFreeList(void* owner, + TraceRootCallback trace) { + PersistentNode* node = nullptr; + if (V8_LIKELY(free_list_head_)) { + node = free_list_head_; + free_list_head_ = free_list_head_->FreeListNext(); + CPPGC_DCHECK(!node->IsUsed()); + node->InitializeAsUsedNode(owner, trace); + nodes_in_use_++; + } + return node; + } + + void FreeNode(PersistentNode* node) { + CPPGC_DCHECK(node); + CPPGC_DCHECK(node->IsUsed()); + node->InitializeAsFreeNode(free_list_head_); + free_list_head_ = node; + CPPGC_DCHECK(nodes_in_use_ > 0); + nodes_in_use_--; + } + + PersistentNode* RefillFreeListAndAllocateNode(void* owner, + TraceRootCallback trace); + + private: + template + void ClearAllUsedNodes(); + + void RefillFreeList(); + + std::vector> nodes_; + PersistentNode* free_list_head_ = nullptr; + size_t nodes_in_use_ = 0; + const FatalOutOfMemoryHandler& oom_handler_; + + friend class CrossThreadPersistentRegion; +}; + +// Variant of PersistentRegionBase that checks whether the allocation and +// freeing happens only on the thread that created the region. +class V8_EXPORT PersistentRegion final : public PersistentRegionBase { + public: + explicit PersistentRegion(const FatalOutOfMemoryHandler&); + // Clears Persistent fields to avoid stale pointers after heap teardown. + ~PersistentRegion() = default; + + PersistentRegion(const PersistentRegion&) = delete; + PersistentRegion& operator=(const PersistentRegion&) = delete; + + V8_INLINE PersistentNode* AllocateNode(void* owner, TraceRootCallback trace) { + CPPGC_DCHECK(IsCreationThread()); + auto* node = TryAllocateNodeFromFreeList(owner, trace); + if (V8_LIKELY(node)) return node; + + // Slow path allocation allows for checking thread correspondence. + CPPGC_CHECK(IsCreationThread()); + return RefillFreeListAndAllocateNode(owner, trace); + } + + V8_INLINE void FreeNode(PersistentNode* node) { + CPPGC_DCHECK(IsCreationThread()); + PersistentRegionBase::FreeNode(node); + } + + private: + bool IsCreationThread(); + + int creation_thread_id_; +}; + +// CrossThreadPersistent uses PersistentRegionBase but protects it using this +// lock when needed. +class V8_EXPORT PersistentRegionLock final { + public: + PersistentRegionLock(); + ~PersistentRegionLock(); + + static void AssertLocked(); +}; + +// Variant of PersistentRegionBase that checks whether the PersistentRegionLock +// is locked. +class V8_EXPORT CrossThreadPersistentRegion final + : protected PersistentRegionBase { + public: + explicit CrossThreadPersistentRegion(const FatalOutOfMemoryHandler&); + // Clears Persistent fields to avoid stale pointers after heap teardown. + ~CrossThreadPersistentRegion(); + + CrossThreadPersistentRegion(const CrossThreadPersistentRegion&) = delete; + CrossThreadPersistentRegion& operator=(const CrossThreadPersistentRegion&) = + delete; + + V8_INLINE PersistentNode* AllocateNode(void* owner, TraceRootCallback trace) { + PersistentRegionLock::AssertLocked(); + auto* node = TryAllocateNodeFromFreeList(owner, trace); + if (V8_LIKELY(node)) return node; + + return RefillFreeListAndAllocateNode(owner, trace); + } + + V8_INLINE void FreeNode(PersistentNode* node) { + PersistentRegionLock::AssertLocked(); + PersistentRegionBase::FreeNode(node); + } + + void Iterate(RootVisitor&); + + size_t NodesInUse() const; + + void ClearAllUsedNodes(); +}; + +} // namespace internal + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/pointer-policies.h b/NativeScript/napi/v8/include_old/cppgc/internal/pointer-policies.h new file mode 100644 index 00000000..06fa884f --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/pointer-policies.h @@ -0,0 +1,243 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ +#define INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ + +#include +#include + +#include "cppgc/internal/member-storage.h" +#include "cppgc/internal/write-barrier.h" +#include "cppgc/sentinel-pointer.h" +#include "cppgc/source-location.h" +#include "cppgc/type-traits.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +class HeapBase; +class PersistentRegion; +class CrossThreadPersistentRegion; + +// Tags to distinguish between strong and weak member types. +class StrongMemberTag; +class WeakMemberTag; +class UntracedMemberTag; + +struct DijkstraWriteBarrierPolicy { + V8_INLINE static void InitializingBarrier(const void*, const void*) { + // Since in initializing writes the source object is always white, having no + // barrier doesn't break the tri-color invariant. + } + + template + V8_INLINE static void AssigningBarrier(const void* slot, const void* value) { +#ifdef CPPGC_SLIM_WRITE_BARRIER + if (V8_UNLIKELY(WriteBarrier::IsEnabled())) + WriteBarrier::CombinedWriteBarrierSlow(slot); +#else // !CPPGC_SLIM_WRITE_BARRIER + WriteBarrier::Params params; + const WriteBarrier::Type type = + WriteBarrier::GetWriteBarrierType(slot, value, params); + WriteBarrier(type, params, slot, value); +#endif // !CPPGC_SLIM_WRITE_BARRIER + } + + template + V8_INLINE static void AssigningBarrier(const void* slot, RawPointer storage) { + static_assert( + SlotType == WriteBarrierSlotType::kUncompressed, + "Assigning storages of Member and UncompressedMember is not supported"); +#ifdef CPPGC_SLIM_WRITE_BARRIER + if (V8_UNLIKELY(WriteBarrier::IsEnabled())) + WriteBarrier::CombinedWriteBarrierSlow(slot); +#else // !CPPGC_SLIM_WRITE_BARRIER + WriteBarrier::Params params; + const WriteBarrier::Type type = + WriteBarrier::GetWriteBarrierType(slot, storage, params); + WriteBarrier(type, params, slot, storage.Load()); +#endif // !CPPGC_SLIM_WRITE_BARRIER + } + +#if defined(CPPGC_POINTER_COMPRESSION) + template + V8_INLINE static void AssigningBarrier(const void* slot, + CompressedPointer storage) { + static_assert( + SlotType == WriteBarrierSlotType::kCompressed, + "Assigning storages of Member and UncompressedMember is not supported"); +#ifdef CPPGC_SLIM_WRITE_BARRIER + if (V8_UNLIKELY(WriteBarrier::IsEnabled())) + WriteBarrier::CombinedWriteBarrierSlow(slot); +#else // !CPPGC_SLIM_WRITE_BARRIER + WriteBarrier::Params params; + const WriteBarrier::Type type = + WriteBarrier::GetWriteBarrierType(slot, storage, params); + WriteBarrier(type, params, slot, storage.Load()); +#endif // !CPPGC_SLIM_WRITE_BARRIER + } +#endif // defined(CPPGC_POINTER_COMPRESSION) + + private: + V8_INLINE static void WriteBarrier(WriteBarrier::Type type, + const WriteBarrier::Params& params, + const void* slot, const void* value) { + switch (type) { + case WriteBarrier::Type::kGenerational: + WriteBarrier::GenerationalBarrier< + WriteBarrier::GenerationalBarrierType::kPreciseSlot>(params, slot); + break; + case WriteBarrier::Type::kMarking: + WriteBarrier::DijkstraMarkingBarrier(params, value); + break; + case WriteBarrier::Type::kNone: + break; + } + } +}; + +struct NoWriteBarrierPolicy { + V8_INLINE static void InitializingBarrier(const void*, const void*) {} + template + V8_INLINE static void AssigningBarrier(const void*, const void*) {} + template + V8_INLINE static void AssigningBarrier(const void*, MemberStorage) {} +}; + +class V8_EXPORT SameThreadEnabledCheckingPolicyBase { + protected: + void CheckPointerImpl(const void* ptr, bool points_to_payload, + bool check_off_heap_assignments); + + const HeapBase* heap_ = nullptr; +}; + +template +class V8_EXPORT SameThreadEnabledCheckingPolicy + : private SameThreadEnabledCheckingPolicyBase { + protected: + template + void CheckPointer(const T* ptr) { + if (!ptr || (kSentinelPointer == ptr)) return; + + CheckPointersImplTrampoline::Call(this, ptr); + } + + private: + template > + struct CheckPointersImplTrampoline { + static void Call(SameThreadEnabledCheckingPolicy* policy, const T* ptr) { + policy->CheckPointerImpl(ptr, false, kCheckOffHeapAssignments); + } + }; + + template + struct CheckPointersImplTrampoline { + static void Call(SameThreadEnabledCheckingPolicy* policy, const T* ptr) { + policy->CheckPointerImpl(ptr, IsGarbageCollectedTypeV, + kCheckOffHeapAssignments); + } + }; +}; + +class DisabledCheckingPolicy { + protected: + V8_INLINE void CheckPointer(const void*) {} +}; + +#ifdef DEBUG +// Off heap members are not connected to object graph and thus cannot ressurect +// dead objects. +using DefaultMemberCheckingPolicy = + SameThreadEnabledCheckingPolicy; +using DefaultPersistentCheckingPolicy = + SameThreadEnabledCheckingPolicy; +#else // !DEBUG +using DefaultMemberCheckingPolicy = DisabledCheckingPolicy; +using DefaultPersistentCheckingPolicy = DisabledCheckingPolicy; +#endif // !DEBUG +// For CT(W)P neither marking information (for value), nor objectstart bitmap +// (for slot) are guaranteed to be present because there's no synchronization +// between heaps after marking. +using DefaultCrossThreadPersistentCheckingPolicy = DisabledCheckingPolicy; + +class KeepLocationPolicy { + public: + constexpr const SourceLocation& Location() const { return location_; } + + protected: + constexpr KeepLocationPolicy() = default; + constexpr explicit KeepLocationPolicy(const SourceLocation& location) + : location_(location) {} + + // KeepLocationPolicy must not copy underlying source locations. + KeepLocationPolicy(const KeepLocationPolicy&) = delete; + KeepLocationPolicy& operator=(const KeepLocationPolicy&) = delete; + + // Location of the original moved from object should be preserved. + KeepLocationPolicy(KeepLocationPolicy&&) = default; + KeepLocationPolicy& operator=(KeepLocationPolicy&&) = default; + + private: + SourceLocation location_; +}; + +class IgnoreLocationPolicy { + public: + constexpr SourceLocation Location() const { return {}; } + + protected: + constexpr IgnoreLocationPolicy() = default; + constexpr explicit IgnoreLocationPolicy(const SourceLocation&) {} +}; + +#if CPPGC_SUPPORTS_OBJECT_NAMES +using DefaultLocationPolicy = KeepLocationPolicy; +#else +using DefaultLocationPolicy = IgnoreLocationPolicy; +#endif + +struct StrongPersistentPolicy { + using IsStrongPersistent = std::true_type; + static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object); +}; + +struct WeakPersistentPolicy { + using IsStrongPersistent = std::false_type; + static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object); +}; + +struct StrongCrossThreadPersistentPolicy { + using IsStrongPersistent = std::true_type; + static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion( + const void* object); +}; + +struct WeakCrossThreadPersistentPolicy { + using IsStrongPersistent = std::false_type; + static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion( + const void* object); +}; + +// Forward declarations setting up the default policies. +template +class BasicCrossThreadPersistent; +template +class BasicPersistent; +template +class BasicMember; + +} // namespace internal + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/internal/write-barrier.h b/NativeScript/napi/v8/include_old/cppgc/internal/write-barrier.h new file mode 100644 index 00000000..566724d3 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/internal/write-barrier.h @@ -0,0 +1,487 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_ +#define INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_ + +#include +#include + +#include "cppgc/heap-handle.h" +#include "cppgc/heap-state.h" +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/atomic-entry-flag.h" +#include "cppgc/internal/base-page-handle.h" +#include "cppgc/internal/member-storage.h" +#include "cppgc/platform.h" +#include "cppgc/sentinel-pointer.h" +#include "cppgc/trace-trait.h" +#include "v8config.h" // NOLINT(build/include_directory) + +#if defined(CPPGC_CAGED_HEAP) +#include "cppgc/internal/caged-heap-local-data.h" +#include "cppgc/internal/caged-heap.h" +#endif + +namespace cppgc { + +class HeapHandle; + +namespace internal { + +#if defined(CPPGC_CAGED_HEAP) +class WriteBarrierTypeForCagedHeapPolicy; +#else // !CPPGC_CAGED_HEAP +class WriteBarrierTypeForNonCagedHeapPolicy; +#endif // !CPPGC_CAGED_HEAP + +class V8_EXPORT WriteBarrier final { + public: + enum class Type : uint8_t { + kNone, + kMarking, + kGenerational, + }; + + enum class GenerationalBarrierType : uint8_t { + kPreciseSlot, + kPreciseUncompressedSlot, + kImpreciseSlot, + }; + + struct Params { + HeapHandle* heap = nullptr; +#if V8_ENABLE_CHECKS + Type type = Type::kNone; +#endif // !V8_ENABLE_CHECKS +#if defined(CPPGC_CAGED_HEAP) + uintptr_t slot_offset = 0; + uintptr_t value_offset = 0; +#endif // CPPGC_CAGED_HEAP + }; + + enum class ValueMode { + kValuePresent, + kNoValuePresent, + }; + + // Returns the required write barrier for a given `slot` and `value`. + static V8_INLINE Type GetWriteBarrierType(const void* slot, const void* value, + Params& params); + // Returns the required write barrier for a given `slot` and `value`. + template + static V8_INLINE Type GetWriteBarrierType(const void* slot, MemberStorage, + Params& params); + // Returns the required write barrier for a given `slot`. + template + static V8_INLINE Type GetWriteBarrierType(const void* slot, Params& params, + HeapHandleCallback callback); + // Returns the required write barrier for a given `value`. + static V8_INLINE Type GetWriteBarrierType(const void* value, Params& params); + +#ifdef CPPGC_SLIM_WRITE_BARRIER + // A write barrier that combines `GenerationalBarrier()` and + // `DijkstraMarkingBarrier()`. We only pass a single parameter here to clobber + // as few registers as possible. + template + static V8_NOINLINE void V8_PRESERVE_MOST + CombinedWriteBarrierSlow(const void* slot); +#endif // CPPGC_SLIM_WRITE_BARRIER + + static V8_INLINE void DijkstraMarkingBarrier(const Params& params, + const void* object); + static V8_INLINE void DijkstraMarkingBarrierRange( + const Params& params, const void* first_element, size_t element_size, + size_t number_of_elements, TraceCallback trace_callback); + static V8_INLINE void SteeleMarkingBarrier(const Params& params, + const void* object); +#if defined(CPPGC_YOUNG_GENERATION) + template + static V8_INLINE void GenerationalBarrier(const Params& params, + const void* slot); +#else // !CPPGC_YOUNG_GENERATION + template + static V8_INLINE void GenerationalBarrier(const Params& params, + const void* slot){} +#endif // CPPGC_YOUNG_GENERATION + +#if V8_ENABLE_CHECKS + static void CheckParams(Type expected_type, const Params& params); +#else // !V8_ENABLE_CHECKS + static void CheckParams(Type expected_type, const Params& params) {} +#endif // !V8_ENABLE_CHECKS + + // The FlagUpdater class allows cppgc internal to update + // |write_barrier_enabled_|. + class FlagUpdater; + static bool IsEnabled() { return write_barrier_enabled_.MightBeEntered(); } + + private: + WriteBarrier() = delete; + +#if defined(CPPGC_CAGED_HEAP) + using WriteBarrierTypePolicy = WriteBarrierTypeForCagedHeapPolicy; +#else // !CPPGC_CAGED_HEAP + using WriteBarrierTypePolicy = WriteBarrierTypeForNonCagedHeapPolicy; +#endif // !CPPGC_CAGED_HEAP + + static void DijkstraMarkingBarrierSlow(const void* value); + static void DijkstraMarkingBarrierSlowWithSentinelCheck(const void* value); + static void DijkstraMarkingBarrierRangeSlow(HeapHandle& heap_handle, + const void* first_element, + size_t element_size, + size_t number_of_elements, + TraceCallback trace_callback); + static void SteeleMarkingBarrierSlow(const void* value); + static void SteeleMarkingBarrierSlowWithSentinelCheck(const void* value); + +#if defined(CPPGC_YOUNG_GENERATION) + static CagedHeapLocalData& GetLocalData(HeapHandle&); + static void GenerationalBarrierSlow(const CagedHeapLocalData& local_data, + const AgeTable& age_table, + const void* slot, uintptr_t value_offset, + HeapHandle* heap_handle); + static void GenerationalBarrierForUncompressedSlotSlow( + const CagedHeapLocalData& local_data, const AgeTable& age_table, + const void* slot, uintptr_t value_offset, HeapHandle* heap_handle); + static void GenerationalBarrierForSourceObjectSlow( + const CagedHeapLocalData& local_data, const void* object, + HeapHandle* heap_handle); +#endif // CPPGC_YOUNG_GENERATION + + static AtomicEntryFlag write_barrier_enabled_; +}; + +template +V8_INLINE WriteBarrier::Type SetAndReturnType(WriteBarrier::Params& params) { + if constexpr (type == WriteBarrier::Type::kNone) + return WriteBarrier::Type::kNone; +#if V8_ENABLE_CHECKS + params.type = type; +#endif // !V8_ENABLE_CHECKS + return type; +} + +#if defined(CPPGC_CAGED_HEAP) +class V8_EXPORT WriteBarrierTypeForCagedHeapPolicy final { + public: + template + static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value, + WriteBarrier::Params& params, + HeapHandleCallback callback) { + return ValueModeDispatch::Get(slot, value, params, callback); + } + + template + static V8_INLINE WriteBarrier::Type Get(const void* slot, MemberStorage value, + WriteBarrier::Params& params, + HeapHandleCallback callback) { + return ValueModeDispatch::Get(slot, value, params, callback); + } + + template + static V8_INLINE WriteBarrier::Type Get(const void* value, + WriteBarrier::Params& params, + HeapHandleCallback callback) { + return GetNoSlot(value, params, callback); + } + + private: + WriteBarrierTypeForCagedHeapPolicy() = delete; + + template + static V8_INLINE WriteBarrier::Type GetNoSlot(const void* value, + WriteBarrier::Params& params, + HeapHandleCallback) { + const bool within_cage = CagedHeapBase::IsWithinCage(value); + if (!within_cage) return WriteBarrier::Type::kNone; + + // We know that |value| points either within the normal page or to the + // beginning of large-page, so extract the page header by bitmasking. + BasePageHandle* page = + BasePageHandle::FromPayload(const_cast(value)); + + HeapHandle& heap_handle = page->heap_handle(); + if (V8_UNLIKELY(heap_handle.is_incremental_marking_in_progress())) { + return SetAndReturnType(params); + } + + return SetAndReturnType(params); + } + + template + struct ValueModeDispatch; +}; + +template <> +struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch< + WriteBarrier::ValueMode::kValuePresent> { + template + static V8_INLINE WriteBarrier::Type Get(const void* slot, + MemberStorage storage, + WriteBarrier::Params& params, + HeapHandleCallback) { + if (V8_LIKELY(!WriteBarrier::IsEnabled())) + return SetAndReturnType(params); + + return BarrierEnabledGet(slot, storage.Load(), params); + } + + template + static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value, + WriteBarrier::Params& params, + HeapHandleCallback) { + if (V8_LIKELY(!WriteBarrier::IsEnabled())) + return SetAndReturnType(params); + + return BarrierEnabledGet(slot, value, params); + } + + private: + static V8_INLINE WriteBarrier::Type BarrierEnabledGet( + const void* slot, const void* value, WriteBarrier::Params& params) { + const bool within_cage = CagedHeapBase::AreWithinCage(slot, value); + if (!within_cage) return WriteBarrier::Type::kNone; + + // We know that |value| points either within the normal page or to the + // beginning of large-page, so extract the page header by bitmasking. + BasePageHandle* page = + BasePageHandle::FromPayload(const_cast(value)); + + HeapHandle& heap_handle = page->heap_handle(); + if (V8_LIKELY(!heap_handle.is_incremental_marking_in_progress())) { +#if defined(CPPGC_YOUNG_GENERATION) + if (!heap_handle.is_young_generation_enabled()) + return WriteBarrier::Type::kNone; + params.heap = &heap_handle; + params.slot_offset = CagedHeapBase::OffsetFromAddress(slot); + params.value_offset = CagedHeapBase::OffsetFromAddress(value); + return SetAndReturnType(params); +#else // !CPPGC_YOUNG_GENERATION + return SetAndReturnType(params); +#endif // !CPPGC_YOUNG_GENERATION + } + + // Use marking barrier. + params.heap = &heap_handle; + return SetAndReturnType(params); + } +}; + +template <> +struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch< + WriteBarrier::ValueMode::kNoValuePresent> { + template + static V8_INLINE WriteBarrier::Type Get(const void* slot, const void*, + WriteBarrier::Params& params, + HeapHandleCallback callback) { + if (V8_LIKELY(!WriteBarrier::IsEnabled())) + return SetAndReturnType(params); + + HeapHandle& handle = callback(); +#if defined(CPPGC_YOUNG_GENERATION) + if (V8_LIKELY(!handle.is_incremental_marking_in_progress())) { + if (!handle.is_young_generation_enabled()) { + return WriteBarrier::Type::kNone; + } + params.heap = &handle; + // Check if slot is on stack. + if (V8_UNLIKELY(!CagedHeapBase::IsWithinCage(slot))) { + return SetAndReturnType(params); + } + params.slot_offset = CagedHeapBase::OffsetFromAddress(slot); + return SetAndReturnType(params); + } +#else // !defined(CPPGC_YOUNG_GENERATION) + if (V8_UNLIKELY(!handle.is_incremental_marking_in_progress())) { + return SetAndReturnType(params); + } +#endif // !defined(CPPGC_YOUNG_GENERATION) + params.heap = &handle; + return SetAndReturnType(params); + } +}; + +#endif // CPPGC_CAGED_HEAP + +class V8_EXPORT WriteBarrierTypeForNonCagedHeapPolicy final { + public: + template + static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value, + WriteBarrier::Params& params, + HeapHandleCallback callback) { + return ValueModeDispatch::Get(slot, value, params, callback); + } + + template + static V8_INLINE WriteBarrier::Type Get(const void* slot, RawPointer value, + WriteBarrier::Params& params, + HeapHandleCallback callback) { + return ValueModeDispatch::Get(slot, value.Load(), params, + callback); + } + + template + static V8_INLINE WriteBarrier::Type Get(const void* value, + WriteBarrier::Params& params, + HeapHandleCallback callback) { + // The slot will never be used in `Get()` below. + return Get(nullptr, value, params, + callback); + } + + private: + template + struct ValueModeDispatch; + + WriteBarrierTypeForNonCagedHeapPolicy() = delete; +}; + +template <> +struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch< + WriteBarrier::ValueMode::kValuePresent> { + template + static V8_INLINE WriteBarrier::Type Get(const void*, const void* object, + WriteBarrier::Params& params, + HeapHandleCallback callback) { + // The following check covers nullptr as well as sentinel pointer. + if (object <= static_cast(kSentinelPointer)) { + return SetAndReturnType(params); + } + if (V8_LIKELY(!WriteBarrier::IsEnabled())) { + return SetAndReturnType(params); + } + // We know that |object| is within the normal page or in the beginning of a + // large page, so extract the page header by bitmasking. + BasePageHandle* page = + BasePageHandle::FromPayload(const_cast(object)); + + HeapHandle& heap_handle = page->heap_handle(); + if (V8_LIKELY(heap_handle.is_incremental_marking_in_progress())) { + return SetAndReturnType(params); + } + return SetAndReturnType(params); + } +}; + +template <> +struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch< + WriteBarrier::ValueMode::kNoValuePresent> { + template + static V8_INLINE WriteBarrier::Type Get(const void*, const void*, + WriteBarrier::Params& params, + HeapHandleCallback callback) { + if (V8_UNLIKELY(WriteBarrier::IsEnabled())) { + HeapHandle& handle = callback(); + if (V8_LIKELY(handle.is_incremental_marking_in_progress())) { + params.heap = &handle; + return SetAndReturnType(params); + } + } + return WriteBarrier::Type::kNone; + } +}; + +// static +WriteBarrier::Type WriteBarrier::GetWriteBarrierType( + const void* slot, const void* value, WriteBarrier::Params& params) { + return WriteBarrierTypePolicy::Get(slot, value, + params, []() {}); +} + +// static +template +WriteBarrier::Type WriteBarrier::GetWriteBarrierType( + const void* slot, MemberStorage value, WriteBarrier::Params& params) { + return WriteBarrierTypePolicy::Get(slot, value, + params, []() {}); +} + +// static +template +WriteBarrier::Type WriteBarrier::GetWriteBarrierType( + const void* slot, WriteBarrier::Params& params, + HeapHandleCallback callback) { + return WriteBarrierTypePolicy::Get( + slot, nullptr, params, callback); +} + +// static +WriteBarrier::Type WriteBarrier::GetWriteBarrierType( + const void* value, WriteBarrier::Params& params) { + return WriteBarrierTypePolicy::Get(value, params, + []() {}); +} + +// static +void WriteBarrier::DijkstraMarkingBarrier(const Params& params, + const void* object) { + CheckParams(Type::kMarking, params); +#if defined(CPPGC_CAGED_HEAP) + // Caged heap already filters out sentinels. + DijkstraMarkingBarrierSlow(object); +#else // !CPPGC_CAGED_HEAP + DijkstraMarkingBarrierSlowWithSentinelCheck(object); +#endif // !CPPGC_CAGED_HEAP +} + +// static +void WriteBarrier::DijkstraMarkingBarrierRange(const Params& params, + const void* first_element, + size_t element_size, + size_t number_of_elements, + TraceCallback trace_callback) { + CheckParams(Type::kMarking, params); + DijkstraMarkingBarrierRangeSlow(*params.heap, first_element, element_size, + number_of_elements, trace_callback); +} + +// static +void WriteBarrier::SteeleMarkingBarrier(const Params& params, + const void* object) { + CheckParams(Type::kMarking, params); +#if defined(CPPGC_CAGED_HEAP) + // Caged heap already filters out sentinels. + SteeleMarkingBarrierSlow(object); +#else // !CPPGC_CAGED_HEAP + SteeleMarkingBarrierSlowWithSentinelCheck(object); +#endif // !CPPGC_CAGED_HEAP +} + +#if defined(CPPGC_YOUNG_GENERATION) + +// static +template +void WriteBarrier::GenerationalBarrier(const Params& params, const void* slot) { + CheckParams(Type::kGenerational, params); + + const CagedHeapLocalData& local_data = CagedHeapLocalData::Get(); + const AgeTable& age_table = local_data.age_table; + + // Bail out if the slot (precise or imprecise) is in young generation. + if (V8_LIKELY(age_table.GetAge(params.slot_offset) == AgeTable::Age::kYoung)) + return; + + // Dispatch between different types of barriers. + // TODO(chromium:1029379): Consider reload local_data in the slow path to + // reduce register pressure. + if constexpr (type == GenerationalBarrierType::kPreciseSlot) { + GenerationalBarrierSlow(local_data, age_table, slot, params.value_offset, + params.heap); + } else if constexpr (type == + GenerationalBarrierType::kPreciseUncompressedSlot) { + GenerationalBarrierForUncompressedSlotSlow( + local_data, age_table, slot, params.value_offset, params.heap); + } else { + GenerationalBarrierForSourceObjectSlow(local_data, slot, params.heap); + } +} + +#endif // !CPPGC_YOUNG_GENERATION + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/liveness-broker.h b/NativeScript/napi/v8/include_old/cppgc/liveness-broker.h new file mode 100644 index 00000000..2c94f1c0 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/liveness-broker.h @@ -0,0 +1,78 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_LIVENESS_BROKER_H_ +#define INCLUDE_CPPGC_LIVENESS_BROKER_H_ + +#include "cppgc/heap.h" +#include "cppgc/member.h" +#include "cppgc/sentinel-pointer.h" +#include "cppgc/trace-trait.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +namespace internal { +class LivenessBrokerFactory; +} // namespace internal + +/** + * The broker is passed to weak callbacks to allow (temporarily) querying + * the liveness state of an object. References to non-live objects must be + * cleared when `IsHeapObjectAlive()` returns false. + * + * \code + * class GCedWithCustomWeakCallback final + * : public GarbageCollected { + * public: + * UntracedMember bar; + * + * void CustomWeakCallbackMethod(const LivenessBroker& broker) { + * if (!broker.IsHeapObjectAlive(bar)) + * bar = nullptr; + * } + * + * void Trace(cppgc::Visitor* visitor) const { + * visitor->RegisterWeakCallbackMethod< + * GCedWithCustomWeakCallback, + * &GCedWithCustomWeakCallback::CustomWeakCallbackMethod>(this); + * } + * }; + * \endcode + */ +class V8_EXPORT LivenessBroker final { + public: + template + bool IsHeapObjectAlive(const T* object) const { + // - nullptr objects are considered alive to allow weakness to be used from + // stack while running into a conservative GC. Treating nullptr as dead + // would mean that e.g. custom collections could not be strongified on + // stack. + // - Sentinel pointers are also preserved in weakness and not cleared. + return !object || object == kSentinelPointer || + IsHeapObjectAliveImpl( + TraceTrait::GetTraceDescriptor(object).base_object_payload); + } + + template + bool IsHeapObjectAlive(const WeakMember& weak_member) const { + return IsHeapObjectAlive(weak_member.Get()); + } + + template + bool IsHeapObjectAlive(const UntracedMember& untraced_member) const { + return IsHeapObjectAlive(untraced_member.Get()); + } + + private: + LivenessBroker() = default; + + bool IsHeapObjectAliveImpl(const void*) const; + + friend class internal::LivenessBrokerFactory; +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_LIVENESS_BROKER_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/macros.h b/NativeScript/napi/v8/include_old/cppgc/macros.h new file mode 100644 index 00000000..a9ac22d7 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/macros.h @@ -0,0 +1,35 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_MACROS_H_ +#define INCLUDE_CPPGC_MACROS_H_ + +#include + +#include "cppgc/internal/compiler-specific.h" + +namespace cppgc { + +// Use CPPGC_STACK_ALLOCATED if the object is only stack allocated. +// Add the CPPGC_STACK_ALLOCATED_IGNORE annotation on a case-by-case basis when +// enforcement of CPPGC_STACK_ALLOCATED should be suppressed. +#if defined(__clang__) +#define CPPGC_STACK_ALLOCATED() \ + public: \ + using IsStackAllocatedTypeMarker CPPGC_UNUSED = int; \ + \ + private: \ + void* operator new(size_t) = delete; \ + void* operator new(size_t, void*) = delete; \ + static_assert(true, "Force semicolon.") +#define CPPGC_STACK_ALLOCATED_IGNORE(bug_or_reason) \ + __attribute__((annotate("stack_allocated_ignore"))) +#else // !defined(__clang__) +#define CPPGC_STACK_ALLOCATED() static_assert(true, "Force semicolon.") +#define CPPGC_STACK_ALLOCATED_IGNORE(bug_or_reason) +#endif // !defined(__clang__) + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_MACROS_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/member.h b/NativeScript/napi/v8/include_old/cppgc/member.h new file mode 100644 index 00000000..457f163b --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/member.h @@ -0,0 +1,629 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_MEMBER_H_ +#define INCLUDE_CPPGC_MEMBER_H_ + +#include +#include +#include + +#include "cppgc/internal/api-constants.h" +#include "cppgc/internal/member-storage.h" +#include "cppgc/internal/pointer-policies.h" +#include "cppgc/sentinel-pointer.h" +#include "cppgc/type-traits.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +namespace subtle { +class HeapConsistency; +} // namespace subtle + +class Visitor; + +namespace internal { + +// MemberBase always refers to the object as const object and defers to +// BasicMember on casting to the right type as needed. +template +class V8_TRIVIAL_ABI MemberBase { + public: + using RawStorage = StorageType; + + protected: + struct AtomicInitializerTag {}; + + V8_INLINE MemberBase() = default; + V8_INLINE explicit MemberBase(const void* value) : raw_(value) {} + V8_INLINE MemberBase(const void* value, AtomicInitializerTag) { + SetRawAtomic(value); + } + + V8_INLINE explicit MemberBase(RawStorage raw) : raw_(raw) {} + V8_INLINE explicit MemberBase(std::nullptr_t) : raw_(nullptr) {} + V8_INLINE explicit MemberBase(SentinelPointer s) : raw_(s) {} + + V8_INLINE const void** GetRawSlot() const { + return reinterpret_cast(const_cast(this)); + } + V8_INLINE const void* GetRaw() const { return raw_.Load(); } + V8_INLINE void SetRaw(void* value) { raw_.Store(value); } + + V8_INLINE const void* GetRawAtomic() const { return raw_.LoadAtomic(); } + V8_INLINE void SetRawAtomic(const void* value) { raw_.StoreAtomic(value); } + + V8_INLINE RawStorage GetRawStorage() const { return raw_; } + V8_INLINE void SetRawStorageAtomic(RawStorage other) { + reinterpret_cast&>(raw_).store( + other, std::memory_order_relaxed); + } + + V8_INLINE bool IsCleared() const { return raw_.IsCleared(); } + + V8_INLINE void ClearFromGC() const { raw_.Clear(); } + + private: + friend class MemberDebugHelper; + + mutable RawStorage raw_; +}; + +// The basic class from which all Member classes are 'generated'. +template +class V8_TRIVIAL_ABI BasicMember final : private MemberBase, + private CheckingPolicy { + using Base = MemberBase; + + public: + using PointeeType = T; + using RawStorage = typename Base::RawStorage; + + V8_INLINE constexpr BasicMember() = default; + V8_INLINE constexpr BasicMember(std::nullptr_t) {} // NOLINT + V8_INLINE BasicMember(SentinelPointer s) : Base(s) {} // NOLINT + V8_INLINE BasicMember(T* raw) : Base(raw) { // NOLINT + InitializingWriteBarrier(raw); + this->CheckPointer(Get()); + } + V8_INLINE BasicMember(T& raw) // NOLINT + : BasicMember(&raw) {} + + // Atomic ctor. Using the AtomicInitializerTag forces BasicMember to + // initialize using atomic assignments. This is required for preventing + // data races with concurrent marking. + using AtomicInitializerTag = typename Base::AtomicInitializerTag; + V8_INLINE BasicMember(std::nullptr_t, AtomicInitializerTag atomic) + : Base(nullptr, atomic) {} + V8_INLINE BasicMember(SentinelPointer s, AtomicInitializerTag atomic) + : Base(s, atomic) {} + V8_INLINE BasicMember(T* raw, AtomicInitializerTag atomic) + : Base(raw, atomic) { + InitializingWriteBarrier(raw); + this->CheckPointer(Get()); + } + V8_INLINE BasicMember(T& raw, AtomicInitializerTag atomic) + : BasicMember(&raw, atomic) {} + + // Copy ctor. + V8_INLINE BasicMember(const BasicMember& other) + : BasicMember(other.GetRawStorage()) {} + + // Heterogeneous copy constructors. When the source pointer have a different + // type, perform a compress-decompress round, because the source pointer may + // need to be adjusted. + template >* = nullptr> + V8_INLINE BasicMember( // NOLINT + const BasicMember& other) + : BasicMember(other.GetRawStorage()) {} + + template >* = nullptr> + V8_INLINE BasicMember( // NOLINT + const BasicMember& other) + : BasicMember(other.Get()) {} + + // Move ctor. + V8_INLINE BasicMember(BasicMember&& other) noexcept + : BasicMember(other.GetRawStorage()) { + other.Clear(); + } + + // Heterogeneous move constructors. When the source pointer have a different + // type, perform a compress-decompress round, because the source pointer may + // need to be adjusted. + template >* = nullptr> + V8_INLINE BasicMember( + BasicMember&& other) noexcept + : BasicMember(other.GetRawStorage()) { + other.Clear(); + } + + template >* = nullptr> + V8_INLINE BasicMember( + BasicMember&& other) noexcept + : BasicMember(other.Get()) { + other.Clear(); + } + + // Construction from Persistent. + template ::value>> + V8_INLINE BasicMember(const BasicPersistent& p) + : BasicMember(p.Get()) {} + + // Copy assignment. + V8_INLINE BasicMember& operator=(const BasicMember& other) { + return operator=(other.GetRawStorage()); + } + + // Heterogeneous copy assignment. When the source pointer have a different + // type, perform a compress-decompress round, because the source pointer may + // need to be adjusted. + template + V8_INLINE BasicMember& operator=( + const BasicMember& other) { + if constexpr (internal::IsDecayedSameV) { + return operator=(other.GetRawStorage()); + } else { + static_assert(internal::IsStrictlyBaseOfV); + return operator=(other.Get()); + } + } + + // Move assignment. + V8_INLINE BasicMember& operator=(BasicMember&& other) noexcept { + operator=(other.GetRawStorage()); + other.Clear(); + return *this; + } + + // Heterogeneous move assignment. When the source pointer have a different + // type, perform a compress-decompress round, because the source pointer may + // need to be adjusted. + template + V8_INLINE BasicMember& operator=( + BasicMember&& other) noexcept { + if constexpr (internal::IsDecayedSameV) { + operator=(other.GetRawStorage()); + } else { + static_assert(internal::IsStrictlyBaseOfV); + operator=(other.Get()); + } + other.Clear(); + return *this; + } + + // Assignment from Persistent. + template ::value>> + V8_INLINE BasicMember& operator=( + const BasicPersistent& + other) { + return operator=(other.Get()); + } + + V8_INLINE BasicMember& operator=(T* other) { + Base::SetRawAtomic(other); + AssigningWriteBarrier(other); + this->CheckPointer(Get()); + return *this; + } + + V8_INLINE BasicMember& operator=(std::nullptr_t) { + Clear(); + return *this; + } + V8_INLINE BasicMember& operator=(SentinelPointer s) { + Base::SetRawAtomic(s); + return *this; + } + + template + V8_INLINE void Swap(BasicMember& other) { + auto tmp = GetRawStorage(); + *this = other; + other = tmp; + } + + V8_INLINE explicit operator bool() const { return !Base::IsCleared(); } + V8_INLINE operator T*() const { return Get(); } + V8_INLINE T* operator->() const { return Get(); } + V8_INLINE T& operator*() const { return *Get(); } + + // CFI cast exemption to allow passing SentinelPointer through T* and support + // heterogeneous assignments between different Member and Persistent handles + // based on their actual types. + V8_INLINE V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { + // Executed by the mutator, hence non atomic load. + // + // The const_cast below removes the constness from MemberBase storage. The + // following static_cast re-adds any constness if specified through the + // user-visible template parameter T. + return static_cast(const_cast(Base::GetRaw())); + } + + V8_INLINE void Clear() { + Base::SetRawStorageAtomic(RawStorage{}); + } + + V8_INLINE T* Release() { + T* result = Get(); + Clear(); + return result; + } + + V8_INLINE const T** GetSlotForTesting() const { + return reinterpret_cast(Base::GetRawSlot()); + } + + V8_INLINE RawStorage GetRawStorage() const { + return Base::GetRawStorage(); + } + + private: + V8_INLINE explicit BasicMember(RawStorage raw) : Base(raw) { + InitializingWriteBarrier(Get()); + this->CheckPointer(Get()); + } + + V8_INLINE BasicMember& operator=(RawStorage other) { + Base::SetRawStorageAtomic(other); + AssigningWriteBarrier(); + this->CheckPointer(Get()); + return *this; + } + + V8_INLINE const T* GetRawAtomic() const { + return static_cast(Base::GetRawAtomic()); + } + + V8_INLINE void InitializingWriteBarrier(T* value) const { + WriteBarrierPolicy::InitializingBarrier(Base::GetRawSlot(), value); + } + V8_INLINE void AssigningWriteBarrier(T* value) const { + WriteBarrierPolicy::template AssigningBarrier< + StorageType::kWriteBarrierSlotType>(Base::GetRawSlot(), value); + } + V8_INLINE void AssigningWriteBarrier() const { + WriteBarrierPolicy::template AssigningBarrier< + StorageType::kWriteBarrierSlotType>(Base::GetRawSlot(), + Base::GetRawStorage()); + } + + V8_INLINE void ClearFromGC() const { Base::ClearFromGC(); } + + V8_INLINE T* GetFromGC() const { return Get(); } + + friend class cppgc::subtle::HeapConsistency; + friend class cppgc::Visitor; + template + friend struct cppgc::TraceTrait; + template + friend class BasicMember; +}; + +// Member equality operators. +template +V8_INLINE bool operator==( + const BasicMember& member1, + const BasicMember& member2) { + if constexpr (internal::IsDecayedSameV) { + // Check compressed pointers if types are the same. + return member1.GetRawStorage() == member2.GetRawStorage(); + } else { + static_assert(internal::IsStrictlyBaseOfV || + internal::IsStrictlyBaseOfV); + // Otherwise, check decompressed pointers. + return member1.Get() == member2.Get(); + } +} + +template +V8_INLINE bool operator!=( + const BasicMember& member1, + const BasicMember& member2) { + return !(member1 == member2); +} + +// Equality with raw pointers. +template +V8_INLINE bool operator==( + const BasicMember& member, + U* raw) { + // Never allow comparison with erased pointers. + static_assert(!internal::IsDecayedSameV); + + if constexpr (internal::IsDecayedSameV) { + // Check compressed pointers if types are the same. + return member.GetRawStorage() == StorageType(raw); + } else if constexpr (internal::IsStrictlyBaseOfV) { + // Cast the raw pointer to T, which may adjust the pointer. + return member.GetRawStorage() == StorageType(static_cast(raw)); + } else { + // Otherwise, decompressed the member. + return member.Get() == raw; + } +} + +template +V8_INLINE bool operator!=( + const BasicMember& member, + U* raw) { + return !(member == raw); +} + +template +V8_INLINE bool operator==( + T* raw, const BasicMember& member) { + return member == raw; +} + +template +V8_INLINE bool operator!=( + T* raw, const BasicMember& member) { + return !(raw == member); +} + +// Equality with sentinel. +template +V8_INLINE bool operator==( + const BasicMember& member, + SentinelPointer) { + return member.GetRawStorage().IsSentinel(); +} + +template +V8_INLINE bool operator!=( + const BasicMember& member, + SentinelPointer s) { + return !(member == s); +} + +template +V8_INLINE bool operator==( + SentinelPointer s, const BasicMember& member) { + return member == s; +} + +template +V8_INLINE bool operator!=( + SentinelPointer s, const BasicMember& member) { + return !(s == member); +} + +// Equality with nullptr. +template +V8_INLINE bool operator==( + const BasicMember& member, + std::nullptr_t) { + return !static_cast(member); +} + +template +V8_INLINE bool operator!=( + const BasicMember& member, + std::nullptr_t n) { + return !(member == n); +} + +template +V8_INLINE bool operator==( + std::nullptr_t n, const BasicMember& member) { + return member == n; +} + +template +V8_INLINE bool operator!=( + std::nullptr_t n, const BasicMember& member) { + return !(n == member); +} + +// Relational operators. +template +V8_INLINE bool operator<( + const BasicMember& member1, + const BasicMember& member2) { + static_assert( + internal::IsDecayedSameV, + "Comparison works only for same pointer type modulo cv-qualifiers"); + return member1.GetRawStorage() < member2.GetRawStorage(); +} + +template +V8_INLINE bool operator<=( + const BasicMember& member1, + const BasicMember& member2) { + static_assert( + internal::IsDecayedSameV, + "Comparison works only for same pointer type modulo cv-qualifiers"); + return member1.GetRawStorage() <= member2.GetRawStorage(); +} + +template +V8_INLINE bool operator>( + const BasicMember& member1, + const BasicMember& member2) { + static_assert( + internal::IsDecayedSameV, + "Comparison works only for same pointer type modulo cv-qualifiers"); + return member1.GetRawStorage() > member2.GetRawStorage(); +} + +template +V8_INLINE bool operator>=( + const BasicMember& member1, + const BasicMember& member2) { + static_assert( + internal::IsDecayedSameV, + "Comparison works only for same pointer type modulo cv-qualifiers"); + return member1.GetRawStorage() >= member2.GetRawStorage(); +} + +template +struct IsWeak> + : std::true_type {}; + +} // namespace internal + +/** + * Members are used in classes to contain strong pointers to other garbage + * collected objects. All Member fields of a class must be traced in the class' + * trace method. + */ +template +using Member = internal::BasicMember< + T, internal::StrongMemberTag, internal::DijkstraWriteBarrierPolicy, + internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>; + +/** + * WeakMember is similar to Member in that it is used to point to other garbage + * collected objects. However instead of creating a strong pointer to the + * object, the WeakMember creates a weak pointer, which does not keep the + * pointee alive. Hence if all pointers to to a heap allocated object are weak + * the object will be garbage collected. At the time of GC the weak pointers + * will automatically be set to null. + */ +template +using WeakMember = internal::BasicMember< + T, internal::WeakMemberTag, internal::DijkstraWriteBarrierPolicy, + internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>; + +/** + * UntracedMember is a pointer to an on-heap object that is not traced for some + * reason. Do not use this unless you know what you are doing. Keeping raw + * pointers to on-heap objects is prohibited unless used from stack. Pointee + * must be kept alive through other means. + */ +template +using UntracedMember = internal::BasicMember< + T, internal::UntracedMemberTag, internal::NoWriteBarrierPolicy, + internal::DefaultMemberCheckingPolicy, internal::DefaultMemberStorage>; + +namespace subtle { + +/** + * UncompressedMember. Use with care in hot paths that would otherwise cause + * many decompression cycles. + */ +template +using UncompressedMember = internal::BasicMember< + T, internal::StrongMemberTag, internal::DijkstraWriteBarrierPolicy, + internal::DefaultMemberCheckingPolicy, internal::RawPointer>; + +#if defined(CPPGC_POINTER_COMPRESSION) +/** + * CompressedMember. Default implementation of cppgc::Member on builds with + * pointer compression. + */ +template +using CompressedMember = internal::BasicMember< + T, internal::StrongMemberTag, internal::DijkstraWriteBarrierPolicy, + internal::DefaultMemberCheckingPolicy, internal::CompressedPointer>; +#endif // defined(CPPGC_POINTER_COMPRESSION) + +} // namespace subtle + +namespace internal { + +struct Dummy; + +static constexpr size_t kSizeOfMember = sizeof(Member); +static constexpr size_t kSizeOfUncompressedMember = + sizeof(subtle::UncompressedMember); +#if defined(CPPGC_POINTER_COMPRESSION) +static constexpr size_t kSizeofCompressedMember = + sizeof(subtle::CompressedMember); +#endif // defined(CPPGC_POINTER_COMPRESSION) + +} // namespace internal + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_MEMBER_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/name-provider.h b/NativeScript/napi/v8/include_old/cppgc/name-provider.h new file mode 100644 index 00000000..216f6098 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/name-provider.h @@ -0,0 +1,65 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_NAME_PROVIDER_H_ +#define INCLUDE_CPPGC_NAME_PROVIDER_H_ + +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +/** + * NameProvider allows for providing a human-readable name for garbage-collected + * objects. + * + * There's two cases of names to distinguish: + * a. Explicitly specified names via using NameProvider. Such names are always + * preserved in the system. + * b. Internal names that Oilpan infers from a C++ type on the class hierarchy + * of the object. This is not necessarily the type of the actually + * instantiated object. + * + * Depending on the build configuration, Oilpan may hide names, i.e., represent + * them with kHiddenName, of case b. to avoid exposing internal details. + */ +class V8_EXPORT NameProvider { + public: + /** + * Name that is used when hiding internals. + */ + static constexpr const char kHiddenName[] = "InternalNode"; + + /** + * Name that is used in case compiler support is missing for composing a name + * from C++ types. + */ + static constexpr const char kNoNameDeducible[] = ""; + + /** + * Indicating whether the build supports extracting C++ names as object names. + * + * @returns true if C++ names should be hidden and represented by kHiddenName. + */ + static constexpr bool SupportsCppClassNamesAsObjectNames() { +#if CPPGC_SUPPORTS_OBJECT_NAMES + return true; +#else // !CPPGC_SUPPORTS_OBJECT_NAMES + return false; +#endif // !CPPGC_SUPPORTS_OBJECT_NAMES + } + + virtual ~NameProvider() = default; + + /** + * Specifies a name for the garbage-collected object. Such names will never + * be hidden, as they are explicitly specified by the user of this API. + * + * @returns a human readable name for the object. + */ + virtual const char* GetHumanReadableName() const = 0; +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_NAME_PROVIDER_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/object-size-trait.h b/NativeScript/napi/v8/include_old/cppgc/object-size-trait.h new file mode 100644 index 00000000..35795596 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/object-size-trait.h @@ -0,0 +1,58 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_ +#define INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_ + +#include + +#include "cppgc/type-traits.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +namespace internal { + +struct V8_EXPORT BaseObjectSizeTrait { + protected: + static size_t GetObjectSizeForGarbageCollected(const void*); + static size_t GetObjectSizeForGarbageCollectedMixin(const void*); +}; + +} // namespace internal + +namespace subtle { + +/** + * Trait specifying how to get the size of an object that was allocated using + * `MakeGarbageCollected()`. Also supports querying the size with an inner + * pointer to a mixin. + */ +template > +struct ObjectSizeTrait; + +template +struct ObjectSizeTrait : cppgc::internal::BaseObjectSizeTrait { + static_assert(sizeof(T), "T must be fully defined"); + static_assert(IsGarbageCollectedTypeV, + "T must be of type GarbageCollected or GarbageCollectedMixin"); + + static size_t GetSize(const T& object) { + return GetObjectSizeForGarbageCollected(&object); + } +}; + +template +struct ObjectSizeTrait : cppgc::internal::BaseObjectSizeTrait { + static_assert(sizeof(T), "T must be fully defined"); + + static size_t GetSize(const T& object) { + return GetObjectSizeForGarbageCollectedMixin(&object); + } +}; + +} // namespace subtle +} // namespace cppgc + +#endif // INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/persistent.h b/NativeScript/napi/v8/include_old/cppgc/persistent.h new file mode 100644 index 00000000..6eb1c659 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/persistent.h @@ -0,0 +1,377 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_PERSISTENT_H_ +#define INCLUDE_CPPGC_PERSISTENT_H_ + +#include + +#include "cppgc/internal/persistent-node.h" +#include "cppgc/internal/pointer-policies.h" +#include "cppgc/sentinel-pointer.h" +#include "cppgc/source-location.h" +#include "cppgc/type-traits.h" +#include "cppgc/visitor.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { + +// PersistentBase always refers to the object as const object and defers to +// BasicPersistent on casting to the right type as needed. +class PersistentBase { + protected: + PersistentBase() = default; + explicit PersistentBase(const void* raw) : raw_(raw) {} + + const void* GetValue() const { return raw_; } + void SetValue(const void* value) { raw_ = value; } + + PersistentNode* GetNode() const { return node_; } + void SetNode(PersistentNode* node) { node_ = node; } + + // Performs a shallow clear which assumes that internal persistent nodes are + // destroyed elsewhere. + void ClearFromGC() const { + raw_ = nullptr; + node_ = nullptr; + } + + protected: + mutable const void* raw_ = nullptr; + mutable PersistentNode* node_ = nullptr; + + friend class PersistentRegionBase; +}; + +// The basic class from which all Persistent classes are generated. +template +class BasicPersistent final : public PersistentBase, + public LocationPolicy, + private WeaknessPolicy, + private CheckingPolicy { + public: + using typename WeaknessPolicy::IsStrongPersistent; + using PointeeType = T; + + // Null-state/sentinel constructors. + BasicPersistent( // NOLINT + const SourceLocation& loc = SourceLocation::Current()) + : LocationPolicy(loc) {} + + BasicPersistent(std::nullptr_t, // NOLINT + const SourceLocation& loc = SourceLocation::Current()) + : LocationPolicy(loc) {} + + BasicPersistent( // NOLINT + SentinelPointer s, const SourceLocation& loc = SourceLocation::Current()) + : PersistentBase(s), LocationPolicy(loc) {} + + // Raw value constructors. + BasicPersistent(T* raw, // NOLINT + const SourceLocation& loc = SourceLocation::Current()) + : PersistentBase(raw), LocationPolicy(loc) { + if (!IsValid()) return; + SetNode(WeaknessPolicy::GetPersistentRegion(GetValue()) + .AllocateNode(this, &TraceAsRoot)); + this->CheckPointer(Get()); + } + + BasicPersistent(T& raw, // NOLINT + const SourceLocation& loc = SourceLocation::Current()) + : BasicPersistent(&raw, loc) {} + + // Copy ctor. + BasicPersistent(const BasicPersistent& other, + const SourceLocation& loc = SourceLocation::Current()) + : BasicPersistent(other.Get(), loc) {} + + // Heterogeneous ctor. + template ::value>> + // NOLINTNEXTLINE + BasicPersistent( + const BasicPersistent& other, + const SourceLocation& loc = SourceLocation::Current()) + : BasicPersistent(other.Get(), loc) {} + + // Move ctor. The heterogeneous move ctor is not supported since e.g. + // persistent can't reuse persistent node from weak persistent. + BasicPersistent( + BasicPersistent&& other, + const SourceLocation& loc = SourceLocation::Current()) noexcept + : PersistentBase(std::move(other)), LocationPolicy(std::move(other)) { + if (!IsValid()) return; + GetNode()->UpdateOwner(this); + other.SetValue(nullptr); + other.SetNode(nullptr); + this->CheckPointer(Get()); + } + + // Constructor from member. + template ::value>> + // NOLINTNEXTLINE + BasicPersistent(const internal::BasicMember< + U, MemberBarrierPolicy, MemberWeaknessTag, + MemberCheckingPolicy, MemberStorageType>& member, + const SourceLocation& loc = SourceLocation::Current()) + : BasicPersistent(member.Get(), loc) {} + + ~BasicPersistent() { Clear(); } + + // Copy assignment. + BasicPersistent& operator=(const BasicPersistent& other) { + return operator=(other.Get()); + } + + template ::value>> + BasicPersistent& operator=( + const BasicPersistent& other) { + return operator=(other.Get()); + } + + // Move assignment. + BasicPersistent& operator=(BasicPersistent&& other) noexcept { + if (this == &other) return *this; + Clear(); + PersistentBase::operator=(std::move(other)); + LocationPolicy::operator=(std::move(other)); + if (!IsValid()) return *this; + GetNode()->UpdateOwner(this); + other.SetValue(nullptr); + other.SetNode(nullptr); + this->CheckPointer(Get()); + return *this; + } + + // Assignment from member. + template ::value>> + BasicPersistent& operator=( + const internal::BasicMember& + member) { + return operator=(member.Get()); + } + + BasicPersistent& operator=(T* other) { + Assign(other); + return *this; + } + + BasicPersistent& operator=(std::nullptr_t) { + Clear(); + return *this; + } + + BasicPersistent& operator=(SentinelPointer s) { + Assign(s); + return *this; + } + + explicit operator bool() const { return Get(); } + // Historically we allow implicit conversions to T*. + // NOLINTNEXTLINE + operator T*() const { return Get(); } + T* operator->() const { return Get(); } + T& operator*() const { return *Get(); } + + // CFI cast exemption to allow passing SentinelPointer through T* and support + // heterogeneous assignments between different Member and Persistent handles + // based on their actual types. + V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { + // The const_cast below removes the constness from PersistentBase storage. + // The following static_cast re-adds any constness if specified through the + // user-visible template parameter T. + return static_cast(const_cast(GetValue())); + } + + void Clear() { + // Simplified version of `Assign()` to allow calling without a complete type + // `T`. + if (IsValid()) { + WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); + SetNode(nullptr); + } + SetValue(nullptr); + } + + T* Release() { + T* result = Get(); + Clear(); + return result; + } + + template + BasicPersistent + To() const { + return BasicPersistent(static_cast(Get())); + } + + private: + static void TraceAsRoot(RootVisitor& root_visitor, const void* ptr) { + root_visitor.Trace(*static_cast(ptr)); + } + + bool IsValid() const { + // Ideally, handling kSentinelPointer would be done by the embedder. On the + // other hand, having Persistent aware of it is beneficial since no node + // gets wasted. + return GetValue() != nullptr && GetValue() != kSentinelPointer; + } + + void Assign(T* ptr) { + if (IsValid()) { + if (ptr && ptr != kSentinelPointer) { + // Simply assign the pointer reusing the existing node. + SetValue(ptr); + this->CheckPointer(ptr); + return; + } + WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); + SetNode(nullptr); + } + SetValue(ptr); + if (!IsValid()) return; + SetNode(WeaknessPolicy::GetPersistentRegion(GetValue()) + .AllocateNode(this, &TraceAsRoot)); + this->CheckPointer(Get()); + } + + void ClearFromGC() const { + if (IsValid()) { + WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); + PersistentBase::ClearFromGC(); + } + } + + // Set Get() for details. + V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") + T* GetFromGC() const { + return static_cast(const_cast(GetValue())); + } + + friend class internal::RootVisitor; +}; + +template +bool operator==(const BasicPersistent& p1, + const BasicPersistent& p2) { + return p1.Get() == p2.Get(); +} + +template +bool operator!=(const BasicPersistent& p1, + const BasicPersistent& p2) { + return !(p1 == p2); +} + +template +bool operator==( + const BasicPersistent& + p, + const BasicMember& m) { + return p.Get() == m.Get(); +} + +template +bool operator!=( + const BasicPersistent& + p, + const BasicMember& m) { + return !(p == m); +} + +template +bool operator==( + const BasicMember& m, + const BasicPersistent& + p) { + return m.Get() == p.Get(); +} + +template +bool operator!=( + const BasicMember& m, + const BasicPersistent& + p) { + return !(m == p); +} + +template +struct IsWeak> : std::true_type {}; +} // namespace internal + +/** + * Persistent is a way to create a strong pointer from an off-heap object to + * another on-heap object. As long as the Persistent handle is alive the GC will + * keep the object pointed to alive. The Persistent handle is always a GC root + * from the point of view of the GC. Persistent must be constructed and + * destructed in the same thread. + */ +template +using Persistent = + internal::BasicPersistent; + +/** + * WeakPersistent is a way to create a weak pointer from an off-heap object to + * an on-heap object. The pointer is automatically cleared when the pointee gets + * collected. WeakPersistent must be constructed and destructed in the same + * thread. + */ +template +using WeakPersistent = + internal::BasicPersistent; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_PERSISTENT_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/platform.h b/NativeScript/napi/v8/include_old/cppgc/platform.h new file mode 100644 index 00000000..ae96579d --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/platform.h @@ -0,0 +1,163 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_PLATFORM_H_ +#define INCLUDE_CPPGC_PLATFORM_H_ + +#include + +#include "cppgc/source-location.h" +#include "v8-platform.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +// TODO(v8:10346): Create separate includes for concepts that are not +// V8-specific. +using IdleTask = v8::IdleTask; +using JobHandle = v8::JobHandle; +using JobDelegate = v8::JobDelegate; +using JobTask = v8::JobTask; +using PageAllocator = v8::PageAllocator; +using Task = v8::Task; +using TaskPriority = v8::TaskPriority; +using TaskRunner = v8::TaskRunner; +using TracingController = v8::TracingController; + +/** + * Platform interface used by Heap. Contains allocators and executors. + */ +class V8_EXPORT Platform { + public: + virtual ~Platform() = default; + + /** + * \returns the allocator used by cppgc to allocate its heap and various + * support structures. Returning nullptr results in using the `PageAllocator` + * provided by `cppgc::InitializeProcess()` instead. + */ + virtual PageAllocator* GetPageAllocator() = 0; + + /** + * Monotonically increasing time in seconds from an arbitrary fixed point in + * the past. This function is expected to return at least + * millisecond-precision values. For this reason, + * it is recommended that the fixed point be no further in the past than + * the epoch. + **/ + virtual double MonotonicallyIncreasingTime() = 0; + + /** + * Foreground task runner that should be used by a Heap. + */ + virtual std::shared_ptr GetForegroundTaskRunner() { + return nullptr; + } + + /** + * Posts `job_task` to run in parallel. Returns a `JobHandle` associated with + * the `Job`, which can be joined or canceled. + * This avoids degenerate cases: + * - Calling `CallOnWorkerThread()` for each work item, causing significant + * overhead. + * - Fixed number of `CallOnWorkerThread()` calls that split the work and + * might run for a long time. This is problematic when many components post + * "num cores" tasks and all expect to use all the cores. In these cases, + * the scheduler lacks context to be fair to multiple same-priority requests + * and/or ability to request lower priority work to yield when high priority + * work comes in. + * A canonical implementation of `job_task` looks like: + * \code + * class MyJobTask : public JobTask { + * public: + * MyJobTask(...) : worker_queue_(...) {} + * // JobTask implementation. + * void Run(JobDelegate* delegate) override { + * while (!delegate->ShouldYield()) { + * // Smallest unit of work. + * auto work_item = worker_queue_.TakeWorkItem(); // Thread safe. + * if (!work_item) return; + * ProcessWork(work_item); + * } + * } + * + * size_t GetMaxConcurrency() const override { + * return worker_queue_.GetSize(); // Thread safe. + * } + * }; + * + * // ... + * auto handle = PostJob(TaskPriority::kUserVisible, + * std::make_unique(...)); + * handle->Join(); + * \endcode + * + * `PostJob()` and methods of the returned JobHandle/JobDelegate, must never + * be called while holding a lock that could be acquired by `JobTask::Run()` + * or `JobTask::GetMaxConcurrency()` -- that could result in a deadlock. This + * is because (1) `JobTask::GetMaxConcurrency()` may be invoked while holding + * internal lock (A), hence `JobTask::GetMaxConcurrency()` can only use a lock + * (B) if that lock is *never* held while calling back into `JobHandle` from + * any thread (A=>B/B=>A deadlock) and (2) `JobTask::Run()` or + * `JobTask::GetMaxConcurrency()` may be invoked synchronously from + * `JobHandle` (B=>JobHandle::foo=>B deadlock). + * + * A sufficient `PostJob()` implementation that uses the default Job provided + * in libplatform looks like: + * \code + * std::unique_ptr PostJob( + * TaskPriority priority, std::unique_ptr job_task) override { + * return std::make_unique( + * std::make_shared( + * this, std::move(job_task), kNumThreads)); + * } + * \endcode + */ + virtual std::unique_ptr PostJob( + TaskPriority priority, std::unique_ptr job_task) { + return nullptr; + } + + /** + * Returns an instance of a `TracingController`. This must be non-nullptr. The + * default implementation returns an empty `TracingController` that consumes + * trace data without effect. + */ + virtual TracingController* GetTracingController(); +}; + +/** + * Process-global initialization of the garbage collector. Must be called before + * creating a Heap. + * + * Can be called multiple times when paired with `ShutdownProcess()`. + * + * \param page_allocator The allocator used for maintaining meta data. Must stay + * always alive and not change between multiple calls to InitializeProcess. If + * no allocator is provided, a default internal version will be used. + * \param desired_heap_size Desired amount of virtual address space to reserve + * for the heap, in bytes. Actual size will be clamped to minimum and maximum + * values based on compile-time settings and may be rounded up. If this + * parameter is zero, a default value will be used. + */ +V8_EXPORT void InitializeProcess(PageAllocator* page_allocator = nullptr, + size_t desired_heap_size = 0); + +/** + * Must be called after destroying the last used heap. Some process-global + * metadata may not be returned and reused upon a subsequent + * `InitializeProcess()` call. + */ +V8_EXPORT void ShutdownProcess(); + +namespace internal { + +V8_EXPORT void Fatal(const std::string& reason = std::string(), + const SourceLocation& = SourceLocation::Current()); + +} // namespace internal + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_PLATFORM_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/prefinalizer.h b/NativeScript/napi/v8/include_old/cppgc/prefinalizer.h new file mode 100644 index 00000000..51f2eac8 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/prefinalizer.h @@ -0,0 +1,75 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_PREFINALIZER_H_ +#define INCLUDE_CPPGC_PREFINALIZER_H_ + +#include "cppgc/internal/compiler-specific.h" +#include "cppgc/liveness-broker.h" + +namespace cppgc { + +namespace internal { + +class V8_EXPORT PrefinalizerRegistration final { + public: + using Callback = bool (*)(const cppgc::LivenessBroker&, void*); + + PrefinalizerRegistration(void*, Callback); + + void* operator new(size_t, void* location) = delete; + void* operator new(size_t) = delete; +}; + +} // namespace internal + +/** + * Macro must be used in the private section of `Class` and registers a + * prefinalization callback `void Class::PreFinalizer()`. The callback is + * invoked on garbage collection after the collector has found an object to be + * dead. + * + * Callback properties: + * - The callback is invoked before a possible destructor for the corresponding + * object. + * - The callback may access the whole object graph, irrespective of whether + * objects are considered dead or alive. + * - The callback is invoked on the same thread as the object was created on. + * + * Example: + * \code + * class WithPrefinalizer : public GarbageCollected { + * CPPGC_USING_PRE_FINALIZER(WithPrefinalizer, Dispose); + * + * public: + * void Trace(Visitor*) const {} + * void Dispose() { prefinalizer_called = true; } + * ~WithPrefinalizer() { + * // prefinalizer_called == true + * } + * private: + * bool prefinalizer_called = false; + * }; + * \endcode + */ +#define CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer) \ + public: \ + static bool InvokePreFinalizer(const cppgc::LivenessBroker& liveness_broker, \ + void* object) { \ + static_assert(cppgc::IsGarbageCollectedOrMixinTypeV, \ + "Only garbage collected objects can have prefinalizers"); \ + Class* self = static_cast(object); \ + if (liveness_broker.IsHeapObjectAlive(self)) return false; \ + self->PreFinalizer(); \ + return true; \ + } \ + \ + private: \ + CPPGC_NO_UNIQUE_ADDRESS cppgc::internal::PrefinalizerRegistration \ + prefinalizer_dummy_{this, Class::InvokePreFinalizer}; \ + static_assert(true, "Force semicolon.") + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_PREFINALIZER_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/process-heap-statistics.h b/NativeScript/napi/v8/include_old/cppgc/process-heap-statistics.h new file mode 100644 index 00000000..774cc92f --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/process-heap-statistics.h @@ -0,0 +1,36 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_ +#define INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_ + +#include +#include + +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { +namespace internal { +class ProcessHeapStatisticsUpdater; +} // namespace internal + +class V8_EXPORT ProcessHeapStatistics final { + public: + static size_t TotalAllocatedObjectSize() { + return total_allocated_object_size_.load(std::memory_order_relaxed); + } + static size_t TotalAllocatedSpace() { + return total_allocated_space_.load(std::memory_order_relaxed); + } + + private: + static std::atomic_size_t total_allocated_space_; + static std::atomic_size_t total_allocated_object_size_; + + friend class internal::ProcessHeapStatisticsUpdater; +}; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/sentinel-pointer.h b/NativeScript/napi/v8/include_old/cppgc/sentinel-pointer.h new file mode 100644 index 00000000..bee96c77 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/sentinel-pointer.h @@ -0,0 +1,39 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_SENTINEL_POINTER_H_ +#define INCLUDE_CPPGC_SENTINEL_POINTER_H_ + +#include + +#include "cppgc/internal/api-constants.h" + +namespace cppgc { +namespace internal { + +// Special tag type used to denote some sentinel member. The semantics of the +// sentinel is defined by the embedder. +struct SentinelPointer { +#if defined(CPPGC_POINTER_COMPRESSION) + static constexpr intptr_t kSentinelValue = + 1 << api_constants::kPointerCompressionShift; +#else // !defined(CPPGC_POINTER_COMPRESSION) + static constexpr intptr_t kSentinelValue = 0b10; +#endif // !defined(CPPGC_POINTER_COMPRESSION) + template + operator T*() const { + return reinterpret_cast(kSentinelValue); + } + // Hidden friends. + friend bool operator==(SentinelPointer, SentinelPointer) { return true; } + friend bool operator!=(SentinelPointer, SentinelPointer) { return false; } +}; + +} // namespace internal + +constexpr internal::SentinelPointer kSentinelPointer; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_SENTINEL_POINTER_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/source-location.h b/NativeScript/napi/v8/include_old/cppgc/source-location.h new file mode 100644 index 00000000..0dc28aed --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/source-location.h @@ -0,0 +1,16 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_SOURCE_LOCATION_H_ +#define INCLUDE_CPPGC_SOURCE_LOCATION_H_ + +#include "v8-source-location.h" + +namespace cppgc { + +using SourceLocation = v8::SourceLocation; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_SOURCE_LOCATION_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/testing.h b/NativeScript/napi/v8/include_old/cppgc/testing.h new file mode 100644 index 00000000..bddd1fc1 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/testing.h @@ -0,0 +1,106 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_TESTING_H_ +#define INCLUDE_CPPGC_TESTING_H_ + +#include "cppgc/common.h" +#include "cppgc/macros.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +class HeapHandle; + +/** + * Namespace contains testing helpers. + */ +namespace testing { + +/** + * Overrides the state of the stack with the provided value. Parameters passed + * to explicit garbage collection calls still take precedence. Must not be + * nested. + * + * This scope is useful to make the garbage collector consider the stack when + * tasks that invoke garbage collection (through the provided platform) contain + * interesting pointers on its stack. + */ +class V8_EXPORT V8_NODISCARD OverrideEmbedderStackStateScope final { + CPPGC_STACK_ALLOCATED(); + + public: + /** + * Constructs a scoped object that automatically enters and leaves the scope. + * + * \param heap_handle The corresponding heap. + */ + explicit OverrideEmbedderStackStateScope(HeapHandle& heap_handle, + EmbedderStackState state); + ~OverrideEmbedderStackStateScope(); + + OverrideEmbedderStackStateScope(const OverrideEmbedderStackStateScope&) = + delete; + OverrideEmbedderStackStateScope& operator=( + const OverrideEmbedderStackStateScope&) = delete; + + private: + HeapHandle& heap_handle_; +}; + +/** + * Testing interface for managed heaps that allows for controlling garbage + * collection timings. Embedders should use this class when testing the + * interaction of their code with incremental/concurrent garbage collection. + */ +class V8_EXPORT StandaloneTestingHeap final { + public: + explicit StandaloneTestingHeap(HeapHandle&); + + /** + * Start an incremental garbage collection. + */ + void StartGarbageCollection(); + + /** + * Perform an incremental step. This will also schedule concurrent steps if + * needed. + * + * \param stack_state The state of the stack during the step. + */ + bool PerformMarkingStep(EmbedderStackState stack_state); + + /** + * Finalize the current garbage collection cycle atomically. + * Assumes that garbage collection is in progress. + * + * \param stack_state The state of the stack for finalizing the garbage + * collection cycle. + */ + void FinalizeGarbageCollection(EmbedderStackState stack_state); + + /** + * Toggle main thread marking on/off. Allows to stress concurrent marking + * (e.g. to better detect data races). + * + * \param should_mark Denotes whether the main thread should contribute to + * marking. Defaults to true. + */ + void ToggleMainThreadMarking(bool should_mark); + + /** + * Force enable compaction for the next garbage collection cycle. + */ + void ForceCompactionForNextGarbageCollection(); + + private: + HeapHandle& heap_handle_; +}; + +V8_EXPORT bool IsHeapObjectOld(void*); + +} // namespace testing +} // namespace cppgc + +#endif // INCLUDE_CPPGC_TESTING_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/trace-trait.h b/NativeScript/napi/v8/include_old/cppgc/trace-trait.h new file mode 100644 index 00000000..5fc863d2 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/trace-trait.h @@ -0,0 +1,128 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_TRACE_TRAIT_H_ +#define INCLUDE_CPPGC_TRACE_TRAIT_H_ + +#include + +#include "cppgc/type-traits.h" +#include "v8config.h" // NOLINT(build/include_directory) + +namespace cppgc { + +class Visitor; + +namespace internal { + +class RootVisitor; + +using TraceRootCallback = void (*)(RootVisitor&, const void* object); + +// Implementation of the default TraceTrait handling GarbageCollected and +// GarbageCollectedMixin. +template ::type>> +struct TraceTraitImpl; + +} // namespace internal + +/** + * Callback for invoking tracing on a given object. + * + * \param visitor The visitor to dispatch to. + * \param object The object to invoke tracing on. + */ +using TraceCallback = void (*)(Visitor* visitor, const void* object); + +/** + * Describes how to trace an object, i.e., how to visit all Oilpan-relevant + * fields of an object. + */ +struct TraceDescriptor { + /** + * Adjusted base pointer, i.e., the pointer to the class inheriting directly + * from GarbageCollected, of the object that is being traced. + */ + const void* base_object_payload; + /** + * Callback for tracing the object. + */ + TraceCallback callback; +}; + +/** + * Callback for getting a TraceDescriptor for a given address. + * + * \param address Possibly inner address of an object. + * \returns a TraceDescriptor for the provided address. + */ +using TraceDescriptorCallback = TraceDescriptor (*)(const void* address); + +namespace internal { + +struct V8_EXPORT TraceTraitFromInnerAddressImpl { + static TraceDescriptor GetTraceDescriptor(const void* address); +}; + +/** + * Trait specifying how the garbage collector processes an object of type T. + * + * Advanced users may override handling by creating a specialization for their + * type. + */ +template +struct TraceTraitBase { + static_assert(internal::IsTraceableV, "T must have a Trace() method"); + + /** + * Accessor for retrieving a TraceDescriptor to process an object of type T. + * + * \param self The object to be processed. + * \returns a TraceDescriptor to process the object. + */ + static TraceDescriptor GetTraceDescriptor(const void* self) { + return internal::TraceTraitImpl::GetTraceDescriptor( + static_cast(self)); + } + + /** + * Function invoking the tracing for an object of type T. + * + * \param visitor The visitor to dispatch to. + * \param self The object to invoke tracing on. + */ + static void Trace(Visitor* visitor, const void* self) { + static_cast(self)->Trace(visitor); + } +}; + +} // namespace internal + +template +struct TraceTrait : public internal::TraceTraitBase {}; + +namespace internal { + +template +struct TraceTraitImpl { + static_assert(IsGarbageCollectedTypeV, + "T must be of type GarbageCollected or GarbageCollectedMixin"); + static TraceDescriptor GetTraceDescriptor(const void* self) { + return {self, TraceTrait::Trace}; + } +}; + +template +struct TraceTraitImpl { + static TraceDescriptor GetTraceDescriptor(const void* self) { + return internal::TraceTraitFromInnerAddressImpl::GetTraceDescriptor(self); + } +}; + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_TRACE_TRAIT_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/type-traits.h b/NativeScript/napi/v8/include_old/cppgc/type-traits.h new file mode 100644 index 00000000..46514353 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/type-traits.h @@ -0,0 +1,250 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_TYPE_TRAITS_H_ +#define INCLUDE_CPPGC_TYPE_TRAITS_H_ + +// This file should stay with minimal dependencies to allow embedder to check +// against Oilpan types without including any other parts. +#include +#include + +namespace cppgc { + +class Visitor; + +namespace internal { +template +class BasicMember; +struct DijkstraWriteBarrierPolicy; +struct NoWriteBarrierPolicy; +class StrongMemberTag; +class UntracedMemberTag; +class WeakMemberTag; + +// Not supposed to be specialized by the user. +template +struct IsWeak : std::false_type {}; + +// IsTraceMethodConst is used to verify that all Trace methods are marked as +// const. It is equivalent to IsTraceable but for a non-const object. +template +struct IsTraceMethodConst : std::false_type {}; + +template +struct IsTraceMethodConst().Trace( + std::declval()))>> : std::true_type { +}; + +template +struct IsTraceable : std::false_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +struct IsTraceable< + T, std::void_t().Trace(std::declval()))>> + : std::true_type { + // All Trace methods should be marked as const. If an object of type + // 'T' is traceable then any object of type 'const T' should also + // be traceable. + static_assert(IsTraceMethodConst(), + "Trace methods should be marked as const."); +}; + +template +constexpr bool IsTraceableV = IsTraceable::value; + +template +struct HasGarbageCollectedMixinTypeMarker : std::false_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +struct HasGarbageCollectedMixinTypeMarker< + T, std::void_t< + typename std::remove_const_t::IsGarbageCollectedMixinTypeMarker>> + : std::true_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +struct HasGarbageCollectedTypeMarker : std::false_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +struct HasGarbageCollectedTypeMarker< + T, + std::void_t::IsGarbageCollectedTypeMarker>> + : std::true_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template ::value, + bool = HasGarbageCollectedMixinTypeMarker::value> +struct IsGarbageCollectedMixinType : std::false_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +struct IsGarbageCollectedMixinType : std::true_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template ::value> +struct IsGarbageCollectedType : std::false_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +struct IsGarbageCollectedType : std::true_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +struct IsGarbageCollectedOrMixinType + : std::integral_constant::value || + IsGarbageCollectedMixinType::value> { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template ::value && + HasGarbageCollectedMixinTypeMarker::value)> +struct IsGarbageCollectedWithMixinType : std::false_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +struct IsGarbageCollectedWithMixinType : std::true_type { + static_assert(sizeof(T), "T must be fully defined"); +}; + +template +struct IsSubclassOfBasicMemberTemplate { + private: + template + static std::true_type SubclassCheck( + BasicMember*); + static std::false_type SubclassCheck(...); + + public: + static constexpr bool value = + decltype(SubclassCheck(std::declval()))::value; +}; + +template ::value> +struct IsMemberType : std::false_type {}; + +template +struct IsMemberType : std::true_type {}; + +template ::value> +struct IsWeakMemberType : std::false_type {}; + +template +struct IsWeakMemberType : std::true_type {}; + +template ::value> +struct IsUntracedMemberType : std::false_type {}; + +template +struct IsUntracedMemberType : std::true_type {}; + +template +struct IsComplete { + private: + template + static std::true_type IsSizeOfKnown(U*); + static std::false_type IsSizeOfKnown(...); + + public: + static constexpr bool value = + decltype(IsSizeOfKnown(std::declval()))::value; +}; + +template +constexpr bool IsDecayedSameV = + std::is_same_v, std::decay_t>; + +template +constexpr bool IsStrictlyBaseOfV = + std::is_base_of_v, std::decay_t> && + !IsDecayedSameV; + +} // namespace internal + +/** + * Value is true for types that inherit from `GarbageCollectedMixin` but not + * `GarbageCollected` (i.e., they are free mixins), and false otherwise. + */ +template +constexpr bool IsGarbageCollectedMixinTypeV = + internal::IsGarbageCollectedMixinType::value; + +/** + * Value is true for types that inherit from `GarbageCollected`, and false + * otherwise. + */ +template +constexpr bool IsGarbageCollectedTypeV = + internal::IsGarbageCollectedType::value; + +/** + * Value is true for types that inherit from either `GarbageCollected` or + * `GarbageCollectedMixin`, and false otherwise. + */ +template +constexpr bool IsGarbageCollectedOrMixinTypeV = + internal::IsGarbageCollectedOrMixinType::value; + +/** + * Value is true for types that inherit from `GarbageCollected` and + * `GarbageCollectedMixin`, and false otherwise. + */ +template +constexpr bool IsGarbageCollectedWithMixinTypeV = + internal::IsGarbageCollectedWithMixinType::value; + +/** + * Value is true for types of type `Member`, and false otherwise. + */ +template +constexpr bool IsMemberTypeV = internal::IsMemberType::value; + +/** + * Value is true for types of type `UntracedMember`, and false otherwise. + */ +template +constexpr bool IsUntracedMemberTypeV = internal::IsUntracedMemberType::value; + +/** + * Value is true for types of type `WeakMember`, and false otherwise. + */ +template +constexpr bool IsWeakMemberTypeV = internal::IsWeakMemberType::value; + +/** + * Value is true for types that are considered weak references, and false + * otherwise. + */ +template +constexpr bool IsWeakV = internal::IsWeak::value; + +/** + * Value is true for types that are complete, and false otherwise. + */ +template +constexpr bool IsCompleteV = internal::IsComplete::value; + +} // namespace cppgc + +#endif // INCLUDE_CPPGC_TYPE_TRAITS_H_ diff --git a/NativeScript/napi/v8/include_old/cppgc/visitor.h b/NativeScript/napi/v8/include_old/cppgc/visitor.h new file mode 100644 index 00000000..1d6b39a1 --- /dev/null +++ b/NativeScript/napi/v8/include_old/cppgc/visitor.h @@ -0,0 +1,504 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_VISITOR_H_ +#define INCLUDE_CPPGC_VISITOR_H_ + +#include + +#include "cppgc/custom-space.h" +#include "cppgc/ephemeron-pair.h" +#include "cppgc/garbage-collected.h" +#include "cppgc/internal/logging.h" +#include "cppgc/internal/member-storage.h" +#include "cppgc/internal/pointer-policies.h" +#include "cppgc/liveness-broker.h" +#include "cppgc/member.h" +#include "cppgc/sentinel-pointer.h" +#include "cppgc/source-location.h" +#include "cppgc/trace-trait.h" +#include "cppgc/type-traits.h" + +namespace cppgc { + +namespace internal { +template +class BasicCrossThreadPersistent; +template +class BasicPersistent; +class ConservativeTracingVisitor; +class VisitorBase; +class VisitorFactory; +} // namespace internal + +using WeakCallback = void (*)(const LivenessBroker&, const void*); + +/** + * Visitor passed to trace methods. All managed pointers must have called the + * Visitor's trace method on them. + * + * \code + * class Foo final : public GarbageCollected { + * public: + * void Trace(Visitor* visitor) const { + * visitor->Trace(foo_); + * visitor->Trace(weak_foo_); + * } + * private: + * Member foo_; + * WeakMember weak_foo_; + * }; + * \endcode + */ +class V8_EXPORT Visitor { + public: + class Key { + private: + Key() = default; + friend class internal::VisitorFactory; + }; + + explicit Visitor(Key) {} + + virtual ~Visitor() = default; + + /** + * Trace method for Member. + * + * \param member Member reference retaining an object. + */ + template + void Trace(const Member& member) { + const T* value = member.GetRawAtomic(); + CPPGC_DCHECK(value != kSentinelPointer); + TraceImpl(value); + } + + /** + * Trace method for WeakMember. + * + * \param weak_member WeakMember reference weakly retaining an object. + */ + template + void Trace(const WeakMember& weak_member) { + static_assert(sizeof(T), "Pointee type must be fully defined."); + static_assert(internal::IsGarbageCollectedOrMixinType::value, + "T must be GarbageCollected or GarbageCollectedMixin type"); + static_assert(!internal::IsAllocatedOnCompactableSpace::value, + "Weak references to compactable objects are not allowed"); + + const T* value = weak_member.GetRawAtomic(); + + // Bailout assumes that WeakMember emits write barrier. + if (!value) { + return; + } + + CPPGC_DCHECK(value != kSentinelPointer); + VisitWeak(value, TraceTrait::GetTraceDescriptor(value), + &HandleWeak>, &weak_member); + } + +#if defined(CPPGC_POINTER_COMPRESSION) + /** + * Trace method for UncompressedMember. + * + * \param member UncompressedMember reference retaining an object. + */ + template + void Trace(const subtle::UncompressedMember& member) { + const T* value = member.GetRawAtomic(); + CPPGC_DCHECK(value != kSentinelPointer); + TraceImpl(value); + } +#endif // defined(CPPGC_POINTER_COMPRESSION) + + template + void TraceMultiple(const subtle::UncompressedMember* start, size_t len) { + static_assert(sizeof(T), "Pointee type must be fully defined."); + static_assert(internal::IsGarbageCollectedOrMixinType::value, + "T must be GarbageCollected or GarbageCollectedMixin type"); + VisitMultipleUncompressedMember(start, len, + &TraceTrait::GetTraceDescriptor); + } + + template , subtle::UncompressedMember>>* = nullptr> + void TraceMultiple(const Member* start, size_t len) { + static_assert(sizeof(T), "Pointee type must be fully defined."); + static_assert(internal::IsGarbageCollectedOrMixinType::value, + "T must be GarbageCollected or GarbageCollectedMixin type"); +#if defined(CPPGC_POINTER_COMPRESSION) + static_assert(std::is_same_v, subtle::CompressedMember>, + "Member and CompressedMember must be the same."); + VisitMultipleCompressedMember(start, len, + &TraceTrait::GetTraceDescriptor); +#endif // defined(CPPGC_POINTER_COMPRESSION) + } + + /** + * Trace method for inlined objects that are not allocated themselves but + * otherwise follow managed heap layout and have a Trace() method. + * + * \param object reference of the inlined object. + */ + template + void Trace(const T& object) { +#if V8_ENABLE_CHECKS + // This object is embedded in potentially multiple nested objects. The + // outermost object must not be in construction as such objects are (a) not + // processed immediately, and (b) only processed conservatively if not + // otherwise possible. + CheckObjectNotInConstruction(&object); +#endif // V8_ENABLE_CHECKS + TraceTrait::Trace(this, &object); + } + + template + void TraceMultiple(const T* start, size_t len) { +#if V8_ENABLE_CHECKS + // This object is embedded in potentially multiple nested objects. The + // outermost object must not be in construction as such objects are (a) not + // processed immediately, and (b) only processed conservatively if not + // otherwise possible. + CheckObjectNotInConstruction(start); +#endif // V8_ENABLE_CHECKS + for (size_t i = 0; i < len; ++i) { + const T* object = &start[i]; + if constexpr (std::is_polymorphic_v) { + // The object's vtable may be uninitialized in which case the object is + // not traced. + if (*reinterpret_cast(object) == 0) continue; + } + TraceTrait::Trace(this, object); + } + } + + /** + * Registers a weak callback method on the object of type T. See + * LivenessBroker for an usage example. + * + * \param object of type T specifying a weak callback method. + */ + template + void RegisterWeakCallbackMethod(const T* object) { + RegisterWeakCallback(&WeakCallbackMethodDelegate, object); + } + + /** + * Trace method for EphemeronPair. + * + * \param ephemeron_pair EphemeronPair reference weakly retaining a key object + * and strongly retaining a value object in case the key object is alive. + */ + template + void Trace(const EphemeronPair& ephemeron_pair) { + TraceEphemeron(ephemeron_pair.key, &ephemeron_pair.value); + RegisterWeakCallbackMethod, + &EphemeronPair::ClearValueIfKeyIsDead>( + &ephemeron_pair); + } + + /** + * Trace method for a single ephemeron. Used for tracing a raw ephemeron in + * which the `key` and `value` are kept separately. + * + * \param weak_member_key WeakMember reference weakly retaining a key object. + * \param member_value Member reference with ephemeron semantics. + */ + template + void TraceEphemeron(const WeakMember& weak_member_key, + const Member* member_value) { + const KeyType* key = weak_member_key.GetRawAtomic(); + if (!key) return; + + // `value` must always be non-null. + CPPGC_DCHECK(member_value); + const ValueType* value = member_value->GetRawAtomic(); + if (!value) return; + + // KeyType and ValueType may refer to GarbageCollectedMixin. + TraceDescriptor value_desc = + TraceTrait::GetTraceDescriptor(value); + CPPGC_DCHECK(value_desc.base_object_payload); + const void* key_base_object_payload = + TraceTrait::GetTraceDescriptor(key).base_object_payload; + CPPGC_DCHECK(key_base_object_payload); + + VisitEphemeron(key_base_object_payload, value, value_desc); + } + + /** + * Trace method for a single ephemeron. Used for tracing a raw ephemeron in + * which the `key` and `value` are kept separately. Note that this overload + * is for non-GarbageCollected `value`s that can be traced though. + * + * \param key `WeakMember` reference weakly retaining a key object. + * \param value Reference weakly retaining a value object. Note that + * `ValueType` here should not be `Member`. It is expected that + * `TraceTrait::GetTraceDescriptor(value)` returns a + * `TraceDescriptor` with a null base pointer but a valid trace method. + */ + template + void TraceEphemeron(const WeakMember& weak_member_key, + const ValueType* value) { + static_assert(!IsGarbageCollectedOrMixinTypeV, + "garbage-collected types must use WeakMember and Member"); + const KeyType* key = weak_member_key.GetRawAtomic(); + if (!key) return; + + // `value` must always be non-null. + CPPGC_DCHECK(value); + TraceDescriptor value_desc = + TraceTrait::GetTraceDescriptor(value); + // `value_desc.base_object_payload` must be null as this override is only + // taken for non-garbage-collected values. + CPPGC_DCHECK(!value_desc.base_object_payload); + + // KeyType might be a GarbageCollectedMixin. + const void* key_base_object_payload = + TraceTrait::GetTraceDescriptor(key).base_object_payload; + CPPGC_DCHECK(key_base_object_payload); + + VisitEphemeron(key_base_object_payload, value, value_desc); + } + + /** + * Trace method that strongifies a WeakMember. + * + * \param weak_member WeakMember reference retaining an object. + */ + template + void TraceStrongly(const WeakMember& weak_member) { + const T* value = weak_member.GetRawAtomic(); + CPPGC_DCHECK(value != kSentinelPointer); + TraceImpl(value); + } + + /** + * Trace method for retaining containers strongly. + * + * \param object reference to the container. + */ + template + void TraceStrongContainer(const T* object) { + TraceImpl(object); + } + + /** + * Trace method for retaining containers weakly. Note that weak containers + * should emit write barriers. + * + * \param object reference to the container. + * \param callback to be invoked. + * \param callback_data custom data that is passed to the callback. + */ + template + void TraceWeakContainer(const T* object, WeakCallback callback, + const void* callback_data) { + if (!object) return; + VisitWeakContainer(object, TraceTrait::GetTraceDescriptor(object), + TraceTrait::GetWeakTraceDescriptor(object), callback, + callback_data); + } + + /** + * Registers a slot containing a reference to an object allocated on a + * compactable space. Such references maybe be arbitrarily moved by the GC. + * + * \param slot location of reference to object that might be moved by the GC. + * The slot must contain an uncompressed pointer. + */ + template + void RegisterMovableReference(const T** slot) { + static_assert(internal::IsAllocatedOnCompactableSpace::value, + "Only references to objects allocated on compactable spaces " + "should be registered as movable slots."); + static_assert(!IsGarbageCollectedMixinTypeV, + "Mixin types do not support compaction."); + HandleMovableReference(reinterpret_cast(slot)); + } + + /** + * Registers a weak callback that is invoked during garbage collection. + * + * \param callback to be invoked. + * \param data custom data that is passed to the callback. + */ + virtual void RegisterWeakCallback(WeakCallback callback, const void* data) {} + + /** + * Defers tracing an object from a concurrent thread to the mutator thread. + * Should be called by Trace methods of types that are not safe to trace + * concurrently. + * + * \param parameter tells the trace callback which object was deferred. + * \param callback to be invoked for tracing on the mutator thread. + * \param deferred_size size of deferred object. + * + * \returns false if the object does not need to be deferred (i.e. currently + * traced on the mutator thread) and true otherwise (i.e. currently traced on + * a concurrent thread). + */ + virtual V8_WARN_UNUSED_RESULT bool DeferTraceToMutatorThreadIfConcurrent( + const void* parameter, TraceCallback callback, size_t deferred_size) { + // By default tracing is not deferred. + return false; + } + + protected: + virtual void Visit(const void* self, TraceDescriptor) {} + virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback, + const void* weak_member) {} + virtual void VisitEphemeron(const void* key, const void* value, + TraceDescriptor value_desc) {} + virtual void VisitWeakContainer(const void* self, TraceDescriptor strong_desc, + TraceDescriptor weak_desc, + WeakCallback callback, const void* data) {} + virtual void HandleMovableReference(const void**) {} + + virtual void VisitMultipleUncompressedMember( + const void* start, size_t len, + TraceDescriptorCallback get_trace_descriptor) { + // Default implementation merely delegates to Visit(). + const char* it = static_cast(start); + const char* end = it + len * internal::kSizeOfUncompressedMember; + for (; it < end; it += internal::kSizeOfUncompressedMember) { + const auto* current = reinterpret_cast(it); + const void* object = current->LoadAtomic(); + if (!object) continue; + + Visit(object, get_trace_descriptor(object)); + } + } + +#if defined(CPPGC_POINTER_COMPRESSION) + virtual void VisitMultipleCompressedMember( + const void* start, size_t len, + TraceDescriptorCallback get_trace_descriptor) { + // Default implementation merely delegates to Visit(). + const char* it = static_cast(start); + const char* end = it + len * internal::kSizeofCompressedMember; + for (; it < end; it += internal::kSizeofCompressedMember) { + const auto* current = + reinterpret_cast(it); + const void* object = current->LoadAtomic(); + if (!object) continue; + + Visit(object, get_trace_descriptor(object)); + } + } +#endif // defined(CPPGC_POINTER_COMPRESSION) + + private: + template + static void WeakCallbackMethodDelegate(const LivenessBroker& info, + const void* self) { + // Callback is registered through a potential const Trace method but needs + // to be able to modify fields. See HandleWeak. + (const_cast(static_cast(self))->*method)(info); + } + + template + static void HandleWeak(const LivenessBroker& info, const void* object) { + const PointerType* weak = static_cast(object); + if (!info.IsHeapObjectAlive(weak->GetFromGC())) { + weak->ClearFromGC(); + } + } + + template + void TraceImpl(const T* t) { + static_assert(sizeof(T), "Pointee type must be fully defined."); + static_assert(internal::IsGarbageCollectedOrMixinType::value, + "T must be GarbageCollected or GarbageCollectedMixin type"); + if (!t) { + return; + } + Visit(t, TraceTrait::GetTraceDescriptor(t)); + } + +#if V8_ENABLE_CHECKS + void CheckObjectNotInConstruction(const void* address); +#endif // V8_ENABLE_CHECKS + + template + friend class internal::BasicCrossThreadPersistent; + template + friend class internal::BasicPersistent; + friend class internal::ConservativeTracingVisitor; + friend class internal::VisitorBase; +}; + +namespace internal { + +class V8_EXPORT RootVisitor { + public: + explicit RootVisitor(Visitor::Key) {} + + virtual ~RootVisitor() = default; + + template * = nullptr> + void Trace(const AnyStrongPersistentType& p) { + using PointeeType = typename AnyStrongPersistentType::PointeeType; + const void* object = Extract(p); + if (!object) { + return; + } + VisitRoot(object, TraceTrait::GetTraceDescriptor(object), + p.Location()); + } + + template * = nullptr> + void Trace(const AnyWeakPersistentType& p) { + using PointeeType = typename AnyWeakPersistentType::PointeeType; + static_assert(!internal::IsAllocatedOnCompactableSpace::value, + "Weak references to compactable objects are not allowed"); + const void* object = Extract(p); + if (!object) { + return; + } + VisitWeakRoot(object, TraceTrait::GetTraceDescriptor(object), + &HandleWeak, &p, p.Location()); + } + + protected: + virtual void VisitRoot(const void*, TraceDescriptor, const SourceLocation&) {} + virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback, + const void* weak_root, const SourceLocation&) {} + + private: + template + static const void* Extract(AnyPersistentType& p) { + using PointeeType = typename AnyPersistentType::PointeeType; + static_assert(sizeof(PointeeType), + "Persistent's pointee type must be fully defined"); + static_assert(internal::IsGarbageCollectedOrMixinType::value, + "Persistent's pointee type must be GarbageCollected or " + "GarbageCollectedMixin"); + return p.GetFromGC(); + } + + template + static void HandleWeak(const LivenessBroker& info, const void* object) { + const PointerType* weak = static_cast(object); + if (!info.IsHeapObjectAlive(weak->GetFromGC())) { + weak->ClearFromGC(); + } + } +}; + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_VISITOR_H_ diff --git a/NativeScript/napi/v8/include_old/inspector/Debugger.h b/NativeScript/napi/v8/include_old/inspector/Debugger.h new file mode 100644 index 00000000..d984c6a4 --- /dev/null +++ b/NativeScript/napi/v8/include_old/inspector/Debugger.h @@ -0,0 +1,59 @@ +// This file is generated by Exported_h.template. + +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_inspector_protocol_Debugger_api_h +#define v8_inspector_protocol_Debugger_api_h + +#include "v8-inspector.h" + +namespace v8_inspector { +namespace protocol { + +#ifndef v8_inspector_protocol_exported_api_h +#define v8_inspector_protocol_exported_api_h +class V8_EXPORT Exported { +public: + virtual void AppendSerialized(std::vector* out) const = 0; + + virtual ~Exported() { } +}; +#endif // !defined(v8_inspector_protocol_exported_api_h) + +namespace Debugger { +namespace API { + +// ------------- Enums. + +namespace Paused { +namespace ReasonEnum { +V8_EXPORT extern const char* Ambiguous; +V8_EXPORT extern const char* Assert; +V8_EXPORT extern const char* CSPViolation; +V8_EXPORT extern const char* DebugCommand; +V8_EXPORT extern const char* DOM; +V8_EXPORT extern const char* EventListener; +V8_EXPORT extern const char* Exception; +V8_EXPORT extern const char* Instrumentation; +V8_EXPORT extern const char* OOM; +V8_EXPORT extern const char* Other; +V8_EXPORT extern const char* PromiseRejection; +V8_EXPORT extern const char* XHR; +} // ReasonEnum +} // Paused + +// ------------- Types. + +class V8_EXPORT SearchMatch : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +} // namespace API +} // namespace Debugger +} // namespace v8_inspector +} // namespace protocol + +#endif // !defined(v8_inspector_protocol_Debugger_api_h) diff --git a/NativeScript/napi/v8/include_old/inspector/Runtime.h b/NativeScript/napi/v8/include_old/inspector/Runtime.h new file mode 100644 index 00000000..f9d515ba --- /dev/null +++ b/NativeScript/napi/v8/include_old/inspector/Runtime.h @@ -0,0 +1,52 @@ +// This file is generated by Exported_h.template. + +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_inspector_protocol_Runtime_api_h +#define v8_inspector_protocol_Runtime_api_h + +#include "v8-inspector.h" + +namespace v8_inspector { +namespace protocol { + +#ifndef v8_inspector_protocol_exported_api_h +#define v8_inspector_protocol_exported_api_h +class V8_EXPORT Exported { +public: + virtual void AppendSerialized(std::vector* out) const = 0; + + virtual ~Exported() { } +}; +#endif // !defined(v8_inspector_protocol_exported_api_h) + +namespace Runtime { +namespace API { + +// ------------- Enums. + +// ------------- Types. + +class V8_EXPORT RemoteObject : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +class V8_EXPORT StackTrace : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +class V8_EXPORT StackTraceId : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +} // namespace API +} // namespace Runtime +} // namespace v8_inspector +} // namespace protocol + +#endif // !defined(v8_inspector_protocol_Runtime_api_h) diff --git a/NativeScript/napi/v8/include_old/inspector/Schema.h b/NativeScript/napi/v8/include_old/inspector/Schema.h new file mode 100644 index 00000000..03a76fa9 --- /dev/null +++ b/NativeScript/napi/v8/include_old/inspector/Schema.h @@ -0,0 +1,42 @@ +// This file is generated by Exported_h.template. + +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_inspector_protocol_Schema_api_h +#define v8_inspector_protocol_Schema_api_h + +#include "v8-inspector.h" + +namespace v8_inspector { +namespace protocol { + +#ifndef v8_inspector_protocol_exported_api_h +#define v8_inspector_protocol_exported_api_h +class V8_EXPORT Exported { +public: + virtual void AppendSerialized(std::vector* out) const = 0; + + virtual ~Exported() { } +}; +#endif // !defined(v8_inspector_protocol_exported_api_h) + +namespace Schema { +namespace API { + +// ------------- Enums. + +// ------------- Types. + +class V8_EXPORT Domain : public Exported { +public: + static std::unique_ptr fromBinary(const uint8_t* data, size_t length); +}; + +} // namespace API +} // namespace Schema +} // namespace v8_inspector +} // namespace protocol + +#endif // !defined(v8_inspector_protocol_Schema_api_h) diff --git a/NativeScript/napi/v8/include_old/js_protocol-1.2.json b/NativeScript/napi/v8/include_old/js_protocol-1.2.json new file mode 100644 index 00000000..aff68062 --- /dev/null +++ b/NativeScript/napi/v8/include_old/js_protocol-1.2.json @@ -0,0 +1,997 @@ +{ + "version": { "major": "1", "minor": "2" }, + "domains": [ + { + "domain": "Schema", + "description": "Provides information about the protocol schema.", + "types": [ + { + "id": "Domain", + "type": "object", + "description": "Description of the protocol domain.", + "exported": true, + "properties": [ + { "name": "name", "type": "string", "description": "Domain name." }, + { "name": "version", "type": "string", "description": "Domain version." } + ] + } + ], + "commands": [ + { + "name": "getDomains", + "description": "Returns supported domains.", + "handlers": ["browser", "renderer"], + "returns": [ + { "name": "domains", "type": "array", "items": { "$ref": "Domain" }, "description": "List of supported domains." } + ] + } + ] + }, + { + "domain": "Runtime", + "description": "Runtime domain exposes JavaScript runtime by means of remote evaluation and mirror objects. Evaluation results are returned as mirror object that expose object type, string representation and unique identifier that can be used for further object reference. Original objects are maintained in memory unless they are either explicitly released or are released along with the other objects in their object group.", + "types": [ + { + "id": "ScriptId", + "type": "string", + "description": "Unique script identifier." + }, + { + "id": "RemoteObjectId", + "type": "string", + "description": "Unique object identifier." + }, + { + "id": "UnserializableValue", + "type": "string", + "enum": ["Infinity", "NaN", "-Infinity", "-0"], + "description": "Primitive value which cannot be JSON-stringified." + }, + { + "id": "RemoteObject", + "type": "object", + "description": "Mirror object referencing original JavaScript object.", + "exported": true, + "properties": [ + { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, + { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "iterator", "generator", "error", "proxy", "promise", "typedarray"], "description": "Object subtype hint. Specified for object type values only." }, + { "name": "className", "type": "string", "optional": true, "description": "Object class (constructor) name. Specified for object type values only." }, + { "name": "value", "type": "any", "optional": true, "description": "Remote object value in case of primitive values or JSON values (if it was requested)." }, + { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "description": "Primitive value which can not be JSON-stringified does not have value, but gets this property." }, + { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, + { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Unique object identifier (for non-primitive values)." }, + { "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview containing abbreviated property values. Specified for object type values only.", "experimental": true }, + { "name": "customPreview", "$ref": "CustomPreview", "optional": true, "experimental": true} + ] + }, + { + "id": "CustomPreview", + "type": "object", + "experimental": true, + "properties": [ + { "name": "header", "type": "string"}, + { "name": "hasBody", "type": "boolean"}, + { "name": "formatterObjectId", "$ref": "RemoteObjectId"}, + { "name": "bindRemoteObjectFunctionId", "$ref": "RemoteObjectId" }, + { "name": "configObjectId", "$ref": "RemoteObjectId", "optional": true } + ] + }, + { + "id": "ObjectPreview", + "type": "object", + "experimental": true, + "description": "Object containing abbreviated remote object value.", + "properties": [ + { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, + { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "iterator", "generator", "error"], "description": "Object subtype hint. Specified for object type values only." }, + { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, + { "name": "overflow", "type": "boolean", "description": "True iff some of the properties or entries of the original object did not fit." }, + { "name": "properties", "type": "array", "items": { "$ref": "PropertyPreview" }, "description": "List of the properties." }, + { "name": "entries", "type": "array", "items": { "$ref": "EntryPreview" }, "optional": true, "description": "List of the entries. Specified for map and set subtype values only." } + ] + }, + { + "id": "PropertyPreview", + "type": "object", + "experimental": true, + "properties": [ + { "name": "name", "type": "string", "description": "Property name." }, + { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol", "accessor"], "description": "Object type. Accessor means that the property itself is an accessor property." }, + { "name": "value", "type": "string", "optional": true, "description": "User-friendly property value string." }, + { "name": "valuePreview", "$ref": "ObjectPreview", "optional": true, "description": "Nested value preview." }, + { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "iterator", "generator", "error"], "description": "Object subtype hint. Specified for object type values only." } + ] + }, + { + "id": "EntryPreview", + "type": "object", + "experimental": true, + "properties": [ + { "name": "key", "$ref": "ObjectPreview", "optional": true, "description": "Preview of the key. Specified for map-like collection entries." }, + { "name": "value", "$ref": "ObjectPreview", "description": "Preview of the value." } + ] + }, + { + "id": "PropertyDescriptor", + "type": "object", + "description": "Object property descriptor.", + "properties": [ + { "name": "name", "type": "string", "description": "Property name or symbol description." }, + { "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." }, + { "name": "writable", "type": "boolean", "optional": true, "description": "True if the value associated with the property may be changed (data descriptors only)." }, + { "name": "get", "$ref": "RemoteObject", "optional": true, "description": "A function which serves as a getter for the property, or undefined if there is no getter (accessor descriptors only)." }, + { "name": "set", "$ref": "RemoteObject", "optional": true, "description": "A function which serves as a setter for the property, or undefined if there is no setter (accessor descriptors only)." }, + { "name": "configurable", "type": "boolean", "description": "True if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object." }, + { "name": "enumerable", "type": "boolean", "description": "True if this property shows up during enumeration of the properties on the corresponding object." }, + { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, + { "name": "isOwn", "optional": true, "type": "boolean", "description": "True if the property is owned for the object." }, + { "name": "symbol", "$ref": "RemoteObject", "optional": true, "description": "Property symbol object, if the property is of the symbol type." } + ] + }, + { + "id": "InternalPropertyDescriptor", + "type": "object", + "description": "Object internal property descriptor. This property isn't normally visible in JavaScript code.", + "properties": [ + { "name": "name", "type": "string", "description": "Conventional property name." }, + { "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." } + ] + }, + { + "id": "CallArgument", + "type": "object", + "description": "Represents function call argument. Either remote object id objectId, primitive value, unserializable primitive value or neither of (for undefined) them should be specified.", + "properties": [ + { "name": "value", "type": "any", "optional": true, "description": "Primitive value." }, + { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "description": "Primitive value which can not be JSON-stringified." }, + { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Remote object handle." } + ] + }, + { + "id": "ExecutionContextId", + "type": "integer", + "description": "Id of an execution context." + }, + { + "id": "ExecutionContextDescription", + "type": "object", + "description": "Description of an isolated world.", + "properties": [ + { "name": "id", "$ref": "ExecutionContextId", "description": "Unique id of the execution context. It can be used to specify in which execution context script evaluation should be performed." }, + { "name": "origin", "type": "string", "description": "Execution context origin." }, + { "name": "name", "type": "string", "description": "Human readable name describing given context." }, + { "name": "auxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." } + ] + }, + { + "id": "ExceptionDetails", + "type": "object", + "description": "Detailed information about exception (or error) that was thrown during script compilation or execution.", + "properties": [ + { "name": "exceptionId", "type": "integer", "description": "Exception id." }, + { "name": "text", "type": "string", "description": "Exception text, which should be used together with exception object when available." }, + { "name": "lineNumber", "type": "integer", "description": "Line number of the exception location (0-based)." }, + { "name": "columnNumber", "type": "integer", "description": "Column number of the exception location (0-based)." }, + { "name": "scriptId", "$ref": "ScriptId", "optional": true, "description": "Script ID of the exception location." }, + { "name": "url", "type": "string", "optional": true, "description": "URL of the exception location, to be used when the script was not reported." }, + { "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "JavaScript stack trace if available." }, + { "name": "exception", "$ref": "RemoteObject", "optional": true, "description": "Exception object if available." }, + { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Identifier of the context where exception happened." } + ] + }, + { + "id": "Timestamp", + "type": "number", + "description": "Number of milliseconds since epoch." + }, + { + "id": "CallFrame", + "type": "object", + "description": "Stack entry for runtime errors and assertions.", + "properties": [ + { "name": "functionName", "type": "string", "description": "JavaScript function name." }, + { "name": "scriptId", "$ref": "ScriptId", "description": "JavaScript script id." }, + { "name": "url", "type": "string", "description": "JavaScript script name or url." }, + { "name": "lineNumber", "type": "integer", "description": "JavaScript script line number (0-based)." }, + { "name": "columnNumber", "type": "integer", "description": "JavaScript script column number (0-based)." } + ] + }, + { + "id": "StackTrace", + "type": "object", + "description": "Call frames for assertions or error messages.", + "exported": true, + "properties": [ + { "name": "description", "type": "string", "optional": true, "description": "String label of this stack trace. For async traces this may be a name of the function that initiated the async call." }, + { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "JavaScript function name." }, + { "name": "parent", "$ref": "StackTrace", "optional": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." } + ] + } + ], + "commands": [ + { + "name": "evaluate", + "async": true, + "parameters": [ + { "name": "expression", "type": "string", "description": "Expression to evaluate." }, + { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }, + { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation." }, + { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, + { "name": "contextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform evaluation. If the parameter is omitted the evaluation will be performed in the context of the inspected page." }, + { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, + { "name": "userGesture", "type": "boolean", "optional": true, "experimental": true, "description": "Whether execution should be treated as initiated by user in the UI." }, + { "name": "awaitPromise", "type": "boolean", "optional":true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." } + ], + "returns": [ + { "name": "result", "$ref": "RemoteObject", "description": "Evaluation result." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} + ], + "description": "Evaluates expression on global object." + }, + { + "name": "awaitPromise", + "async": true, + "parameters": [ + { "name": "promiseObjectId", "$ref": "RemoteObjectId", "description": "Identifier of the promise." }, + { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, + { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." } + ], + "returns": [ + { "name": "result", "$ref": "RemoteObject", "description": "Promise result. Will contain rejected value if promise was rejected." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details if stack strace is available."} + ], + "description": "Add handler to promise with given promise object id." + }, + { + "name": "callFunctionOn", + "async": true, + "parameters": [ + { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to call function on." }, + { "name": "functionDeclaration", "type": "string", "description": "Declaration of the function to call." }, + { "name": "arguments", "type": "array", "items": { "$ref": "CallArgument", "description": "Call argument." }, "optional": true, "description": "Call arguments. All call arguments must belong to the same JavaScript world as the target object." }, + { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, + { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." }, + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, + { "name": "userGesture", "type": "boolean", "optional": true, "experimental": true, "description": "Whether execution should be treated as initiated by user in the UI." }, + { "name": "awaitPromise", "type": "boolean", "optional":true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." } + ], + "returns": [ + { "name": "result", "$ref": "RemoteObject", "description": "Call result." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} + ], + "description": "Calls function with given declaration on the given object. Object group of the result is inherited from the target object." + }, + { + "name": "getProperties", + "parameters": [ + { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to return properties for." }, + { "name": "ownProperties", "optional": true, "type": "boolean", "description": "If true, returns properties belonging only to the element itself, not to its prototype chain." }, + { "name": "accessorPropertiesOnly", "optional": true, "type": "boolean", "description": "If true, returns accessor properties (with getter/setter) only; internal properties are not returned either.", "experimental": true }, + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the results." } + ], + "returns": [ + { "name": "result", "type": "array", "items": { "$ref": "PropertyDescriptor" }, "description": "Object properties." }, + { "name": "internalProperties", "optional": true, "type": "array", "items": { "$ref": "InternalPropertyDescriptor" }, "description": "Internal object properties (only of the element itself)." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} + ], + "description": "Returns properties of a given object. Object group of the result is inherited from the target object." + }, + { + "name": "releaseObject", + "parameters": [ + { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to release." } + ], + "description": "Releases remote object with given id." + }, + { + "name": "releaseObjectGroup", + "parameters": [ + { "name": "objectGroup", "type": "string", "description": "Symbolic object group name." } + ], + "description": "Releases all remote objects that belong to a given group." + }, + { + "name": "runIfWaitingForDebugger", + "description": "Tells inspected instance to run if it was waiting for debugger to attach." + }, + { + "name": "enable", + "description": "Enables reporting of execution contexts creation by means of executionContextCreated event. When the reporting gets enabled the event will be sent immediately for each existing execution context." + }, + { + "name": "disable", + "description": "Disables reporting of execution contexts creation." + }, + { + "name": "discardConsoleEntries", + "description": "Discards collected exceptions and console API calls." + }, + { + "name": "setCustomObjectFormatterEnabled", + "parameters": [ + { + "name": "enabled", + "type": "boolean" + } + ], + "experimental": true + }, + { + "name": "compileScript", + "parameters": [ + { "name": "expression", "type": "string", "description": "Expression to compile." }, + { "name": "sourceURL", "type": "string", "description": "Source url to be set for the script." }, + { "name": "persistScript", "type": "boolean", "description": "Specifies whether the compiled script should be persisted." }, + { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page." } + ], + "returns": [ + { "name": "scriptId", "$ref": "ScriptId", "optional": true, "description": "Id of the script." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} + ], + "description": "Compiles expression." + }, + { + "name": "runScript", + "async": true, + "parameters": [ + { "name": "scriptId", "$ref": "ScriptId", "description": "Id of the script to run." }, + { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page." }, + { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }, + { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, + { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation." }, + { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." }, + { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." }, + { "name": "awaitPromise", "type": "boolean", "optional": true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." } + ], + "returns": [ + { "name": "result", "$ref": "RemoteObject", "description": "Run result." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} + ], + "description": "Runs script with given id in a given context." + } + ], + "events": [ + { + "name": "executionContextCreated", + "parameters": [ + { "name": "context", "$ref": "ExecutionContextDescription", "description": "A newly created execution contex." } + ], + "description": "Issued when new execution context is created." + }, + { + "name": "executionContextDestroyed", + "parameters": [ + { "name": "executionContextId", "$ref": "ExecutionContextId", "description": "Id of the destroyed context" } + ], + "description": "Issued when execution context is destroyed." + }, + { + "name": "executionContextsCleared", + "description": "Issued when all executionContexts were cleared in browser" + }, + { + "name": "exceptionThrown", + "description": "Issued when exception was thrown and unhandled.", + "parameters": [ + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp of the exception." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails" } + ] + }, + { + "name": "exceptionRevoked", + "description": "Issued when unhandled exception was revoked.", + "parameters": [ + { "name": "reason", "type": "string", "description": "Reason describing why exception was revoked." }, + { "name": "exceptionId", "type": "integer", "description": "The id of revoked exception, as reported in exceptionUnhandled." } + ] + }, + { + "name": "consoleAPICalled", + "description": "Issued when console API was called.", + "parameters": [ + { "name": "type", "type": "string", "enum": ["log", "debug", "info", "error", "warning", "dir", "dirxml", "table", "trace", "clear", "startGroup", "startGroupCollapsed", "endGroup", "assert", "profile", "profileEnd"], "description": "Type of the call." }, + { "name": "args", "type": "array", "items": { "$ref": "RemoteObject" }, "description": "Call arguments." }, + { "name": "executionContextId", "$ref": "ExecutionContextId", "description": "Identifier of the context where the call was made." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Call timestamp." }, + { "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "Stack trace captured when the call was made." } + ] + }, + { + "name": "inspectRequested", + "description": "Issued when object should be inspected (for example, as a result of inspect() command line API call).", + "parameters": [ + { "name": "object", "$ref": "RemoteObject" }, + { "name": "hints", "type": "object" } + ] + } + ] + }, + { + "domain": "Debugger", + "description": "Debugger domain exposes JavaScript debugging capabilities. It allows setting and removing breakpoints, stepping through execution, exploring stack traces, etc.", + "dependencies": ["Runtime"], + "types": [ + { + "id": "BreakpointId", + "type": "string", + "description": "Breakpoint identifier." + }, + { + "id": "CallFrameId", + "type": "string", + "description": "Call frame identifier." + }, + { + "id": "Location", + "type": "object", + "properties": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Script identifier as reported in the Debugger.scriptParsed." }, + { "name": "lineNumber", "type": "integer", "description": "Line number in the script (0-based)." }, + { "name": "columnNumber", "type": "integer", "optional": true, "description": "Column number in the script (0-based)." } + ], + "description": "Location in the source code." + }, + { + "id": "ScriptPosition", + "experimental": true, + "type": "object", + "properties": [ + { "name": "lineNumber", "type": "integer" }, + { "name": "columnNumber", "type": "integer" } + ], + "description": "Location in the source code." + }, + { + "id": "CallFrame", + "type": "object", + "properties": [ + { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier. This identifier is only valid while the virtual machine is paused." }, + { "name": "functionName", "type": "string", "description": "Name of the JavaScript function called on this call frame." }, + { "name": "functionLocation", "$ref": "Location", "optional": true, "experimental": true, "description": "Location in the source code." }, + { "name": "location", "$ref": "Location", "description": "Location in the source code." }, + { "name": "scopeChain", "type": "array", "items": { "$ref": "Scope" }, "description": "Scope chain for this call frame." }, + { "name": "this", "$ref": "Runtime.RemoteObject", "description": "this object for this call frame." }, + { "name": "returnValue", "$ref": "Runtime.RemoteObject", "optional": true, "description": "The value being returned, if the function is at return point." } + ], + "description": "JavaScript call frame. Array of call frames form the call stack." + }, + { + "id": "Scope", + "type": "object", + "properties": [ + { "name": "type", "type": "string", "enum": ["global", "local", "with", "closure", "catch", "block", "script"], "description": "Scope type." }, + { "name": "object", "$ref": "Runtime.RemoteObject", "description": "Object representing the scope. For global and with scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties." }, + { "name": "name", "type": "string", "optional": true }, + { "name": "startLocation", "$ref": "Location", "optional": true, "description": "Location in the source code where scope starts" }, + { "name": "endLocation", "$ref": "Location", "optional": true, "description": "Location in the source code where scope ends" } + ], + "description": "Scope description." + }, + { + "id": "SearchMatch", + "type": "object", + "description": "Search match for resource.", + "exported": true, + "properties": [ + { "name": "lineNumber", "type": "number", "description": "Line number in resource content." }, + { "name": "lineContent", "type": "string", "description": "Line with match content." } + ], + "experimental": true + } + ], + "commands": [ + { + "name": "enable", + "description": "Enables debugger for the given page. Clients should not assume that the debugging has been enabled until the result for this command is received." + }, + { + "name": "disable", + "description": "Disables debugger for given page." + }, + { + "name": "setBreakpointsActive", + "parameters": [ + { "name": "active", "type": "boolean", "description": "New value for breakpoints active state." } + ], + "description": "Activates / deactivates all breakpoints on the page." + }, + { + "name": "setSkipAllPauses", + "parameters": [ + { "name": "skip", "type": "boolean", "description": "New value for skip pauses state." } + ], + "description": "Makes page not interrupt on any pauses (breakpoint, exception, dom exception etc)." + }, + { + "name": "setBreakpointByUrl", + "parameters": [ + { "name": "lineNumber", "type": "integer", "description": "Line number to set breakpoint at." }, + { "name": "url", "type": "string", "optional": true, "description": "URL of the resources to set breakpoint on." }, + { "name": "urlRegex", "type": "string", "optional": true, "description": "Regex pattern for the URLs of the resources to set breakpoints on. Either url or urlRegex must be specified." }, + { "name": "columnNumber", "type": "integer", "optional": true, "description": "Offset in the line to set breakpoint at." }, + { "name": "condition", "type": "string", "optional": true, "description": "Expression to use as a breakpoint condition. When specified, debugger will only stop on the breakpoint if this expression evaluates to true." } + ], + "returns": [ + { "name": "breakpointId", "$ref": "BreakpointId", "description": "Id of the created breakpoint for further reference." }, + { "name": "locations", "type": "array", "items": { "$ref": "Location" }, "description": "List of the locations this breakpoint resolved into upon addition." } + ], + "description": "Sets JavaScript breakpoint at given location specified either by URL or URL regex. Once this command is issued, all existing parsed scripts will have breakpoints resolved and returned in locations property. Further matching script parsing will result in subsequent breakpointResolved events issued. This logical breakpoint will survive page reloads." + }, + { + "name": "setBreakpoint", + "parameters": [ + { "name": "location", "$ref": "Location", "description": "Location to set breakpoint in." }, + { "name": "condition", "type": "string", "optional": true, "description": "Expression to use as a breakpoint condition. When specified, debugger will only stop on the breakpoint if this expression evaluates to true." } + ], + "returns": [ + { "name": "breakpointId", "$ref": "BreakpointId", "description": "Id of the created breakpoint for further reference." }, + { "name": "actualLocation", "$ref": "Location", "description": "Location this breakpoint resolved into." } + ], + "description": "Sets JavaScript breakpoint at a given location." + }, + { + "name": "removeBreakpoint", + "parameters": [ + { "name": "breakpointId", "$ref": "BreakpointId" } + ], + "description": "Removes JavaScript breakpoint." + }, + { + "name": "continueToLocation", + "parameters": [ + { "name": "location", "$ref": "Location", "description": "Location to continue to." } + ], + "description": "Continues execution until specific location is reached." + }, + { + "name": "stepOver", + "description": "Steps over the statement." + }, + { + "name": "stepInto", + "description": "Steps into the function call." + }, + { + "name": "stepOut", + "description": "Steps out of the function call." + }, + { + "name": "pause", + "description": "Stops on the next JavaScript statement." + }, + { + "name": "resume", + "description": "Resumes JavaScript execution." + }, + { + "name": "searchInContent", + "parameters": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to search in." }, + { "name": "query", "type": "string", "description": "String to search for." }, + { "name": "caseSensitive", "type": "boolean", "optional": true, "description": "If true, search is case sensitive." }, + { "name": "isRegex", "type": "boolean", "optional": true, "description": "If true, treats string parameter as regex." } + ], + "returns": [ + { "name": "result", "type": "array", "items": { "$ref": "SearchMatch" }, "description": "List of search matches." } + ], + "experimental": true, + "description": "Searches for given string in script content." + }, + { + "name": "setScriptSource", + "parameters": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to edit." }, + { "name": "scriptSource", "type": "string", "description": "New content of the script." }, + { "name": "dryRun", "type": "boolean", "optional": true, "description": " If true the change will not actually be applied. Dry run may be used to get result description without actually modifying the code." } + ], + "returns": [ + { "name": "callFrames", "type": "array", "optional": true, "items": { "$ref": "CallFrame" }, "description": "New stack trace in case editing has happened while VM was stopped." }, + { "name": "stackChanged", "type": "boolean", "optional": true, "description": "Whether current call stack was modified after applying the changes." }, + { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." }, + { "name": "exceptionDetails", "optional": true, "$ref": "Runtime.ExceptionDetails", "description": "Exception details if any." } + ], + "description": "Edits JavaScript source live." + }, + { + "name": "restartFrame", + "parameters": [ + { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier to evaluate on." } + ], + "returns": [ + { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "New stack trace." }, + { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." } + ], + "description": "Restarts particular call frame from the beginning." + }, + { + "name": "getScriptSource", + "parameters": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to get source for." } + ], + "returns": [ + { "name": "scriptSource", "type": "string", "description": "Script source." } + ], + "description": "Returns source for the script with given id." + }, + { + "name": "setPauseOnExceptions", + "parameters": [ + { "name": "state", "type": "string", "enum": ["none", "uncaught", "all"], "description": "Pause on exceptions mode." } + ], + "description": "Defines pause on exceptions state. Can be set to stop on all exceptions, uncaught exceptions or no exceptions. Initial pause on exceptions state is none." + }, + { + "name": "evaluateOnCallFrame", + "parameters": [ + { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier to evaluate on." }, + { "name": "expression", "type": "string", "description": "Expression to evaluate." }, + { "name": "objectGroup", "type": "string", "optional": true, "description": "String object group name to put result into (allows rapid releasing resulting object handles using releaseObjectGroup)." }, + { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Specifies whether command line API should be available to the evaluated expression, defaults to false." }, + { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, + { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." } + ], + "returns": [ + { "name": "result", "$ref": "Runtime.RemoteObject", "description": "Object wrapper for the evaluation result." }, + { "name": "exceptionDetails", "$ref": "Runtime.ExceptionDetails", "optional": true, "description": "Exception details."} + ], + "description": "Evaluates expression on a given call frame." + }, + { + "name": "setVariableValue", + "parameters": [ + { "name": "scopeNumber", "type": "integer", "description": "0-based number of scope as was listed in scope chain. Only 'local', 'closure' and 'catch' scope types are allowed. Other scopes could be manipulated manually." }, + { "name": "variableName", "type": "string", "description": "Variable name." }, + { "name": "newValue", "$ref": "Runtime.CallArgument", "description": "New variable value." }, + { "name": "callFrameId", "$ref": "CallFrameId", "description": "Id of callframe that holds variable." } + ], + "description": "Changes value of variable in a callframe. Object-based scopes are not supported and must be mutated manually." + }, + { + "name": "setAsyncCallStackDepth", + "parameters": [ + { "name": "maxDepth", "type": "integer", "description": "Maximum depth of async call stacks. Setting to 0 will effectively disable collecting async call stacks (default)." } + ], + "description": "Enables or disables async call stacks tracking." + }, + { + "name": "setBlackboxPatterns", + "parameters": [ + { "name": "patterns", "type": "array", "items": { "type": "string" }, "description": "Array of regexps that will be used to check script url for blackbox state." } + ], + "experimental": true, + "description": "Replace previous blackbox patterns with passed ones. Forces backend to skip stepping/pausing in scripts with url matching one of the patterns. VM will try to leave blackboxed script by performing 'step in' several times, finally resorting to 'step out' if unsuccessful." + }, + { + "name": "setBlackboxedRanges", + "parameters": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script." }, + { "name": "positions", "type": "array", "items": { "$ref": "ScriptPosition" } } + ], + "experimental": true, + "description": "Makes backend skip steps in the script in blackboxed ranges. VM will try leave blacklisted scripts by performing 'step in' several times, finally resorting to 'step out' if unsuccessful. Positions array contains positions where blackbox state is changed. First interval isn't blackboxed. Array should be sorted." + } + ], + "events": [ + { + "name": "scriptParsed", + "parameters": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Identifier of the script parsed." }, + { "name": "url", "type": "string", "description": "URL or name of the script parsed (if any)." }, + { "name": "startLine", "type": "integer", "description": "Line offset of the script within the resource with given URL (for script tags)." }, + { "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." }, + { "name": "endLine", "type": "integer", "description": "Last line of the script." }, + { "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." }, + { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context." }, + { "name": "hash", "type": "string", "description": "Content hash of the script."}, + { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." }, + { "name": "isLiveEdit", "type": "boolean", "optional": true, "description": "True, if this script is generated as a result of the live edit operation.", "experimental": true }, + { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." }, + { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "experimental": true } + ], + "description": "Fired when virtual machine parses script. This event is also fired for all known and uncollected scripts upon enabling debugger." + }, + { + "name": "scriptFailedToParse", + "parameters": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Identifier of the script parsed." }, + { "name": "url", "type": "string", "description": "URL or name of the script parsed (if any)." }, + { "name": "startLine", "type": "integer", "description": "Line offset of the script within the resource with given URL (for script tags)." }, + { "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." }, + { "name": "endLine", "type": "integer", "description": "Last line of the script." }, + { "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." }, + { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context." }, + { "name": "hash", "type": "string", "description": "Content hash of the script."}, + { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." }, + { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." }, + { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "experimental": true } + ], + "description": "Fired when virtual machine fails to parse the script." + }, + { + "name": "breakpointResolved", + "parameters": [ + { "name": "breakpointId", "$ref": "BreakpointId", "description": "Breakpoint unique identifier." }, + { "name": "location", "$ref": "Location", "description": "Actual breakpoint location." } + ], + "description": "Fired when breakpoint is resolved to an actual script and location." + }, + { + "name": "paused", + "parameters": [ + { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." }, + { "name": "reason", "type": "string", "enum": [ "XHR", "DOM", "EventListener", "exception", "assert", "debugCommand", "promiseRejection", "other" ], "description": "Pause reason.", "exported": true }, + { "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." }, + { "name": "hitBreakpoints", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Hit breakpoints IDs" }, + { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." } + ], + "description": "Fired when the virtual machine stopped on breakpoint or exception or any other stop criteria." + }, + { + "name": "resumed", + "description": "Fired when the virtual machine resumed execution." + } + ] + }, + { + "domain": "Console", + "description": "This domain is deprecated - use Runtime or Log instead.", + "dependencies": ["Runtime"], + "deprecated": true, + "types": [ + { + "id": "ConsoleMessage", + "type": "object", + "description": "Console message.", + "properties": [ + { "name": "source", "type": "string", "enum": ["xml", "javascript", "network", "console-api", "storage", "appcache", "rendering", "security", "other", "deprecation", "worker"], "description": "Message source." }, + { "name": "level", "type": "string", "enum": ["log", "warning", "error", "debug", "info"], "description": "Message severity." }, + { "name": "text", "type": "string", "description": "Message text." }, + { "name": "url", "type": "string", "optional": true, "description": "URL of the message origin." }, + { "name": "line", "type": "integer", "optional": true, "description": "Line number in the resource that generated this message (1-based)." }, + { "name": "column", "type": "integer", "optional": true, "description": "Column number in the resource that generated this message (1-based)." } + ] + } + ], + "commands": [ + { + "name": "enable", + "description": "Enables console domain, sends the messages collected so far to the client by means of the messageAdded notification." + }, + { + "name": "disable", + "description": "Disables console domain, prevents further console messages from being reported to the client." + }, + { + "name": "clearMessages", + "description": "Does nothing." + } + ], + "events": [ + { + "name": "messageAdded", + "parameters": [ + { "name": "message", "$ref": "ConsoleMessage", "description": "Console message that has been added." } + ], + "description": "Issued when new console message is added." + } + ] + }, + { + "domain": "Profiler", + "dependencies": ["Runtime", "Debugger"], + "types": [ + { + "id": "ProfileNode", + "type": "object", + "description": "Profile node. Holds callsite information, execution statistics and child nodes.", + "properties": [ + { "name": "id", "type": "integer", "description": "Unique id of the node." }, + { "name": "callFrame", "$ref": "Runtime.CallFrame", "description": "Function location." }, + { "name": "hitCount", "type": "integer", "optional": true, "experimental": true, "description": "Number of samples where this node was on top of the call stack." }, + { "name": "children", "type": "array", "items": { "type": "integer" }, "optional": true, "description": "Child node ids." }, + { "name": "deoptReason", "type": "string", "optional": true, "description": "The reason of being not optimized. The function may be deoptimized or marked as don't optimize."}, + { "name": "positionTicks", "type": "array", "items": { "$ref": "PositionTickInfo" }, "optional": true, "experimental": true, "description": "An array of source position ticks." } + ] + }, + { + "id": "Profile", + "type": "object", + "description": "Profile.", + "properties": [ + { "name": "nodes", "type": "array", "items": { "$ref": "ProfileNode" }, "description": "The list of profile nodes. First item is the root node." }, + { "name": "startTime", "type": "number", "description": "Profiling start timestamp in microseconds." }, + { "name": "endTime", "type": "number", "description": "Profiling end timestamp in microseconds." }, + { "name": "samples", "optional": true, "type": "array", "items": { "type": "integer" }, "description": "Ids of samples top nodes." }, + { "name": "timeDeltas", "optional": true, "type": "array", "items": { "type": "integer" }, "description": "Time intervals between adjacent samples in microseconds. The first delta is relative to the profile startTime." } + ] + }, + { + "id": "PositionTickInfo", + "type": "object", + "experimental": true, + "description": "Specifies a number of samples attributed to a certain source position.", + "properties": [ + { "name": "line", "type": "integer", "description": "Source line number (1-based)." }, + { "name": "ticks", "type": "integer", "description": "Number of samples attributed to the source line." } + ] + } + ], + "commands": [ + { + "name": "enable" + }, + { + "name": "disable" + }, + { + "name": "setSamplingInterval", + "parameters": [ + { "name": "interval", "type": "integer", "description": "New sampling interval in microseconds." } + ], + "description": "Changes CPU profiler sampling interval. Must be called before CPU profiles recording started." + }, + { + "name": "start" + }, + { + "name": "stop", + "returns": [ + { "name": "profile", "$ref": "Profile", "description": "Recorded profile." } + ] + } + ], + "events": [ + { + "name": "consoleProfileStarted", + "parameters": [ + { "name": "id", "type": "string" }, + { "name": "location", "$ref": "Debugger.Location", "description": "Location of console.profile()." }, + { "name": "title", "type": "string", "optional": true, "description": "Profile title passed as an argument to console.profile()." } + ], + "description": "Sent when new profile recodring is started using console.profile() call." + }, + { + "name": "consoleProfileFinished", + "parameters": [ + { "name": "id", "type": "string" }, + { "name": "location", "$ref": "Debugger.Location", "description": "Location of console.profileEnd()." }, + { "name": "profile", "$ref": "Profile" }, + { "name": "title", "type": "string", "optional": true, "description": "Profile title passed as an argument to console.profile()." } + ] + } + ] + }, + { + "domain": "HeapProfiler", + "dependencies": ["Runtime"], + "experimental": true, + "types": [ + { + "id": "HeapSnapshotObjectId", + "type": "string", + "description": "Heap snapshot object id." + }, + { + "id": "SamplingHeapProfileNode", + "type": "object", + "description": "Sampling Heap Profile node. Holds callsite information, allocation statistics and child nodes.", + "properties": [ + { "name": "callFrame", "$ref": "Runtime.CallFrame", "description": "Function location." }, + { "name": "selfSize", "type": "number", "description": "Allocations size in bytes for the node excluding children." }, + { "name": "children", "type": "array", "items": { "$ref": "SamplingHeapProfileNode" }, "description": "Child nodes." } + ] + }, + { + "id": "SamplingHeapProfile", + "type": "object", + "description": "Profile.", + "properties": [ + { "name": "head", "$ref": "SamplingHeapProfileNode" } + ] + } + ], + "commands": [ + { + "name": "enable" + }, + { + "name": "disable" + }, + { + "name": "startTrackingHeapObjects", + "parameters": [ + { "name": "trackAllocations", "type": "boolean", "optional": true } + ] + }, + { + "name": "stopTrackingHeapObjects", + "parameters": [ + { "name": "reportProgress", "type": "boolean", "optional": true, "description": "If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken when the tracking is stopped." } + ] + }, + { + "name": "takeHeapSnapshot", + "parameters": [ + { "name": "reportProgress", "type": "boolean", "optional": true, "description": "If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken." } + ] + }, + { + "name": "collectGarbage" + }, + { + "name": "getObjectByHeapObjectId", + "parameters": [ + { "name": "objectId", "$ref": "HeapSnapshotObjectId" }, + { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." } + ], + "returns": [ + { "name": "result", "$ref": "Runtime.RemoteObject", "description": "Evaluation result." } + ] + }, + { + "name": "addInspectedHeapObject", + "parameters": [ + { "name": "heapObjectId", "$ref": "HeapSnapshotObjectId", "description": "Heap snapshot object id to be accessible by means of $x command line API." } + ], + "description": "Enables console to refer to the node with given id via $x (see Command Line API for more details $x functions)." + }, + { + "name": "getHeapObjectId", + "parameters": [ + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "Identifier of the object to get heap object id for." } + ], + "returns": [ + { "name": "heapSnapshotObjectId", "$ref": "HeapSnapshotObjectId", "description": "Id of the heap snapshot object corresponding to the passed remote object id." } + ] + }, + { + "name": "startSampling", + "parameters": [ + { "name": "samplingInterval", "type": "number", "optional": true, "description": "Average sample interval in bytes. Poisson distribution is used for the intervals. The default value is 32768 bytes." } + ] + }, + { + "name": "stopSampling", + "returns": [ + { "name": "profile", "$ref": "SamplingHeapProfile", "description": "Recorded sampling heap profile." } + ] + } + ], + "events": [ + { + "name": "addHeapSnapshotChunk", + "parameters": [ + { "name": "chunk", "type": "string" } + ] + }, + { + "name": "resetProfiles" + }, + { + "name": "reportHeapSnapshotProgress", + "parameters": [ + { "name": "done", "type": "integer" }, + { "name": "total", "type": "integer" }, + { "name": "finished", "type": "boolean", "optional": true } + ] + }, + { + "name": "lastSeenObjectId", + "description": "If heap objects tracking has been started then backend regulary sends a current value for last seen object id and corresponding timestamp. If the were changes in the heap since last event then one or more heapStatsUpdate events will be sent before a new lastSeenObjectId event.", + "parameters": [ + { "name": "lastSeenObjectId", "type": "integer" }, + { "name": "timestamp", "type": "number" } + ] + }, + { + "name": "heapStatsUpdate", + "description": "If heap objects tracking has been started then backend may send update for one or more fragments", + "parameters": [ + { "name": "statsUpdate", "type": "array", "items": { "type": "integer" }, "description": "An array of triplets. Each triplet describes a fragment. The first integer is the fragment index, the second integer is a total count of objects for the fragment, the third integer is a total size of the objects for the fragment."} + ] + } + ] + }] +} diff --git a/NativeScript/napi/v8/include_old/js_protocol-1.3.json b/NativeScript/napi/v8/include_old/js_protocol-1.3.json new file mode 100644 index 00000000..a998d461 --- /dev/null +++ b/NativeScript/napi/v8/include_old/js_protocol-1.3.json @@ -0,0 +1,1159 @@ +{ + "version": { "major": "1", "minor": "3" }, + "domains": [ + { + "domain": "Schema", + "description": "This domain is deprecated.", + "deprecated": true, + "types": [ + { + "id": "Domain", + "type": "object", + "description": "Description of the protocol domain.", + "properties": [ + { "name": "name", "type": "string", "description": "Domain name." }, + { "name": "version", "type": "string", "description": "Domain version." } + ] + } + ], + "commands": [ + { + "name": "getDomains", + "description": "Returns supported domains.", + "handlers": ["browser", "renderer"], + "returns": [ + { "name": "domains", "type": "array", "items": { "$ref": "Domain" }, "description": "List of supported domains." } + ] + } + ] + }, + { + "domain": "Runtime", + "description": "Runtime domain exposes JavaScript runtime by means of remote evaluation and mirror objects. Evaluation results are returned as mirror object that expose object type, string representation and unique identifier that can be used for further object reference. Original objects are maintained in memory unless they are either explicitly released or are released along with the other objects in their object group.", + "types": [ + { + "id": "ScriptId", + "type": "string", + "description": "Unique script identifier." + }, + { + "id": "RemoteObjectId", + "type": "string", + "description": "Unique object identifier." + }, + { + "id": "UnserializableValue", + "type": "string", + "enum": ["Infinity", "NaN", "-Infinity", "-0"], + "description": "Primitive value which cannot be JSON-stringified." + }, + { + "id": "RemoteObject", + "type": "object", + "description": "Mirror object referencing original JavaScript object.", + "properties": [ + { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, + { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "weakmap", "weakset", "iterator", "generator", "error", "proxy", "promise", "typedarray"], "description": "Object subtype hint. Specified for object type values only." }, + { "name": "className", "type": "string", "optional": true, "description": "Object class (constructor) name. Specified for object type values only." }, + { "name": "value", "type": "any", "optional": true, "description": "Remote object value in case of primitive values or JSON values (if it was requested)." }, + { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "description": "Primitive value which can not be JSON-stringified does not have value, but gets this property." }, + { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, + { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Unique object identifier (for non-primitive values)." }, + { "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview containing abbreviated property values. Specified for object type values only.", "experimental": true }, + { "name": "customPreview", "$ref": "CustomPreview", "optional": true, "experimental": true} + ] + }, + { + "id": "CustomPreview", + "type": "object", + "experimental": true, + "properties": [ + { "name": "header", "type": "string"}, + { "name": "hasBody", "type": "boolean"}, + { "name": "formatterObjectId", "$ref": "RemoteObjectId"}, + { "name": "bindRemoteObjectFunctionId", "$ref": "RemoteObjectId" }, + { "name": "configObjectId", "$ref": "RemoteObjectId", "optional": true } + ] + }, + { + "id": "ObjectPreview", + "type": "object", + "experimental": true, + "description": "Object containing abbreviated remote object value.", + "properties": [ + { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, + { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "weakmap", "weakset", "iterator", "generator", "error"], "description": "Object subtype hint. Specified for object type values only." }, + { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, + { "name": "overflow", "type": "boolean", "description": "True iff some of the properties or entries of the original object did not fit." }, + { "name": "properties", "type": "array", "items": { "$ref": "PropertyPreview" }, "description": "List of the properties." }, + { "name": "entries", "type": "array", "items": { "$ref": "EntryPreview" }, "optional": true, "description": "List of the entries. Specified for map and set subtype values only." } + ] + }, + { + "id": "PropertyPreview", + "type": "object", + "experimental": true, + "properties": [ + { "name": "name", "type": "string", "description": "Property name." }, + { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol", "accessor"], "description": "Object type. Accessor means that the property itself is an accessor property." }, + { "name": "value", "type": "string", "optional": true, "description": "User-friendly property value string." }, + { "name": "valuePreview", "$ref": "ObjectPreview", "optional": true, "description": "Nested value preview." }, + { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "weakmap", "weakset", "iterator", "generator", "error"], "description": "Object subtype hint. Specified for object type values only." } + ] + }, + { + "id": "EntryPreview", + "type": "object", + "experimental": true, + "properties": [ + { "name": "key", "$ref": "ObjectPreview", "optional": true, "description": "Preview of the key. Specified for map-like collection entries." }, + { "name": "value", "$ref": "ObjectPreview", "description": "Preview of the value." } + ] + }, + { + "id": "PropertyDescriptor", + "type": "object", + "description": "Object property descriptor.", + "properties": [ + { "name": "name", "type": "string", "description": "Property name or symbol description." }, + { "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." }, + { "name": "writable", "type": "boolean", "optional": true, "description": "True if the value associated with the property may be changed (data descriptors only)." }, + { "name": "get", "$ref": "RemoteObject", "optional": true, "description": "A function which serves as a getter for the property, or undefined if there is no getter (accessor descriptors only)." }, + { "name": "set", "$ref": "RemoteObject", "optional": true, "description": "A function which serves as a setter for the property, or undefined if there is no setter (accessor descriptors only)." }, + { "name": "configurable", "type": "boolean", "description": "True if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object." }, + { "name": "enumerable", "type": "boolean", "description": "True if this property shows up during enumeration of the properties on the corresponding object." }, + { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, + { "name": "isOwn", "optional": true, "type": "boolean", "description": "True if the property is owned for the object." }, + { "name": "symbol", "$ref": "RemoteObject", "optional": true, "description": "Property symbol object, if the property is of the symbol type." } + ] + }, + { + "id": "InternalPropertyDescriptor", + "type": "object", + "description": "Object internal property descriptor. This property isn't normally visible in JavaScript code.", + "properties": [ + { "name": "name", "type": "string", "description": "Conventional property name." }, + { "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." } + ] + }, + { + "id": "CallArgument", + "type": "object", + "description": "Represents function call argument. Either remote object id objectId, primitive value, unserializable primitive value or neither of (for undefined) them should be specified.", + "properties": [ + { "name": "value", "type": "any", "optional": true, "description": "Primitive value or serializable javascript object." }, + { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "description": "Primitive value which can not be JSON-stringified." }, + { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Remote object handle." } + ] + }, + { + "id": "ExecutionContextId", + "type": "integer", + "description": "Id of an execution context." + }, + { + "id": "ExecutionContextDescription", + "type": "object", + "description": "Description of an isolated world.", + "properties": [ + { "name": "id", "$ref": "ExecutionContextId", "description": "Unique id of the execution context. It can be used to specify in which execution context script evaluation should be performed." }, + { "name": "origin", "type": "string", "description": "Execution context origin." }, + { "name": "name", "type": "string", "description": "Human readable name describing given context." }, + { "name": "auxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." } + ] + }, + { + "id": "ExceptionDetails", + "type": "object", + "description": "Detailed information about exception (or error) that was thrown during script compilation or execution.", + "properties": [ + { "name": "exceptionId", "type": "integer", "description": "Exception id." }, + { "name": "text", "type": "string", "description": "Exception text, which should be used together with exception object when available." }, + { "name": "lineNumber", "type": "integer", "description": "Line number of the exception location (0-based)." }, + { "name": "columnNumber", "type": "integer", "description": "Column number of the exception location (0-based)." }, + { "name": "scriptId", "$ref": "ScriptId", "optional": true, "description": "Script ID of the exception location." }, + { "name": "url", "type": "string", "optional": true, "description": "URL of the exception location, to be used when the script was not reported." }, + { "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "JavaScript stack trace if available." }, + { "name": "exception", "$ref": "RemoteObject", "optional": true, "description": "Exception object if available." }, + { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Identifier of the context where exception happened." } + ] + }, + { + "id": "Timestamp", + "type": "number", + "description": "Number of milliseconds since epoch." + }, + { + "id": "CallFrame", + "type": "object", + "description": "Stack entry for runtime errors and assertions.", + "properties": [ + { "name": "functionName", "type": "string", "description": "JavaScript function name." }, + { "name": "scriptId", "$ref": "ScriptId", "description": "JavaScript script id." }, + { "name": "url", "type": "string", "description": "JavaScript script name or url." }, + { "name": "lineNumber", "type": "integer", "description": "JavaScript script line number (0-based)." }, + { "name": "columnNumber", "type": "integer", "description": "JavaScript script column number (0-based)." } + ] + }, + { + "id": "StackTrace", + "type": "object", + "description": "Call frames for assertions or error messages.", + "properties": [ + { "name": "description", "type": "string", "optional": true, "description": "String label of this stack trace. For async traces this may be a name of the function that initiated the async call." }, + { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "JavaScript function name." }, + { "name": "parent", "$ref": "StackTrace", "optional": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." }, + { "name": "parentId", "$ref": "StackTraceId", "optional": true, "experimental": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." } + ] + }, + { + "id": "UniqueDebuggerId", + "type": "string", + "description": "Unique identifier of current debugger.", + "experimental": true + }, + { + "id": "StackTraceId", + "type": "object", + "description": "If debuggerId is set stack trace comes from another debugger and can be resolved there. This allows to track cross-debugger calls. See Runtime.StackTrace and Debugger.paused for usages.", + "properties": [ + { "name": "id", "type": "string" }, + { "name": "debuggerId", "$ref": "UniqueDebuggerId", "optional": true } + ], + "experimental": true + } + ], + "commands": [ + { + "name": "evaluate", + "parameters": [ + { "name": "expression", "type": "string", "description": "Expression to evaluate." }, + { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }, + { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation." }, + { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, + { "name": "contextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform evaluation. If the parameter is omitted the evaluation will be performed in the context of the inspected page." }, + { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, + { "name": "userGesture", "type": "boolean", "optional": true, "description": "Whether execution should be treated as initiated by user in the UI." }, + { "name": "awaitPromise", "type": "boolean", "optional":true, "description": "Whether execution should await for resulting value and return once awaited promise is resolved." } + ], + "returns": [ + { "name": "result", "$ref": "RemoteObject", "description": "Evaluation result." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} + ], + "description": "Evaluates expression on global object." + }, + { + "name": "awaitPromise", + "parameters": [ + { "name": "promiseObjectId", "$ref": "RemoteObjectId", "description": "Identifier of the promise." }, + { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, + { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." } + ], + "returns": [ + { "name": "result", "$ref": "RemoteObject", "description": "Promise result. Will contain rejected value if promise was rejected." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details if stack strace is available."} + ], + "description": "Add handler to promise with given promise object id." + }, + { + "name": "callFunctionOn", + "parameters": [ + { "name": "functionDeclaration", "type": "string", "description": "Declaration of the function to call." }, + { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Identifier of the object to call function on. Either objectId or executionContextId should be specified." }, + { "name": "arguments", "type": "array", "items": { "$ref": "CallArgument", "description": "Call argument." }, "optional": true, "description": "Call arguments. All call arguments must belong to the same JavaScript world as the target object." }, + { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, + { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." }, + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, + { "name": "userGesture", "type": "boolean", "optional": true, "description": "Whether execution should be treated as initiated by user in the UI." }, + { "name": "awaitPromise", "type": "boolean", "optional":true, "description": "Whether execution should await for resulting value and return once awaited promise is resolved." }, + { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies execution context which global object will be used to call function on. Either executionContextId or objectId should be specified." }, + { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects. If objectGroup is not specified and objectId is, objectGroup will be inherited from object." } + ], + "returns": [ + { "name": "result", "$ref": "RemoteObject", "description": "Call result." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} + ], + "description": "Calls function with given declaration on the given object. Object group of the result is inherited from the target object." + }, + { + "name": "getProperties", + "parameters": [ + { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to return properties for." }, + { "name": "ownProperties", "optional": true, "type": "boolean", "description": "If true, returns properties belonging only to the element itself, not to its prototype chain." }, + { "name": "accessorPropertiesOnly", "optional": true, "type": "boolean", "description": "If true, returns accessor properties (with getter/setter) only; internal properties are not returned either.", "experimental": true }, + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the results." } + ], + "returns": [ + { "name": "result", "type": "array", "items": { "$ref": "PropertyDescriptor" }, "description": "Object properties." }, + { "name": "internalProperties", "optional": true, "type": "array", "items": { "$ref": "InternalPropertyDescriptor" }, "description": "Internal object properties (only of the element itself)." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} + ], + "description": "Returns properties of a given object. Object group of the result is inherited from the target object." + }, + { + "name": "releaseObject", + "parameters": [ + { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to release." } + ], + "description": "Releases remote object with given id." + }, + { + "name": "releaseObjectGroup", + "parameters": [ + { "name": "objectGroup", "type": "string", "description": "Symbolic object group name." } + ], + "description": "Releases all remote objects that belong to a given group." + }, + { + "name": "runIfWaitingForDebugger", + "description": "Tells inspected instance to run if it was waiting for debugger to attach." + }, + { + "name": "enable", + "description": "Enables reporting of execution contexts creation by means of executionContextCreated event. When the reporting gets enabled the event will be sent immediately for each existing execution context." + }, + { + "name": "disable", + "description": "Disables reporting of execution contexts creation." + }, + { + "name": "discardConsoleEntries", + "description": "Discards collected exceptions and console API calls." + }, + { + "name": "setCustomObjectFormatterEnabled", + "parameters": [ + { + "name": "enabled", + "type": "boolean" + } + ], + "experimental": true + }, + { + "name": "compileScript", + "parameters": [ + { "name": "expression", "type": "string", "description": "Expression to compile." }, + { "name": "sourceURL", "type": "string", "description": "Source url to be set for the script." }, + { "name": "persistScript", "type": "boolean", "description": "Specifies whether the compiled script should be persisted." }, + { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page." } + ], + "returns": [ + { "name": "scriptId", "$ref": "ScriptId", "optional": true, "description": "Id of the script." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} + ], + "description": "Compiles expression." + }, + { + "name": "runScript", + "parameters": [ + { "name": "scriptId", "$ref": "ScriptId", "description": "Id of the script to run." }, + { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page." }, + { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }, + { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, + { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation." }, + { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." }, + { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." }, + { "name": "awaitPromise", "type": "boolean", "optional": true, "description": "Whether execution should await for resulting value and return once awaited promise is resolved." } + ], + "returns": [ + { "name": "result", "$ref": "RemoteObject", "description": "Run result." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "description": "Exception details."} + ], + "description": "Runs script with given id in a given context." + }, + { + "name": "queryObjects", + "parameters": [ + { "name": "prototypeObjectId", "$ref": "RemoteObjectId", "description": "Identifier of the prototype to return objects for." } + ], + "returns": [ + { "name": "objects", "$ref": "RemoteObject", "description": "Array with objects." } + ] + }, + { + "name": "globalLexicalScopeNames", + "parameters": [ + { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to lookup global scope variables." } + ], + "returns": [ + { "name": "names", "type": "array", "items": { "type": "string" } } + ], + "description": "Returns all let, const and class variables from global scope." + } + ], + "events": [ + { + "name": "executionContextCreated", + "parameters": [ + { "name": "context", "$ref": "ExecutionContextDescription", "description": "A newly created execution context." } + ], + "description": "Issued when new execution context is created." + }, + { + "name": "executionContextDestroyed", + "parameters": [ + { "name": "executionContextId", "$ref": "ExecutionContextId", "description": "Id of the destroyed context" } + ], + "description": "Issued when execution context is destroyed." + }, + { + "name": "executionContextsCleared", + "description": "Issued when all executionContexts were cleared in browser" + }, + { + "name": "exceptionThrown", + "description": "Issued when exception was thrown and unhandled.", + "parameters": [ + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp of the exception." }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails" } + ] + }, + { + "name": "exceptionRevoked", + "description": "Issued when unhandled exception was revoked.", + "parameters": [ + { "name": "reason", "type": "string", "description": "Reason describing why exception was revoked." }, + { "name": "exceptionId", "type": "integer", "description": "The id of revoked exception, as reported in exceptionThrown." } + ] + }, + { + "name": "consoleAPICalled", + "description": "Issued when console API was called.", + "parameters": [ + { "name": "type", "type": "string", "enum": ["log", "debug", "info", "error", "warning", "dir", "dirxml", "table", "trace", "clear", "startGroup", "startGroupCollapsed", "endGroup", "assert", "profile", "profileEnd", "count", "timeEnd"], "description": "Type of the call." }, + { "name": "args", "type": "array", "items": { "$ref": "RemoteObject" }, "description": "Call arguments." }, + { "name": "executionContextId", "$ref": "ExecutionContextId", "description": "Identifier of the context where the call was made." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Call timestamp." }, + { "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "Stack trace captured when the call was made." }, + { "name": "context", "type": "string", "optional": true, "experimental": true, "description": "Console context descriptor for calls on non-default console context (not console.*): 'anonymous#unique-logger-id' for call on unnamed context, 'name#unique-logger-id' for call on named context." } + ] + }, + { + "name": "inspectRequested", + "description": "Issued when object should be inspected (for example, as a result of inspect() command line API call).", + "parameters": [ + { "name": "object", "$ref": "RemoteObject" }, + { "name": "hints", "type": "object" } + ] + } + ] + }, + { + "domain": "Debugger", + "description": "Debugger domain exposes JavaScript debugging capabilities. It allows setting and removing breakpoints, stepping through execution, exploring stack traces, etc.", + "dependencies": ["Runtime"], + "types": [ + { + "id": "BreakpointId", + "type": "string", + "description": "Breakpoint identifier." + }, + { + "id": "CallFrameId", + "type": "string", + "description": "Call frame identifier." + }, + { + "id": "Location", + "type": "object", + "properties": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Script identifier as reported in the Debugger.scriptParsed." }, + { "name": "lineNumber", "type": "integer", "description": "Line number in the script (0-based)." }, + { "name": "columnNumber", "type": "integer", "optional": true, "description": "Column number in the script (0-based)." } + ], + "description": "Location in the source code." + }, + { + "id": "ScriptPosition", + "experimental": true, + "type": "object", + "properties": [ + { "name": "lineNumber", "type": "integer" }, + { "name": "columnNumber", "type": "integer" } + ], + "description": "Location in the source code." + }, + { + "id": "CallFrame", + "type": "object", + "properties": [ + { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier. This identifier is only valid while the virtual machine is paused." }, + { "name": "functionName", "type": "string", "description": "Name of the JavaScript function called on this call frame." }, + { "name": "functionLocation", "$ref": "Location", "optional": true, "description": "Location in the source code." }, + { "name": "location", "$ref": "Location", "description": "Location in the source code." }, + { "name": "url", "type": "string", "description": "JavaScript script name or url." }, + { "name": "scopeChain", "type": "array", "items": { "$ref": "Scope" }, "description": "Scope chain for this call frame." }, + { "name": "this", "$ref": "Runtime.RemoteObject", "description": "this object for this call frame." }, + { "name": "returnValue", "$ref": "Runtime.RemoteObject", "optional": true, "description": "The value being returned, if the function is at return point." } + ], + "description": "JavaScript call frame. Array of call frames form the call stack." + }, + { + "id": "Scope", + "type": "object", + "properties": [ + { "name": "type", "type": "string", "enum": ["global", "local", "with", "closure", "catch", "block", "script", "eval", "module"], "description": "Scope type." }, + { "name": "object", "$ref": "Runtime.RemoteObject", "description": "Object representing the scope. For global and with scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties." }, + { "name": "name", "type": "string", "optional": true }, + { "name": "startLocation", "$ref": "Location", "optional": true, "description": "Location in the source code where scope starts" }, + { "name": "endLocation", "$ref": "Location", "optional": true, "description": "Location in the source code where scope ends" } + ], + "description": "Scope description." + }, + { + "id": "SearchMatch", + "type": "object", + "description": "Search match for resource.", + "properties": [ + { "name": "lineNumber", "type": "number", "description": "Line number in resource content." }, + { "name": "lineContent", "type": "string", "description": "Line with match content." } + ] + }, + { + "id": "BreakLocation", + "type": "object", + "properties": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Script identifier as reported in the Debugger.scriptParsed." }, + { "name": "lineNumber", "type": "integer", "description": "Line number in the script (0-based)." }, + { "name": "columnNumber", "type": "integer", "optional": true, "description": "Column number in the script (0-based)." }, + { "name": "type", "type": "string", "enum": [ "debuggerStatement", "call", "return" ], "optional": true } + ] + } + ], + "commands": [ + { + "name": "enable", + "returns": [ + { "name": "debuggerId", "$ref": "Runtime.UniqueDebuggerId", "experimental": true, "description": "Unique identifier of the debugger." } + ], + "description": "Enables debugger for the given page. Clients should not assume that the debugging has been enabled until the result for this command is received." + }, + { + "name": "disable", + "description": "Disables debugger for given page." + }, + { + "name": "setBreakpointsActive", + "parameters": [ + { "name": "active", "type": "boolean", "description": "New value for breakpoints active state." } + ], + "description": "Activates / deactivates all breakpoints on the page." + }, + { + "name": "setSkipAllPauses", + "parameters": [ + { "name": "skip", "type": "boolean", "description": "New value for skip pauses state." } + ], + "description": "Makes page not interrupt on any pauses (breakpoint, exception, dom exception etc)." + }, + { + "name": "setBreakpointByUrl", + "parameters": [ + { "name": "lineNumber", "type": "integer", "description": "Line number to set breakpoint at." }, + { "name": "url", "type": "string", "optional": true, "description": "URL of the resources to set breakpoint on." }, + { "name": "urlRegex", "type": "string", "optional": true, "description": "Regex pattern for the URLs of the resources to set breakpoints on. Either url or urlRegex must be specified." }, + { "name": "scriptHash", "type": "string", "optional": true, "description": "Script hash of the resources to set breakpoint on." }, + { "name": "columnNumber", "type": "integer", "optional": true, "description": "Offset in the line to set breakpoint at." }, + { "name": "condition", "type": "string", "optional": true, "description": "Expression to use as a breakpoint condition. When specified, debugger will only stop on the breakpoint if this expression evaluates to true." } + ], + "returns": [ + { "name": "breakpointId", "$ref": "BreakpointId", "description": "Id of the created breakpoint for further reference." }, + { "name": "locations", "type": "array", "items": { "$ref": "Location" }, "description": "List of the locations this breakpoint resolved into upon addition." } + ], + "description": "Sets JavaScript breakpoint at given location specified either by URL or URL regex. Once this command is issued, all existing parsed scripts will have breakpoints resolved and returned in locations property. Further matching script parsing will result in subsequent breakpointResolved events issued. This logical breakpoint will survive page reloads." + }, + { + "name": "setBreakpoint", + "parameters": [ + { "name": "location", "$ref": "Location", "description": "Location to set breakpoint in." }, + { "name": "condition", "type": "string", "optional": true, "description": "Expression to use as a breakpoint condition. When specified, debugger will only stop on the breakpoint if this expression evaluates to true." } + ], + "returns": [ + { "name": "breakpointId", "$ref": "BreakpointId", "description": "Id of the created breakpoint for further reference." }, + { "name": "actualLocation", "$ref": "Location", "description": "Location this breakpoint resolved into." } + ], + "description": "Sets JavaScript breakpoint at a given location." + }, + { + "name": "removeBreakpoint", + "parameters": [ + { "name": "breakpointId", "$ref": "BreakpointId" } + ], + "description": "Removes JavaScript breakpoint." + }, + { + "name": "getPossibleBreakpoints", + "parameters": [ + { "name": "start", "$ref": "Location", "description": "Start of range to search possible breakpoint locations in." }, + { "name": "end", "$ref": "Location", "optional": true, "description": "End of range to search possible breakpoint locations in (excluding). When not specified, end of scripts is used as end of range." }, + { "name": "restrictToFunction", "type": "boolean", "optional": true, "description": "Only consider locations which are in the same (non-nested) function as start." } + ], + "returns": [ + { "name": "locations", "type": "array", "items": { "$ref": "BreakLocation" }, "description": "List of the possible breakpoint locations." } + ], + "description": "Returns possible locations for breakpoint. scriptId in start and end range locations should be the same." + }, + { + "name": "continueToLocation", + "parameters": [ + { "name": "location", "$ref": "Location", "description": "Location to continue to." }, + { "name": "targetCallFrames", "type": "string", "enum": ["any", "current"], "optional": true } + ], + "description": "Continues execution until specific location is reached." + }, + { + "name": "pauseOnAsyncCall", + "parameters": [ + { "name": "parentStackTraceId", "$ref": "Runtime.StackTraceId", "description": "Debugger will pause when async call with given stack trace is started." } + ], + "experimental": true + }, + { + "name": "stepOver", + "description": "Steps over the statement." + }, + { + "name": "stepInto", + "parameters": [ + { "name": "breakOnAsyncCall", "type": "boolean", "optional": true, "experimental": true, "description": "Debugger will issue additional Debugger.paused notification if any async task is scheduled before next pause." } + ], + "description": "Steps into the function call." + }, + { + "name": "stepOut", + "description": "Steps out of the function call." + }, + { + "name": "pause", + "description": "Stops on the next JavaScript statement." + }, + { + "name": "scheduleStepIntoAsync", + "description": "This method is deprecated - use Debugger.stepInto with breakOnAsyncCall and Debugger.pauseOnAsyncTask instead. Steps into next scheduled async task if any is scheduled before next pause. Returns success when async task is actually scheduled, returns error if no task were scheduled or another scheduleStepIntoAsync was called.", + "experimental": true + }, + { + "name": "resume", + "description": "Resumes JavaScript execution." + }, + { + "name": "getStackTrace", + "parameters": [ + { "name": "stackTraceId", "$ref": "Runtime.StackTraceId" } + ], + "returns": [ + { "name": "stackTrace", "$ref": "Runtime.StackTrace" } + ], + "description": "Returns stack trace with given stackTraceId.", + "experimental": true + }, + { + "name": "searchInContent", + "parameters": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to search in." }, + { "name": "query", "type": "string", "description": "String to search for." }, + { "name": "caseSensitive", "type": "boolean", "optional": true, "description": "If true, search is case sensitive." }, + { "name": "isRegex", "type": "boolean", "optional": true, "description": "If true, treats string parameter as regex." } + ], + "returns": [ + { "name": "result", "type": "array", "items": { "$ref": "SearchMatch" }, "description": "List of search matches." } + ], + "description": "Searches for given string in script content." + }, + { + "name": "setScriptSource", + "parameters": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to edit." }, + { "name": "scriptSource", "type": "string", "description": "New content of the script." }, + { "name": "dryRun", "type": "boolean", "optional": true, "description": " If true the change will not actually be applied. Dry run may be used to get result description without actually modifying the code." } + ], + "returns": [ + { "name": "callFrames", "type": "array", "optional": true, "items": { "$ref": "CallFrame" }, "description": "New stack trace in case editing has happened while VM was stopped." }, + { "name": "stackChanged", "type": "boolean", "optional": true, "description": "Whether current call stack was modified after applying the changes." }, + { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." }, + { "name": "asyncStackTraceId", "$ref": "Runtime.StackTraceId", "optional": true, "experimental": true, "description": "Async stack trace, if any." }, + { "name": "exceptionDetails", "optional": true, "$ref": "Runtime.ExceptionDetails", "description": "Exception details if any." } + ], + "description": "Edits JavaScript source live." + }, + { + "name": "restartFrame", + "parameters": [ + { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier to evaluate on." } + ], + "returns": [ + { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "New stack trace." }, + { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." }, + { "name": "asyncStackTraceId", "$ref": "Runtime.StackTraceId", "optional": true, "experimental": true, "description": "Async stack trace, if any." } + ], + "description": "Restarts particular call frame from the beginning." + }, + { + "name": "getScriptSource", + "parameters": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to get source for." } + ], + "returns": [ + { "name": "scriptSource", "type": "string", "description": "Script source." } + ], + "description": "Returns source for the script with given id." + }, + { + "name": "setPauseOnExceptions", + "parameters": [ + { "name": "state", "type": "string", "enum": ["none", "uncaught", "all"], "description": "Pause on exceptions mode." } + ], + "description": "Defines pause on exceptions state. Can be set to stop on all exceptions, uncaught exceptions or no exceptions. Initial pause on exceptions state is none." + }, + { + "name": "evaluateOnCallFrame", + "parameters": [ + { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier to evaluate on." }, + { "name": "expression", "type": "string", "description": "Expression to evaluate." }, + { "name": "objectGroup", "type": "string", "optional": true, "description": "String object group name to put result into (allows rapid releasing resulting object handles using releaseObjectGroup)." }, + { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Specifies whether command line API should be available to the evaluated expression, defaults to false." }, + { "name": "silent", "type": "boolean", "optional": true, "description": "In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state." }, + { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, + { "name": "throwOnSideEffect", "type": "boolean", "optional": true, "description": "Whether to throw an exception if side effect cannot be ruled out during evaluation." } + ], + "returns": [ + { "name": "result", "$ref": "Runtime.RemoteObject", "description": "Object wrapper for the evaluation result." }, + { "name": "exceptionDetails", "$ref": "Runtime.ExceptionDetails", "optional": true, "description": "Exception details."} + ], + "description": "Evaluates expression on a given call frame." + }, + { + "name": "setVariableValue", + "parameters": [ + { "name": "scopeNumber", "type": "integer", "description": "0-based number of scope as was listed in scope chain. Only 'local', 'closure' and 'catch' scope types are allowed. Other scopes could be manipulated manually." }, + { "name": "variableName", "type": "string", "description": "Variable name." }, + { "name": "newValue", "$ref": "Runtime.CallArgument", "description": "New variable value." }, + { "name": "callFrameId", "$ref": "CallFrameId", "description": "Id of callframe that holds variable." } + ], + "description": "Changes value of variable in a callframe. Object-based scopes are not supported and must be mutated manually." + }, + { + "name": "setReturnValue", + "parameters": [ + { "name": "newValue", "$ref": "Runtime.CallArgument", "description": "New return value." } + ], + "experimental": true, + "description": "Changes return value in top frame. Available only at return break position." + }, + { + "name": "setAsyncCallStackDepth", + "parameters": [ + { "name": "maxDepth", "type": "integer", "description": "Maximum depth of async call stacks. Setting to 0 will effectively disable collecting async call stacks (default)." } + ], + "description": "Enables or disables async call stacks tracking." + }, + { + "name": "setBlackboxPatterns", + "parameters": [ + { "name": "patterns", "type": "array", "items": { "type": "string" }, "description": "Array of regexps that will be used to check script url for blackbox state." } + ], + "experimental": true, + "description": "Replace previous blackbox patterns with passed ones. Forces backend to skip stepping/pausing in scripts with url matching one of the patterns. VM will try to leave blackboxed script by performing 'step in' several times, finally resorting to 'step out' if unsuccessful." + }, + { + "name": "setBlackboxedRanges", + "parameters": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script." }, + { "name": "positions", "type": "array", "items": { "$ref": "ScriptPosition" } } + ], + "experimental": true, + "description": "Makes backend skip steps in the script in blackboxed ranges. VM will try leave blacklisted scripts by performing 'step in' several times, finally resorting to 'step out' if unsuccessful. Positions array contains positions where blackbox state is changed. First interval isn't blackboxed. Array should be sorted." + } + ], + "events": [ + { + "name": "scriptParsed", + "parameters": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Identifier of the script parsed." }, + { "name": "url", "type": "string", "description": "URL or name of the script parsed (if any)." }, + { "name": "startLine", "type": "integer", "description": "Line offset of the script within the resource with given URL (for script tags)." }, + { "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." }, + { "name": "endLine", "type": "integer", "description": "Last line of the script." }, + { "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." }, + { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context." }, + { "name": "hash", "type": "string", "description": "Content hash of the script."}, + { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." }, + { "name": "isLiveEdit", "type": "boolean", "optional": true, "description": "True, if this script is generated as a result of the live edit operation.", "experimental": true }, + { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." }, + { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL." }, + { "name": "isModule", "type": "boolean", "optional": true, "description": "True, if this script is ES6 module." }, + { "name": "length", "type": "integer", "optional": true, "description": "This script length." }, + { "name": "stackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "JavaScript top stack frame of where the script parsed event was triggered if available.", "experimental": true } + ], + "description": "Fired when virtual machine parses script. This event is also fired for all known and uncollected scripts upon enabling debugger." + }, + { + "name": "scriptFailedToParse", + "parameters": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Identifier of the script parsed." }, + { "name": "url", "type": "string", "description": "URL or name of the script parsed (if any)." }, + { "name": "startLine", "type": "integer", "description": "Line offset of the script within the resource with given URL (for script tags)." }, + { "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." }, + { "name": "endLine", "type": "integer", "description": "Last line of the script." }, + { "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." }, + { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context." }, + { "name": "hash", "type": "string", "description": "Content hash of the script."}, + { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data." }, + { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." }, + { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL." }, + { "name": "isModule", "type": "boolean", "optional": true, "description": "True, if this script is ES6 module." }, + { "name": "length", "type": "integer", "optional": true, "description": "This script length." }, + { "name": "stackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "JavaScript top stack frame of where the script parsed event was triggered if available.", "experimental": true } + ], + "description": "Fired when virtual machine fails to parse the script." + }, + { + "name": "breakpointResolved", + "parameters": [ + { "name": "breakpointId", "$ref": "BreakpointId", "description": "Breakpoint unique identifier." }, + { "name": "location", "$ref": "Location", "description": "Actual breakpoint location." } + ], + "description": "Fired when breakpoint is resolved to an actual script and location." + }, + { + "name": "paused", + "parameters": [ + { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." }, + { "name": "reason", "type": "string", "enum": [ "XHR", "DOM", "EventListener", "exception", "assert", "debugCommand", "promiseRejection", "OOM", "other", "ambiguous" ], "description": "Pause reason." }, + { "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." }, + { "name": "hitBreakpoints", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Hit breakpoints IDs" }, + { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." }, + { "name": "asyncStackTraceId", "$ref": "Runtime.StackTraceId", "optional": true, "experimental": true, "description": "Async stack trace, if any." }, + { "name": "asyncCallStackTraceId", "$ref": "Runtime.StackTraceId", "optional": true, "experimental": true, "description": "Just scheduled async call will have this stack trace as parent stack during async execution. This field is available only after Debugger.stepInto call with breakOnAsynCall flag." } + ], + "description": "Fired when the virtual machine stopped on breakpoint or exception or any other stop criteria." + }, + { + "name": "resumed", + "description": "Fired when the virtual machine resumed execution." + } + ] + }, + { + "domain": "Console", + "description": "This domain is deprecated - use Runtime or Log instead.", + "dependencies": ["Runtime"], + "deprecated": true, + "types": [ + { + "id": "ConsoleMessage", + "type": "object", + "description": "Console message.", + "properties": [ + { "name": "source", "type": "string", "enum": ["xml", "javascript", "network", "console-api", "storage", "appcache", "rendering", "security", "other", "deprecation", "worker"], "description": "Message source." }, + { "name": "level", "type": "string", "enum": ["log", "warning", "error", "debug", "info"], "description": "Message severity." }, + { "name": "text", "type": "string", "description": "Message text." }, + { "name": "url", "type": "string", "optional": true, "description": "URL of the message origin." }, + { "name": "line", "type": "integer", "optional": true, "description": "Line number in the resource that generated this message (1-based)." }, + { "name": "column", "type": "integer", "optional": true, "description": "Column number in the resource that generated this message (1-based)." } + ] + } + ], + "commands": [ + { + "name": "enable", + "description": "Enables console domain, sends the messages collected so far to the client by means of the messageAdded notification." + }, + { + "name": "disable", + "description": "Disables console domain, prevents further console messages from being reported to the client." + }, + { + "name": "clearMessages", + "description": "Does nothing." + } + ], + "events": [ + { + "name": "messageAdded", + "parameters": [ + { "name": "message", "$ref": "ConsoleMessage", "description": "Console message that has been added." } + ], + "description": "Issued when new console message is added." + } + ] + }, + { + "domain": "Profiler", + "dependencies": ["Runtime", "Debugger"], + "types": [ + { + "id": "ProfileNode", + "type": "object", + "description": "Profile node. Holds callsite information, execution statistics and child nodes.", + "properties": [ + { "name": "id", "type": "integer", "description": "Unique id of the node." }, + { "name": "callFrame", "$ref": "Runtime.CallFrame", "description": "Function location." }, + { "name": "hitCount", "type": "integer", "optional": true, "description": "Number of samples where this node was on top of the call stack." }, + { "name": "children", "type": "array", "items": { "type": "integer" }, "optional": true, "description": "Child node ids." }, + { "name": "deoptReason", "type": "string", "optional": true, "description": "The reason of being not optimized. The function may be deoptimized or marked as don't optimize."}, + { "name": "positionTicks", "type": "array", "items": { "$ref": "PositionTickInfo" }, "optional": true, "description": "An array of source position ticks." } + ] + }, + { + "id": "Profile", + "type": "object", + "description": "Profile.", + "properties": [ + { "name": "nodes", "type": "array", "items": { "$ref": "ProfileNode" }, "description": "The list of profile nodes. First item is the root node." }, + { "name": "startTime", "type": "number", "description": "Profiling start timestamp in microseconds." }, + { "name": "endTime", "type": "number", "description": "Profiling end timestamp in microseconds." }, + { "name": "samples", "optional": true, "type": "array", "items": { "type": "integer" }, "description": "Ids of samples top nodes." }, + { "name": "timeDeltas", "optional": true, "type": "array", "items": { "type": "integer" }, "description": "Time intervals between adjacent samples in microseconds. The first delta is relative to the profile startTime." } + ] + }, + { + "id": "PositionTickInfo", + "type": "object", + "description": "Specifies a number of samples attributed to a certain source position.", + "properties": [ + { "name": "line", "type": "integer", "description": "Source line number (1-based)." }, + { "name": "ticks", "type": "integer", "description": "Number of samples attributed to the source line." } + ] + }, + { "id": "CoverageRange", + "type": "object", + "description": "Coverage data for a source range.", + "properties": [ + { "name": "startOffset", "type": "integer", "description": "JavaScript script source offset for the range start." }, + { "name": "endOffset", "type": "integer", "description": "JavaScript script source offset for the range end." }, + { "name": "count", "type": "integer", "description": "Collected execution count of the source range." } + ] + }, + { "id": "FunctionCoverage", + "type": "object", + "description": "Coverage data for a JavaScript function.", + "properties": [ + { "name": "functionName", "type": "string", "description": "JavaScript function name." }, + { "name": "ranges", "type": "array", "items": { "$ref": "CoverageRange" }, "description": "Source ranges inside the function with coverage data." }, + { "name": "isBlockCoverage", "type": "boolean", "description": "Whether coverage data for this function has block granularity." } + ] + }, + { + "id": "ScriptCoverage", + "type": "object", + "description": "Coverage data for a JavaScript script.", + "properties": [ + { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "JavaScript script id." }, + { "name": "url", "type": "string", "description": "JavaScript script name or url." }, + { "name": "functions", "type": "array", "items": { "$ref": "FunctionCoverage" }, "description": "Functions contained in the script that has coverage data." } + ] + } + ], + "commands": [ + { + "name": "enable" + }, + { + "name": "disable" + }, + { + "name": "setSamplingInterval", + "parameters": [ + { "name": "interval", "type": "integer", "description": "New sampling interval in microseconds." } + ], + "description": "Changes CPU profiler sampling interval. Must be called before CPU profiles recording started." + }, + { + "name": "start" + }, + { + "name": "stop", + "returns": [ + { "name": "profile", "$ref": "Profile", "description": "Recorded profile." } + ] + }, + { + "name": "startPreciseCoverage", + "parameters": [ + { "name": "callCount", "type": "boolean", "optional": true, "description": "Collect accurate call counts beyond simple 'covered' or 'not covered'." }, + { "name": "detailed", "type": "boolean", "optional": true, "description": "Collect block-based coverage." } + ], + "description": "Enable precise code coverage. Coverage data for JavaScript executed before enabling precise code coverage may be incomplete. Enabling prevents running optimized code and resets execution counters." + }, + { + "name": "stopPreciseCoverage", + "description": "Disable precise code coverage. Disabling releases unnecessary execution count records and allows executing optimized code." + }, + { + "name": "takePreciseCoverage", + "returns": [ + { "name": "result", "type": "array", "items": { "$ref": "ScriptCoverage" }, "description": "Coverage data for the current isolate." } + ], + "description": "Collect coverage data for the current isolate, and resets execution counters. Precise code coverage needs to have started." + }, + { + "name": "getBestEffortCoverage", + "returns": [ + { "name": "result", "type": "array", "items": { "$ref": "ScriptCoverage" }, "description": "Coverage data for the current isolate." } + ], + "description": "Collect coverage data for the current isolate. The coverage data may be incomplete due to garbage collection." + } + ], + "events": [ + { + "name": "consoleProfileStarted", + "parameters": [ + { "name": "id", "type": "string" }, + { "name": "location", "$ref": "Debugger.Location", "description": "Location of console.profile()." }, + { "name": "title", "type": "string", "optional": true, "description": "Profile title passed as an argument to console.profile()." } + ], + "description": "Sent when new profile recording is started using console.profile() call." + }, + { + "name": "consoleProfileFinished", + "parameters": [ + { "name": "id", "type": "string" }, + { "name": "location", "$ref": "Debugger.Location", "description": "Location of console.profileEnd()." }, + { "name": "profile", "$ref": "Profile" }, + { "name": "title", "type": "string", "optional": true, "description": "Profile title passed as an argument to console.profile()." } + ] + } + ] + }, + { + "domain": "HeapProfiler", + "dependencies": ["Runtime"], + "experimental": true, + "types": [ + { + "id": "HeapSnapshotObjectId", + "type": "string", + "description": "Heap snapshot object id." + }, + { + "id": "SamplingHeapProfileNode", + "type": "object", + "description": "Sampling Heap Profile node. Holds callsite information, allocation statistics and child nodes.", + "properties": [ + { "name": "callFrame", "$ref": "Runtime.CallFrame", "description": "Function location." }, + { "name": "selfSize", "type": "number", "description": "Allocations size in bytes for the node excluding children." }, + { "name": "children", "type": "array", "items": { "$ref": "SamplingHeapProfileNode" }, "description": "Child nodes." } + ] + }, + { + "id": "SamplingHeapProfile", + "type": "object", + "description": "Profile.", + "properties": [ + { "name": "head", "$ref": "SamplingHeapProfileNode" } + ] + } + ], + "commands": [ + { + "name": "enable" + }, + { + "name": "disable" + }, + { + "name": "startTrackingHeapObjects", + "parameters": [ + { "name": "trackAllocations", "type": "boolean", "optional": true } + ] + }, + { + "name": "stopTrackingHeapObjects", + "parameters": [ + { "name": "reportProgress", "type": "boolean", "optional": true, "description": "If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken when the tracking is stopped." } + ] + }, + { + "name": "takeHeapSnapshot", + "parameters": [ + { "name": "reportProgress", "type": "boolean", "optional": true, "description": "If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken." } + ] + }, + { + "name": "collectGarbage" + }, + { + "name": "getObjectByHeapObjectId", + "parameters": [ + { "name": "objectId", "$ref": "HeapSnapshotObjectId" }, + { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." } + ], + "returns": [ + { "name": "result", "$ref": "Runtime.RemoteObject", "description": "Evaluation result." } + ] + }, + { + "name": "addInspectedHeapObject", + "parameters": [ + { "name": "heapObjectId", "$ref": "HeapSnapshotObjectId", "description": "Heap snapshot object id to be accessible by means of $x command line API." } + ], + "description": "Enables console to refer to the node with given id via $x (see Command Line API for more details $x functions)." + }, + { + "name": "getHeapObjectId", + "parameters": [ + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "Identifier of the object to get heap object id for." } + ], + "returns": [ + { "name": "heapSnapshotObjectId", "$ref": "HeapSnapshotObjectId", "description": "Id of the heap snapshot object corresponding to the passed remote object id." } + ] + }, + { + "name": "startSampling", + "parameters": [ + { "name": "samplingInterval", "type": "number", "optional": true, "description": "Average sample interval in bytes. Poisson distribution is used for the intervals. The default value is 32768 bytes." } + ] + }, + { + "name": "stopSampling", + "returns": [ + { "name": "profile", "$ref": "SamplingHeapProfile", "description": "Recorded sampling heap profile." } + ] + }, + { + "name": "getSamplingProfile", + "returns": [ + { "name": "profile", "$ref": "SamplingHeapProfile", "description": "Return the sampling profile being collected." } + ] + } + ], + "events": [ + { + "name": "addHeapSnapshotChunk", + "parameters": [ + { "name": "chunk", "type": "string" } + ] + }, + { + "name": "resetProfiles" + }, + { + "name": "reportHeapSnapshotProgress", + "parameters": [ + { "name": "done", "type": "integer" }, + { "name": "total", "type": "integer" }, + { "name": "finished", "type": "boolean", "optional": true } + ] + }, + { + "name": "lastSeenObjectId", + "description": "If heap objects tracking has been started then backend regularly sends a current value for last seen object id and corresponding timestamp. If the were changes in the heap since last event then one or more heapStatsUpdate events will be sent before a new lastSeenObjectId event.", + "parameters": [ + { "name": "lastSeenObjectId", "type": "integer" }, + { "name": "timestamp", "type": "number" } + ] + }, + { + "name": "heapStatsUpdate", + "description": "If heap objects tracking has been started then backend may send update for one or more fragments", + "parameters": [ + { "name": "statsUpdate", "type": "array", "items": { "type": "integer" }, "description": "An array of triplets. Each triplet describes a fragment. The first integer is the fragment index, the second integer is a total count of objects for the fragment, the third integer is a total size of the objects for the fragment."} + ] + } + ] + }] +} diff --git a/NativeScript/napi/v8/include_old/js_protocol.pdl b/NativeScript/napi/v8/include_old/js_protocol.pdl new file mode 100644 index 00000000..4754f17c --- /dev/null +++ b/NativeScript/napi/v8/include_old/js_protocol.pdl @@ -0,0 +1,1806 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +version + major 1 + minor 3 + +# This domain is deprecated - use Runtime or Log instead. +deprecated domain Console + depends on Runtime + + # Console message. + type ConsoleMessage extends object + properties + # Message source. + enum source + xml + javascript + network + console-api + storage + appcache + rendering + security + other + deprecation + worker + # Message severity. + enum level + log + warning + error + debug + info + # Message text. + string text + # URL of the message origin. + optional string url + # Line number in the resource that generated this message (1-based). + optional integer line + # Column number in the resource that generated this message (1-based). + optional integer column + + # Does nothing. + command clearMessages + + # Disables console domain, prevents further console messages from being reported to the client. + command disable + + # Enables console domain, sends the messages collected so far to the client by means of the + # `messageAdded` notification. + command enable + + # Issued when new console message is added. + event messageAdded + parameters + # Console message that has been added. + ConsoleMessage message + +# Debugger domain exposes JavaScript debugging capabilities. It allows setting and removing +# breakpoints, stepping through execution, exploring stack traces, etc. +domain Debugger + depends on Runtime + + # Breakpoint identifier. + type BreakpointId extends string + + # Call frame identifier. + type CallFrameId extends string + + # Location in the source code. + type Location extends object + properties + # Script identifier as reported in the `Debugger.scriptParsed`. + Runtime.ScriptId scriptId + # Line number in the script (0-based). + integer lineNumber + # Column number in the script (0-based). + optional integer columnNumber + + # Location in the source code. + experimental type ScriptPosition extends object + properties + integer lineNumber + integer columnNumber + + # Location range within one script. + experimental type LocationRange extends object + properties + Runtime.ScriptId scriptId + ScriptPosition start + ScriptPosition end + + # JavaScript call frame. Array of call frames form the call stack. + type CallFrame extends object + properties + # Call frame identifier. This identifier is only valid while the virtual machine is paused. + CallFrameId callFrameId + # Name of the JavaScript function called on this call frame. + string functionName + # Location in the source code. + optional Location functionLocation + # Location in the source code. + Location location + # JavaScript script name or url. + # Deprecated in favor of using the `location.scriptId` to resolve the URL via a previously + # sent `Debugger.scriptParsed` event. + deprecated string url + # Scope chain for this call frame. + array of Scope scopeChain + # `this` object for this call frame. + Runtime.RemoteObject this + # The value being returned, if the function is at return point. + optional Runtime.RemoteObject returnValue + # Valid only while the VM is paused and indicates whether this frame + # can be restarted or not. Note that a `true` value here does not + # guarantee that Debugger#restartFrame with this CallFrameId will be + # successful, but it is very likely. + experimental optional boolean canBeRestarted + + # Scope description. + type Scope extends object + properties + # Scope type. + enum type + global + local + with + closure + catch + block + script + eval + module + wasm-expression-stack + # Object representing the scope. For `global` and `with` scopes it represents the actual + # object; for the rest of the scopes, it is artificial transient object enumerating scope + # variables as its properties. + Runtime.RemoteObject object + optional string name + # Location in the source code where scope starts + optional Location startLocation + # Location in the source code where scope ends + optional Location endLocation + + # Search match for resource. + type SearchMatch extends object + properties + # Line number in resource content. + number lineNumber + # Line with match content. + string lineContent + + type BreakLocation extends object + properties + # Script identifier as reported in the `Debugger.scriptParsed`. + Runtime.ScriptId scriptId + # Line number in the script (0-based). + integer lineNumber + # Column number in the script (0-based). + optional integer columnNumber + optional enum type + debuggerStatement + call + return + + # Continues execution until specific location is reached. + command continueToLocation + parameters + # Location to continue to. + Location location + optional enum targetCallFrames + any + current + + # Disables debugger for given page. + command disable + + # Enables debugger for the given page. Clients should not assume that the debugging has been + # enabled until the result for this command is received. + command enable + parameters + # The maximum size in bytes of collected scripts (not referenced by other heap objects) + # the debugger can hold. Puts no limit if parameter is omitted. + experimental optional number maxScriptsCacheSize + returns + # Unique identifier of the debugger. + experimental Runtime.UniqueDebuggerId debuggerId + + # Evaluates expression on a given call frame. + command evaluateOnCallFrame + parameters + # Call frame identifier to evaluate on. + CallFrameId callFrameId + # Expression to evaluate. + string expression + # String object group name to put result into (allows rapid releasing resulting object handles + # using `releaseObjectGroup`). + optional string objectGroup + # Specifies whether command line API should be available to the evaluated expression, defaults + # to false. + optional boolean includeCommandLineAPI + # In silent mode exceptions thrown during evaluation are not reported and do not pause + # execution. Overrides `setPauseOnException` state. + optional boolean silent + # Whether the result is expected to be a JSON object that should be sent by value. + optional boolean returnByValue + # Whether preview should be generated for the result. + experimental optional boolean generatePreview + # Whether to throw an exception if side effect cannot be ruled out during evaluation. + optional boolean throwOnSideEffect + # Terminate execution after timing out (number of milliseconds). + experimental optional Runtime.TimeDelta timeout + returns + # Object wrapper for the evaluation result. + Runtime.RemoteObject result + # Exception details. + optional Runtime.ExceptionDetails exceptionDetails + + # Returns possible locations for breakpoint. scriptId in start and end range locations should be + # the same. + command getPossibleBreakpoints + parameters + # Start of range to search possible breakpoint locations in. + Location start + # End of range to search possible breakpoint locations in (excluding). When not specified, end + # of scripts is used as end of range. + optional Location end + # Only consider locations which are in the same (non-nested) function as start. + optional boolean restrictToFunction + returns + # List of the possible breakpoint locations. + array of BreakLocation locations + + # Returns source for the script with given id. + command getScriptSource + parameters + # Id of the script to get source for. + Runtime.ScriptId scriptId + returns + # Script source (empty in case of Wasm bytecode). + string scriptSource + # Wasm bytecode. + optional binary bytecode + + experimental type WasmDisassemblyChunk extends object + properties + # The next chunk of disassembled lines. + array of string lines + # The bytecode offsets describing the start of each line. + array of integer bytecodeOffsets + + experimental command disassembleWasmModule + parameters + # Id of the script to disassemble + Runtime.ScriptId scriptId + returns + # For large modules, return a stream from which additional chunks of + # disassembly can be read successively. + optional string streamId + # The total number of lines in the disassembly text. + integer totalNumberOfLines + # The offsets of all function bodies, in the format [start1, end1, + # start2, end2, ...] where all ends are exclusive. + array of integer functionBodyOffsets + # The first chunk of disassembly. + WasmDisassemblyChunk chunk + + # Disassemble the next chunk of lines for the module corresponding to the + # stream. If disassembly is complete, this API will invalidate the streamId + # and return an empty chunk. Any subsequent calls for the now invalid stream + # will return errors. + experimental command nextWasmDisassemblyChunk + parameters + string streamId + returns + # The next chunk of disassembly. + WasmDisassemblyChunk chunk + + # This command is deprecated. Use getScriptSource instead. + deprecated command getWasmBytecode + parameters + # Id of the Wasm script to get source for. + Runtime.ScriptId scriptId + returns + # Script source. + binary bytecode + + # Returns stack trace with given `stackTraceId`. + experimental command getStackTrace + parameters + Runtime.StackTraceId stackTraceId + returns + Runtime.StackTrace stackTrace + + # Stops on the next JavaScript statement. + command pause + + experimental deprecated command pauseOnAsyncCall + parameters + # Debugger will pause when async call with given stack trace is started. + Runtime.StackTraceId parentStackTraceId + + # Removes JavaScript breakpoint. + command removeBreakpoint + parameters + BreakpointId breakpointId + + # Restarts particular call frame from the beginning. The old, deprecated + # behavior of `restartFrame` is to stay paused and allow further CDP commands + # after a restart was scheduled. This can cause problems with restarting, so + # we now continue execution immediatly after it has been scheduled until we + # reach the beginning of the restarted frame. + # + # To stay back-wards compatible, `restartFrame` now expects a `mode` + # parameter to be present. If the `mode` parameter is missing, `restartFrame` + # errors out. + # + # The various return values are deprecated and `callFrames` is always empty. + # Use the call frames from the `Debugger#paused` events instead, that fires + # once V8 pauses at the beginning of the restarted function. + command restartFrame + parameters + # Call frame identifier to evaluate on. + CallFrameId callFrameId + # The `mode` parameter must be present and set to 'StepInto', otherwise + # `restartFrame` will error out. + experimental optional enum mode + # Pause at the beginning of the restarted function + StepInto + returns + # New stack trace. + deprecated array of CallFrame callFrames + # Async stack trace, if any. + deprecated optional Runtime.StackTrace asyncStackTrace + # Async stack trace, if any. + deprecated optional Runtime.StackTraceId asyncStackTraceId + + # Resumes JavaScript execution. + command resume + parameters + # Set to true to terminate execution upon resuming execution. In contrast + # to Runtime.terminateExecution, this will allows to execute further + # JavaScript (i.e. via evaluation) until execution of the paused code + # is actually resumed, at which point termination is triggered. + # If execution is currently not paused, this parameter has no effect. + optional boolean terminateOnResume + + # Searches for given string in script content. + command searchInContent + parameters + # Id of the script to search in. + Runtime.ScriptId scriptId + # String to search for. + string query + # If true, search is case sensitive. + optional boolean caseSensitive + # If true, treats string parameter as regex. + optional boolean isRegex + returns + # List of search matches. + array of SearchMatch result + + # Enables or disables async call stacks tracking. + command setAsyncCallStackDepth + parameters + # Maximum depth of async call stacks. Setting to `0` will effectively disable collecting async + # call stacks (default). + integer maxDepth + + # Replace previous blackbox patterns with passed ones. Forces backend to skip stepping/pausing in + # scripts with url matching one of the patterns. VM will try to leave blackboxed script by + # performing 'step in' several times, finally resorting to 'step out' if unsuccessful. + experimental command setBlackboxPatterns + parameters + # Array of regexps that will be used to check script url for blackbox state. + array of string patterns + + # Makes backend skip steps in the script in blackboxed ranges. VM will try leave blacklisted + # scripts by performing 'step in' several times, finally resorting to 'step out' if unsuccessful. + # Positions array contains positions where blackbox state is changed. First interval isn't + # blackboxed. Array should be sorted. + experimental command setBlackboxedRanges + parameters + # Id of the script. + Runtime.ScriptId scriptId + array of ScriptPosition positions + + # Sets JavaScript breakpoint at a given location. + command setBreakpoint + parameters + # Location to set breakpoint in. + Location location + # Expression to use as a breakpoint condition. When specified, debugger will only stop on the + # breakpoint if this expression evaluates to true. + optional string condition + returns + # Id of the created breakpoint for further reference. + BreakpointId breakpointId + # Location this breakpoint resolved into. + Location actualLocation + + # Sets instrumentation breakpoint. + command setInstrumentationBreakpoint + parameters + # Instrumentation name. + enum instrumentation + beforeScriptExecution + beforeScriptWithSourceMapExecution + returns + # Id of the created breakpoint for further reference. + BreakpointId breakpointId + + # Sets JavaScript breakpoint at given location specified either by URL or URL regex. Once this + # command is issued, all existing parsed scripts will have breakpoints resolved and returned in + # `locations` property. Further matching script parsing will result in subsequent + # `breakpointResolved` events issued. This logical breakpoint will survive page reloads. + command setBreakpointByUrl + parameters + # Line number to set breakpoint at. + integer lineNumber + # URL of the resources to set breakpoint on. + optional string url + # Regex pattern for the URLs of the resources to set breakpoints on. Either `url` or + # `urlRegex` must be specified. + optional string urlRegex + # Script hash of the resources to set breakpoint on. + optional string scriptHash + # Offset in the line to set breakpoint at. + optional integer columnNumber + # Expression to use as a breakpoint condition. When specified, debugger will only stop on the + # breakpoint if this expression evaluates to true. + optional string condition + returns + # Id of the created breakpoint for further reference. + BreakpointId breakpointId + # List of the locations this breakpoint resolved into upon addition. + array of Location locations + + # Sets JavaScript breakpoint before each call to the given function. + # If another function was created from the same source as a given one, + # calling it will also trigger the breakpoint. + experimental command setBreakpointOnFunctionCall + parameters + # Function object id. + Runtime.RemoteObjectId objectId + # Expression to use as a breakpoint condition. When specified, debugger will + # stop on the breakpoint if this expression evaluates to true. + optional string condition + returns + # Id of the created breakpoint for further reference. + BreakpointId breakpointId + + # Activates / deactivates all breakpoints on the page. + command setBreakpointsActive + parameters + # New value for breakpoints active state. + boolean active + + # Defines pause on exceptions state. Can be set to stop on all exceptions, uncaught exceptions, + # or caught exceptions, no exceptions. Initial pause on exceptions state is `none`. + command setPauseOnExceptions + parameters + # Pause on exceptions mode. + enum state + none + caught + uncaught + all + + # Changes return value in top frame. Available only at return break position. + experimental command setReturnValue + parameters + # New return value. + Runtime.CallArgument newValue + + # Edits JavaScript source live. + # + # In general, functions that are currently on the stack can not be edited with + # a single exception: If the edited function is the top-most stack frame and + # that is the only activation of that function on the stack. In this case + # the live edit will be successful and a `Debugger.restartFrame` for the + # top-most function is automatically triggered. + command setScriptSource + parameters + # Id of the script to edit. + Runtime.ScriptId scriptId + # New content of the script. + string scriptSource + # If true the change will not actually be applied. Dry run may be used to get result + # description without actually modifying the code. + optional boolean dryRun + # If true, then `scriptSource` is allowed to change the function on top of the stack + # as long as the top-most stack frame is the only activation of that function. + experimental optional boolean allowTopFrameEditing + returns + # New stack trace in case editing has happened while VM was stopped. + deprecated optional array of CallFrame callFrames + # Whether current call stack was modified after applying the changes. + deprecated optional boolean stackChanged + # Async stack trace, if any. + deprecated optional Runtime.StackTrace asyncStackTrace + # Async stack trace, if any. + deprecated optional Runtime.StackTraceId asyncStackTraceId + # Whether the operation was successful or not. Only `Ok` denotes a + # successful live edit while the other enum variants denote why + # the live edit failed. + experimental enum status + Ok + CompileError + BlockedByActiveGenerator + BlockedByActiveFunction + BlockedByTopLevelEsModuleChange + # Exception details if any. Only present when `status` is `CompileError`. + optional Runtime.ExceptionDetails exceptionDetails + + # Makes page not interrupt on any pauses (breakpoint, exception, dom exception etc). + command setSkipAllPauses + parameters + # New value for skip pauses state. + boolean skip + + # Changes value of variable in a callframe. Object-based scopes are not supported and must be + # mutated manually. + command setVariableValue + parameters + # 0-based number of scope as was listed in scope chain. Only 'local', 'closure' and 'catch' + # scope types are allowed. Other scopes could be manipulated manually. + integer scopeNumber + # Variable name. + string variableName + # New variable value. + Runtime.CallArgument newValue + # Id of callframe that holds variable. + CallFrameId callFrameId + + # Steps into the function call. + command stepInto + parameters + # Debugger will pause on the execution of the first async task which was scheduled + # before next pause. + experimental optional boolean breakOnAsyncCall + # The skipList specifies location ranges that should be skipped on step into. + experimental optional array of LocationRange skipList + + # Steps out of the function call. + command stepOut + + # Steps over the statement. + command stepOver + parameters + # The skipList specifies location ranges that should be skipped on step over. + experimental optional array of LocationRange skipList + + # Fired when breakpoint is resolved to an actual script and location. + event breakpointResolved + parameters + # Breakpoint unique identifier. + BreakpointId breakpointId + # Actual breakpoint location. + Location location + + # Fired when the virtual machine stopped on breakpoint or exception or any other stop criteria. + event paused + parameters + # Call stack the virtual machine stopped on. + array of CallFrame callFrames + # Pause reason. + enum reason + ambiguous + assert + CSPViolation + debugCommand + DOM + EventListener + exception + instrumentation + OOM + other + promiseRejection + XHR + step + # Object containing break-specific auxiliary properties. + optional object data + # Hit breakpoints IDs + optional array of string hitBreakpoints + # Async stack trace, if any. + optional Runtime.StackTrace asyncStackTrace + # Async stack trace, if any. + experimental optional Runtime.StackTraceId asyncStackTraceId + # Never present, will be removed. + experimental deprecated optional Runtime.StackTraceId asyncCallStackTraceId + + # Fired when the virtual machine resumed execution. + event resumed + + # Enum of possible script languages. + type ScriptLanguage extends string + enum + JavaScript + WebAssembly + + # Debug symbols available for a wasm script. + type DebugSymbols extends object + properties + # Type of the debug symbols. + enum type + None + SourceMap + EmbeddedDWARF + ExternalDWARF + # URL of the external symbol source. + optional string externalURL + + # Fired when virtual machine fails to parse the script. + event scriptFailedToParse + parameters + # Identifier of the script parsed. + Runtime.ScriptId scriptId + # URL or name of the script parsed (if any). + string url + # Line offset of the script within the resource with given URL (for script tags). + integer startLine + # Column offset of the script within the resource with given URL. + integer startColumn + # Last line of the script. + integer endLine + # Length of the last line of the script. + integer endColumn + # Specifies script creation context. + Runtime.ExecutionContextId executionContextId + # Content hash of the script, SHA-256. + string hash + # Embedder-specific auxiliary data likely matching {isDefault: boolean, type: 'default'|'isolated'|'worker', frameId: string} + optional object executionContextAuxData + # URL of source map associated with script (if any). + optional string sourceMapURL + # True, if this script has sourceURL. + optional boolean hasSourceURL + # True, if this script is ES6 module. + optional boolean isModule + # This script length. + optional integer length + # JavaScript top stack frame of where the script parsed event was triggered if available. + experimental optional Runtime.StackTrace stackTrace + # If the scriptLanguage is WebAssembly, the code section offset in the module. + experimental optional integer codeOffset + # The language of the script. + experimental optional Debugger.ScriptLanguage scriptLanguage + # The name the embedder supplied for this script. + experimental optional string embedderName + + # Fired when virtual machine parses script. This event is also fired for all known and uncollected + # scripts upon enabling debugger. + event scriptParsed + parameters + # Identifier of the script parsed. + Runtime.ScriptId scriptId + # URL or name of the script parsed (if any). + string url + # Line offset of the script within the resource with given URL (for script tags). + integer startLine + # Column offset of the script within the resource with given URL. + integer startColumn + # Last line of the script. + integer endLine + # Length of the last line of the script. + integer endColumn + # Specifies script creation context. + Runtime.ExecutionContextId executionContextId + # Content hash of the script, SHA-256. + string hash + # Embedder-specific auxiliary data likely matching {isDefault: boolean, type: 'default'|'isolated'|'worker', frameId: string} + optional object executionContextAuxData + # True, if this script is generated as a result of the live edit operation. + experimental optional boolean isLiveEdit + # URL of source map associated with script (if any). + optional string sourceMapURL + # True, if this script has sourceURL. + optional boolean hasSourceURL + # True, if this script is ES6 module. + optional boolean isModule + # This script length. + optional integer length + # JavaScript top stack frame of where the script parsed event was triggered if available. + experimental optional Runtime.StackTrace stackTrace + # If the scriptLanguage is WebAssembly, the code section offset in the module. + experimental optional integer codeOffset + # The language of the script. + experimental optional Debugger.ScriptLanguage scriptLanguage + # If the scriptLanguage is WebASsembly, the source of debug symbols for the module. + experimental optional Debugger.DebugSymbols debugSymbols + # The name the embedder supplied for this script. + experimental optional string embedderName + +experimental domain HeapProfiler + depends on Runtime + + # Heap snapshot object id. + type HeapSnapshotObjectId extends string + + # Sampling Heap Profile node. Holds callsite information, allocation statistics and child nodes. + type SamplingHeapProfileNode extends object + properties + # Function location. + Runtime.CallFrame callFrame + # Allocations size in bytes for the node excluding children. + number selfSize + # Node id. Ids are unique across all profiles collected between startSampling and stopSampling. + integer id + # Child nodes. + array of SamplingHeapProfileNode children + + # A single sample from a sampling profile. + type SamplingHeapProfileSample extends object + properties + # Allocation size in bytes attributed to the sample. + number size + # Id of the corresponding profile tree node. + integer nodeId + # Time-ordered sample ordinal number. It is unique across all profiles retrieved + # between startSampling and stopSampling. + number ordinal + + # Sampling profile. + type SamplingHeapProfile extends object + properties + SamplingHeapProfileNode head + array of SamplingHeapProfileSample samples + + # Enables console to refer to the node with given id via $x (see Command Line API for more details + # $x functions). + command addInspectedHeapObject + parameters + # Heap snapshot object id to be accessible by means of $x command line API. + HeapSnapshotObjectId heapObjectId + + command collectGarbage + + command disable + + command enable + + command getHeapObjectId + parameters + # Identifier of the object to get heap object id for. + Runtime.RemoteObjectId objectId + returns + # Id of the heap snapshot object corresponding to the passed remote object id. + HeapSnapshotObjectId heapSnapshotObjectId + + command getObjectByHeapObjectId + parameters + HeapSnapshotObjectId objectId + # Symbolic group name that can be used to release multiple objects. + optional string objectGroup + returns + # Evaluation result. + Runtime.RemoteObject result + + command getSamplingProfile + returns + # Return the sampling profile being collected. + SamplingHeapProfile profile + + command startSampling + parameters + # Average sample interval in bytes. Poisson distribution is used for the intervals. The + # default value is 32768 bytes. + optional number samplingInterval + # By default, the sampling heap profiler reports only objects which are + # still alive when the profile is returned via getSamplingProfile or + # stopSampling, which is useful for determining what functions contribute + # the most to steady-state memory usage. This flag instructs the sampling + # heap profiler to also include information about objects discarded by + # major GC, which will show which functions cause large temporary memory + # usage or long GC pauses. + optional boolean includeObjectsCollectedByMajorGC + # By default, the sampling heap profiler reports only objects which are + # still alive when the profile is returned via getSamplingProfile or + # stopSampling, which is useful for determining what functions contribute + # the most to steady-state memory usage. This flag instructs the sampling + # heap profiler to also include information about objects discarded by + # minor GC, which is useful when tuning a latency-sensitive application + # for minimal GC activity. + optional boolean includeObjectsCollectedByMinorGC + + command startTrackingHeapObjects + parameters + optional boolean trackAllocations + + command stopSampling + returns + # Recorded sampling heap profile. + SamplingHeapProfile profile + + command stopTrackingHeapObjects + parameters + # If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken + # when the tracking is stopped. + optional boolean reportProgress + # Deprecated in favor of `exposeInternals`. + deprecated optional boolean treatGlobalObjectsAsRoots + # If true, numerical values are included in the snapshot + optional boolean captureNumericValue + # If true, exposes internals of the snapshot. + experimental optional boolean exposeInternals + + command takeHeapSnapshot + parameters + # If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken. + optional boolean reportProgress + # If true, a raw snapshot without artificial roots will be generated. + # Deprecated in favor of `exposeInternals`. + deprecated optional boolean treatGlobalObjectsAsRoots + # If true, numerical values are included in the snapshot + optional boolean captureNumericValue + # If true, exposes internals of the snapshot. + experimental optional boolean exposeInternals + + event addHeapSnapshotChunk + parameters + string chunk + + # If heap objects tracking has been started then backend may send update for one or more fragments + event heapStatsUpdate + parameters + # An array of triplets. Each triplet describes a fragment. The first integer is the fragment + # index, the second integer is a total count of objects for the fragment, the third integer is + # a total size of the objects for the fragment. + array of integer statsUpdate + + # If heap objects tracking has been started then backend regularly sends a current value for last + # seen object id and corresponding timestamp. If the were changes in the heap since last event + # then one or more heapStatsUpdate events will be sent before a new lastSeenObjectId event. + event lastSeenObjectId + parameters + integer lastSeenObjectId + number timestamp + + event reportHeapSnapshotProgress + parameters + integer done + integer total + optional boolean finished + + event resetProfiles + +domain Profiler + depends on Runtime + depends on Debugger + + # Profile node. Holds callsite information, execution statistics and child nodes. + type ProfileNode extends object + properties + # Unique id of the node. + integer id + # Function location. + Runtime.CallFrame callFrame + # Number of samples where this node was on top of the call stack. + optional integer hitCount + # Child node ids. + optional array of integer children + # The reason of being not optimized. The function may be deoptimized or marked as don't + # optimize. + optional string deoptReason + # An array of source position ticks. + optional array of PositionTickInfo positionTicks + + # Profile. + type Profile extends object + properties + # The list of profile nodes. First item is the root node. + array of ProfileNode nodes + # Profiling start timestamp in microseconds. + number startTime + # Profiling end timestamp in microseconds. + number endTime + # Ids of samples top nodes. + optional array of integer samples + # Time intervals between adjacent samples in microseconds. The first delta is relative to the + # profile startTime. + optional array of integer timeDeltas + + # Specifies a number of samples attributed to a certain source position. + type PositionTickInfo extends object + properties + # Source line number (1-based). + integer line + # Number of samples attributed to the source line. + integer ticks + + # Coverage data for a source range. + type CoverageRange extends object + properties + # JavaScript script source offset for the range start. + integer startOffset + # JavaScript script source offset for the range end. + integer endOffset + # Collected execution count of the source range. + integer count + + # Coverage data for a JavaScript function. + type FunctionCoverage extends object + properties + # JavaScript function name. + string functionName + # Source ranges inside the function with coverage data. + array of CoverageRange ranges + # Whether coverage data for this function has block granularity. + boolean isBlockCoverage + + # Coverage data for a JavaScript script. + type ScriptCoverage extends object + properties + # JavaScript script id. + Runtime.ScriptId scriptId + # JavaScript script name or url. + string url + # Functions contained in the script that has coverage data. + array of FunctionCoverage functions + + command disable + + command enable + + # Collect coverage data for the current isolate. The coverage data may be incomplete due to + # garbage collection. + command getBestEffortCoverage + returns + # Coverage data for the current isolate. + array of ScriptCoverage result + + # Changes CPU profiler sampling interval. Must be called before CPU profiles recording started. + command setSamplingInterval + parameters + # New sampling interval in microseconds. + integer interval + + command start + + # Enable precise code coverage. Coverage data for JavaScript executed before enabling precise code + # coverage may be incomplete. Enabling prevents running optimized code and resets execution + # counters. + command startPreciseCoverage + parameters + # Collect accurate call counts beyond simple 'covered' or 'not covered'. + optional boolean callCount + # Collect block-based coverage. + optional boolean detailed + # Allow the backend to send updates on its own initiative + optional boolean allowTriggeredUpdates + returns + # Monotonically increasing time (in seconds) when the coverage update was taken in the backend. + number timestamp + + command stop + returns + # Recorded profile. + Profile profile + + # Disable precise code coverage. Disabling releases unnecessary execution count records and allows + # executing optimized code. + command stopPreciseCoverage + + # Collect coverage data for the current isolate, and resets execution counters. Precise code + # coverage needs to have started. + command takePreciseCoverage + returns + # Coverage data for the current isolate. + array of ScriptCoverage result + # Monotonically increasing time (in seconds) when the coverage update was taken in the backend. + number timestamp + + event consoleProfileFinished + parameters + string id + # Location of console.profileEnd(). + Debugger.Location location + Profile profile + # Profile title passed as an argument to console.profile(). + optional string title + + # Sent when new profile recording is started using console.profile() call. + event consoleProfileStarted + parameters + string id + # Location of console.profile(). + Debugger.Location location + # Profile title passed as an argument to console.profile(). + optional string title + + # Reports coverage delta since the last poll (either from an event like this, or from + # `takePreciseCoverage` for the current isolate. May only be sent if precise code + # coverage has been started. This event can be trigged by the embedder to, for example, + # trigger collection of coverage data immediately at a certain point in time. + experimental event preciseCoverageDeltaUpdate + parameters + # Monotonically increasing time (in seconds) when the coverage update was taken in the backend. + number timestamp + # Identifier for distinguishing coverage events. + string occasion + # Coverage data for the current isolate. + array of ScriptCoverage result + +# Runtime domain exposes JavaScript runtime by means of remote evaluation and mirror objects. +# Evaluation results are returned as mirror object that expose object type, string representation +# and unique identifier that can be used for further object reference. Original objects are +# maintained in memory unless they are either explicitly released or are released along with the +# other objects in their object group. +domain Runtime + + # Unique script identifier. + type ScriptId extends string + + # Represents options for serialization. Overrides `generatePreview` and `returnByValue`. + type SerializationOptions extends object + properties + enum serialization + # Whether the result should be deep-serialized. The result is put into + # `deepSerializedValue` and `ObjectId` is provided. + deep + # Whether the result is expected to be a JSON object which should be sent by value. + # The result is put either into `value` or into `unserializableValue`. Synonym of + # `returnByValue: true`. Overrides `returnByValue`. + json + # Only remote object id is put in the result. Same bahaviour as if no + # `serializationOptions`, `generatePreview` nor `returnByValue` are provided. + idOnly + + # Deep serialization depth. Default is full depth. Respected only in `deep` serialization mode. + optional integer maxDepth + + # Embedder-specific parameters. For example if connected to V8 in Chrome these control DOM + # serialization via `maxNodeDepth: integer` and `includeShadowTree: "none" | "open" | "all"`. + # Values can be only of type string or integer. + optional object additionalParameters + + # Represents deep serialized value. + type DeepSerializedValue extends object + properties + enum type + undefined + null + string + number + boolean + bigint + regexp + date + symbol + array + object + function + map + set + weakmap + weakset + error + proxy + promise + typedarray + arraybuffer + node + window + generator + optional any value + optional string objectId + # Set if value reference met more then once during serialization. In such + # case, value is provided only to one of the serialized values. Unique + # per value in the scope of one CDP call. + optional integer weakLocalObjectReference + + # Unique object identifier. + type RemoteObjectId extends string + + # Primitive value which cannot be JSON-stringified. Includes values `-0`, `NaN`, `Infinity`, + # `-Infinity`, and bigint literals. + type UnserializableValue extends string + + # Mirror object referencing original JavaScript object. + type RemoteObject extends object + properties + # Object type. + enum type + object + function + undefined + string + number + boolean + symbol + bigint + # Object subtype hint. Specified for `object` type values only. + # NOTE: If you change anything here, make sure to also update + # `subtype` in `ObjectPreview` and `PropertyPreview` below. + optional enum subtype + array + null + node + regexp + date + map + set + weakmap + weakset + iterator + generator + error + proxy + promise + typedarray + arraybuffer + dataview + webassemblymemory + wasmvalue + # Object class (constructor) name. Specified for `object` type values only. + optional string className + # Remote object value in case of primitive values or JSON values (if it was requested). + optional any value + # Primitive value which can not be JSON-stringified does not have `value`, but gets this + # property. + optional UnserializableValue unserializableValue + # String representation of the object. + optional string description + # Deep serialized value. + experimental optional DeepSerializedValue deepSerializedValue + # Unique object identifier (for non-primitive values). + optional RemoteObjectId objectId + # Preview containing abbreviated property values. Specified for `object` type values only. + experimental optional ObjectPreview preview + experimental optional CustomPreview customPreview + + experimental type CustomPreview extends object + properties + # The JSON-stringified result of formatter.header(object, config) call. + # It contains json ML array that represents RemoteObject. + string header + # If formatter returns true as a result of formatter.hasBody call then bodyGetterId will + # contain RemoteObjectId for the function that returns result of formatter.body(object, config) call. + # The result value is json ML array. + optional RemoteObjectId bodyGetterId + + # Object containing abbreviated remote object value. + experimental type ObjectPreview extends object + properties + # Object type. + enum type + object + function + undefined + string + number + boolean + symbol + bigint + # Object subtype hint. Specified for `object` type values only. + optional enum subtype + array + null + node + regexp + date + map + set + weakmap + weakset + iterator + generator + error + proxy + promise + typedarray + arraybuffer + dataview + webassemblymemory + wasmvalue + # String representation of the object. + optional string description + # True iff some of the properties or entries of the original object did not fit. + boolean overflow + # List of the properties. + array of PropertyPreview properties + # List of the entries. Specified for `map` and `set` subtype values only. + optional array of EntryPreview entries + + experimental type PropertyPreview extends object + properties + # Property name. + string name + # Object type. Accessor means that the property itself is an accessor property. + enum type + object + function + undefined + string + number + boolean + symbol + accessor + bigint + # User-friendly property value string. + optional string value + # Nested value preview. + optional ObjectPreview valuePreview + # Object subtype hint. Specified for `object` type values only. + optional enum subtype + array + null + node + regexp + date + map + set + weakmap + weakset + iterator + generator + error + proxy + promise + typedarray + arraybuffer + dataview + webassemblymemory + wasmvalue + + experimental type EntryPreview extends object + properties + # Preview of the key. Specified for map-like collection entries. + optional ObjectPreview key + # Preview of the value. + ObjectPreview value + + # Object property descriptor. + type PropertyDescriptor extends object + properties + # Property name or symbol description. + string name + # The value associated with the property. + optional RemoteObject value + # True if the value associated with the property may be changed (data descriptors only). + optional boolean writable + # A function which serves as a getter for the property, or `undefined` if there is no getter + # (accessor descriptors only). + optional RemoteObject get + # A function which serves as a setter for the property, or `undefined` if there is no setter + # (accessor descriptors only). + optional RemoteObject set + # True if the type of this property descriptor may be changed and if the property may be + # deleted from the corresponding object. + boolean configurable + # True if this property shows up during enumeration of the properties on the corresponding + # object. + boolean enumerable + # True if the result was thrown during the evaluation. + optional boolean wasThrown + # True if the property is owned for the object. + optional boolean isOwn + # Property symbol object, if the property is of the `symbol` type. + optional RemoteObject symbol + + # Object internal property descriptor. This property isn't normally visible in JavaScript code. + type InternalPropertyDescriptor extends object + properties + # Conventional property name. + string name + # The value associated with the property. + optional RemoteObject value + + # Object private field descriptor. + experimental type PrivatePropertyDescriptor extends object + properties + # Private property name. + string name + # The value associated with the private property. + optional RemoteObject value + # A function which serves as a getter for the private property, + # or `undefined` if there is no getter (accessor descriptors only). + optional RemoteObject get + # A function which serves as a setter for the private property, + # or `undefined` if there is no setter (accessor descriptors only). + optional RemoteObject set + + # Represents function call argument. Either remote object id `objectId`, primitive `value`, + # unserializable primitive value or neither of (for undefined) them should be specified. + type CallArgument extends object + properties + # Primitive value or serializable javascript object. + optional any value + # Primitive value which can not be JSON-stringified. + optional UnserializableValue unserializableValue + # Remote object handle. + optional RemoteObjectId objectId + + # Id of an execution context. + type ExecutionContextId extends integer + + # Description of an isolated world. + type ExecutionContextDescription extends object + properties + # Unique id of the execution context. It can be used to specify in which execution context + # script evaluation should be performed. + ExecutionContextId id + # Execution context origin. + string origin + # Human readable name describing given context. + string name + # A system-unique execution context identifier. Unlike the id, this is unique across + # multiple processes, so can be reliably used to identify specific context while backend + # performs a cross-process navigation. + experimental string uniqueId + # Embedder-specific auxiliary data likely matching {isDefault: boolean, type: 'default'|'isolated'|'worker', frameId: string} + optional object auxData + + # Detailed information about exception (or error) that was thrown during script compilation or + # execution. + type ExceptionDetails extends object + properties + # Exception id. + integer exceptionId + # Exception text, which should be used together with exception object when available. + string text + # Line number of the exception location (0-based). + integer lineNumber + # Column number of the exception location (0-based). + integer columnNumber + # Script ID of the exception location. + optional ScriptId scriptId + # URL of the exception location, to be used when the script was not reported. + optional string url + # JavaScript stack trace if available. + optional StackTrace stackTrace + # Exception object if available. + optional RemoteObject exception + # Identifier of the context where exception happened. + optional ExecutionContextId executionContextId + # Dictionary with entries of meta data that the client associated + # with this exception, such as information about associated network + # requests, etc. + experimental optional object exceptionMetaData + + # Number of milliseconds since epoch. + type Timestamp extends number + + # Number of milliseconds. + type TimeDelta extends number + + # Stack entry for runtime errors and assertions. + type CallFrame extends object + properties + # JavaScript function name. + string functionName + # JavaScript script id. + ScriptId scriptId + # JavaScript script name or url. + string url + # JavaScript script line number (0-based). + integer lineNumber + # JavaScript script column number (0-based). + integer columnNumber + + # Call frames for assertions or error messages. + type StackTrace extends object + properties + # String label of this stack trace. For async traces this may be a name of the function that + # initiated the async call. + optional string description + # JavaScript function name. + array of CallFrame callFrames + # Asynchronous JavaScript stack trace that preceded this stack, if available. + optional StackTrace parent + # Asynchronous JavaScript stack trace that preceded this stack, if available. + experimental optional StackTraceId parentId + + # Unique identifier of current debugger. + experimental type UniqueDebuggerId extends string + + # If `debuggerId` is set stack trace comes from another debugger and can be resolved there. This + # allows to track cross-debugger calls. See `Runtime.StackTrace` and `Debugger.paused` for usages. + experimental type StackTraceId extends object + properties + string id + optional UniqueDebuggerId debuggerId + + # Add handler to promise with given promise object id. + command awaitPromise + parameters + # Identifier of the promise. + RemoteObjectId promiseObjectId + # Whether the result is expected to be a JSON object that should be sent by value. + optional boolean returnByValue + # Whether preview should be generated for the result. + optional boolean generatePreview + returns + # Promise result. Will contain rejected value if promise was rejected. + RemoteObject result + # Exception details if stack strace is available. + optional ExceptionDetails exceptionDetails + + # Calls function with given declaration on the given object. Object group of the result is + # inherited from the target object. + command callFunctionOn + parameters + # Declaration of the function to call. + string functionDeclaration + # Identifier of the object to call function on. Either objectId or executionContextId should + # be specified. + optional RemoteObjectId objectId + # Call arguments. All call arguments must belong to the same JavaScript world as the target + # object. + optional array of CallArgument arguments + # In silent mode exceptions thrown during evaluation are not reported and do not pause + # execution. Overrides `setPauseOnException` state. + optional boolean silent + # Whether the result is expected to be a JSON object which should be sent by value. + # Can be overriden by `serializationOptions`. + optional boolean returnByValue + # Whether preview should be generated for the result. + experimental optional boolean generatePreview + # Whether execution should be treated as initiated by user in the UI. + optional boolean userGesture + # Whether execution should `await` for resulting value and return once awaited promise is + # resolved. + optional boolean awaitPromise + # Specifies execution context which global object will be used to call function on. Either + # executionContextId or objectId should be specified. + optional ExecutionContextId executionContextId + # Symbolic group name that can be used to release multiple objects. If objectGroup is not + # specified and objectId is, objectGroup will be inherited from object. + optional string objectGroup + # Whether to throw an exception if side effect cannot be ruled out during evaluation. + experimental optional boolean throwOnSideEffect + # An alternative way to specify the execution context to call function on. + # Compared to contextId that may be reused across processes, this is guaranteed to be + # system-unique, so it can be used to prevent accidental function call + # in context different than intended (e.g. as a result of navigation across process + # boundaries). + # This is mutually exclusive with `executionContextId`. + experimental optional string uniqueContextId + # Specifies the result serialization. If provided, overrides + # `generatePreview` and `returnByValue`. + experimental optional SerializationOptions serializationOptions + + returns + # Call result. + RemoteObject result + # Exception details. + optional ExceptionDetails exceptionDetails + + # Compiles expression. + command compileScript + parameters + # Expression to compile. + string expression + # Source url to be set for the script. + string sourceURL + # Specifies whether the compiled script should be persisted. + boolean persistScript + # Specifies in which execution context to perform script run. If the parameter is omitted the + # evaluation will be performed in the context of the inspected page. + optional ExecutionContextId executionContextId + returns + # Id of the script. + optional ScriptId scriptId + # Exception details. + optional ExceptionDetails exceptionDetails + + # Disables reporting of execution contexts creation. + command disable + + # Discards collected exceptions and console API calls. + command discardConsoleEntries + + # Enables reporting of execution contexts creation by means of `executionContextCreated` event. + # When the reporting gets enabled the event will be sent immediately for each existing execution + # context. + command enable + + # Evaluates expression on global object. + command evaluate + parameters + # Expression to evaluate. + string expression + # Symbolic group name that can be used to release multiple objects. + optional string objectGroup + # Determines whether Command Line API should be available during the evaluation. + optional boolean includeCommandLineAPI + # In silent mode exceptions thrown during evaluation are not reported and do not pause + # execution. Overrides `setPauseOnException` state. + optional boolean silent + # Specifies in which execution context to perform evaluation. If the parameter is omitted the + # evaluation will be performed in the context of the inspected page. + # This is mutually exclusive with `uniqueContextId`, which offers an + # alternative way to identify the execution context that is more reliable + # in a multi-process environment. + optional ExecutionContextId contextId + # Whether the result is expected to be a JSON object that should be sent by value. + optional boolean returnByValue + # Whether preview should be generated for the result. + experimental optional boolean generatePreview + # Whether execution should be treated as initiated by user in the UI. + optional boolean userGesture + # Whether execution should `await` for resulting value and return once awaited promise is + # resolved. + optional boolean awaitPromise + # Whether to throw an exception if side effect cannot be ruled out during evaluation. + # This implies `disableBreaks` below. + experimental optional boolean throwOnSideEffect + # Terminate execution after timing out (number of milliseconds). + experimental optional TimeDelta timeout + # Disable breakpoints during execution. + experimental optional boolean disableBreaks + # Setting this flag to true enables `let` re-declaration and top-level `await`. + # Note that `let` variables can only be re-declared if they originate from + # `replMode` themselves. + experimental optional boolean replMode + # The Content Security Policy (CSP) for the target might block 'unsafe-eval' + # which includes eval(), Function(), setTimeout() and setInterval() + # when called with non-callable arguments. This flag bypasses CSP for this + # evaluation and allows unsafe-eval. Defaults to true. + experimental optional boolean allowUnsafeEvalBlockedByCSP + # An alternative way to specify the execution context to evaluate in. + # Compared to contextId that may be reused across processes, this is guaranteed to be + # system-unique, so it can be used to prevent accidental evaluation of the expression + # in context different than intended (e.g. as a result of navigation across process + # boundaries). + # This is mutually exclusive with `contextId`. + experimental optional string uniqueContextId + # Specifies the result serialization. If provided, overrides + # `generatePreview` and `returnByValue`. + experimental optional SerializationOptions serializationOptions + returns + # Evaluation result. + RemoteObject result + # Exception details. + optional ExceptionDetails exceptionDetails + + # Returns the isolate id. + experimental command getIsolateId + returns + # The isolate id. + string id + + # Returns the JavaScript heap usage. + # It is the total usage of the corresponding isolate not scoped to a particular Runtime. + experimental command getHeapUsage + returns + # Used heap size in bytes. + number usedSize + # Allocated heap size in bytes. + number totalSize + + # Returns properties of a given object. Object group of the result is inherited from the target + # object. + command getProperties + parameters + # Identifier of the object to return properties for. + RemoteObjectId objectId + # If true, returns properties belonging only to the element itself, not to its prototype + # chain. + optional boolean ownProperties + # If true, returns accessor properties (with getter/setter) only; internal properties are not + # returned either. + experimental optional boolean accessorPropertiesOnly + # Whether preview should be generated for the results. + experimental optional boolean generatePreview + # If true, returns non-indexed properties only. + experimental optional boolean nonIndexedPropertiesOnly + returns + # Object properties. + array of PropertyDescriptor result + # Internal object properties (only of the element itself). + optional array of InternalPropertyDescriptor internalProperties + # Object private properties. + experimental optional array of PrivatePropertyDescriptor privateProperties + # Exception details. + optional ExceptionDetails exceptionDetails + + # Returns all let, const and class variables from global scope. + command globalLexicalScopeNames + parameters + # Specifies in which execution context to lookup global scope variables. + optional ExecutionContextId executionContextId + returns + array of string names + + command queryObjects + parameters + # Identifier of the prototype to return objects for. + RemoteObjectId prototypeObjectId + # Symbolic group name that can be used to release the results. + optional string objectGroup + returns + # Array with objects. + RemoteObject objects + + # Releases remote object with given id. + command releaseObject + parameters + # Identifier of the object to release. + RemoteObjectId objectId + + # Releases all remote objects that belong to a given group. + command releaseObjectGroup + parameters + # Symbolic object group name. + string objectGroup + + # Tells inspected instance to run if it was waiting for debugger to attach. + command runIfWaitingForDebugger + + # Runs script with given id in a given context. + command runScript + parameters + # Id of the script to run. + ScriptId scriptId + # Specifies in which execution context to perform script run. If the parameter is omitted the + # evaluation will be performed in the context of the inspected page. + optional ExecutionContextId executionContextId + # Symbolic group name that can be used to release multiple objects. + optional string objectGroup + # In silent mode exceptions thrown during evaluation are not reported and do not pause + # execution. Overrides `setPauseOnException` state. + optional boolean silent + # Determines whether Command Line API should be available during the evaluation. + optional boolean includeCommandLineAPI + # Whether the result is expected to be a JSON object which should be sent by value. + optional boolean returnByValue + # Whether preview should be generated for the result. + optional boolean generatePreview + # Whether execution should `await` for resulting value and return once awaited promise is + # resolved. + optional boolean awaitPromise + returns + # Run result. + RemoteObject result + # Exception details. + optional ExceptionDetails exceptionDetails + + # Enables or disables async call stacks tracking. + command setAsyncCallStackDepth + redirect Debugger + parameters + # Maximum depth of async call stacks. Setting to `0` will effectively disable collecting async + # call stacks (default). + integer maxDepth + + experimental command setCustomObjectFormatterEnabled + parameters + boolean enabled + + experimental command setMaxCallStackSizeToCapture + parameters + integer size + + # Terminate current or next JavaScript execution. + # Will cancel the termination when the outer-most script execution ends. + experimental command terminateExecution + + # If executionContextId is empty, adds binding with the given name on the + # global objects of all inspected contexts, including those created later, + # bindings survive reloads. + # Binding function takes exactly one argument, this argument should be string, + # in case of any other input, function throws an exception. + # Each binding function call produces Runtime.bindingCalled notification. + experimental command addBinding + parameters + string name + # If specified, the binding would only be exposed to the specified + # execution context. If omitted and `executionContextName` is not set, + # the binding is exposed to all execution contexts of the target. + # This parameter is mutually exclusive with `executionContextName`. + # Deprecated in favor of `executionContextName` due to an unclear use case + # and bugs in implementation (crbug.com/1169639). `executionContextId` will be + # removed in the future. + deprecated optional ExecutionContextId executionContextId + # If specified, the binding is exposed to the executionContext with + # matching name, even for contexts created after the binding is added. + # See also `ExecutionContext.name` and `worldName` parameter to + # `Page.addScriptToEvaluateOnNewDocument`. + # This parameter is mutually exclusive with `executionContextId`. + experimental optional string executionContextName + + # This method does not remove binding function from global object but + # unsubscribes current runtime agent from Runtime.bindingCalled notifications. + experimental command removeBinding + parameters + string name + + # This method tries to lookup and populate exception details for a + # JavaScript Error object. + # Note that the stackTrace portion of the resulting exceptionDetails will + # only be populated if the Runtime domain was enabled at the time when the + # Error was thrown. + experimental command getExceptionDetails + parameters + # The error object for which to resolve the exception details. + RemoteObjectId errorObjectId + returns + optional ExceptionDetails exceptionDetails + + # Notification is issued every time when binding is called. + experimental event bindingCalled + parameters + string name + string payload + # Identifier of the context where the call was made. + ExecutionContextId executionContextId + + # Issued when console API was called. + event consoleAPICalled + parameters + # Type of the call. + enum type + log + debug + info + error + warning + dir + dirxml + table + trace + clear + startGroup + startGroupCollapsed + endGroup + assert + profile + profileEnd + count + timeEnd + # Call arguments. + array of RemoteObject args + # Identifier of the context where the call was made. + ExecutionContextId executionContextId + # Call timestamp. + Timestamp timestamp + # Stack trace captured when the call was made. The async stack chain is automatically reported for + # the following call types: `assert`, `error`, `trace`, `warning`. For other types the async call + # chain can be retrieved using `Debugger.getStackTrace` and `stackTrace.parentId` field. + optional StackTrace stackTrace + # Console context descriptor for calls on non-default console context (not console.*): + # 'anonymous#unique-logger-id' for call on unnamed context, 'name#unique-logger-id' for call + # on named context. + experimental optional string context + + # Issued when unhandled exception was revoked. + event exceptionRevoked + parameters + # Reason describing why exception was revoked. + string reason + # The id of revoked exception, as reported in `exceptionThrown`. + integer exceptionId + + # Issued when exception was thrown and unhandled. + event exceptionThrown + parameters + # Timestamp of the exception. + Timestamp timestamp + ExceptionDetails exceptionDetails + + # Issued when new execution context is created. + event executionContextCreated + parameters + # A newly created execution context. + ExecutionContextDescription context + + # Issued when execution context is destroyed. + event executionContextDestroyed + parameters + # Id of the destroyed context + deprecated ExecutionContextId executionContextId + # Unique Id of the destroyed context + experimental string executionContextUniqueId + + # Issued when all executionContexts were cleared in browser + event executionContextsCleared + + # Issued when object should be inspected (for example, as a result of inspect() command line API + # call). + event inspectRequested + parameters + RemoteObject object + object hints + # Identifier of the context where the call was made. + experimental optional ExecutionContextId executionContextId + +# This domain is deprecated. +deprecated domain Schema + + # Description of the protocol domain. + type Domain extends object + properties + # Domain name. + string name + # Domain version. + string version + + # Returns supported domains. + command getDomains + returns + # List of supported domains. + array of Domain domains diff --git a/NativeScript/napi/v8/include_old/libplatform/DEPS b/NativeScript/napi/v8/include_old/libplatform/DEPS new file mode 100644 index 00000000..d8bcf998 --- /dev/null +++ b/NativeScript/napi/v8/include_old/libplatform/DEPS @@ -0,0 +1,9 @@ +include_rules = [ + "+libplatform/libplatform-export.h", +] + +specific_include_rules = { + "libplatform\.h": [ + "+libplatform/v8-tracing.h", + ], +} diff --git a/NativeScript/napi/v8/include_old/libplatform/libplatform-export.h b/NativeScript/napi/v8/include_old/libplatform/libplatform-export.h new file mode 100644 index 00000000..15618434 --- /dev/null +++ b/NativeScript/napi/v8/include_old/libplatform/libplatform-export.h @@ -0,0 +1,29 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_ +#define V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_ + +#if defined(_WIN32) + +#ifdef BUILDING_V8_PLATFORM_SHARED +#define V8_PLATFORM_EXPORT __declspec(dllexport) +#elif USING_V8_PLATFORM_SHARED +#define V8_PLATFORM_EXPORT __declspec(dllimport) +#else +#define V8_PLATFORM_EXPORT +#endif // BUILDING_V8_PLATFORM_SHARED + +#else // defined(_WIN32) + +// Setup for Linux shared library export. +#ifdef BUILDING_V8_PLATFORM_SHARED +#define V8_PLATFORM_EXPORT __attribute__((visibility("default"))) +#else +#define V8_PLATFORM_EXPORT +#endif + +#endif // defined(_WIN32) + +#endif // V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_ diff --git a/NativeScript/napi/v8/include_old/libplatform/libplatform.h b/NativeScript/napi/v8/include_old/libplatform/libplatform.h new file mode 100644 index 00000000..6a34f432 --- /dev/null +++ b/NativeScript/napi/v8/include_old/libplatform/libplatform.h @@ -0,0 +1,112 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_LIBPLATFORM_LIBPLATFORM_H_ +#define V8_LIBPLATFORM_LIBPLATFORM_H_ + +#include + +#include "libplatform/libplatform-export.h" +#include "libplatform/v8-tracing.h" +#include "v8-platform.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { +namespace platform { + +enum class IdleTaskSupport { kDisabled, kEnabled }; +enum class InProcessStackDumping { kDisabled, kEnabled }; + +enum class MessageLoopBehavior : bool { + kDoNotWait = false, + kWaitForWork = true +}; + +enum class PriorityMode : bool { kDontApply, kApply }; + +/** + * Returns a new instance of the default v8::Platform implementation. + * + * The caller will take ownership of the returned pointer. |thread_pool_size| + * is the number of worker threads to allocate for background jobs. If a value + * of zero is passed, a suitable default based on the current number of + * processors online will be chosen. + * If |idle_task_support| is enabled then the platform will accept idle + * tasks (IdleTasksEnabled will return true) and will rely on the embedder + * calling v8::platform::RunIdleTasks to process the idle tasks. + * If |tracing_controller| is nullptr, the default platform will create a + * v8::platform::TracingController instance and use it. + * If |priority_mode| is PriorityMode::kApply, the default platform will use + * multiple task queues executed by threads different system-level priorities + * (where available) to schedule tasks. + */ +V8_PLATFORM_EXPORT std::unique_ptr NewDefaultPlatform( + int thread_pool_size = 0, + IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled, + InProcessStackDumping in_process_stack_dumping = + InProcessStackDumping::kDisabled, + std::unique_ptr tracing_controller = {}, + PriorityMode priority_mode = PriorityMode::kDontApply); + +/** + * The same as NewDefaultPlatform but disables the worker thread pool. + * It must be used with the --single-threaded V8 flag. + */ +V8_PLATFORM_EXPORT std::unique_ptr +NewSingleThreadedDefaultPlatform( + IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled, + InProcessStackDumping in_process_stack_dumping = + InProcessStackDumping::kDisabled, + std::unique_ptr tracing_controller = {}); + +/** + * Returns a new instance of the default v8::JobHandle implementation. + * + * The job will be executed by spawning up to |num_worker_threads| many worker + * threads on the provided |platform| with the given |priority|. + */ +V8_PLATFORM_EXPORT std::unique_ptr NewDefaultJobHandle( + v8::Platform* platform, v8::TaskPriority priority, + std::unique_ptr job_task, size_t num_worker_threads); + +/** + * Pumps the message loop for the given isolate. + * + * The caller has to make sure that this is called from the right thread. + * Returns true if a task was executed, and false otherwise. If the call to + * PumpMessageLoop is nested within another call to PumpMessageLoop, only + * nestable tasks may run. Otherwise, any task may run. Unless requested through + * the |behavior| parameter, this call does not block if no task is pending. The + * |platform| has to be created using |NewDefaultPlatform|. + */ +V8_PLATFORM_EXPORT bool PumpMessageLoop( + v8::Platform* platform, v8::Isolate* isolate, + MessageLoopBehavior behavior = MessageLoopBehavior::kDoNotWait); + +/** + * Runs pending idle tasks for at most |idle_time_in_seconds| seconds. + * + * The caller has to make sure that this is called from the right thread. + * This call does not block if no task is pending. The |platform| has to be + * created using |NewDefaultPlatform|. + */ +V8_PLATFORM_EXPORT void RunIdleTasks(v8::Platform* platform, + v8::Isolate* isolate, + double idle_time_in_seconds); + +/** + * Notifies the given platform about the Isolate getting deleted soon. Has to be + * called for all Isolates which are deleted - unless we're shutting down the + * platform. + * + * The |platform| has to be created using |NewDefaultPlatform|. + * + */ +V8_PLATFORM_EXPORT void NotifyIsolateShutdown(v8::Platform* platform, + Isolate* isolate); + +} // namespace platform +} // namespace v8 + +#endif // V8_LIBPLATFORM_LIBPLATFORM_H_ diff --git a/NativeScript/napi/v8/include_old/libplatform/v8-tracing.h b/NativeScript/napi/v8/include_old/libplatform/v8-tracing.h new file mode 100644 index 00000000..6039a9c5 --- /dev/null +++ b/NativeScript/napi/v8/include_old/libplatform/v8-tracing.h @@ -0,0 +1,333 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_LIBPLATFORM_V8_TRACING_H_ +#define V8_LIBPLATFORM_V8_TRACING_H_ + +#include +#include +#include +#include +#include + +#include "libplatform/libplatform-export.h" +#include "v8-platform.h" // NOLINT(build/include_directory) + +namespace perfetto { +namespace trace_processor { +class TraceProcessorStorage; +} +class TracingSession; +} + +namespace v8 { + +namespace base { +class Mutex; +} // namespace base + +namespace platform { +namespace tracing { + +class TraceEventListener; + +const int kTraceMaxNumArgs = 2; + +class V8_PLATFORM_EXPORT TraceObject { + public: + union ArgValue { + uint64_t as_uint; + int64_t as_int; + double as_double; + const void* as_pointer; + const char* as_string; + }; + + TraceObject() = default; + ~TraceObject(); + void Initialize( + char phase, const uint8_t* category_enabled_flag, const char* name, + const char* scope, uint64_t id, uint64_t bind_id, int num_args, + const char** arg_names, const uint8_t* arg_types, + const uint64_t* arg_values, + std::unique_ptr* arg_convertables, + unsigned int flags, int64_t timestamp, int64_t cpu_timestamp); + void UpdateDuration(int64_t timestamp, int64_t cpu_timestamp); + void InitializeForTesting( + char phase, const uint8_t* category_enabled_flag, const char* name, + const char* scope, uint64_t id, uint64_t bind_id, int num_args, + const char** arg_names, const uint8_t* arg_types, + const uint64_t* arg_values, + std::unique_ptr* arg_convertables, + unsigned int flags, int pid, int tid, int64_t ts, int64_t tts, + uint64_t duration, uint64_t cpu_duration); + + int pid() const { return pid_; } + int tid() const { return tid_; } + char phase() const { return phase_; } + const uint8_t* category_enabled_flag() const { + return category_enabled_flag_; + } + const char* name() const { return name_; } + const char* scope() const { return scope_; } + uint64_t id() const { return id_; } + uint64_t bind_id() const { return bind_id_; } + int num_args() const { return num_args_; } + const char** arg_names() { return arg_names_; } + uint8_t* arg_types() { return arg_types_; } + ArgValue* arg_values() { return arg_values_; } + std::unique_ptr* arg_convertables() { + return arg_convertables_; + } + unsigned int flags() const { return flags_; } + int64_t ts() { return ts_; } + int64_t tts() { return tts_; } + uint64_t duration() { return duration_; } + uint64_t cpu_duration() { return cpu_duration_; } + + private: + int pid_; + int tid_; + char phase_; + const char* name_; + const char* scope_; + const uint8_t* category_enabled_flag_; + uint64_t id_; + uint64_t bind_id_; + int num_args_ = 0; + const char* arg_names_[kTraceMaxNumArgs]; + uint8_t arg_types_[kTraceMaxNumArgs]; + ArgValue arg_values_[kTraceMaxNumArgs]; + std::unique_ptr + arg_convertables_[kTraceMaxNumArgs]; + char* parameter_copy_storage_ = nullptr; + unsigned int flags_; + int64_t ts_; + int64_t tts_; + uint64_t duration_; + uint64_t cpu_duration_; + + // Disallow copy and assign + TraceObject(const TraceObject&) = delete; + void operator=(const TraceObject&) = delete; +}; + +class V8_PLATFORM_EXPORT TraceWriter { + public: + TraceWriter() = default; + virtual ~TraceWriter() = default; + virtual void AppendTraceEvent(TraceObject* trace_event) = 0; + virtual void Flush() = 0; + + static TraceWriter* CreateJSONTraceWriter(std::ostream& stream); + static TraceWriter* CreateJSONTraceWriter(std::ostream& stream, + const std::string& tag); + + static TraceWriter* CreateSystemInstrumentationTraceWriter(); + + private: + // Disallow copy and assign + TraceWriter(const TraceWriter&) = delete; + void operator=(const TraceWriter&) = delete; +}; + +class V8_PLATFORM_EXPORT TraceBufferChunk { + public: + explicit TraceBufferChunk(uint32_t seq); + + void Reset(uint32_t new_seq); + bool IsFull() const { return next_free_ == kChunkSize; } + TraceObject* AddTraceEvent(size_t* event_index); + TraceObject* GetEventAt(size_t index) { return &chunk_[index]; } + + uint32_t seq() const { return seq_; } + size_t size() const { return next_free_; } + + static const size_t kChunkSize = 64; + + private: + size_t next_free_ = 0; + TraceObject chunk_[kChunkSize]; + uint32_t seq_; + + // Disallow copy and assign + TraceBufferChunk(const TraceBufferChunk&) = delete; + void operator=(const TraceBufferChunk&) = delete; +}; + +class V8_PLATFORM_EXPORT TraceBuffer { + public: + TraceBuffer() = default; + virtual ~TraceBuffer() = default; + + virtual TraceObject* AddTraceEvent(uint64_t* handle) = 0; + virtual TraceObject* GetEventByHandle(uint64_t handle) = 0; + virtual bool Flush() = 0; + + static const size_t kRingBufferChunks = 1024; + + static TraceBuffer* CreateTraceBufferRingBuffer(size_t max_chunks, + TraceWriter* trace_writer); + + private: + // Disallow copy and assign + TraceBuffer(const TraceBuffer&) = delete; + void operator=(const TraceBuffer&) = delete; +}; + +// Options determines how the trace buffer stores data. +enum TraceRecordMode { + // Record until the trace buffer is full. + RECORD_UNTIL_FULL, + + // Record until the user ends the trace. The trace buffer is a fixed size + // and we use it as a ring buffer during recording. + RECORD_CONTINUOUSLY, + + // Record until the trace buffer is full, but with a huge buffer size. + RECORD_AS_MUCH_AS_POSSIBLE, + + // Echo to console. Events are discarded. + ECHO_TO_CONSOLE, +}; + +class V8_PLATFORM_EXPORT TraceConfig { + public: + typedef std::vector StringList; + + static TraceConfig* CreateDefaultTraceConfig(); + + TraceConfig() : enable_systrace_(false), enable_argument_filter_(false) {} + TraceRecordMode GetTraceRecordMode() const { return record_mode_; } + const StringList& GetEnabledCategories() const { + return included_categories_; + } + bool IsSystraceEnabled() const { return enable_systrace_; } + bool IsArgumentFilterEnabled() const { return enable_argument_filter_; } + + void SetTraceRecordMode(TraceRecordMode mode) { record_mode_ = mode; } + void EnableSystrace() { enable_systrace_ = true; } + void EnableArgumentFilter() { enable_argument_filter_ = true; } + + void AddIncludedCategory(const char* included_category); + + bool IsCategoryGroupEnabled(const char* category_group) const; + + private: + TraceRecordMode record_mode_; + bool enable_systrace_ : 1; + bool enable_argument_filter_ : 1; + StringList included_categories_; + + // Disallow copy and assign + TraceConfig(const TraceConfig&) = delete; + void operator=(const TraceConfig&) = delete; +}; + +#if defined(_MSC_VER) +#define V8_PLATFORM_NON_EXPORTED_BASE(code) \ + __pragma(warning(suppress : 4275)) code +#else +#define V8_PLATFORM_NON_EXPORTED_BASE(code) code +#endif // defined(_MSC_VER) + +class V8_PLATFORM_EXPORT TracingController + : public V8_PLATFORM_NON_EXPORTED_BASE(v8::TracingController) { + public: + TracingController(); + ~TracingController() override; + +#if defined(V8_USE_PERFETTO) + // Must be called before StartTracing() if V8_USE_PERFETTO is true. Provides + // the output stream for the JSON trace data. + void InitializeForPerfetto(std::ostream* output_stream); + // Provide an optional listener for testing that will receive trace events. + // Must be called before StartTracing(). + void SetTraceEventListenerForTesting(TraceEventListener* listener); +#else // defined(V8_USE_PERFETTO) + // The pointer returned from GetCategoryGroupEnabled() points to a value with + // zero or more of the following bits. Used in this class only. The + // TRACE_EVENT macros should only use the value as a bool. These values must + // be in sync with macro values in TraceEvent.h in Blink. + enum CategoryGroupEnabledFlags { + // Category group enabled for the recording mode. + ENABLED_FOR_RECORDING = 1 << 0, + // Category group enabled by SetEventCallbackEnabled(). + ENABLED_FOR_EVENT_CALLBACK = 1 << 2, + // Category group enabled to export events to ETW. + ENABLED_FOR_ETW_EXPORT = 1 << 3 + }; + + // Takes ownership of |trace_buffer|. + void Initialize(TraceBuffer* trace_buffer); + + // v8::TracingController implementation. + const uint8_t* GetCategoryGroupEnabled(const char* category_group) override; + uint64_t AddTraceEvent( + char phase, const uint8_t* category_enabled_flag, const char* name, + const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, + const char** arg_names, const uint8_t* arg_types, + const uint64_t* arg_values, + std::unique_ptr* arg_convertables, + unsigned int flags) override; + uint64_t AddTraceEventWithTimestamp( + char phase, const uint8_t* category_enabled_flag, const char* name, + const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, + const char** arg_names, const uint8_t* arg_types, + const uint64_t* arg_values, + std::unique_ptr* arg_convertables, + unsigned int flags, int64_t timestamp) override; + void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, + const char* name, uint64_t handle) override; + + static const char* GetCategoryGroupName(const uint8_t* category_enabled_flag); + + void AddTraceStateObserver( + v8::TracingController::TraceStateObserver* observer) override; + void RemoveTraceStateObserver( + v8::TracingController::TraceStateObserver* observer) override; +#endif // !defined(V8_USE_PERFETTO) + + void StartTracing(TraceConfig* trace_config); + void StopTracing(); + + protected: +#if !defined(V8_USE_PERFETTO) + virtual int64_t CurrentTimestampMicroseconds(); + virtual int64_t CurrentCpuTimestampMicroseconds(); +#endif // !defined(V8_USE_PERFETTO) + + private: +#if !defined(V8_USE_PERFETTO) + void UpdateCategoryGroupEnabledFlag(size_t category_index); + void UpdateCategoryGroupEnabledFlags(); +#endif // !defined(V8_USE_PERFETTO) + + std::unique_ptr mutex_; + std::unique_ptr trace_config_; + std::atomic_bool recording_{false}; + +#if defined(V8_USE_PERFETTO) + std::ostream* output_stream_ = nullptr; + std::unique_ptr + trace_processor_; + TraceEventListener* listener_for_testing_ = nullptr; + std::unique_ptr tracing_session_; +#else // !defined(V8_USE_PERFETTO) + std::unordered_set observers_; + std::unique_ptr trace_buffer_; +#endif // !defined(V8_USE_PERFETTO) + + // Disallow copy and assign + TracingController(const TracingController&) = delete; + void operator=(const TracingController&) = delete; +}; + +#undef V8_PLATFORM_NON_EXPORTED_BASE + +} // namespace tracing +} // namespace platform +} // namespace v8 + +#endif // V8_LIBPLATFORM_V8_TRACING_H_ diff --git a/NativeScript/napi/v8/include_old/v8-array-buffer.h b/NativeScript/napi/v8/include_old/v8-array-buffer.h new file mode 100644 index 00000000..804fc42c --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-array-buffer.h @@ -0,0 +1,512 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_ARRAY_BUFFER_H_ +#define INCLUDE_V8_ARRAY_BUFFER_H_ + +#include + +#include + +#include "v8-local-handle.h" // NOLINT(build/include_directory) +#include "v8-object.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { + +class SharedArrayBuffer; + +#ifndef V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT +// The number of required internal fields can be defined by embedder. +#define V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT 2 +#endif + +enum class ArrayBufferCreationMode { kInternalized, kExternalized }; + +/** + * A wrapper around the backing store (i.e. the raw memory) of an array buffer. + * See a document linked in http://crbug.com/v8/9908 for more information. + * + * The allocation and destruction of backing stores is generally managed by + * V8. Clients should always use standard C++ memory ownership types (i.e. + * std::unique_ptr and std::shared_ptr) to manage lifetimes of backing stores + * properly, since V8 internal objects may alias backing stores. + * + * This object does not keep the underlying |ArrayBuffer::Allocator| alive by + * default. Use Isolate::CreateParams::array_buffer_allocator_shared when + * creating the Isolate to make it hold a reference to the allocator itself. + */ +class V8_EXPORT BackingStore : public v8::internal::BackingStoreBase { + public: + ~BackingStore(); + + /** + * Return a pointer to the beginning of the memory block for this backing + * store. The pointer is only valid as long as this backing store object + * lives. + */ + void* Data() const; + + /** + * The length (in bytes) of this backing store. + */ + size_t ByteLength() const; + + /** + * The maximum length (in bytes) that this backing store may grow to. + * + * If this backing store was created for a resizable ArrayBuffer or a growable + * SharedArrayBuffer, it is >= ByteLength(). Otherwise it is == + * ByteLength(). + */ + size_t MaxByteLength() const; + + /** + * Indicates whether the backing store was created for an ArrayBuffer or + * a SharedArrayBuffer. + */ + bool IsShared() const; + + /** + * Indicates whether the backing store was created for a resizable ArrayBuffer + * or a growable SharedArrayBuffer, and thus may be resized by user JavaScript + * code. + */ + bool IsResizableByUserJavaScript() const; + + /** + * Prevent implicit instantiation of operator delete with size_t argument. + * The size_t argument would be incorrect because ptr points to the + * internal BackingStore object. + */ + void operator delete(void* ptr) { ::operator delete(ptr); } + + /** + * Wrapper around ArrayBuffer::Allocator::Reallocate that preserves IsShared. + * Assumes that the backing_store was allocated by the ArrayBuffer allocator + * of the given isolate. + */ + static std::unique_ptr Reallocate( + v8::Isolate* isolate, std::unique_ptr backing_store, + size_t byte_length); + + /** + * This callback is used only if the memory block for a BackingStore cannot be + * allocated with an ArrayBuffer::Allocator. In such cases the destructor of + * the BackingStore invokes the callback to free the memory block. + */ + using DeleterCallback = void (*)(void* data, size_t length, + void* deleter_data); + + /** + * If the memory block of a BackingStore is static or is managed manually, + * then this empty deleter along with nullptr deleter_data can be passed to + * ArrayBuffer::NewBackingStore to indicate that. + * + * The manually managed case should be used with caution and only when it + * is guaranteed that the memory block freeing happens after detaching its + * ArrayBuffer. + */ + static void EmptyDeleter(void* data, size_t length, void* deleter_data); + + private: + /** + * See [Shared]ArrayBuffer::GetBackingStore and + * [Shared]ArrayBuffer::NewBackingStore. + */ + BackingStore(); +}; + +#if !defined(V8_IMMINENT_DEPRECATION_WARNINGS) +// Use v8::BackingStore::DeleterCallback instead. +using BackingStoreDeleterCallback = void (*)(void* data, size_t length, + void* deleter_data); + +#endif + +/** + * An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5). + */ +class V8_EXPORT ArrayBuffer : public Object { + public: + /** + * A thread-safe allocator that V8 uses to allocate |ArrayBuffer|'s memory. + * The allocator is a global V8 setting. It has to be set via + * Isolate::CreateParams. + * + * Memory allocated through this allocator by V8 is accounted for as external + * memory by V8. Note that V8 keeps track of the memory for all internalized + * |ArrayBuffer|s. Responsibility for tracking external memory (using + * Isolate::AdjustAmountOfExternalAllocatedMemory) is handed over to the + * embedder upon externalization and taken over upon internalization (creating + * an internalized buffer from an existing buffer). + * + * Note that it is unsafe to call back into V8 from any of the allocator + * functions. + */ + class V8_EXPORT Allocator { + public: + virtual ~Allocator() = default; + + /** + * Allocate |length| bytes. Return nullptr if allocation is not successful. + * Memory should be initialized to zeroes. + */ + virtual void* Allocate(size_t length) = 0; + + /** + * Allocate |length| bytes. Return nullptr if allocation is not successful. + * Memory does not have to be initialized. + */ + virtual void* AllocateUninitialized(size_t length) = 0; + + /** + * Free the memory block of size |length|, pointed to by |data|. + * That memory is guaranteed to be previously allocated by |Allocate|. + */ + virtual void Free(void* data, size_t length) = 0; + + /** + * Reallocate the memory block of size |old_length| to a memory block of + * size |new_length| by expanding, contracting, or copying the existing + * memory block. If |new_length| > |old_length|, then the new part of + * the memory must be initialized to zeros. Return nullptr if reallocation + * is not successful. + * + * The caller guarantees that the memory block was previously allocated + * using Allocate or AllocateUninitialized. + * + * The default implementation allocates a new block and copies data. + */ + virtual void* Reallocate(void* data, size_t old_length, size_t new_length); + + /** + * ArrayBuffer allocation mode. kNormal is a malloc/free style allocation, + * while kReservation is for larger allocations with the ability to set + * access permissions. + */ + enum class AllocationMode { kNormal, kReservation }; + + /** + * Convenience allocator. + * + * When the sandbox is enabled, this allocator will allocate its backing + * memory inside the sandbox. Otherwise, it will rely on malloc/free. + * + * Caller takes ownership, i.e. the returned object needs to be freed using + * |delete allocator| once it is no longer in use. + */ + static Allocator* NewDefaultAllocator(); + }; + + /** + * Data length in bytes. + */ + size_t ByteLength() const; + + /** + * Maximum length in bytes. + */ + size_t MaxByteLength() const; + + /** + * Create a new ArrayBuffer. Allocate |byte_length| bytes. + * Allocated memory will be owned by a created ArrayBuffer and + * will be deallocated when it is garbage-collected, + * unless the object is externalized. + */ + static Local New(Isolate* isolate, size_t byte_length); + + /** + * Create a new ArrayBuffer with an existing backing store. + * The created array keeps a reference to the backing store until the array + * is garbage collected. Note that the IsExternal bit does not affect this + * reference from the array to the backing store. + * + * In future IsExternal bit will be removed. Until then the bit is set as + * follows. If the backing store does not own the underlying buffer, then + * the array is created in externalized state. Otherwise, the array is created + * in internalized state. In the latter case the array can be transitioned + * to the externalized state using Externalize(backing_store). + */ + static Local New(Isolate* isolate, + std::shared_ptr backing_store); + + /** + * Returns a new standalone BackingStore that is allocated using the array + * buffer allocator of the isolate. The result can be later passed to + * ArrayBuffer::New. + * + * If the allocator returns nullptr, then the function may cause GCs in the + * given isolate and re-try the allocation. If GCs do not help, then the + * function will crash with an out-of-memory error. + */ + static std::unique_ptr NewBackingStore(Isolate* isolate, + size_t byte_length); + /** + * Returns a new standalone BackingStore that takes over the ownership of + * the given buffer. The destructor of the BackingStore invokes the given + * deleter callback. + * + * The result can be later passed to ArrayBuffer::New. The raw pointer + * to the buffer must not be passed again to any V8 API function. + */ + static std::unique_ptr NewBackingStore( + void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter, + void* deleter_data); + + /** + * Returns a new resizable standalone BackingStore that is allocated using the + * array buffer allocator of the isolate. The result can be later passed to + * ArrayBuffer::New. + * + * |byte_length| must be <= |max_byte_length|. + * + * This function is usable without an isolate. Unlike |NewBackingStore| calls + * with an isolate, GCs cannot be triggered, and there are no + * retries. Allocation failure will cause the function to crash with an + * out-of-memory error. + */ + static std::unique_ptr NewResizableBackingStore( + size_t byte_length, size_t max_byte_length); + + /** + * Returns true if this ArrayBuffer may be detached. + */ + bool IsDetachable() const; + + /** + * Returns true if this ArrayBuffer has been detached. + */ + bool WasDetached() const; + + /** + * Detaches this ArrayBuffer and all its views (typed arrays). + * Detaching sets the byte length of the buffer and all typed arrays to zero, + * preventing JavaScript from ever accessing underlying backing store. + * ArrayBuffer should have been externalized and must be detachable. + */ + V8_DEPRECATE_SOON( + "Use the version which takes a key parameter (passing a null handle is " + "ok).") + void Detach(); + + /** + * Detaches this ArrayBuffer and all its views (typed arrays). + * Detaching sets the byte length of the buffer and all typed arrays to zero, + * preventing JavaScript from ever accessing underlying backing store. + * ArrayBuffer should have been externalized and must be detachable. Returns + * Nothing if the key didn't pass the [[ArrayBufferDetachKey]] check, + * Just(true) otherwise. + */ + V8_WARN_UNUSED_RESULT Maybe Detach(v8::Local key); + + /** + * Sets the ArrayBufferDetachKey. + */ + void SetDetachKey(v8::Local key); + + /** + * Get a shared pointer to the backing store of this array buffer. This + * pointer coordinates the lifetime management of the internal storage + * with any live ArrayBuffers on the heap, even across isolates. The embedder + * should not attempt to manage lifetime of the storage through other means. + * + * The returned shared pointer will not be empty, even if the ArrayBuffer has + * been detached. Use |WasDetached| to tell if it has been detached instead. + */ + std::shared_ptr GetBackingStore(); + + /** + * More efficient shortcut for GetBackingStore()->Data(). The returned pointer + * is valid as long as the ArrayBuffer is alive. + */ + void* Data() const; + + V8_INLINE static ArrayBuffer* Cast(Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); + } + + static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; + static const int kEmbedderFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; + + private: + ArrayBuffer(); + static void CheckCast(Value* obj); +}; + +#ifndef V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT +// The number of required internal fields can be defined by embedder. +#define V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT 2 +#endif + +/** + * A base class for an instance of one of "views" over ArrayBuffer, + * including TypedArrays and DataView (ES6 draft 15.13). + */ +class V8_EXPORT ArrayBufferView : public Object { + public: + /** + * Returns underlying ArrayBuffer. + */ + Local Buffer(); + /** + * Byte offset in |Buffer|. + */ + size_t ByteOffset(); + /** + * Size of a view in bytes. + */ + size_t ByteLength(); + + /** + * Copy the contents of the ArrayBufferView's buffer to an embedder defined + * memory without additional overhead that calling ArrayBufferView::Buffer + * might incur. + * + * Will write at most min(|byte_length|, ByteLength) bytes starting at + * ByteOffset of the underlying buffer to the memory starting at |dest|. + * Returns the number of bytes actually written. + */ + size_t CopyContents(void* dest, size_t byte_length); + + /** + * Returns true if ArrayBufferView's backing ArrayBuffer has already been + * allocated. + */ + bool HasBuffer() const; + + V8_INLINE static ArrayBufferView* Cast(Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); + } + + static const int kInternalFieldCount = + V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT; + static const int kEmbedderFieldCount = + V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT; + + private: + ArrayBufferView(); + static void CheckCast(Value* obj); +}; + +/** + * An instance of DataView constructor (ES6 draft 15.13.7). + */ +class V8_EXPORT DataView : public ArrayBufferView { + public: + static Local New(Local array_buffer, + size_t byte_offset, size_t length); + static Local New(Local shared_array_buffer, + size_t byte_offset, size_t length); + V8_INLINE static DataView* Cast(Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); + } + + private: + DataView(); + static void CheckCast(Value* obj); +}; + +/** + * An instance of the built-in SharedArrayBuffer constructor. + */ +class V8_EXPORT SharedArrayBuffer : public Object { + public: + /** + * Data length in bytes. + */ + size_t ByteLength() const; + + /** + * Maximum length in bytes. + */ + size_t MaxByteLength() const; + + /** + * Create a new SharedArrayBuffer. Allocate |byte_length| bytes. + * Allocated memory will be owned by a created SharedArrayBuffer and + * will be deallocated when it is garbage-collected, + * unless the object is externalized. + */ + static Local New(Isolate* isolate, size_t byte_length); + + /** + * Create a new SharedArrayBuffer with an existing backing store. + * The created array keeps a reference to the backing store until the array + * is garbage collected. Note that the IsExternal bit does not affect this + * reference from the array to the backing store. + * + * In future IsExternal bit will be removed. Until then the bit is set as + * follows. If the backing store does not own the underlying buffer, then + * the array is created in externalized state. Otherwise, the array is created + * in internalized state. In the latter case the array can be transitioned + * to the externalized state using Externalize(backing_store). + */ + static Local New( + Isolate* isolate, std::shared_ptr backing_store); + + /** + * Returns a new standalone BackingStore that is allocated using the array + * buffer allocator of the isolate. The result can be later passed to + * SharedArrayBuffer::New. + * + * If the allocator returns nullptr, then the function may cause GCs in the + * given isolate and re-try the allocation. If GCs do not help, then the + * function will crash with an out-of-memory error. + */ + static std::unique_ptr NewBackingStore(Isolate* isolate, + size_t byte_length); + /** + * Returns a new standalone BackingStore that takes over the ownership of + * the given buffer. The destructor of the BackingStore invokes the given + * deleter callback. + * + * The result can be later passed to SharedArrayBuffer::New. The raw pointer + * to the buffer must not be passed again to any V8 functions. + */ + static std::unique_ptr NewBackingStore( + void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter, + void* deleter_data); + + /** + * Get a shared pointer to the backing store of this array buffer. This + * pointer coordinates the lifetime management of the internal storage + * with any live ArrayBuffers on the heap, even across isolates. The embedder + * should not attempt to manage lifetime of the storage through other means. + */ + std::shared_ptr GetBackingStore(); + + /** + * More efficient shortcut for GetBackingStore()->Data(). The returned pointer + * is valid as long as the ArrayBuffer is alive. + */ + void* Data() const; + + V8_INLINE static SharedArrayBuffer* Cast(Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); + } + + static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; + + private: + SharedArrayBuffer(); + static void CheckCast(Value* obj); +}; + +} // namespace v8 + +#endif // INCLUDE_V8_ARRAY_BUFFER_H_ diff --git a/NativeScript/napi/v8/include_old/v8-callbacks.h b/NativeScript/napi/v8/include_old/v8-callbacks.h new file mode 100644 index 00000000..2a25b9ee --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-callbacks.h @@ -0,0 +1,468 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_ISOLATE_CALLBACKS_H_ +#define INCLUDE_V8_ISOLATE_CALLBACKS_H_ + +#include + +#include +#include + +#include "cppgc/common.h" +#include "v8-data.h" // NOLINT(build/include_directory) +#include "v8-local-handle.h" // NOLINT(build/include_directory) +#include "v8-promise.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +#if defined(V8_OS_WIN) +struct _EXCEPTION_POINTERS; +#endif + +namespace v8 { + +template +class FunctionCallbackInfo; +class Isolate; +class Message; +class Module; +class Object; +class Promise; +class ScriptOrModule; +class String; +class UnboundScript; +class Value; + +/** + * A JIT code event is issued each time code is added, moved or removed. + * + * \note removal events are not currently issued. + */ +struct JitCodeEvent { + enum EventType { + CODE_ADDED, + CODE_MOVED, + CODE_REMOVED, + CODE_ADD_LINE_POS_INFO, + CODE_START_LINE_INFO_RECORDING, + CODE_END_LINE_INFO_RECORDING + }; + // Definition of the code position type. The "POSITION" type means the place + // in the source code which are of interest when making stack traces to + // pin-point the source location of a stack frame as close as possible. + // The "STATEMENT_POSITION" means the place at the beginning of each + // statement, and is used to indicate possible break locations. + enum PositionType { POSITION, STATEMENT_POSITION }; + + // There are three different kinds of CodeType, one for JIT code generated + // by the optimizing compiler, one for byte code generated for the + // interpreter, and one for code generated from Wasm. For JIT_CODE and + // WASM_CODE, |code_start| points to the beginning of jitted assembly code, + // while for BYTE_CODE events, |code_start| points to the first bytecode of + // the interpreted function. + enum CodeType { BYTE_CODE, JIT_CODE, WASM_CODE }; + + // Type of event. + EventType type; + CodeType code_type; + // Start of the instructions. + void* code_start; + // Size of the instructions. + size_t code_len; + // Script info for CODE_ADDED event. + Local script; + // User-defined data for *_LINE_INFO_* event. It's used to hold the source + // code line information which is returned from the + // CODE_START_LINE_INFO_RECORDING event. And it's passed to subsequent + // CODE_ADD_LINE_POS_INFO and CODE_END_LINE_INFO_RECORDING events. + void* user_data; + + struct name_t { + // Name of the object associated with the code, note that the string is not + // zero-terminated. + const char* str; + // Number of chars in str. + size_t len; + }; + + struct line_info_t { + // PC offset + size_t offset; + // Code position + size_t pos; + // The position type. + PositionType position_type; + }; + + struct wasm_source_info_t { + // Source file name. + const char* filename; + // Length of filename. + size_t filename_size; + // Line number table, which maps offsets of JITted code to line numbers of + // source file. + const line_info_t* line_number_table; + // Number of entries in the line number table. + size_t line_number_table_size; + }; + + wasm_source_info_t* wasm_source_info = nullptr; + + union { + // Only valid for CODE_ADDED. + struct name_t name; + + // Only valid for CODE_ADD_LINE_POS_INFO + struct line_info_t line_info; + + // New location of instructions. Only valid for CODE_MOVED. + void* new_code_start; + }; + + Isolate* isolate; +}; + +/** + * Option flags passed to the SetJitCodeEventHandler function. + */ +enum JitCodeEventOptions { + kJitCodeEventDefault = 0, + // Generate callbacks for already existent code. + kJitCodeEventEnumExisting = 1 +}; + +/** + * Callback function passed to SetJitCodeEventHandler. + * + * \param event code add, move or removal event. + */ +using JitCodeEventHandler = void (*)(const JitCodeEvent* event); + +// --- Garbage Collection Callbacks --- + +/** + * Applications can register callback functions which will be called before and + * after certain garbage collection operations. Allocations are not allowed in + * the callback functions, you therefore cannot manipulate objects (set or + * delete properties for example) since it is possible such operations will + * result in the allocation of objects. + * TODO(v8:12612): Deprecate kGCTypeMinorMarkSweep after updating blink. + */ +enum GCType { + kGCTypeScavenge = 1 << 0, + kGCTypeMinorMarkSweep = 1 << 1, + kGCTypeMinorMarkCompact V8_DEPRECATE_SOON( + "Use kGCTypeMinorMarkSweep instead of kGCTypeMinorMarkCompact.") = + kGCTypeMinorMarkSweep, + kGCTypeMarkSweepCompact = 1 << 2, + kGCTypeIncrementalMarking = 1 << 3, + kGCTypeProcessWeakCallbacks = 1 << 4, + kGCTypeAll = kGCTypeScavenge | kGCTypeMinorMarkSweep | + kGCTypeMarkSweepCompact | kGCTypeIncrementalMarking | + kGCTypeProcessWeakCallbacks +}; + +/** + * GCCallbackFlags is used to notify additional information about the GC + * callback. + * - kGCCallbackFlagConstructRetainedObjectInfos: The GC callback is for + * constructing retained object infos. + * - kGCCallbackFlagForced: The GC callback is for a forced GC for testing. + * - kGCCallbackFlagSynchronousPhantomCallbackProcessing: The GC callback + * is called synchronously without getting posted to an idle task. + * - kGCCallbackFlagCollectAllAvailableGarbage: The GC callback is called + * in a phase where V8 is trying to collect all available garbage + * (e.g., handling a low memory notification). + * - kGCCallbackScheduleIdleGarbageCollection: The GC callback is called to + * trigger an idle garbage collection. + */ +enum GCCallbackFlags { + kNoGCCallbackFlags = 0, + kGCCallbackFlagConstructRetainedObjectInfos = 1 << 1, + kGCCallbackFlagForced = 1 << 2, + kGCCallbackFlagSynchronousPhantomCallbackProcessing = 1 << 3, + kGCCallbackFlagCollectAllAvailableGarbage = 1 << 4, + kGCCallbackFlagCollectAllExternalMemory = 1 << 5, + kGCCallbackScheduleIdleGarbageCollection = 1 << 6, +}; + +using GCCallback = void (*)(GCType type, GCCallbackFlags flags); + +using InterruptCallback = void (*)(Isolate* isolate, void* data); + +/** + * This callback is invoked when the heap size is close to the heap limit and + * V8 is likely to abort with out-of-memory error. + * The callback can extend the heap limit by returning a value that is greater + * than the current_heap_limit. The initial heap limit is the limit that was + * set after heap setup. + */ +using NearHeapLimitCallback = size_t (*)(void* data, size_t current_heap_limit, + size_t initial_heap_limit); + +/** + * Callback function passed to SetUnhandledExceptionCallback. + */ +#if defined(V8_OS_WIN) +using UnhandledExceptionCallback = + int (*)(_EXCEPTION_POINTERS* exception_pointers); +#endif + +// --- Counters Callbacks --- + +using CounterLookupCallback = int* (*)(const char* name); + +using CreateHistogramCallback = void* (*)(const char* name, int min, int max, + size_t buckets); + +using AddHistogramSampleCallback = void (*)(void* histogram, int sample); + +// --- Exceptions --- + +using FatalErrorCallback = void (*)(const char* location, const char* message); + +struct OOMDetails { + bool is_heap_oom = false; + const char* detail = nullptr; +}; + +using OOMErrorCallback = void (*)(const char* location, + const OOMDetails& details); + +using MessageCallback = void (*)(Local message, Local data); + +// --- Tracing --- + +enum LogEventStatus : int { kStart = 0, kEnd = 1, kStamp = 2 }; +using LogEventCallback = void (*)(const char* name, + int /* LogEventStatus */ status); + +// --- Crashkeys Callback --- +enum class CrashKeyId { + kIsolateAddress, + kReadonlySpaceFirstPageAddress, + kMapSpaceFirstPageAddress V8_ENUM_DEPRECATE_SOON("Map space got removed"), + kOldSpaceFirstPageAddress, + kCodeRangeBaseAddress, + kCodeSpaceFirstPageAddress, + kDumpType, + kSnapshotChecksumCalculated, + kSnapshotChecksumExpected, +}; + +using AddCrashKeyCallback = void (*)(CrashKeyId id, const std::string& value); + +// --- Enter/Leave Script Callback --- +using BeforeCallEnteredCallback = void (*)(Isolate*); +using CallCompletedCallback = void (*)(Isolate*); + +// --- AllowCodeGenerationFromStrings callbacks --- + +/** + * Callback to check if code generation from strings is allowed. See + * Context::AllowCodeGenerationFromStrings. + */ +using AllowCodeGenerationFromStringsCallback = bool (*)(Local context, + Local source); + +struct ModifyCodeGenerationFromStringsResult { + // If true, proceed with the codegen algorithm. Otherwise, block it. + bool codegen_allowed = false; + // Overwrite the original source with this string, if present. + // Use the original source if empty. + // This field is considered only if codegen_allowed is true. + MaybeLocal modified_source; +}; + +/** + * Access type specification. + */ +enum AccessType { + ACCESS_GET, + ACCESS_SET, + ACCESS_HAS, + ACCESS_DELETE, + ACCESS_KEYS +}; + +// --- Failed Access Check Callback --- + +using FailedAccessCheckCallback = void (*)(Local target, + AccessType type, Local data); + +/** + * Callback to check if codegen is allowed from a source object, and convert + * the source to string if necessary. See: ModifyCodeGenerationFromStrings. + */ +using ModifyCodeGenerationFromStringsCallback = + ModifyCodeGenerationFromStringsResult (*)(Local context, + Local source); +using ModifyCodeGenerationFromStringsCallback2 = + ModifyCodeGenerationFromStringsResult (*)(Local context, + Local source, + bool is_code_like); + +// --- WebAssembly compilation callbacks --- +using ExtensionCallback = bool (*)(const FunctionCallbackInfo&); + +using AllowWasmCodeGenerationCallback = bool (*)(Local context, + Local source); + +// --- Callback for APIs defined on v8-supported objects, but implemented +// by the embedder. Example: WebAssembly.{compile|instantiate}Streaming --- +using ApiImplementationCallback = void (*)(const FunctionCallbackInfo&); + +// --- Callback for WebAssembly.compileStreaming --- +using WasmStreamingCallback = void (*)(const FunctionCallbackInfo&); + +enum class WasmAsyncSuccess { kSuccess, kFail }; + +// --- Callback called when async WebAssembly operations finish --- +using WasmAsyncResolvePromiseCallback = void (*)( + Isolate* isolate, Local context, Local resolver, + Local result, WasmAsyncSuccess success); + +// --- Callback for loading source map file for Wasm profiling support +using WasmLoadSourceMapCallback = Local (*)(Isolate* isolate, + const char* name); + +// --- Callback for checking if WebAssembly GC is enabled --- +// If the callback returns true, it will also enable Wasm stringrefs. +using WasmGCEnabledCallback = bool (*)(Local context); + +// --- Callback for checking if WebAssembly imported strings are enabled --- +using WasmImportedStringsEnabledCallback = bool (*)(Local context); + +// --- Callback for checking if the SharedArrayBuffer constructor is enabled --- +using SharedArrayBufferConstructorEnabledCallback = + bool (*)(Local context); + +// --- Callback for checking if the compile hints magic comments are enabled --- +using JavaScriptCompileHintsMagicEnabledCallback = + bool (*)(Local context); + +/** + * HostImportModuleDynamicallyCallback is called when we + * require the embedder to load a module. This is used as part of the dynamic + * import syntax. + * + * The referrer contains metadata about the script/module that calls + * import. + * + * The specifier is the name of the module that should be imported. + * + * The import_assertions are import assertions for this request in the form: + * [key1, value1, key2, value2, ...] where the keys and values are of type + * v8::String. Note, unlike the FixedArray passed to ResolveModuleCallback and + * returned from ModuleRequest::GetImportAssertions(), this array does not + * contain the source Locations of the assertions. + * + * The embedder must compile, instantiate, evaluate the Module, and + * obtain its namespace object. + * + * The Promise returned from this function is forwarded to userland + * JavaScript. The embedder must resolve this promise with the module + * namespace object. In case of an exception, the embedder must reject + * this promise with the exception. If the promise creation itself + * fails (e.g. due to stack overflow), the embedder must propagate + * that exception by returning an empty MaybeLocal. + */ +using HostImportModuleDynamicallyWithImportAssertionsCallback = + MaybeLocal (*)(Local context, + Local referrer, + Local specifier, + Local import_assertions); +using HostImportModuleDynamicallyCallback = MaybeLocal (*)( + Local context, Local host_defined_options, + Local resource_name, Local specifier, + Local import_assertions); + +/** + * Callback for requesting a compile hint for a function from the embedder. The + * first parameter is the position of the function in source code and the second + * parameter is embedder data to be passed back. + */ +using CompileHintCallback = bool (*)(int, void*); + +/** + * HostInitializeImportMetaObjectCallback is called the first time import.meta + * is accessed for a module. Subsequent access will reuse the same value. + * + * The method combines two implementation-defined abstract operations into one: + * HostGetImportMetaProperties and HostFinalizeImportMeta. + * + * The embedder should use v8::Object::CreateDataProperty to add properties on + * the meta object. + */ +using HostInitializeImportMetaObjectCallback = void (*)(Local context, + Local module, + Local meta); + +/** + * HostCreateShadowRealmContextCallback is called each time a ShadowRealm is + * being constructed in the initiator_context. + * + * The method combines Context creation and implementation defined abstract + * operation HostInitializeShadowRealm into one. + * + * The embedder should use v8::Context::New or v8::Context:NewFromSnapshot to + * create a new context. If the creation fails, the embedder must propagate + * that exception by returning an empty MaybeLocal. + */ +using HostCreateShadowRealmContextCallback = + MaybeLocal (*)(Local initiator_context); + +/** + * PrepareStackTraceCallback is called when the stack property of an error is + * first accessed. The return value will be used as the stack value. If this + * callback is registed, the |Error.prepareStackTrace| API will be disabled. + * |sites| is an array of call sites, specified in + * https://v8.dev/docs/stack-trace-api + */ +using PrepareStackTraceCallback = MaybeLocal (*)(Local context, + Local error, + Local sites); + +#if defined(V8_OS_WIN) +/** + * Callback to selectively enable ETW tracing based on the document URL. + * Implemented by the embedder, it should never call back into V8. + * + * Windows allows passing additional data to the ETW EnableCallback: + * https://learn.microsoft.com/en-us/windows/win32/api/evntprov/nc-evntprov-penablecallback + * + * This data can be configured in a WPR (Windows Performance Recorder) + * profile, adding a CustomFilter to an EventProvider like the following: + * + * + * + * + * + * Where: + * - Name="57277741-3638-4A4B-BDBA-0AC6E45DA56C" is the GUID of the V8 + * ETW provider, (see src/libplatform/etw/etw-provider-win.h), + * - Type="0x80000000" is EVENT_FILTER_TYPE_SCHEMATIZED, + * - Value="AQABAAAAAA..." is a base64-encoded byte array that is + * base64-decoded by Windows and passed to the ETW enable callback in + * the 'PEVENT_FILTER_DESCRIPTOR FilterData' argument; see: + * https://learn.microsoft.com/en-us/windows/win32/api/evntprov/ns-evntprov-event_filter_descriptor. + * + * This array contains a struct EVENT_FILTER_HEADER followed by a + * variable length payload, and as payload we pass a string in JSON format, + * with a list of regular expressions that should match the document URL + * in order to enable ETW tracing: + * { + * "version": "1.0", + * "filtered_urls": [ + * "https:\/\/.*\.chromium\.org\/.*", "https://v8.dev/";, "..." + * ] + * } + */ +using FilterETWSessionByURLCallback = + bool (*)(Local context, const std::string& etw_filter_payload); +#endif // V8_OS_WIN + +} // namespace v8 + +#endif // INCLUDE_V8_ISOLATE_CALLBACKS_H_ diff --git a/NativeScript/napi/v8/include_old/v8-container.h b/NativeScript/napi/v8/include_old/v8-container.h new file mode 100644 index 00000000..1d9e72c1 --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-container.h @@ -0,0 +1,165 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_CONTAINER_H_ +#define INCLUDE_V8_CONTAINER_H_ + +#include +#include + +#include "v8-local-handle.h" // NOLINT(build/include_directory) +#include "v8-object.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { + +class Context; +class Isolate; + +/** + * An instance of the built-in array constructor (ECMA-262, 15.4.2). + */ +class V8_EXPORT Array : public Object { + public: + uint32_t Length() const; + + /** + * Creates a JavaScript array with the given length. If the length + * is negative the returned array will have length 0. + */ + static Local New(Isolate* isolate, int length = 0); + + /** + * Creates a JavaScript array out of a Local array in C++ + * with a known length. + */ + static Local New(Isolate* isolate, Local* elements, + size_t length); + V8_INLINE static Array* Cast(Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); + } + + enum class CallbackResult { + kException, + kBreak, + kContinue, + }; + using IterationCallback = CallbackResult (*)(uint32_t index, + Local element, + void* data); + + /** + * Calls {callback} for every element of this array, passing {callback_data} + * as its {data} parameter. + * This function will typically be faster than calling {Get()} repeatedly. + * As a consequence of being optimized for low overhead, the provided + * callback must adhere to the following restrictions: + * - It must not allocate any V8 objects and continue iterating; it may + * allocate (e.g. an error message/object) and then immediately terminate + * the iteration. + * - It must not modify the array being iterated. + * - It must not call back into V8 (unless it can guarantee that such a + * call does not violate the above restrictions, which is difficult). + * - The {Local element} must not "escape", i.e. must not be assigned + * to any other {Local}. Creating a {Global} from it, or updating a + * v8::TypecheckWitness with it, is safe. + * These restrictions may be lifted in the future if use cases arise that + * justify a slower but more robust implementation. + * + * Returns {Nothing} on exception; use a {TryCatch} to catch and handle this + * exception. + * When the {callback} returns {kException}, iteration is terminated + * immediately, returning {Nothing}. By returning {kBreak}, the callback + * can request non-exceptional early termination of the iteration. + */ + Maybe Iterate(Local context, IterationCallback callback, + void* callback_data); + + private: + Array(); + static void CheckCast(Value* obj); +}; + +/** + * An instance of the built-in Map constructor (ECMA-262, 6th Edition, 23.1.1). + */ +class V8_EXPORT Map : public Object { + public: + size_t Size() const; + void Clear(); + V8_WARN_UNUSED_RESULT MaybeLocal Get(Local context, + Local key); + V8_WARN_UNUSED_RESULT MaybeLocal Set(Local context, + Local key, + Local value); + V8_WARN_UNUSED_RESULT Maybe Has(Local context, + Local key); + V8_WARN_UNUSED_RESULT Maybe Delete(Local context, + Local key); + + /** + * Returns an array of length Size() * 2, where index N is the Nth key and + * index N + 1 is the Nth value. + */ + Local AsArray() const; + + /** + * Creates a new empty Map. + */ + static Local New(Isolate* isolate); + + V8_INLINE static Map* Cast(Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); + } + + private: + Map(); + static void CheckCast(Value* obj); +}; + +/** + * An instance of the built-in Set constructor (ECMA-262, 6th Edition, 23.2.1). + */ +class V8_EXPORT Set : public Object { + public: + size_t Size() const; + void Clear(); + V8_WARN_UNUSED_RESULT MaybeLocal Add(Local context, + Local key); + V8_WARN_UNUSED_RESULT Maybe Has(Local context, + Local key); + V8_WARN_UNUSED_RESULT Maybe Delete(Local context, + Local key); + + /** + * Returns an array of the keys in this Set. + */ + Local AsArray() const; + + /** + * Creates a new empty Set. + */ + static Local New(Isolate* isolate); + + V8_INLINE static Set* Cast(Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); + } + + private: + Set(); + static void CheckCast(Value* obj); +}; + +} // namespace v8 + +#endif // INCLUDE_V8_CONTAINER_H_ diff --git a/NativeScript/napi/v8/include_old/v8-context.h b/NativeScript/napi/v8/include_old/v8-context.h new file mode 100644 index 00000000..50c7e6f4 --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-context.h @@ -0,0 +1,456 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_CONTEXT_H_ +#define INCLUDE_V8_CONTEXT_H_ + +#include + +#include + +#include "v8-data.h" // NOLINT(build/include_directory) +#include "v8-local-handle.h" // NOLINT(build/include_directory) +#include "v8-maybe.h" // NOLINT(build/include_directory) +#include "v8-snapshot.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { + +class Function; +class MicrotaskQueue; +class Object; +class ObjectTemplate; +class Value; +class String; + +/** + * A container for extension names. + */ +class V8_EXPORT ExtensionConfiguration { + public: + ExtensionConfiguration() : name_count_(0), names_(nullptr) {} + ExtensionConfiguration(int name_count, const char* names[]) + : name_count_(name_count), names_(names) {} + + const char** begin() const { return &names_[0]; } + const char** end() const { return &names_[name_count_]; } + + private: + const int name_count_; + const char** names_; +}; + +/** + * A sandboxed execution context with its own set of built-in objects + * and functions. + */ +class V8_EXPORT Context : public Data { + public: + /** + * Returns the global proxy object. + * + * Global proxy object is a thin wrapper whose prototype points to actual + * context's global object with the properties like Object, etc. This is done + * that way for security reasons (for more details see + * https://wiki.mozilla.org/Gecko:SplitWindow). + * + * Please note that changes to global proxy object prototype most probably + * would break VM---v8 expects only global object as a prototype of global + * proxy object. + */ + Local Global(); + + /** + * Detaches the global object from its context before + * the global object can be reused to create a new context. + */ + void DetachGlobal(); + + /** + * Creates a new context and returns a handle to the newly allocated + * context. + * + * \param isolate The isolate in which to create the context. + * + * \param extensions An optional extension configuration containing + * the extensions to be installed in the newly created context. + * + * \param global_template An optional object template from which the + * global object for the newly created context will be created. + * + * \param global_object An optional global object to be reused for + * the newly created context. This global object must have been + * created by a previous call to Context::New with the same global + * template. The state of the global object will be completely reset + * and only object identify will remain. + */ + static Local New( + Isolate* isolate, ExtensionConfiguration* extensions = nullptr, + MaybeLocal global_template = MaybeLocal(), + MaybeLocal global_object = MaybeLocal(), + DeserializeInternalFieldsCallback internal_fields_deserializer = + DeserializeInternalFieldsCallback(), + MicrotaskQueue* microtask_queue = nullptr); + + /** + * Create a new context from a (non-default) context snapshot. There + * is no way to provide a global object template since we do not create + * a new global object from template, but we can reuse a global object. + * + * \param isolate See v8::Context::New. + * + * \param context_snapshot_index The index of the context snapshot to + * deserialize from. Use v8::Context::New for the default snapshot. + * + * \param embedder_fields_deserializer Optional callback to deserialize + * internal fields. It should match the SerializeInternalFieldCallback used + * to serialize. + * + * \param extensions See v8::Context::New. + * + * \param global_object See v8::Context::New. + */ + static MaybeLocal FromSnapshot( + Isolate* isolate, size_t context_snapshot_index, + DeserializeInternalFieldsCallback embedder_fields_deserializer = + DeserializeInternalFieldsCallback(), + ExtensionConfiguration* extensions = nullptr, + MaybeLocal global_object = MaybeLocal(), + MicrotaskQueue* microtask_queue = nullptr); + + /** + * Returns an global object that isn't backed by an actual context. + * + * The global template needs to have access checks with handlers installed. + * If an existing global object is passed in, the global object is detached + * from its context. + * + * Note that this is different from a detached context where all accesses to + * the global proxy will fail. Instead, the access check handlers are invoked. + * + * It is also not possible to detach an object returned by this method. + * Instead, the access check handlers need to return nothing to achieve the + * same effect. + * + * It is possible, however, to create a new context from the global object + * returned by this method. + */ + static MaybeLocal NewRemoteContext( + Isolate* isolate, Local global_template, + MaybeLocal global_object = MaybeLocal()); + + /** + * Sets the security token for the context. To access an object in + * another context, the security tokens must match. + */ + void SetSecurityToken(Local token); + + /** Restores the security token to the default value. */ + void UseDefaultSecurityToken(); + + /** Returns the security token of this context.*/ + Local GetSecurityToken(); + + /** + * Enter this context. After entering a context, all code compiled + * and run is compiled and run in this context. If another context + * is already entered, this old context is saved so it can be + * restored when the new context is exited. + */ + void Enter(); + + /** + * Exit this context. Exiting the current context restores the + * context that was in place when entering the current context. + */ + void Exit(); + + /** + * Delegate to help with Deep freezing embedder-specific objects (such as + * JSApiObjects) that can not be frozen natively. + */ + class DeepFreezeDelegate { + public: + /** + * Performs embedder-specific operations to freeze the provided embedder + * object. The provided object *will* be frozen by DeepFreeze after this + * function returns, so only embedder-specific objects need to be frozen. + * This function *may not* create new JS objects or perform JS allocations. + * Any v8 objects reachable from the provided embedder object that should + * also be considered for freezing should be added to the children_out + * parameter. Returns true if the operation completed successfully. + */ + virtual bool FreezeEmbedderObjectAndGetChildren( + Local obj, std::vector>& children_out) = 0; + }; + + /** + * Attempts to recursively freeze all objects reachable from this context. + * Some objects (generators, iterators, non-const closures) can not be frozen + * and will cause this method to throw an error. An optional delegate can be + * provided to help freeze embedder-specific objects. + * + * Freezing occurs in two steps: + * 1. "Marking" where we iterate through all objects reachable by this + * context, accumulating a list of objects that need to be frozen and + * looking for objects that can't be frozen. This step is separated because + * it is more efficient when we can assume there is no garbage collection. + * 2. "Freezing" where we go through the list of objects and freezing them. + * This effectively requires copying them so it may trigger garbage + * collection. + */ + Maybe DeepFreeze(DeepFreezeDelegate* delegate = nullptr); + + /** Returns the isolate associated with a current context. */ + Isolate* GetIsolate(); + + /** Returns the microtask queue associated with a current context. */ + MicrotaskQueue* GetMicrotaskQueue(); + + /** Sets the microtask queue associated with the current context. */ + void SetMicrotaskQueue(MicrotaskQueue* queue); + + /** + * The field at kDebugIdIndex used to be reserved for the inspector. + * It now serves no purpose. + */ + enum EmbedderDataFields { kDebugIdIndex = 0 }; + + /** + * Return the number of fields allocated for embedder data. + */ + uint32_t GetNumberOfEmbedderDataFields(); + + /** + * Gets the embedder data with the given index, which must have been set by a + * previous call to SetEmbedderData with the same index. + */ + V8_INLINE Local GetEmbedderData(int index); + + /** + * Gets the binding object used by V8 extras. Extra natives get a reference + * to this object and can use it to "export" functionality by adding + * properties. Extra natives can also "import" functionality by accessing + * properties added by the embedder using the V8 API. + */ + Local GetExtrasBindingObject(); + + /** + * Sets the embedder data with the given index, growing the data as + * needed. Note that index 0 currently has a special meaning for Chrome's + * debugger. + */ + void SetEmbedderData(int index, Local value); + + /** + * Gets a 2-byte-aligned native pointer from the embedder data with the given + * index, which must have been set by a previous call to + * SetAlignedPointerInEmbedderData with the same index. Note that index 0 + * currently has a special meaning for Chrome's debugger. + */ + V8_INLINE void* GetAlignedPointerFromEmbedderData(int index); + + /** + * Sets a 2-byte-aligned native pointer in the embedder data with the given + * index, growing the data as needed. Note that index 0 currently has a + * special meaning for Chrome's debugger. + */ + void SetAlignedPointerInEmbedderData(int index, void* value); + + /** + * Control whether code generation from strings is allowed. Calling + * this method with false will disable 'eval' and the 'Function' + * constructor for code running in this context. If 'eval' or the + * 'Function' constructor are used an exception will be thrown. + * + * If code generation from strings is not allowed the + * V8::AllowCodeGenerationFromStrings callback will be invoked if + * set before blocking the call to 'eval' or the 'Function' + * constructor. If that callback returns true, the call will be + * allowed, otherwise an exception will be thrown. If no callback is + * set an exception will be thrown. + */ + void AllowCodeGenerationFromStrings(bool allow); + + /** + * Returns true if code generation from strings is allowed for the context. + * For more details see AllowCodeGenerationFromStrings(bool) documentation. + */ + bool IsCodeGenerationFromStringsAllowed() const; + + /** + * Sets the error description for the exception that is thrown when + * code generation from strings is not allowed and 'eval' or the 'Function' + * constructor are called. + */ + void SetErrorMessageForCodeGenerationFromStrings(Local message); + + /** + * Sets the error description for the exception that is thrown when + * wasm code generation is not allowed. + */ + void SetErrorMessageForWasmCodeGeneration(Local message); + + /** + * Return data that was previously attached to the context snapshot via + * SnapshotCreator, and removes the reference to it. + * Repeated call with the same index returns an empty MaybeLocal. + */ + template + V8_INLINE MaybeLocal GetDataFromSnapshotOnce(size_t index); + + /** + * If callback is set, abort any attempt to execute JavaScript in this + * context, call the specified callback, and throw an exception. + * To unset abort, pass nullptr as callback. + */ + using AbortScriptExecutionCallback = void (*)(Isolate* isolate, + Local context); + void SetAbortScriptExecution(AbortScriptExecutionCallback callback); + + /** + * Returns the value that was set or restored by + * SetContinuationPreservedEmbedderData(), if any. + */ + Local GetContinuationPreservedEmbedderData() const; + + /** + * Sets a value that will be stored on continuations and reset while the + * continuation runs. + */ + void SetContinuationPreservedEmbedderData(Local context); + + /** + * Set or clear hooks to be invoked for promise lifecycle operations. + * To clear a hook, set it to an empty v8::Function. Each function will + * receive the observed promise as the first argument. If a chaining + * operation is used on a promise, the init will additionally receive + * the parent promise as the second argument. + */ + void SetPromiseHooks(Local init_hook, Local before_hook, + Local after_hook, + Local resolve_hook); + + bool HasTemplateLiteralObject(Local object); + /** + * Stack-allocated class which sets the execution context for all + * operations executed within a local scope. + */ + class V8_NODISCARD Scope { + public: + explicit V8_INLINE Scope(Local context) : context_(context) { + context_->Enter(); + } + V8_INLINE ~Scope() { context_->Exit(); } + + private: + Local context_; + }; + + /** + * Stack-allocated class to support the backup incumbent settings object + * stack. + * https://html.spec.whatwg.org/multipage/webappapis.html#backup-incumbent-settings-object-stack + */ + class V8_EXPORT V8_NODISCARD BackupIncumbentScope final { + public: + /** + * |backup_incumbent_context| is pushed onto the backup incumbent settings + * object stack. + */ + explicit BackupIncumbentScope(Local backup_incumbent_context); + ~BackupIncumbentScope(); + + private: + friend class internal::Isolate; + + uintptr_t JSStackComparableAddressPrivate() const { + return js_stack_comparable_address_; + } + + Local backup_incumbent_context_; + uintptr_t js_stack_comparable_address_ = 0; + const BackupIncumbentScope* prev_ = nullptr; + }; + + V8_INLINE static Context* Cast(Data* data); + + private: + friend class Value; + friend class Script; + friend class Object; + friend class Function; + + static void CheckCast(Data* obj); + + internal::Address* GetDataFromSnapshotOnce(size_t index); + Local SlowGetEmbedderData(int index); + void* SlowGetAlignedPointerFromEmbedderData(int index); +}; + +// --- Implementation --- + +Local Context::GetEmbedderData(int index) { +#ifndef V8_ENABLE_CHECKS + using A = internal::Address; + using I = internal::Internals; + A ctx = internal::ValueHelper::ValueAsAddress(this); + A embedder_data = + I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset); + int value_offset = + I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index); + A value = I::ReadRawField(embedder_data, value_offset); +#ifdef V8_COMPRESS_POINTERS + // We read the full pointer value and then decompress it in order to avoid + // dealing with potential endiannes issues. + value = I::DecompressTaggedField(embedder_data, static_cast(value)); +#endif + + auto isolate = reinterpret_cast( + internal::IsolateFromNeverReadOnlySpaceObject(ctx)); + return Local::New(isolate, value); +#else + return SlowGetEmbedderData(index); +#endif +} + +void* Context::GetAlignedPointerFromEmbedderData(int index) { +#if !defined(V8_ENABLE_CHECKS) + using A = internal::Address; + using I = internal::Internals; + A ctx = internal::ValueHelper::ValueAsAddress(this); + A embedder_data = + I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset); + int value_offset = I::kEmbedderDataArrayHeaderSize + + (I::kEmbedderDataSlotSize * index) + + I::kEmbedderDataSlotExternalPointerOffset; + Isolate* isolate = I::GetIsolateForSandbox(ctx); + return reinterpret_cast( + I::ReadExternalPointerField( + isolate, embedder_data, value_offset)); +#else + return SlowGetAlignedPointerFromEmbedderData(index); +#endif +} + +template +MaybeLocal Context::GetDataFromSnapshotOnce(size_t index) { + auto slot = GetDataFromSnapshotOnce(index); + if (slot) { + internal::PerformCastCheck( + internal::ValueHelper::SlotAsValue(slot)); + } + return Local::FromSlot(slot); +} + +Context* Context::Cast(v8::Data* data) { +#ifdef V8_ENABLE_CHECKS + CheckCast(data); +#endif + return static_cast(data); +} + +} // namespace v8 + +#endif // INCLUDE_V8_CONTEXT_H_ diff --git a/NativeScript/napi/v8/include_old/v8-cppgc.h b/NativeScript/napi/v8/include_old/v8-cppgc.h new file mode 100644 index 00000000..e0d76f45 --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-cppgc.h @@ -0,0 +1,245 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_CPPGC_H_ +#define INCLUDE_V8_CPPGC_H_ + +#include +#include +#include + +#include "cppgc/common.h" +#include "cppgc/custom-space.h" +#include "cppgc/heap-statistics.h" +#include "cppgc/visitor.h" +#include "v8-internal.h" // NOLINT(build/include_directory) +#include "v8-platform.h" // NOLINT(build/include_directory) +#include "v8-traced-handle.h" // NOLINT(build/include_directory) + +namespace cppgc { +class AllocationHandle; +class HeapHandle; +} // namespace cppgc + +namespace v8 { + +class Object; + +namespace internal { +class CppHeap; +} // namespace internal + +class CustomSpaceStatisticsReceiver; + +/** + * Describes how V8 wrapper objects maintain references to garbage-collected C++ + * objects. + */ +struct WrapperDescriptor final { + /** + * The index used on `v8::Ojbect::SetAlignedPointerFromInternalField()` and + * related APIs to add additional data to an object which is used to identify + * JS->C++ references. + */ + using InternalFieldIndex = int; + + /** + * Unknown embedder id. The value is reserved for internal usages and must not + * be used with `CppHeap`. + */ + static constexpr uint16_t kUnknownEmbedderId = UINT16_MAX; + + constexpr WrapperDescriptor(InternalFieldIndex wrappable_type_index, + InternalFieldIndex wrappable_instance_index, + uint16_t embedder_id_for_garbage_collected) + : wrappable_type_index(wrappable_type_index), + wrappable_instance_index(wrappable_instance_index), + embedder_id_for_garbage_collected(embedder_id_for_garbage_collected) {} + + /** + * Index of the wrappable type. + */ + InternalFieldIndex wrappable_type_index; + + /** + * Index of the wrappable instance. + */ + InternalFieldIndex wrappable_instance_index; + + /** + * Embedder id identifying instances of garbage-collected objects. It is + * expected that the first field of the wrappable type is a uint16_t holding + * the id. Only references to instances of wrappables types with an id of + * `embedder_id_for_garbage_collected` will be considered by CppHeap. + */ + uint16_t embedder_id_for_garbage_collected; +}; + +struct V8_EXPORT CppHeapCreateParams { + CppHeapCreateParams( + std::vector> custom_spaces, + WrapperDescriptor wrapper_descriptor) + : custom_spaces(std::move(custom_spaces)), + wrapper_descriptor(wrapper_descriptor) {} + + CppHeapCreateParams(const CppHeapCreateParams&) = delete; + CppHeapCreateParams& operator=(const CppHeapCreateParams&) = delete; + + std::vector> custom_spaces; + WrapperDescriptor wrapper_descriptor; + /** + * Specifies which kind of marking are supported by the heap. The type may be + * further reduced via runtime flags when attaching the heap to an Isolate. + */ + cppgc::Heap::MarkingType marking_support = + cppgc::Heap::MarkingType::kIncrementalAndConcurrent; + /** + * Specifies which kind of sweeping is supported by the heap. The type may be + * further reduced via runtime flags when attaching the heap to an Isolate. + */ + cppgc::Heap::SweepingType sweeping_support = + cppgc::Heap::SweepingType::kIncrementalAndConcurrent; +}; + +/** + * A heap for allocating managed C++ objects. + * + * Similar to v8::Isolate, the heap may only be accessed from one thread at a + * time. The heap may be used from different threads using the + * v8::Locker/v8::Unlocker APIs which is different from generic Oilpan. + */ +class V8_EXPORT CppHeap { + public: + static std::unique_ptr Create(v8::Platform* platform, + const CppHeapCreateParams& params); + + virtual ~CppHeap() = default; + + /** + * \returns the opaque handle for allocating objects using + * `MakeGarbageCollected()`. + */ + cppgc::AllocationHandle& GetAllocationHandle(); + + /** + * \returns the opaque heap handle which may be used to refer to this heap in + * other APIs. Valid as long as the underlying `CppHeap` is alive. + */ + cppgc::HeapHandle& GetHeapHandle(); + + /** + * Terminate clears all roots and performs multiple garbage collections to + * reclaim potentially newly created objects in destructors. + * + * After this call, object allocation is prohibited. + */ + void Terminate(); + + /** + * \param detail_level specifies whether should return detailed + * statistics or only brief summary statistics. + * \returns current CppHeap statistics regarding memory consumption + * and utilization. + */ + cppgc::HeapStatistics CollectStatistics( + cppgc::HeapStatistics::DetailLevel detail_level); + + /** + * Collects statistics for the given spaces and reports them to the receiver. + * + * \param custom_spaces a collection of custom space indicies. + * \param receiver an object that gets the results. + */ + void CollectCustomSpaceStatisticsAtLastGC( + std::vector custom_spaces, + std::unique_ptr receiver); + + /** + * Enables a detached mode that allows testing garbage collection using + * `cppgc::testing` APIs. Once used, the heap cannot be attached to an + * `Isolate` anymore. + */ + void EnableDetachedGarbageCollectionsForTesting(); + + /** + * Performs a stop-the-world garbage collection for testing purposes. + * + * \param stack_state The stack state to assume for the garbage collection. + */ + void CollectGarbageForTesting(cppgc::EmbedderStackState stack_state); + + /** + * Performs a stop-the-world minor garbage collection for testing purposes. + * + * \param stack_state The stack state to assume for the garbage collection. + */ + void CollectGarbageInYoungGenerationForTesting( + cppgc::EmbedderStackState stack_state); + + /** + * \returns the wrapper descriptor of this CppHeap. + */ + v8::WrapperDescriptor wrapper_descriptor() const; + + private: + CppHeap() = default; + + friend class internal::CppHeap; +}; + +class JSVisitor : public cppgc::Visitor { + public: + explicit JSVisitor(cppgc::Visitor::Key key) : cppgc::Visitor(key) {} + ~JSVisitor() override = default; + + void Trace(const TracedReferenceBase& ref) { + if (ref.IsEmptyThreadSafe()) return; + Visit(ref); + } + + protected: + using cppgc::Visitor::Visit; + + virtual void Visit(const TracedReferenceBase& ref) {} +}; + +/** + * Provided as input to `CppHeap::CollectCustomSpaceStatisticsAtLastGC()`. + * + * Its method is invoked with the results of the statistic collection. + */ +class CustomSpaceStatisticsReceiver { + public: + virtual ~CustomSpaceStatisticsReceiver() = default; + /** + * Reports the size of a space at the last GC. It is called for each space + * that was requested in `CollectCustomSpaceStatisticsAtLastGC()`. + * + * \param space_index The index of the space. + * \param bytes The total size of live objects in the space at the last GC. + * It is zero if there was no GC yet. + */ + virtual void AllocatedBytes(cppgc::CustomSpaceIndex space_index, + size_t bytes) = 0; +}; + +} // namespace v8 + +namespace cppgc { + +template +struct TraceTrait> { + static cppgc::TraceDescriptor GetTraceDescriptor(const void* self) { + return {nullptr, Trace}; + } + + static void Trace(Visitor* visitor, const void* self) { + static_cast(visitor)->Trace( + *static_cast*>(self)); + } +}; + +} // namespace cppgc + +#endif // INCLUDE_V8_CPPGC_H_ diff --git a/NativeScript/napi/v8/include_old/v8-data.h b/NativeScript/napi/v8/include_old/v8-data.h new file mode 100644 index 00000000..fc4dea92 --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-data.h @@ -0,0 +1,80 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_DATA_H_ +#define INCLUDE_V8_DATA_H_ + +#include "v8-local-handle.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { + +class Context; + +/** + * The superclass of objects that can reside on V8's heap. + */ +class V8_EXPORT Data { + public: + /** + * Returns true if this data is a |v8::Value|. + */ + bool IsValue() const; + + /** + * Returns true if this data is a |v8::Module|. + */ + bool IsModule() const; + + /** + * Returns tru if this data is a |v8::FixedArray| + */ + bool IsFixedArray() const; + + /** + * Returns true if this data is a |v8::Private|. + */ + bool IsPrivate() const; + + /** + * Returns true if this data is a |v8::ObjectTemplate|. + */ + bool IsObjectTemplate() const; + + /** + * Returns true if this data is a |v8::FunctionTemplate|. + */ + bool IsFunctionTemplate() const; + + /** + * Returns true if this data is a |v8::Context|. + */ + bool IsContext() const; + + private: + Data() = delete; +}; + +/** + * A fixed-sized array with elements of type Data. + */ +class V8_EXPORT FixedArray : public Data { + public: + int Length() const; + Local Get(Local context, int i) const; + + V8_INLINE static FixedArray* Cast(Data* data) { +#ifdef V8_ENABLE_CHECKS + CheckCast(data); +#endif + return reinterpret_cast(data); + } + + private: + static void CheckCast(Data* obj); +}; + +} // namespace v8 + +#endif // INCLUDE_V8_DATA_H_ diff --git a/NativeScript/napi/v8/include_old/v8-date.h b/NativeScript/napi/v8/include_old/v8-date.h new file mode 100644 index 00000000..8d82ccc9 --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-date.h @@ -0,0 +1,48 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_DATE_H_ +#define INCLUDE_V8_DATE_H_ + +#include "v8-local-handle.h" // NOLINT(build/include_directory) +#include "v8-object.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { + +class Context; + +/** + * An instance of the built-in Date constructor (ECMA-262, 15.9). + */ +class V8_EXPORT Date : public Object { + public: + static V8_WARN_UNUSED_RESULT MaybeLocal New(Local context, + double time); + + /** + * A specialization of Value::NumberValue that is more efficient + * because we know the structure of this object. + */ + double ValueOf() const; + + /** + * Generates ISO string representation. + */ + v8::Local ToISOString() const; + + V8_INLINE static Date* Cast(Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); + } + + private: + static void CheckCast(Value* obj); +}; + +} // namespace v8 + +#endif // INCLUDE_V8_DATE_H_ diff --git a/NativeScript/napi/v8/include_old/v8-debug.h b/NativeScript/napi/v8/include_old/v8-debug.h new file mode 100644 index 00000000..52255f37 --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-debug.h @@ -0,0 +1,168 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_DEBUG_H_ +#define INCLUDE_V8_DEBUG_H_ + +#include + +#include "v8-script.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { + +class Isolate; +class String; + +/** + * A single JavaScript stack frame. + */ +class V8_EXPORT StackFrame { + public: + /** + * Returns the source location, 0-based, for the associated function call. + */ + Location GetLocation() const; + + /** + * Returns the number, 1-based, of the line for the associate function call. + * This method will return Message::kNoLineNumberInfo if it is unable to + * retrieve the line number, or if kLineNumber was not passed as an option + * when capturing the StackTrace. + */ + int GetLineNumber() const { return GetLocation().GetLineNumber() + 1; } + + /** + * Returns the 1-based column offset on the line for the associated function + * call. + * This method will return Message::kNoColumnInfo if it is unable to retrieve + * the column number, or if kColumnOffset was not passed as an option when + * capturing the StackTrace. + */ + int GetColumn() const { return GetLocation().GetColumnNumber() + 1; } + + /** + * Returns the id of the script for the function for this StackFrame. + * This method will return Message::kNoScriptIdInfo if it is unable to + * retrieve the script id, or if kScriptId was not passed as an option when + * capturing the StackTrace. + */ + int GetScriptId() const; + + /** + * Returns the name of the resource that contains the script for the + * function for this StackFrame. + */ + Local GetScriptName() const; + + /** + * Returns the name of the resource that contains the script for the + * function for this StackFrame or sourceURL value if the script name + * is undefined and its source ends with //# sourceURL=... string or + * deprecated //@ sourceURL=... string. + */ + Local GetScriptNameOrSourceURL() const; + + /** + * Returns the source of the script for the function for this StackFrame. + */ + Local GetScriptSource() const; + + /** + * Returns the source mapping URL (if one is present) of the script for + * the function for this StackFrame. + */ + Local GetScriptSourceMappingURL() const; + + /** + * Returns the name of the function associated with this stack frame. + */ + Local GetFunctionName() const; + + /** + * Returns whether or not the associated function is compiled via a call to + * eval(). + */ + bool IsEval() const; + + /** + * Returns whether or not the associated function is called as a + * constructor via "new". + */ + bool IsConstructor() const; + + /** + * Returns whether or not the associated functions is defined in wasm. + */ + bool IsWasm() const; + + /** + * Returns whether or not the associated function is defined by the user. + */ + bool IsUserJavaScript() const; +}; + +/** + * Representation of a JavaScript stack trace. The information collected is a + * snapshot of the execution stack and the information remains valid after + * execution continues. + */ +class V8_EXPORT StackTrace { + public: + /** + * Flags that determine what information is placed captured for each + * StackFrame when grabbing the current stack trace. + * Note: these options are deprecated and we always collect all available + * information (kDetailed). + */ + enum StackTraceOptions { + kLineNumber = 1, + kColumnOffset = 1 << 1 | kLineNumber, + kScriptName = 1 << 2, + kFunctionName = 1 << 3, + kIsEval = 1 << 4, + kIsConstructor = 1 << 5, + kScriptNameOrSourceURL = 1 << 6, + kScriptId = 1 << 7, + kExposeFramesAcrossSecurityOrigins = 1 << 8, + kOverview = kLineNumber | kColumnOffset | kScriptName | kFunctionName, + kDetailed = kOverview | kIsEval | kIsConstructor | kScriptNameOrSourceURL + }; + + /** + * Returns a StackFrame at a particular index. + */ + Local GetFrame(Isolate* isolate, uint32_t index) const; + + /** + * Returns the number of StackFrames. + */ + int GetFrameCount() const; + + /** + * Grab a snapshot of the current JavaScript execution stack. + * + * \param frame_limit The maximum number of stack frames we want to capture. + * \param options Enumerates the set of things we will capture for each + * StackFrame. + */ + static Local CurrentStackTrace( + Isolate* isolate, int frame_limit, StackTraceOptions options = kDetailed); + + /** + * Returns the first valid script name or source URL starting at the top of + * the JS stack. The returned string is either an empty handle if no script + * name/url was found or a non-zero-length string. + * + * This method is equivalent to calling StackTrace::CurrentStackTrace and + * walking the resulting frames from the beginning until a non-empty script + * name/url is found. The difference is that this method won't allocate + * a stack trace. + */ + static Local CurrentScriptNameOrSourceURL(Isolate* isolate); +}; + +} // namespace v8 + +#endif // INCLUDE_V8_DEBUG_H_ diff --git a/NativeScript/napi/v8/include_old/v8-embedder-heap.h b/NativeScript/napi/v8/include_old/v8-embedder-heap.h new file mode 100644 index 00000000..c37dadf7 --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-embedder-heap.h @@ -0,0 +1,66 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_EMBEDDER_HEAP_H_ +#define INCLUDE_V8_EMBEDDER_HEAP_H_ + +#include "v8-traced-handle.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { + +class Isolate; +class Value; + +/** + * Handler for embedder roots on non-unified heap garbage collections. + */ +class V8_EXPORT EmbedderRootsHandler { + public: + virtual ~EmbedderRootsHandler() = default; + + /** + * Returns true if the |TracedReference| handle should be considered as root + * for the currently running non-tracing garbage collection and false + * otherwise. The default implementation will keep all |TracedReference| + * references as roots. + * + * If this returns false, then V8 may decide that the object referred to by + * such a handle is reclaimed. In that case, V8 calls |ResetRoot()| for the + * |TracedReference|. + * + * Note that the `handle` is different from the handle that the embedder holds + * for retaining the object. The embedder may use |WrapperClassId()| to + * distinguish cases where it wants handles to be treated as roots from not + * being treated as roots. + * + * The concrete implementations must be thread-safe. + */ + virtual bool IsRoot(const v8::TracedReference& handle) = 0; + + /** + * Used in combination with |IsRoot|. Called by V8 when an + * object that is backed by a handle is reclaimed by a non-tracing garbage + * collection. It is up to the embedder to reset the original handle. + * + * Note that the |handle| is different from the handle that the embedder holds + * for retaining the object. It is up to the embedder to find the original + * handle via the object or class id. + */ + virtual void ResetRoot(const v8::TracedReference& handle) = 0; + + /** + * Similar to |ResetRoot()|, but opportunistic. The function is called in + * parallel for different handles and as such must be thread-safe. In case, + * |false| is returned, |ResetRoot()| will be recalled for the same handle. + */ + virtual bool TryResetRoot(const v8::TracedReference& handle) { + ResetRoot(handle); + return true; + } +}; + +} // namespace v8 + +#endif // INCLUDE_V8_EMBEDDER_HEAP_H_ diff --git a/NativeScript/napi/v8/include_old/v8-embedder-state-scope.h b/NativeScript/napi/v8/include_old/v8-embedder-state-scope.h new file mode 100644 index 00000000..d8a3b08d --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-embedder-state-scope.h @@ -0,0 +1,51 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_EMBEDDER_STATE_SCOPE_H_ +#define INCLUDE_V8_EMBEDDER_STATE_SCOPE_H_ + +#include + +#include "v8-context.h" // NOLINT(build/include_directory) +#include "v8-internal.h" // NOLINT(build/include_directory) +#include "v8-local-handle.h" // NOLINT(build/include_directory) + +namespace v8 { + +namespace internal { +class EmbedderState; +} // namespace internal + +// A StateTag represents a possible state of the embedder. +enum class EmbedderStateTag : uint8_t { + // reserved + EMPTY = 0, + OTHER = 1, + // embedder can define any state after +}; + +// A stack-allocated class that manages an embedder state on the isolate. +// After an EmbedderState scope has been created, a new embedder state will be +// pushed on the isolate stack. +class V8_EXPORT EmbedderStateScope { + public: + EmbedderStateScope(Isolate* isolate, Local context, + EmbedderStateTag tag); + + ~EmbedderStateScope(); + + private: + // Declaring operator new and delete as deleted is not spec compliant. + // Therefore declare them private instead to disable dynamic alloc + void* operator new(size_t size); + void* operator new[](size_t size); + void operator delete(void*, size_t); + void operator delete[](void*, size_t); + + std::unique_ptr embedder_state_; +}; + +} // namespace v8 + +#endif // INCLUDE_V8_EMBEDDER_STATE_SCOPE_H_ diff --git a/NativeScript/napi/v8/include_old/v8-exception.h b/NativeScript/napi/v8/include_old/v8-exception.h new file mode 100644 index 00000000..3b76636c --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-exception.h @@ -0,0 +1,224 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_EXCEPTION_H_ +#define INCLUDE_V8_EXCEPTION_H_ + +#include + +#include "v8-local-handle.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { + +class Context; +class Isolate; +class Message; +class StackTrace; +class String; +class Value; + +namespace internal { +class Isolate; +class ThreadLocalTop; +} // namespace internal + +/** + * Create new error objects by calling the corresponding error object + * constructor with the message. + */ +class V8_EXPORT Exception { + public: + static Local RangeError(Local message, + Local options = {}); + static Local ReferenceError(Local message, + Local options = {}); + static Local SyntaxError(Local message, + Local options = {}); + static Local TypeError(Local message, + Local options = {}); + static Local WasmCompileError(Local message, + Local options = {}); + static Local WasmLinkError(Local message, + Local options = {}); + static Local WasmRuntimeError(Local message, + Local options = {}); + static Local Error(Local message, Local options = {}); + + /** + * Creates an error message for the given exception. + * Will try to reconstruct the original stack trace from the exception value, + * or capture the current stack trace if not available. + */ + static Local CreateMessage(Isolate* isolate, Local exception); + + /** + * Returns the original stack trace that was captured at the creation time + * of a given exception, or an empty handle if not available. + */ + static Local GetStackTrace(Local exception); +}; + +/** + * An external exception handler. + */ +class V8_EXPORT TryCatch { + public: + /** + * Creates a new try/catch block and registers it with v8. Note that + * all TryCatch blocks should be stack allocated because the memory + * location itself is compared against JavaScript try/catch blocks. + */ + explicit TryCatch(Isolate* isolate); + + /** + * Unregisters and deletes this try/catch block. + */ + ~TryCatch(); + + /** + * Returns true if an exception has been caught by this try/catch block. + */ + bool HasCaught() const; + + /** + * For certain types of exceptions, it makes no sense to continue execution. + * + * If CanContinue returns false, the correct action is to perform any C++ + * cleanup needed and then return. If CanContinue returns false and + * HasTerminated returns true, it is possible to call + * CancelTerminateExecution in order to continue calling into the engine. + */ + bool CanContinue() const; + + /** + * Returns true if an exception has been caught due to script execution + * being terminated. + * + * There is no JavaScript representation of an execution termination + * exception. Such exceptions are thrown when the TerminateExecution + * methods are called to terminate a long-running script. + * + * If such an exception has been thrown, HasTerminated will return true, + * indicating that it is possible to call CancelTerminateExecution in order + * to continue calling into the engine. + */ + bool HasTerminated() const; + + /** + * Throws the exception caught by this TryCatch in a way that avoids + * it being caught again by this same TryCatch. As with ThrowException + * it is illegal to execute any JavaScript operations after calling + * ReThrow; the caller must return immediately to where the exception + * is caught. + */ + Local ReThrow(); + + /** + * Returns the exception caught by this try/catch block. If no exception has + * been caught an empty handle is returned. + */ + Local Exception() const; + + /** + * Returns the .stack property of an object. If no .stack + * property is present an empty handle is returned. + */ + V8_WARN_UNUSED_RESULT static MaybeLocal StackTrace( + Local context, Local exception); + + /** + * Returns the .stack property of the thrown object. If no .stack property is + * present or if this try/catch block has not caught an exception, an empty + * handle is returned. + */ + V8_WARN_UNUSED_RESULT MaybeLocal StackTrace( + Local context) const; + + /** + * Returns the message associated with this exception. If there is + * no message associated an empty handle is returned. + */ + Local Message() const; + + /** + * Clears any exceptions that may have been caught by this try/catch block. + * After this method has been called, HasCaught() will return false. Cancels + * the scheduled exception if it is caught and ReThrow() is not called before. + * + * It is not necessary to clear a try/catch block before using it again; if + * another exception is thrown the previously caught exception will just be + * overwritten. However, it is often a good idea since it makes it easier + * to determine which operation threw a given exception. + */ + void Reset(); + + /** + * Set verbosity of the external exception handler. + * + * By default, exceptions that are caught by an external exception + * handler are not reported. Call SetVerbose with true on an + * external exception handler to have exceptions caught by the + * handler reported as if they were not caught. + */ + void SetVerbose(bool value); + + /** + * Returns true if verbosity is enabled. + */ + bool IsVerbose() const; + + /** + * Set whether or not this TryCatch should capture a Message object + * which holds source information about where the exception + * occurred. True by default. + */ + void SetCaptureMessage(bool value); + + TryCatch(const TryCatch&) = delete; + void operator=(const TryCatch&) = delete; + + private: + // Declaring operator new and delete as deleted is not spec compliant. + // Therefore declare them private instead to disable dynamic alloc + void* operator new(size_t size); + void* operator new[](size_t size); + void operator delete(void*, size_t); + void operator delete[](void*, size_t); + + /** + * There are cases when the raw address of C++ TryCatch object cannot be + * used for comparisons with addresses into the JS stack. The cases are: + * 1) ARM, ARM64 and MIPS simulators which have separate JS stack. + * 2) Address sanitizer allocates local C++ object in the heap when + * UseAfterReturn mode is enabled. + * This method returns address that can be used for comparisons with + * addresses into the JS stack. When neither simulator nor ASAN's + * UseAfterReturn is enabled, then the address returned will be the address + * of the C++ try catch handler itself. + */ + internal::Address JSStackComparableAddressPrivate() { + return js_stack_comparable_address_; + } + + void ResetInternal(); + + internal::Isolate* i_isolate_; + TryCatch* next_; + void* exception_; + void* message_obj_; + internal::Address js_stack_comparable_address_; + bool is_verbose_ : 1; + bool can_continue_ : 1; + bool capture_message_ : 1; + bool rethrow_ : 1; + bool has_terminated_ : 1; + + friend class internal::Isolate; + friend class internal::ThreadLocalTop; +}; + +} // namespace v8 + +#endif // INCLUDE_V8_EXCEPTION_H_ diff --git a/NativeScript/napi/v8/include_old/v8-extension.h b/NativeScript/napi/v8/include_old/v8-extension.h new file mode 100644 index 00000000..0705e2af --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-extension.h @@ -0,0 +1,62 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_EXTENSION_H_ +#define INCLUDE_V8_EXTENSION_H_ + +#include + +#include "v8-local-handle.h" // NOLINT(build/include_directory) +#include "v8-primitive.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { + +class FunctionTemplate; + +// --- Extensions --- + +/** + * Ignore + */ +class V8_EXPORT Extension { + public: + // Note that the strings passed into this constructor must live as long + // as the Extension itself. + Extension(const char* name, const char* source = nullptr, int dep_count = 0, + const char** deps = nullptr, int source_length = -1); + virtual ~Extension() { delete source_; } + virtual Local GetNativeFunctionTemplate( + Isolate* isolate, Local name) { + return Local(); + } + + const char* name() const { return name_; } + size_t source_length() const { return source_length_; } + const String::ExternalOneByteStringResource* source() const { + return source_; + } + int dependency_count() const { return dep_count_; } + const char** dependencies() const { return deps_; } + void set_auto_enable(bool value) { auto_enable_ = value; } + bool auto_enable() { return auto_enable_; } + + // Disallow copying and assigning. + Extension(const Extension&) = delete; + void operator=(const Extension&) = delete; + + private: + const char* name_; + size_t source_length_; // expected to initialize before source_ + String::ExternalOneByteStringResource* source_; + int dep_count_; + const char** deps_; + bool auto_enable_; +}; + +void V8_EXPORT RegisterExtension(std::unique_ptr); + +} // namespace v8 + +#endif // INCLUDE_V8_EXTENSION_H_ diff --git a/NativeScript/napi/v8/include_old/v8-external.h b/NativeScript/napi/v8/include_old/v8-external.h new file mode 100644 index 00000000..2e245036 --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-external.h @@ -0,0 +1,37 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_EXTERNAL_H_ +#define INCLUDE_V8_EXTERNAL_H_ + +#include "v8-value.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { + +class Isolate; + +/** + * A JavaScript value that wraps a C++ void*. This type of value is mainly used + * to associate C++ data structures with JavaScript objects. + */ +class V8_EXPORT External : public Value { + public: + static Local New(Isolate* isolate, void* value); + V8_INLINE static External* Cast(Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); + } + + void* Value() const; + + private: + static void CheckCast(v8::Value* obj); +}; + +} // namespace v8 + +#endif // INCLUDE_V8_EXTERNAL_H_ diff --git a/NativeScript/napi/v8/include_old/v8-fast-api-calls.h b/NativeScript/napi/v8/include_old/v8-fast-api-calls.h new file mode 100644 index 00000000..e40f1068 --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-fast-api-calls.h @@ -0,0 +1,975 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * This file provides additional API on top of the default one for making + * API calls, which come from embedder C++ functions. The functions are being + * called directly from optimized code, doing all the necessary typechecks + * in the compiler itself, instead of on the embedder side. Hence the "fast" + * in the name. Example usage might look like: + * + * \code + * void FastMethod(int param, bool another_param); + * + * v8::FunctionTemplate::New(isolate, SlowCallback, data, + * signature, length, constructor_behavior + * side_effect_type, + * &v8::CFunction::Make(FastMethod)); + * \endcode + * + * By design, fast calls are limited by the following requirements, which + * the embedder should enforce themselves: + * - they should not allocate on the JS heap; + * - they should not trigger JS execution. + * To enforce them, the embedder could use the existing + * v8::Isolate::DisallowJavascriptExecutionScope and a utility similar to + * Blink's NoAllocationScope: + * https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/platform/heap/thread_state_scopes.h;l=16 + * + * Due to these limitations, it's not directly possible to report errors by + * throwing a JS exception or to otherwise do an allocation. There is an + * alternative way of creating fast calls that supports falling back to the + * slow call and then performing the necessary allocation. When one creates + * the fast method by using CFunction::MakeWithFallbackSupport instead of + * CFunction::Make, the fast callback gets as last parameter an output variable, + * through which it can request falling back to the slow call. So one might + * declare their method like: + * + * \code + * void FastMethodWithFallback(int param, FastApiCallbackOptions& options); + * \endcode + * + * If the callback wants to signal an error condition or to perform an + * allocation, it must set options.fallback to true and do an early return from + * the fast method. Then V8 checks the value of options.fallback and if it's + * true, falls back to executing the SlowCallback, which is capable of reporting + * the error (either by throwing a JS exception or logging to the console) or + * doing the allocation. It's the embedder's responsibility to ensure that the + * fast callback is idempotent up to the point where error and fallback + * conditions are checked, because otherwise executing the slow callback might + * produce visible side-effects twice. + * + * An example for custom embedder type support might employ a way to wrap/ + * unwrap various C++ types in JSObject instances, e.g: + * + * \code + * + * // Helper method with a check for field count. + * template + * inline T* GetInternalField(v8::Local wrapper) { + * assert(offset < wrapper->InternalFieldCount()); + * return reinterpret_cast( + * wrapper->GetAlignedPointerFromInternalField(offset)); + * } + * + * class CustomEmbedderType { + * public: + * // Returns the raw C object from a wrapper JS object. + * static CustomEmbedderType* Unwrap(v8::Local wrapper) { + * return GetInternalField(wrapper); + * } + * static void FastMethod(v8::Local receiver_obj, int param) { + * CustomEmbedderType* receiver = static_cast( + * receiver_obj->GetAlignedPointerFromInternalField( + * kV8EmbedderWrapperObjectIndex)); + * + * // Type checks are already done by the optimized code. + * // Then call some performance-critical method like: + * // receiver->Method(param); + * } + * + * static void SlowMethod( + * const v8::FunctionCallbackInfo& info) { + * v8::Local instance = + * v8::Local::Cast(info.Holder()); + * CustomEmbedderType* receiver = Unwrap(instance); + * // TODO: Do type checks and extract {param}. + * receiver->Method(param); + * } + * }; + * + * // TODO(mslekova): Clean-up these constants + * // The constants kV8EmbedderWrapperTypeIndex and + * // kV8EmbedderWrapperObjectIndex describe the offsets for the type info + * // struct and the native object, when expressed as internal field indices + * // within a JSObject. The existance of this helper function assumes that + * // all embedder objects have their JSObject-side type info at the same + * // offset, but this is not a limitation of the API itself. For a detailed + * // use case, see the third example. + * static constexpr int kV8EmbedderWrapperTypeIndex = 0; + * static constexpr int kV8EmbedderWrapperObjectIndex = 1; + * + * // The following setup function can be templatized based on + * // the {embedder_object} argument. + * void SetupCustomEmbedderObject(v8::Isolate* isolate, + * v8::Local context, + * CustomEmbedderType* embedder_object) { + * isolate->set_embedder_wrapper_type_index( + * kV8EmbedderWrapperTypeIndex); + * isolate->set_embedder_wrapper_object_index( + * kV8EmbedderWrapperObjectIndex); + * + * v8::CFunction c_func = + * MakeV8CFunction(CustomEmbedderType::FastMethod); + * + * Local method_template = + * v8::FunctionTemplate::New( + * isolate, CustomEmbedderType::SlowMethod, v8::Local(), + * v8::Local(), 1, v8::ConstructorBehavior::kAllow, + * v8::SideEffectType::kHasSideEffect, &c_func); + * + * v8::Local object_template = + * v8::ObjectTemplate::New(isolate); + * object_template->SetInternalFieldCount( + * kV8EmbedderWrapperObjectIndex + 1); + * object_template->Set(isolate, "method", method_template); + * + * // Instantiate the wrapper JS object. + * v8::Local object = + * object_template->NewInstance(context).ToLocalChecked(); + * object->SetAlignedPointerInInternalField( + * kV8EmbedderWrapperObjectIndex, + * reinterpret_cast(embedder_object)); + * + * // TODO: Expose {object} where it's necessary. + * } + * \endcode + * + * For instance if {object} is exposed via a global "obj" variable, + * one could write in JS: + * function hot_func() { + * obj.method(42); + * } + * and once {hot_func} gets optimized, CustomEmbedderType::FastMethod + * will be called instead of the slow version, with the following arguments: + * receiver := the {embedder_object} from above + * param := 42 + * + * Currently supported return types: + * - void + * - bool + * - int32_t + * - uint32_t + * - float32_t + * - float64_t + * Currently supported argument types: + * - pointer to an embedder type + * - JavaScript array of primitive types + * - bool + * - int32_t + * - uint32_t + * - int64_t + * - uint64_t + * - float32_t + * - float64_t + * + * The 64-bit integer types currently have the IDL (unsigned) long long + * semantics: https://heycam.github.io/webidl/#abstract-opdef-converttoint + * In the future we'll extend the API to also provide conversions from/to + * BigInt to preserve full precision. + * The floating point types currently have the IDL (unrestricted) semantics, + * which is the only one used by WebGL. We plan to add support also for + * restricted floats/doubles, similarly to the BigInt conversion policies. + * We also differ from the specific NaN bit pattern that WebIDL prescribes + * (https://heycam.github.io/webidl/#es-unrestricted-float) in that Blink + * passes NaN values as-is, i.e. doesn't normalize them. + * + * To be supported types: + * - TypedArrays and ArrayBuffers + * - arrays of embedder types + * + * + * The API offers a limited support for function overloads: + * + * \code + * void FastMethod_2Args(int param, bool another_param); + * void FastMethod_3Args(int param, bool another_param, int third_param); + * + * v8::CFunction fast_method_2args_c_func = + * MakeV8CFunction(FastMethod_2Args); + * v8::CFunction fast_method_3args_c_func = + * MakeV8CFunction(FastMethod_3Args); + * const v8::CFunction fast_method_overloads[] = {fast_method_2args_c_func, + * fast_method_3args_c_func}; + * Local method_template = + * v8::FunctionTemplate::NewWithCFunctionOverloads( + * isolate, SlowCallback, data, signature, length, + * constructor_behavior, side_effect_type, + * {fast_method_overloads, 2}); + * \endcode + * + * In this example a single FunctionTemplate is associated to multiple C++ + * functions. The overload resolution is currently only based on the number of + * arguments passed in a call. For example, if this method_template is + * registered with a wrapper JS object as described above, a call with two + * arguments: + * obj.method(42, true); + * will result in a fast call to FastMethod_2Args, while a call with three or + * more arguments: + * obj.method(42, true, 11); + * will result in a fast call to FastMethod_3Args. Instead a call with less than + * two arguments, like: + * obj.method(42); + * would not result in a fast call but would fall back to executing the + * associated SlowCallback. + */ + +#ifndef INCLUDE_V8_FAST_API_CALLS_H_ +#define INCLUDE_V8_FAST_API_CALLS_H_ + +#include +#include + +#include +#include + +#include "v8-internal.h" // NOLINT(build/include_directory) +#include "v8-local-handle.h" // NOLINT(build/include_directory) +#include "v8-typed-array.h" // NOLINT(build/include_directory) +#include "v8-value.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { + +class Isolate; + +class CTypeInfo { + public: + enum class Type : uint8_t { + kVoid, + kBool, + kUint8, + kInt32, + kUint32, + kInt64, + kUint64, + kFloat32, + kFloat64, + kPointer, + kV8Value, + kSeqOneByteString, + kApiObject, // This will be deprecated once all users have + // migrated from v8::ApiObject to v8::Local. + kAny, // This is added to enable untyped representation of fast + // call arguments for test purposes. It can represent any of + // the other types stored in the same memory as a union (see + // the AnyCType struct declared below). This allows for + // uniform passing of arguments w.r.t. their location + // (in a register or on the stack), independent of their + // actual type. It's currently used by the arm64 simulator + // and can be added to the other simulators as well when fast + // calls having both GP and FP params need to be supported. + }; + + // kCallbackOptionsType is not part of the Type enum + // because it is only used internally. Use value 255 that is larger + // than any valid Type enum. + static constexpr Type kCallbackOptionsType = Type(255); + + enum class SequenceType : uint8_t { + kScalar, + kIsSequence, // sequence + kIsTypedArray, // TypedArray of T or any ArrayBufferView if T + // is void + kIsArrayBuffer // ArrayBuffer + }; + + enum class Flags : uint8_t { + kNone = 0, + kAllowSharedBit = 1 << 0, // Must be an ArrayBuffer or TypedArray + kEnforceRangeBit = 1 << 1, // T must be integral + kClampBit = 1 << 2, // T must be integral + kIsRestrictedBit = 1 << 3, // T must be float or double + }; + + explicit constexpr CTypeInfo( + Type type, SequenceType sequence_type = SequenceType::kScalar, + Flags flags = Flags::kNone) + : type_(type), sequence_type_(sequence_type), flags_(flags) {} + + typedef uint32_t Identifier; + explicit constexpr CTypeInfo(Identifier identifier) + : CTypeInfo(static_cast(identifier >> 16), + static_cast((identifier >> 8) & 255), + static_cast(identifier & 255)) {} + constexpr Identifier GetId() const { + return static_cast(type_) << 16 | + static_cast(sequence_type_) << 8 | + static_cast(flags_); + } + + constexpr Type GetType() const { return type_; } + constexpr SequenceType GetSequenceType() const { return sequence_type_; } + constexpr Flags GetFlags() const { return flags_; } + + static constexpr bool IsIntegralType(Type type) { + return type == Type::kUint8 || type == Type::kInt32 || + type == Type::kUint32 || type == Type::kInt64 || + type == Type::kUint64; + } + + static constexpr bool IsFloatingPointType(Type type) { + return type == Type::kFloat32 || type == Type::kFloat64; + } + + static constexpr bool IsPrimitive(Type type) { + return IsIntegralType(type) || IsFloatingPointType(type) || + type == Type::kBool; + } + + private: + Type type_; + SequenceType sequence_type_; + Flags flags_; +}; + +struct FastApiTypedArrayBase { + public: + // Returns the length in number of elements. + size_t V8_EXPORT length() const { return length_; } + // Checks whether the given index is within the bounds of the collection. + void V8_EXPORT ValidateIndex(size_t index) const; + + protected: + size_t length_ = 0; +}; + +template +struct FastApiTypedArray : public FastApiTypedArrayBase { + public: + V8_INLINE T get(size_t index) const { +#ifdef DEBUG + ValidateIndex(index); +#endif // DEBUG + T tmp; + memcpy(&tmp, reinterpret_cast(data_) + index, sizeof(T)); + return tmp; + } + + bool getStorageIfAligned(T** elements) const { + if (reinterpret_cast(data_) % alignof(T) != 0) { + return false; + } + *elements = reinterpret_cast(data_); + return true; + } + + private: + // This pointer should include the typed array offset applied. + // It's not guaranteed that it's aligned to sizeof(T), it's only + // guaranteed that it's 4-byte aligned, so for 8-byte types we need to + // provide a special implementation for reading from it, which hides + // the possibly unaligned read in the `get` method. + void* data_; +}; + +// Any TypedArray. It uses kTypedArrayBit with base type void +// Overloaded args of ArrayBufferView and TypedArray are not supported +// (for now) because the generic “any” ArrayBufferView doesn’t have its +// own instance type. It could be supported if we specify that +// TypedArray always has precedence over the generic ArrayBufferView, +// but this complicates overload resolution. +struct FastApiArrayBufferView { + void* data; + size_t byte_length; +}; + +struct FastApiArrayBuffer { + void* data; + size_t byte_length; +}; + +struct FastOneByteString { + const char* data; + uint32_t length; +}; + +class V8_EXPORT CFunctionInfo { + public: + enum class Int64Representation : uint8_t { + kNumber = 0, // Use numbers to represent 64 bit integers. + kBigInt = 1, // Use BigInts to represent 64 bit integers. + }; + + // Construct a struct to hold a CFunction's type information. + // |return_info| describes the function's return type. + // |arg_info| is an array of |arg_count| CTypeInfos describing the + // arguments. Only the last argument may be of the special type + // CTypeInfo::kCallbackOptionsType. + CFunctionInfo(const CTypeInfo& return_info, unsigned int arg_count, + const CTypeInfo* arg_info, + Int64Representation repr = Int64Representation::kNumber); + + const CTypeInfo& ReturnInfo() const { return return_info_; } + + // The argument count, not including the v8::FastApiCallbackOptions + // if present. + unsigned int ArgumentCount() const { + return HasOptions() ? arg_count_ - 1 : arg_count_; + } + + Int64Representation GetInt64Representation() const { return repr_; } + + // |index| must be less than ArgumentCount(). + // Note: if the last argument passed on construction of CFunctionInfo + // has type CTypeInfo::kCallbackOptionsType, it is not included in + // ArgumentCount(). + const CTypeInfo& ArgumentInfo(unsigned int index) const; + + bool HasOptions() const { + // The options arg is always the last one. + return arg_count_ > 0 && arg_info_[arg_count_ - 1].GetType() == + CTypeInfo::kCallbackOptionsType; + } + + private: + const CTypeInfo return_info_; + const Int64Representation repr_; + const unsigned int arg_count_; + const CTypeInfo* arg_info_; +}; + +struct FastApiCallbackOptions; + +// Provided for testing. +struct AnyCType { + AnyCType() : int64_value(0) {} + + union { + bool bool_value; + int32_t int32_value; + uint32_t uint32_value; + int64_t int64_value; + uint64_t uint64_value; + float float_value; + double double_value; + void* pointer_value; + Local object_value; + Local sequence_value; + const FastApiTypedArray* uint8_ta_value; + const FastApiTypedArray* int32_ta_value; + const FastApiTypedArray* uint32_ta_value; + const FastApiTypedArray* int64_ta_value; + const FastApiTypedArray* uint64_ta_value; + const FastApiTypedArray* float_ta_value; + const FastApiTypedArray* double_ta_value; + const FastOneByteString* string_value; + FastApiCallbackOptions* options_value; + }; +}; + +static_assert( + sizeof(AnyCType) == 8, + "The AnyCType struct should have size == 64 bits, as this is assumed " + "by EffectControlLinearizer."); + +class V8_EXPORT CFunction { + public: + constexpr CFunction() : address_(nullptr), type_info_(nullptr) {} + + const CTypeInfo& ReturnInfo() const { return type_info_->ReturnInfo(); } + + const CTypeInfo& ArgumentInfo(unsigned int index) const { + return type_info_->ArgumentInfo(index); + } + + unsigned int ArgumentCount() const { return type_info_->ArgumentCount(); } + + const void* GetAddress() const { return address_; } + CFunctionInfo::Int64Representation GetInt64Representation() const { + return type_info_->GetInt64Representation(); + } + const CFunctionInfo* GetTypeInfo() const { return type_info_; } + + enum class OverloadResolution { kImpossible, kAtRuntime, kAtCompileTime }; + + // Returns whether an overload between this and the given CFunction can + // be resolved at runtime by the RTTI available for the arguments or at + // compile time for functions with different number of arguments. + OverloadResolution GetOverloadResolution(const CFunction* other) { + // Runtime overload resolution can only deal with functions with the + // same number of arguments. Functions with different arity are handled + // by compile time overload resolution though. + if (ArgumentCount() != other->ArgumentCount()) { + return OverloadResolution::kAtCompileTime; + } + + // The functions can only differ by a single argument position. + int diff_index = -1; + for (unsigned int i = 0; i < ArgumentCount(); ++i) { + if (ArgumentInfo(i).GetSequenceType() != + other->ArgumentInfo(i).GetSequenceType()) { + if (diff_index >= 0) { + return OverloadResolution::kImpossible; + } + diff_index = i; + + // We only support overload resolution between sequence types. + if (ArgumentInfo(i).GetSequenceType() == + CTypeInfo::SequenceType::kScalar || + other->ArgumentInfo(i).GetSequenceType() == + CTypeInfo::SequenceType::kScalar) { + return OverloadResolution::kImpossible; + } + } + } + + return OverloadResolution::kAtRuntime; + } + + template + static CFunction Make(F* func) { + return ArgUnwrap::Make(func); + } + + // Provided for testing purposes. + template + static CFunction Make(R (*func)(Args...), + R_Patch (*patching_func)(Args_Patch...)) { + CFunction c_func = ArgUnwrap::Make(func); + static_assert( + sizeof...(Args_Patch) == sizeof...(Args), + "The patching function must have the same number of arguments."); + c_func.address_ = reinterpret_cast(patching_func); + return c_func; + } + + CFunction(const void* address, const CFunctionInfo* type_info); + + private: + const void* address_; + const CFunctionInfo* type_info_; + + template + class ArgUnwrap { + static_assert(sizeof(F) != sizeof(F), + "CFunction must be created from a function pointer."); + }; + + template + class ArgUnwrap { + public: + static CFunction Make(R (*func)(Args...)); + }; +}; + +/** + * A struct which may be passed to a fast call callback, like so: + * \code + * void FastMethodWithOptions(int param, FastApiCallbackOptions& options); + * \endcode + */ +struct FastApiCallbackOptions { + /** + * Creates a new instance of FastApiCallbackOptions for testing purpose. The + * returned instance may be filled with mock data. + */ + static FastApiCallbackOptions CreateForTesting(Isolate* isolate) { + return {false, {0}, nullptr}; + } + + /** + * If the callback wants to signal an error condition or to perform an + * allocation, it must set options.fallback to true and do an early return + * from the fast method. Then V8 checks the value of options.fallback and if + * it's true, falls back to executing the SlowCallback, which is capable of + * reporting the error (either by throwing a JS exception or logging to the + * console) or doing the allocation. It's the embedder's responsibility to + * ensure that the fast callback is idempotent up to the point where error and + * fallback conditions are checked, because otherwise executing the slow + * callback might produce visible side-effects twice. + */ + bool fallback; + + /** + * The `data` passed to the FunctionTemplate constructor, or `undefined`. + * `data_ptr` allows for default constructing FastApiCallbackOptions. + */ + union { + uintptr_t data_ptr; + v8::Local data; + }; + + /** + * When called from WebAssembly, a view of the calling module's memory. + */ + FastApiTypedArray* const wasm_memory; +}; + +namespace internal { + +// Helper to count the number of occurances of `T` in `List` +template +struct count : std::integral_constant {}; +template +struct count + : std::integral_constant::value> {}; +template +struct count : count {}; + +template +class CFunctionInfoImpl : public CFunctionInfo { + static constexpr int kOptionsArgCount = + count(); + static constexpr int kReceiverCount = 1; + + static_assert(kOptionsArgCount == 0 || kOptionsArgCount == 1, + "Only one options parameter is supported."); + + static_assert(sizeof...(ArgBuilders) >= kOptionsArgCount + kReceiverCount, + "The receiver or the options argument is missing."); + + public: + constexpr CFunctionInfoImpl() + : CFunctionInfo(RetBuilder::Build(), sizeof...(ArgBuilders), + arg_info_storage_, Representation), + arg_info_storage_{ArgBuilders::Build()...} { + constexpr CTypeInfo::Type kReturnType = RetBuilder::Build().GetType(); + static_assert(kReturnType == CTypeInfo::Type::kVoid || + kReturnType == CTypeInfo::Type::kBool || + kReturnType == CTypeInfo::Type::kInt32 || + kReturnType == CTypeInfo::Type::kUint32 || + kReturnType == CTypeInfo::Type::kInt64 || + kReturnType == CTypeInfo::Type::kUint64 || + kReturnType == CTypeInfo::Type::kFloat32 || + kReturnType == CTypeInfo::Type::kFloat64 || + kReturnType == CTypeInfo::Type::kPointer || + kReturnType == CTypeInfo::Type::kAny, + "String and api object values are not currently " + "supported return types."); + } + + private: + const CTypeInfo arg_info_storage_[sizeof...(ArgBuilders)]; +}; + +template +struct TypeInfoHelper { + static_assert(sizeof(T) != sizeof(T), "This type is not supported"); +}; + +#define SPECIALIZE_GET_TYPE_INFO_HELPER_FOR(T, Enum) \ + template <> \ + struct TypeInfoHelper { \ + static constexpr CTypeInfo::Flags Flags() { \ + return CTypeInfo::Flags::kNone; \ + } \ + \ + static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::Enum; } \ + static constexpr CTypeInfo::SequenceType SequenceType() { \ + return CTypeInfo::SequenceType::kScalar; \ + } \ + }; + +template +struct CTypeInfoTraits {}; + +#define DEFINE_TYPE_INFO_TRAITS(CType, Enum) \ + template <> \ + struct CTypeInfoTraits { \ + using ctype = CType; \ + }; + +#define PRIMITIVE_C_TYPES(V) \ + V(bool, kBool) \ + V(uint8_t, kUint8) \ + V(int32_t, kInt32) \ + V(uint32_t, kUint32) \ + V(int64_t, kInt64) \ + V(uint64_t, kUint64) \ + V(float, kFloat32) \ + V(double, kFloat64) \ + V(void*, kPointer) + +// Same as above, but includes deprecated types for compatibility. +#define ALL_C_TYPES(V) \ + PRIMITIVE_C_TYPES(V) \ + V(void, kVoid) \ + V(v8::Local, kV8Value) \ + V(v8::Local, kV8Value) \ + V(AnyCType, kAny) + +// ApiObject was a temporary solution to wrap the pointer to the v8::Value. +// Please use v8::Local in new code for the arguments and +// v8::Local for the receiver, as ApiObject will be deprecated. + +ALL_C_TYPES(SPECIALIZE_GET_TYPE_INFO_HELPER_FOR) +PRIMITIVE_C_TYPES(DEFINE_TYPE_INFO_TRAITS) + +#undef PRIMITIVE_C_TYPES +#undef ALL_C_TYPES + +#define SPECIALIZE_GET_TYPE_INFO_HELPER_FOR_TA(T, Enum) \ + template <> \ + struct TypeInfoHelper&> { \ + static constexpr CTypeInfo::Flags Flags() { \ + return CTypeInfo::Flags::kNone; \ + } \ + \ + static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::Enum; } \ + static constexpr CTypeInfo::SequenceType SequenceType() { \ + return CTypeInfo::SequenceType::kIsTypedArray; \ + } \ + }; + +#define TYPED_ARRAY_C_TYPES(V) \ + V(uint8_t, kUint8) \ + V(int32_t, kInt32) \ + V(uint32_t, kUint32) \ + V(int64_t, kInt64) \ + V(uint64_t, kUint64) \ + V(float, kFloat32) \ + V(double, kFloat64) + +TYPED_ARRAY_C_TYPES(SPECIALIZE_GET_TYPE_INFO_HELPER_FOR_TA) + +#undef TYPED_ARRAY_C_TYPES + +template <> +struct TypeInfoHelper> { + static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; } + + static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::kVoid; } + static constexpr CTypeInfo::SequenceType SequenceType() { + return CTypeInfo::SequenceType::kIsSequence; + } +}; + +template <> +struct TypeInfoHelper> { + static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; } + + static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::kUint32; } + static constexpr CTypeInfo::SequenceType SequenceType() { + return CTypeInfo::SequenceType::kIsTypedArray; + } +}; + +template <> +struct TypeInfoHelper { + static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; } + + static constexpr CTypeInfo::Type Type() { + return CTypeInfo::kCallbackOptionsType; + } + static constexpr CTypeInfo::SequenceType SequenceType() { + return CTypeInfo::SequenceType::kScalar; + } +}; + +template <> +struct TypeInfoHelper { + static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; } + + static constexpr CTypeInfo::Type Type() { + return CTypeInfo::Type::kSeqOneByteString; + } + static constexpr CTypeInfo::SequenceType SequenceType() { + return CTypeInfo::SequenceType::kScalar; + } +}; + +#define STATIC_ASSERT_IMPLIES(COND, ASSERTION, MSG) \ + static_assert(((COND) == 0) || (ASSERTION), MSG) + +} // namespace internal + +template +class V8_EXPORT CTypeInfoBuilder { + public: + using BaseType = T; + + static constexpr CTypeInfo Build() { + constexpr CTypeInfo::Flags kFlags = + MergeFlags(internal::TypeInfoHelper::Flags(), Flags...); + constexpr CTypeInfo::Type kType = internal::TypeInfoHelper::Type(); + constexpr CTypeInfo::SequenceType kSequenceType = + internal::TypeInfoHelper::SequenceType(); + + STATIC_ASSERT_IMPLIES( + uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kAllowSharedBit), + (kSequenceType == CTypeInfo::SequenceType::kIsTypedArray || + kSequenceType == CTypeInfo::SequenceType::kIsArrayBuffer), + "kAllowSharedBit is only allowed for TypedArrays and ArrayBuffers."); + STATIC_ASSERT_IMPLIES( + uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kEnforceRangeBit), + CTypeInfo::IsIntegralType(kType), + "kEnforceRangeBit is only allowed for integral types."); + STATIC_ASSERT_IMPLIES( + uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kClampBit), + CTypeInfo::IsIntegralType(kType), + "kClampBit is only allowed for integral types."); + STATIC_ASSERT_IMPLIES( + uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kIsRestrictedBit), + CTypeInfo::IsFloatingPointType(kType), + "kIsRestrictedBit is only allowed for floating point types."); + STATIC_ASSERT_IMPLIES(kSequenceType == CTypeInfo::SequenceType::kIsSequence, + kType == CTypeInfo::Type::kVoid, + "Sequences are only supported from void type."); + STATIC_ASSERT_IMPLIES( + kSequenceType == CTypeInfo::SequenceType::kIsTypedArray, + CTypeInfo::IsPrimitive(kType) || kType == CTypeInfo::Type::kVoid, + "TypedArrays are only supported from primitive types or void."); + + // Return the same type with the merged flags. + return CTypeInfo(internal::TypeInfoHelper::Type(), + internal::TypeInfoHelper::SequenceType(), kFlags); + } + + private: + template + static constexpr CTypeInfo::Flags MergeFlags(CTypeInfo::Flags flags, + Rest... rest) { + return CTypeInfo::Flags(uint8_t(flags) | uint8_t(MergeFlags(rest...))); + } + static constexpr CTypeInfo::Flags MergeFlags() { return CTypeInfo::Flags(0); } +}; + +namespace internal { +template +class CFunctionBuilderWithFunction { + public: + explicit constexpr CFunctionBuilderWithFunction(const void* fn) : fn_(fn) {} + + template + constexpr auto Ret() { + return CFunctionBuilderWithFunction< + CTypeInfoBuilder, + ArgBuilders...>(fn_); + } + + template + constexpr auto Arg() { + // Return a copy of the builder with the Nth arg builder merged with + // template parameter pack Flags. + return ArgImpl( + std::make_index_sequence()); + } + + // Provided for testing purposes. + template + auto Patch(Ret (*patching_func)(Args...)) { + static_assert( + sizeof...(Args) == sizeof...(ArgBuilders), + "The patching function must have the same number of arguments."); + fn_ = reinterpret_cast(patching_func); + return *this; + } + + template + auto Build() { + static CFunctionInfoImpl + instance; + return CFunction(fn_, &instance); + } + + private: + template + struct GetArgBuilder; + + // Returns the same ArgBuilder as the one at index N, including its flags. + // Flags in the template parameter pack are ignored. + template + struct GetArgBuilder { + using type = + typename std::tuple_element>::type; + }; + + // Returns an ArgBuilder with the same base type as the one at index N, + // but merges the flags with the flags in the template parameter pack. + template + struct GetArgBuilder { + using type = CTypeInfoBuilder< + typename std::tuple_element>::type::BaseType, + std::tuple_element>::type::Build() + .GetFlags(), + Flags...>; + }; + + // Return a copy of the CFunctionBuilder, but merges the Flags on + // ArgBuilder index N with the new Flags passed in the template parameter + // pack. + template + constexpr auto ArgImpl(std::index_sequence) { + return CFunctionBuilderWithFunction< + RetBuilder, typename GetArgBuilder::type...>(fn_); + } + + const void* fn_; +}; + +class CFunctionBuilder { + public: + constexpr CFunctionBuilder() {} + + template + constexpr auto Fn(R (*fn)(Args...)) { + return CFunctionBuilderWithFunction, + CTypeInfoBuilder...>( + reinterpret_cast(fn)); + } +}; + +} // namespace internal + +// static +template +CFunction CFunction::ArgUnwrap::Make(R (*func)(Args...)) { + return internal::CFunctionBuilder().Fn(func).Build(); +} + +using CFunctionBuilder = internal::CFunctionBuilder; + +static constexpr CTypeInfo kTypeInfoInt32 = CTypeInfo(CTypeInfo::Type::kInt32); +static constexpr CTypeInfo kTypeInfoFloat64 = + CTypeInfo(CTypeInfo::Type::kFloat64); + +/** + * Copies the contents of this JavaScript array to a C++ buffer with + * a given max_length. A CTypeInfo is passed as an argument, + * instructing different rules for conversion (e.g. restricted float/double). + * The element type T of the destination array must match the C type + * corresponding to the CTypeInfo (specified by CTypeInfoTraits). + * If the array length is larger than max_length or the array is of + * unsupported type, the operation will fail, returning false. Generally, an + * array which contains objects, undefined, null or anything not convertible + * to the requested destination type, is considered unsupported. The operation + * returns true on success. `type_info` will be used for conversions. + */ +template +bool V8_EXPORT V8_WARN_UNUSED_RESULT TryToCopyAndConvertArrayToCppBuffer( + Local src, T* dst, uint32_t max_length); + +template <> +bool V8_EXPORT V8_WARN_UNUSED_RESULT +TryToCopyAndConvertArrayToCppBuffer::Build().GetId(), + int32_t>(Local src, int32_t* dst, + uint32_t max_length); + +template <> +bool V8_EXPORT V8_WARN_UNUSED_RESULT +TryToCopyAndConvertArrayToCppBuffer::Build().GetId(), + uint32_t>(Local src, uint32_t* dst, + uint32_t max_length); + +template <> +bool V8_EXPORT V8_WARN_UNUSED_RESULT +TryToCopyAndConvertArrayToCppBuffer::Build().GetId(), + float>(Local src, float* dst, + uint32_t max_length); + +template <> +bool V8_EXPORT V8_WARN_UNUSED_RESULT +TryToCopyAndConvertArrayToCppBuffer::Build().GetId(), + double>(Local src, double* dst, + uint32_t max_length); + +} // namespace v8 + +#endif // INCLUDE_V8_FAST_API_CALLS_H_ diff --git a/NativeScript/napi/v8/include_old/v8-forward.h b/NativeScript/napi/v8/include_old/v8-forward.h new file mode 100644 index 00000000..db3a2017 --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-forward.h @@ -0,0 +1,81 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_FORWARD_H_ +#define INCLUDE_V8_FORWARD_H_ + +// This header is intended to be used by headers that pass around V8 types, +// either by pointer or using Local. The full definitions can be included +// either via v8.h or the more fine-grained headers. + +#include "v8-local-handle.h" // NOLINT(build/include_directory) + +namespace v8 { + +class AccessorSignature; +class Array; +class ArrayBuffer; +class ArrayBufferView; +class BigInt; +class BigInt64Array; +class BigIntObject; +class BigUint64Array; +class Boolean; +class BooleanObject; +class Context; +class DataView; +class Data; +class Date; +class Extension; +class External; +class FixedArray; +class Float32Array; +class Float64Array; +class Function; +template +class FunctionCallbackInfo; +class FunctionTemplate; +class Int16Array; +class Int32; +class Int32Array; +class Int8Array; +class Integer; +class Isolate; +class Map; +class Module; +class Name; +class Number; +class NumberObject; +class Object; +class ObjectTemplate; +class Platform; +class Primitive; +class Private; +class Promise; +class Proxy; +class RegExp; +class Script; +class Set; +class SharedArrayBuffer; +class Signature; +class String; +class StringObject; +class Symbol; +class SymbolObject; +class Template; +class TryCatch; +class TypedArray; +class Uint16Array; +class Uint32; +class Uint32Array; +class Uint8Array; +class Uint8ClampedArray; +class UnboundModuleScript; +class Value; +class WasmMemoryObject; +class WasmModuleObject; + +} // namespace v8 + +#endif // INCLUDE_V8_FORWARD_H_ diff --git a/NativeScript/napi/v8/include_old/v8-function-callback.h b/NativeScript/napi/v8/include_old/v8-function-callback.h new file mode 100644 index 00000000..17b37cdd --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-function-callback.h @@ -0,0 +1,498 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_FUNCTION_CALLBACK_H_ +#define INCLUDE_V8_FUNCTION_CALLBACK_H_ + +#include "v8-local-handle.h" // NOLINT(build/include_directory) +#include "v8-primitive.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { + +template +class BasicTracedReference; +template +class Global; +class Object; +class Value; + +namespace internal { +class FunctionCallbackArguments; +class PropertyCallbackArguments; +class Builtins; +} // namespace internal + +namespace debug { +class ConsoleCallArguments; +} // namespace debug + +template +class ReturnValue { + public: + template + V8_INLINE ReturnValue(const ReturnValue& that) : value_(that.value_) { + static_assert(std::is_base_of::value, "type check"); + } + // Local setters + template + V8_INLINE void Set(const Global& handle); + template + V8_INLINE void Set(const BasicTracedReference& handle); + template + V8_INLINE void Set(const Local handle); + // Fast primitive setters + V8_INLINE void Set(bool value); + V8_INLINE void Set(double i); + V8_INLINE void Set(int32_t i); + V8_INLINE void Set(uint32_t i); + // Fast JS primitive setters + V8_INLINE void SetNull(); + V8_INLINE void SetUndefined(); + V8_INLINE void SetEmptyString(); + // Convenience getter for Isolate + V8_INLINE Isolate* GetIsolate() const; + + // Pointer setter: Uncompilable to prevent inadvertent misuse. + template + V8_INLINE void Set(S* whatever); + + // Getter. Creates a new Local<> so it comes with a certain performance + // hit. If the ReturnValue was not yet set, this will return the undefined + // value. + V8_INLINE Local Get() const; + + private: + template + friend class ReturnValue; + template + friend class FunctionCallbackInfo; + template + friend class PropertyCallbackInfo; + template + friend class PersistentValueMapBase; + V8_INLINE void SetInternal(internal::Address value) { *value_ = value; } + V8_INLINE internal::Address GetDefaultValue(); + V8_INLINE explicit ReturnValue(internal::Address* slot); + + // See FunctionCallbackInfo. + static constexpr int kIsolateValueIndex = -2; + + internal::Address* value_; +}; + +/** + * The argument information given to function call callbacks. This + * class provides access to information about the context of the call, + * including the receiver, the number and values of arguments, and + * the holder of the function. + */ +template +class FunctionCallbackInfo { + public: + /** The number of available arguments. */ + V8_INLINE int Length() const; + /** + * Accessor for the available arguments. Returns `undefined` if the index + * is out of bounds. + */ + V8_INLINE Local operator[](int i) const; + /** Returns the receiver. This corresponds to the "this" value. */ + V8_INLINE Local This() const; + /** + * If the callback was created without a Signature, this is the same + * value as This(). If there is a signature, and the signature didn't match + * This() but one of its hidden prototypes, this will be the respective + * hidden prototype. + * + * Note that this is not the prototype of This() on which the accessor + * referencing this callback was found (which in V8 internally is often + * referred to as holder [sic]). + */ + V8_INLINE Local Holder() const; + /** For construct calls, this returns the "new.target" value. */ + V8_INLINE Local NewTarget() const; + /** Indicates whether this is a regular call or a construct call. */ + V8_INLINE bool IsConstructCall() const; + /** The data argument specified when creating the callback. */ + V8_INLINE Local Data() const; + /** The current Isolate. */ + V8_INLINE Isolate* GetIsolate() const; + /** The ReturnValue for the call. */ + V8_INLINE ReturnValue GetReturnValue() const; + + private: + friend class internal::FunctionCallbackArguments; + friend class internal::CustomArguments; + friend class debug::ConsoleCallArguments; + + static constexpr int kHolderIndex = 0; + static constexpr int kIsolateIndex = 1; + static constexpr int kUnusedIndex = 2; + static constexpr int kReturnValueIndex = 3; + static constexpr int kDataIndex = 4; + static constexpr int kNewTargetIndex = 5; + static constexpr int kArgsLength = 6; + + static constexpr int kArgsLengthWithReceiver = kArgsLength + 1; + + // Codegen constants: + static constexpr int kSize = 3 * internal::kApiSystemPointerSize; + static constexpr int kImplicitArgsOffset = 0; + static constexpr int kValuesOffset = + kImplicitArgsOffset + internal::kApiSystemPointerSize; + static constexpr int kLengthOffset = + kValuesOffset + internal::kApiSystemPointerSize; + + static constexpr int kThisValuesIndex = -1; + static_assert(ReturnValue::kIsolateValueIndex == + kIsolateIndex - kReturnValueIndex); + + V8_INLINE FunctionCallbackInfo(internal::Address* implicit_args, + internal::Address* values, int length); + internal::Address* implicit_args_; + internal::Address* values_; + int length_; +}; + +/** + * The information passed to a property callback about the context + * of the property access. + */ +template +class PropertyCallbackInfo { + public: + /** + * \return The isolate of the property access. + */ + V8_INLINE Isolate* GetIsolate() const; + + /** + * \return The data set in the configuration, i.e., in + * `NamedPropertyHandlerConfiguration` or + * `IndexedPropertyHandlerConfiguration.` + */ + V8_INLINE Local Data() const; + + /** + * \return The receiver. In many cases, this is the object on which the + * property access was intercepted. When using + * `Reflect.get`, `Function.prototype.call`, or similar functions, it is the + * object passed in as receiver or thisArg. + * + * \code + * void GetterCallback(Local name, + * const v8::PropertyCallbackInfo& info) { + * auto context = info.GetIsolate()->GetCurrentContext(); + * + * v8::Local a_this = + * info.This() + * ->GetRealNamedProperty(context, v8_str("a")) + * .ToLocalChecked(); + * v8::Local a_holder = + * info.Holder() + * ->GetRealNamedProperty(context, v8_str("a")) + * .ToLocalChecked(); + * + * CHECK(v8_str("r")->Equals(context, a_this).FromJust()); + * CHECK(v8_str("obj")->Equals(context, a_holder).FromJust()); + * + * info.GetReturnValue().Set(name); + * } + * + * v8::Local templ = + * v8::FunctionTemplate::New(isolate); + * templ->InstanceTemplate()->SetHandler( + * v8::NamedPropertyHandlerConfiguration(GetterCallback)); + * LocalContext env; + * env->Global() + * ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local()) + * .ToLocalChecked() + * ->NewInstance(env.local()) + * .ToLocalChecked()) + * .FromJust(); + * + * CompileRun("obj.a = 'obj'; var r = {a: 'r'}; Reflect.get(obj, 'x', r)"); + * \endcode + */ + V8_INLINE Local This() const; + + /** + * \return The object in the prototype chain of the receiver that has the + * interceptor. Suppose you have `x` and its prototype is `y`, and `y` + * has an interceptor. Then `info.This()` is `x` and `info.Holder()` is `y`. + * The Holder() could be a hidden object (the global object, rather + * than the global proxy). + * + * \note For security reasons, do not pass the object back into the runtime. + */ + V8_INLINE Local Holder() const; + + /** + * \return The return value of the callback. + * Can be changed by calling Set(). + * \code + * info.GetReturnValue().Set(...) + * \endcode + * + */ + V8_INLINE ReturnValue GetReturnValue() const; + + /** + * \return True if the intercepted function should throw if an error occurs. + * Usually, `true` corresponds to `'use strict'`. + * + * \note Always `false` when intercepting `Reflect.set()` + * independent of the language mode. + */ + V8_INLINE bool ShouldThrowOnError() const; + + private: + friend class MacroAssembler; + friend class internal::PropertyCallbackArguments; + friend class internal::CustomArguments; + static constexpr int kShouldThrowOnErrorIndex = 0; + static constexpr int kHolderIndex = 1; + static constexpr int kIsolateIndex = 2; + static constexpr int kUnusedIndex = 3; + static constexpr int kReturnValueIndex = 4; + static constexpr int kDataIndex = 5; + static constexpr int kThisIndex = 6; + static constexpr int kArgsLength = 7; + + static constexpr int kSize = 1 * internal::kApiSystemPointerSize; + + V8_INLINE explicit PropertyCallbackInfo(internal::Address* args) + : args_(args) {} + + internal::Address* args_; +}; + +using FunctionCallback = void (*)(const FunctionCallbackInfo& info); + +// --- Implementation --- + +template +ReturnValue::ReturnValue(internal::Address* slot) : value_(slot) {} + +template +template +void ReturnValue::Set(const Global& handle) { + static_assert(std::is_base_of::value, "type check"); + if (V8_UNLIKELY(handle.IsEmpty())) { + *value_ = GetDefaultValue(); + } else { + *value_ = handle.ptr(); + } +} + +template +template +void ReturnValue::Set(const BasicTracedReference& handle) { + static_assert(std::is_base_of::value, "type check"); + if (V8_UNLIKELY(handle.IsEmpty())) { + *value_ = GetDefaultValue(); + } else { + *value_ = handle.ptr(); + } +} + +template +template +void ReturnValue::Set(const Local handle) { + static_assert(std::is_void::value || std::is_base_of::value, + "type check"); + if (V8_UNLIKELY(handle.IsEmpty())) { + *value_ = GetDefaultValue(); + } else { + *value_ = handle.ptr(); + } +} + +template +void ReturnValue::Set(double i) { + static_assert(std::is_base_of::value, "type check"); + Set(Number::New(GetIsolate(), i)); +} + +template +void ReturnValue::Set(int32_t i) { + static_assert(std::is_base_of::value, "type check"); + using I = internal::Internals; + if (V8_LIKELY(I::IsValidSmi(i))) { + *value_ = I::IntToSmi(i); + return; + } + Set(Integer::New(GetIsolate(), i)); +} + +template +void ReturnValue::Set(uint32_t i) { + static_assert(std::is_base_of::value, "type check"); + // Can't simply use INT32_MAX here for whatever reason. + bool fits_into_int32_t = (i & (1U << 31)) == 0; + if (V8_LIKELY(fits_into_int32_t)) { + Set(static_cast(i)); + return; + } + Set(Integer::NewFromUnsigned(GetIsolate(), i)); +} + +template +void ReturnValue::Set(bool value) { + static_assert(std::is_base_of::value, "type check"); + using I = internal::Internals; + int root_index; + if (value) { + root_index = I::kTrueValueRootIndex; + } else { + root_index = I::kFalseValueRootIndex; + } + *value_ = I::GetRoot(GetIsolate(), root_index); +} + +template +void ReturnValue::SetNull() { + static_assert(std::is_base_of::value, "type check"); + using I = internal::Internals; + *value_ = I::GetRoot(GetIsolate(), I::kNullValueRootIndex); +} + +template +void ReturnValue::SetUndefined() { + static_assert(std::is_base_of::value, "type check"); + using I = internal::Internals; + *value_ = I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex); +} + +template +void ReturnValue::SetEmptyString() { + static_assert(std::is_base_of::value, "type check"); + using I = internal::Internals; + *value_ = I::GetRoot(GetIsolate(), I::kEmptyStringRootIndex); +} + +template +Isolate* ReturnValue::GetIsolate() const { + return *reinterpret_cast(&value_[kIsolateValueIndex]); +} + +template +Local ReturnValue::Get() const { + using I = internal::Internals; +#if V8_STATIC_ROOTS_BOOL + if (I::is_identical(*value_, I::StaticReadOnlyRoot::kTheHoleValue)) { +#else + if (*value_ == I::GetRoot(GetIsolate(), I::kTheHoleValueRootIndex)) { +#endif + return Undefined(GetIsolate()); + } + return Local::New(GetIsolate(), reinterpret_cast(value_)); +} + +template +template +void ReturnValue::Set(S* whatever) { + static_assert(sizeof(S) < 0, "incompilable to prevent inadvertent misuse"); +} + +template +internal::Address ReturnValue::GetDefaultValue() { + using I = internal::Internals; + return I::GetRoot(GetIsolate(), I::kTheHoleValueRootIndex); +} + +template +FunctionCallbackInfo::FunctionCallbackInfo(internal::Address* implicit_args, + internal::Address* values, + int length) + : implicit_args_(implicit_args), values_(values), length_(length) {} + +template +Local FunctionCallbackInfo::operator[](int i) const { + // values_ points to the first argument (not the receiver). + if (i < 0 || length_ <= i) return Undefined(GetIsolate()); + return Local::FromSlot(values_ + i); +} + +template +Local FunctionCallbackInfo::This() const { + // values_ points to the first argument (not the receiver). + return Local::FromSlot(values_ + kThisValuesIndex); +} + +template +Local FunctionCallbackInfo::Holder() const { + return Local::FromSlot(&implicit_args_[kHolderIndex]); +} + +template +Local FunctionCallbackInfo::NewTarget() const { + return Local::FromSlot(&implicit_args_[kNewTargetIndex]); +} + +template +Local FunctionCallbackInfo::Data() const { + return Local::FromSlot(&implicit_args_[kDataIndex]); +} + +template +Isolate* FunctionCallbackInfo::GetIsolate() const { + return *reinterpret_cast(&implicit_args_[kIsolateIndex]); +} + +template +ReturnValue FunctionCallbackInfo::GetReturnValue() const { + return ReturnValue(&implicit_args_[kReturnValueIndex]); +} + +template +bool FunctionCallbackInfo::IsConstructCall() const { + return !NewTarget()->IsUndefined(); +} + +template +int FunctionCallbackInfo::Length() const { + return length_; +} + +template +Isolate* PropertyCallbackInfo::GetIsolate() const { + return *reinterpret_cast(&args_[kIsolateIndex]); +} + +template +Local PropertyCallbackInfo::Data() const { + return Local::FromSlot(&args_[kDataIndex]); +} + +template +Local PropertyCallbackInfo::This() const { + return Local::FromSlot(&args_[kThisIndex]); +} + +template +Local PropertyCallbackInfo::Holder() const { + return Local::FromSlot(&args_[kHolderIndex]); +} + +template +ReturnValue PropertyCallbackInfo::GetReturnValue() const { + return ReturnValue(&args_[kReturnValueIndex]); +} + +template +bool PropertyCallbackInfo::ShouldThrowOnError() const { + using I = internal::Internals; + if (args_[kShouldThrowOnErrorIndex] != + I::IntToSmi(I::kInferShouldThrowMode)) { + return args_[kShouldThrowOnErrorIndex] != I::IntToSmi(I::kDontThrow); + } + return v8::internal::ShouldThrowOnError( + reinterpret_cast(GetIsolate())); +} + +} // namespace v8 + +#endif // INCLUDE_V8_FUNCTION_CALLBACK_H_ diff --git a/NativeScript/napi/v8/include_old/v8-function.h b/NativeScript/napi/v8/include_old/v8-function.h new file mode 100644 index 00000000..30a9fcfe --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-function.h @@ -0,0 +1,140 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_FUNCTION_H_ +#define INCLUDE_V8_FUNCTION_H_ + +#include +#include + +#include "v8-function-callback.h" // NOLINT(build/include_directory) +#include "v8-local-handle.h" // NOLINT(build/include_directory) +#include "v8-message.h" // NOLINT(build/include_directory) +#include "v8-object.h" // NOLINT(build/include_directory) +#include "v8-template.h" // NOLINT(build/include_directory) +#include "v8config.h" // NOLINT(build/include_directory) + +namespace v8 { + +class Context; +class UnboundScript; + +/** + * A JavaScript function object (ECMA-262, 15.3). + */ +class V8_EXPORT Function : public Object { + public: + /** + * Create a function in the current execution context + * for a given FunctionCallback. + */ + static MaybeLocal New( + Local context, FunctionCallback callback, + Local data = Local(), int length = 0, + ConstructorBehavior behavior = ConstructorBehavior::kAllow, + SideEffectType side_effect_type = SideEffectType::kHasSideEffect); + + V8_WARN_UNUSED_RESULT MaybeLocal NewInstance( + Local context, int argc, Local argv[]) const; + + V8_WARN_UNUSED_RESULT MaybeLocal NewInstance( + Local context) const { + return NewInstance(context, 0, nullptr); + } + + /** + * When side effect checks are enabled, passing kHasNoSideEffect allows the + * constructor to be invoked without throwing. Calls made within the + * constructor are still checked. + */ + V8_WARN_UNUSED_RESULT MaybeLocal NewInstanceWithSideEffectType( + Local context, int argc, Local argv[], + SideEffectType side_effect_type = SideEffectType::kHasSideEffect) const; + + V8_WARN_UNUSED_RESULT MaybeLocal Call(Local context, + Local recv, int argc, + Local argv[]); + + void SetName(Local name); + Local GetName() const; + + V8_DEPRECATED("No direct replacement") + MaybeLocal GetUnboundScript() const; + + /** + * Name inferred from variable or property assignment of this function. + * Used to facilitate debugging and profiling of JavaScript code written + * in an OO style, where many functions are anonymous but are assigned + * to object properties. + */ + Local GetInferredName() const; + + /** + * displayName if it is set, otherwise name if it is configured, otherwise + * function name, otherwise inferred name. + */ + Local GetDebugName() const; + + /** + * Returns zero based line number of function body and + * kLineOffsetNotFound if no information available. + */ + int GetScriptLineNumber() const; + /** + * Returns zero based column number of function body and + * kLineOffsetNotFound if no information available. + */ + int GetScriptColumnNumber() const; + + /** + * Returns zero based start position (character offset) of function body and + * kLineOffsetNotFound if no information available. + */ + int GetScriptStartPosition() const; + + /** + * Returns scriptId. + */ + int ScriptId() const; + + /** + * Returns the original function if this function is bound, else returns + * v8::Undefined. + */ + Local GetBoundFunction() const; + + /** + * Calls builtin Function.prototype.toString on this function. + * This is different from Value::ToString() that may call a user-defined + * toString() function, and different than Object::ObjectProtoToString() which + * always serializes "[object Function]". + */ + V8_WARN_UNUSED_RESULT MaybeLocal FunctionProtoToString( + Local context); + + /** + * Returns true if the function does nothing. + * The function returns false on error. + * Note that this function is experimental. Embedders should not rely on + * this existing. We may remove this function in the future. + */ + V8_WARN_UNUSED_RESULT bool Experimental_IsNopFunction() const; + + ScriptOrigin GetScriptOrigin() const; + V8_INLINE static Function* Cast(Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); + } + + static const int kLineOffsetNotFound; + + private: + Function(); + static void CheckCast(Value* obj); +}; +} // namespace v8 + +#endif // INCLUDE_V8_FUNCTION_H_ diff --git a/NativeScript/napi/v8/include_old/v8-handle-base.h b/NativeScript/napi/v8/include_old/v8-handle-base.h new file mode 100644 index 00000000..d346a80d --- /dev/null +++ b/NativeScript/napi/v8/include_old/v8-handle-base.h @@ -0,0 +1,185 @@ +// Copyright 2023 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_V8_HANDLE_BASE_H_ +#define INCLUDE_V8_HANDLE_BASE_H_ + +#include "v8-internal.h" // NOLINT(build/include_directory) + +namespace v8 { + +namespace internal { + +// Helper functions about values contained in handles. +// A value is either an indirect pointer or a direct pointer, depending on +// whether direct local support is enabled. +class ValueHelper final { + public: +#ifdef V8_ENABLE_DIRECT_LOCAL + static constexpr Address kTaggedNullAddress = 1; + static constexpr Address kEmpty = kTaggedNullAddress; +#else + static constexpr Address kEmpty = kNullAddress; +#endif // V8_ENABLE_DIRECT_LOCAL + + template + V8_INLINE static bool IsEmpty(T* value) { + return reinterpret_cast
(value) == kEmpty; + } + + // Returns a handle's "value" for all kinds of abstract handles. For Local, + // it is equivalent to `*handle`. The variadic parameters support handle + // types with extra type parameters, like `Persistent`. + template