Created
August 25, 2025 13:55
-
-
Save andrewmd5/70b98411a34bbeb63d2cf3402f0465cb to your computer and use it in GitHub Desktop.
JavaScriptCore ECMAScript modules (C API)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <string.h> | |
| #include <JavaScriptCore/JavaScript.h> | |
| // Main module that imports JSON files | |
| static const char* MAIN_MODULE = | |
| "import config from './config.json' with { type: 'json' };\n" | |
| "import data from './data.json' with { type: 'json' };\n" | |
| "\n" | |
| "export function getConfig() { return config; }\n" | |
| "export function getData() { return data; }\n" | |
| "export function calculate(x, y) {\n" | |
| " return (x + y) * config.multiplier;\n" | |
| "}"; | |
| // JSON files | |
| static const char* CONFIG_JSON = | |
| "{\n" | |
| " \"multiplier\": 3,\n" | |
| " \"appName\": \"Test App\",\n" | |
| " \"enabled\": true\n" | |
| "}"; | |
| static const char* DATA_JSON = | |
| "{\n" | |
| " \"users\": [\"Alice\", \"Bob\", \"Charlie\"],\n" | |
| " \"count\": 3,\n" | |
| " \"version\": \"1.0.0\"\n" | |
| "}"; | |
| // Module resolver - just returns the module key as-is | |
| JSStringRef resolveCallback(JSContextRef ctx, JSStringRef spec, JSStringRef ref, void* info) { | |
| return JSStringRetain(spec); | |
| } | |
| // Module fetcher - provides module source code | |
| JSValueRef fetchCallback(JSContextRef ctx, JSStringRef key, JSObjectRef attrs, void* info) { | |
| char keyBuffer[256]; | |
| JSStringGetUTF8CString(key, keyBuffer, sizeof(keyBuffer)); | |
| // Check if this is a JSON import | |
| int sourceType = 1; // Default: Module | |
| if (attrs) { | |
| JSStringRef typeProp = JSStringCreateWithUTF8CString("type"); | |
| JSValueRef typeValue = JSObjectGetProperty(ctx, attrs, typeProp, NULL); | |
| JSStringRelease(typeProp); | |
| if (!JSValueIsUndefined(ctx, typeValue)) { | |
| JSStringRef typeStr = JSValueToStringCopy(ctx, typeValue, NULL); | |
| char typeBuffer[64]; | |
| JSStringGetUTF8CString(typeStr, typeBuffer, sizeof(typeBuffer)); | |
| if (strcmp(typeBuffer, "json") == 0) { | |
| sourceType = 3; // JSON module type | |
| } | |
| JSStringRelease(typeStr); | |
| } | |
| } | |
| // Return appropriate module source | |
| JSStringRef source = NULL; | |
| if (strcmp(keyBuffer, "main.js") == 0) { | |
| source = JSStringCreateWithUTF8CString(MAIN_MODULE); | |
| } else if (strcmp(keyBuffer, "./config.json") == 0) { | |
| source = JSStringCreateWithUTF8CString(CONFIG_JSON); | |
| } else if (strcmp(keyBuffer, "./data.json") == 0) { | |
| source = JSStringCreateWithUTF8CString(DATA_JSON); | |
| } | |
| if (source) { | |
| JSValueRef result = JSModuleSourceCreate(ctx, source, key, sourceType); | |
| JSStringRelease(source); | |
| return result; | |
| } | |
| return NULL; | |
| } | |
| // Helper to print JS values | |
| void printValue(JSContextRef ctx, JSValueRef value) { | |
| if (JSValueIsNull(ctx, value)) { | |
| printf("null"); | |
| } else if (JSValueIsUndefined(ctx, value)) { | |
| printf("undefined"); | |
| } else if (JSValueIsBoolean(ctx, value)) { | |
| printf("%s", JSValueToBoolean(ctx, value) ? "true" : "false"); | |
| } else if (JSValueIsNumber(ctx, value)) { | |
| double num = JSValueToNumber(ctx, value, NULL); | |
| printf("%.0f", num); | |
| } else if (JSValueIsString(ctx, value)) { | |
| JSStringRef str = JSValueToStringCopy(ctx, value, NULL); | |
| char buffer[256]; | |
| JSStringGetUTF8CString(str, buffer, sizeof(buffer)); | |
| printf("\"%s\"", buffer); | |
| JSStringRelease(str); | |
| } else if (JSValueIsObject(ctx, value)) { | |
| // Convert to JSON string for display | |
| JSStringRef jsonStr = JSValueCreateJSONString(ctx, value, 2, NULL); | |
| if (jsonStr) { | |
| char buffer[1024]; | |
| JSStringGetUTF8CString(jsonStr, buffer, sizeof(buffer)); | |
| printf("%s", buffer); | |
| JSStringRelease(jsonStr); | |
| } else { | |
| printf("[object]"); | |
| } | |
| } | |
| } | |
| // Helper to get and print a property | |
| void printProperty(JSContextRef ctx, JSValueRef obj, const char* propName) { | |
| JSStringRef prop = JSStringCreateWithUTF8CString(propName); | |
| JSValueRef value = JSObjectGetProperty(ctx, JSValueToObject(ctx, obj, NULL), prop, NULL); | |
| printf(" %s: ", propName); | |
| printValue(ctx, value); | |
| printf("\n"); | |
| JSStringRelease(prop); | |
| } | |
| int main() { | |
| printf("=== Module Test ===\n\n"); | |
| JSGlobalContextRef ctx = JSGlobalContextCreateWithModuleLoaderEx( | |
| NULL, resolveCallback, fetchCallback, NULL, NULL, NULL | |
| ); | |
| JSStringRef moduleKey = JSStringCreateWithUTF8CString("main.js"); | |
| JSValueRef exception = NULL; | |
| JSObjectRef promise = JSEvaluateModule(ctx, moduleKey, &exception); | |
| if (exception) { | |
| printf("Error starting module evaluation\n"); | |
| JSStringRelease(moduleKey); | |
| JSGlobalContextRelease(ctx); | |
| return 1; | |
| } | |
| // Check if module loaded successfully | |
| JSPromiseState state = JSValueGetPromiseState(ctx, promise, &exception); | |
| if (state != kJSPromiseStateFulfilled) { | |
| printf("Module failed to load\n"); | |
| JSStringRelease(moduleKey); | |
| JSGlobalContextRelease(ctx); | |
| return 1; | |
| } | |
| printf("✓ Module loaded successfully!\n\n"); | |
| // Get the module namespace | |
| JSValueRef moduleNS = JSValueGetPromiseResult(ctx, promise, &exception); | |
| JSObjectRef module = JSValueToObject(ctx, moduleNS, &exception); | |
| // Test 1: Call getConfig() and verify JSON was imported | |
| printf("Test 1: getConfig()\n"); | |
| JSStringRef getConfigProp = JSStringCreateWithUTF8CString("getConfig"); | |
| JSValueRef getConfigFunc = JSObjectGetProperty(ctx, module, getConfigProp, NULL); | |
| JSValueRef configResult = JSObjectCallAsFunction(ctx, | |
| JSValueToObject(ctx, getConfigFunc, NULL), NULL, 0, NULL, &exception); | |
| if (configResult) { | |
| printProperty(ctx, configResult, "multiplier"); | |
| printProperty(ctx, configResult, "appName"); | |
| printProperty(ctx, configResult, "enabled"); | |
| } | |
| JSStringRelease(getConfigProp); | |
| // Test 2: Call getData() and verify JSON was imported | |
| printf("\nTest 2: getData()\n"); | |
| JSStringRef getDataProp = JSStringCreateWithUTF8CString("getData"); | |
| JSValueRef getDataFunc = JSObjectGetProperty(ctx, module, getDataProp, NULL); | |
| JSValueRef dataResult = JSObjectCallAsFunction(ctx, | |
| JSValueToObject(ctx, getDataFunc, NULL), NULL, 0, NULL, &exception); | |
| if (dataResult) { | |
| printProperty(ctx, dataResult, "users"); | |
| printProperty(ctx, dataResult, "count"); | |
| printProperty(ctx, dataResult, "version"); | |
| } | |
| JSStringRelease(getDataProp); | |
| // Test 3: Call calculate() which uses the imported config | |
| printf("\nTest 3: calculate(5, 7)\n"); | |
| JSStringRef calcProp = JSStringCreateWithUTF8CString("calculate"); | |
| JSValueRef calcFunc = JSObjectGetProperty(ctx, module, calcProp, NULL); | |
| JSValueRef args[] = { | |
| JSValueMakeNumber(ctx, 5), | |
| JSValueMakeNumber(ctx, 7) | |
| }; | |
| JSValueRef result = JSObjectCallAsFunction(ctx, | |
| JSValueToObject(ctx, calcFunc, NULL), NULL, 2, args, &exception); | |
| printf(" Result: "); | |
| printValue(ctx, result); | |
| printf(" (expected: (5+7)*3 = 36)\n"); | |
| JSStringRelease(calcProp); | |
| printf("\n✓ All tests completed!\n"); | |
| // Cleanup | |
| JSStringRelease(moduleKey); | |
| JSGlobalContextRelease(ctx); | |
| return 0; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git forkSrcPrefix/Source/JavaScriptCore/API/JSValueRef.h forkDstPrefix/Source/JavaScriptCore/API/JSValueRef.h | |
| index 0d93dfb45c2dead191e48c604fa3768db11308cb..7265ff37956f633c2ef0f2848be78e1d0ef62467 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/API/JSValueRef.h | |
| +++ forkDstPrefix/Source/JavaScriptCore/API/JSValueRef.h | |
| @@ -548,8 +548,60 @@ JS_EXPORT void JSValueProtect(JSC_NULL_UNSPECIFIED JSContextRef ctx, JSC_NULL_UN | |
| */ | |
| JS_EXPORT void JSValueUnprotect(JSC_NULL_UNSPECIFIED JSContextRef ctx, JSC_NULL_UNSPECIFIED JSValueRef value); | |
| +/*! | |
| +@enum JSPromiseState | |
| +@abstract The state of a promise. | |
| +@constant kJSPromiseStatePending The promise is pending. | |
| +@constant kJSPromiseStateFulfilled The promise has been fulfilled with a value. | |
| +@constant kJSPromiseStateRejected The promise has been rejected with a reason. | |
| +*/ | |
| +typedef enum { | |
| + kJSPromiseStatePending, | |
| + kJSPromiseStateFulfilled, | |
| + kJSPromiseStateRejected | |
| +} JSPromiseState JSC_API_AVAILABLE(macos(13.3), ios(16.4)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Tests whether a JavaScript value is a Promise. | |
| +@param ctx The execution context to use. | |
| +@param value The JSValue to test. | |
| +@result true if value is a Promise, otherwise false. | |
| +*/ | |
| +JS_EXPORT bool JSValueIsPromise(JSC_NULL_UNSPECIFIED JSContextRef ctx, JSC_NULL_UNSPECIFIED JSValueRef value) JSC_API_AVAILABLE(macos(13.3), ios(16.4)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Gets the state of a Promise. | |
| +@param ctx The execution context to use. | |
| +@param promise The promise value to check. | |
| +@param exception A pointer to store an exception if the value is not a promise. | |
| +@result The state of the promise, or kJSPromiseStatePending if not a promise. | |
| +*/ | |
| +JS_EXPORT JSPromiseState JSValueGetPromiseState(JSC_NULL_UNSPECIFIED JSContextRef ctx, JSC_NULL_UNSPECIFIED JSValueRef promise, JSC_NULL_UNSPECIFIED JSValueRef* JSC_NULL_UNSPECIFIED exception) JSC_API_AVAILABLE(macos(13.3), ios(16.4)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Gets the fulfilled value of a Promise. | |
| +@param ctx The execution context to use. | |
| +@param promise The promise value. | |
| +@param exception A pointer to store an exception if the promise is not fulfilled or not a promise. | |
| +@result The fulfilled value, or NULL if the promise is not fulfilled. | |
| +*/ | |
| +JS_EXPORT JSC_NULL_UNSPECIFIED JSValueRef JSValueGetPromiseResult(JSC_NULL_UNSPECIFIED JSContextRef ctx, JSC_NULL_UNSPECIFIED JSValueRef promise, JSC_NULL_UNSPECIFIED JSValueRef* JSC_NULL_UNSPECIFIED exception) JSC_API_AVAILABLE(macos(13.3), ios(16.4)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Gets the rejection reason of a Promise. | |
| +@param ctx The execution context to use. | |
| +@param promise The promise value. | |
| +@param exception A pointer to store an exception if the promise is not rejected or not a promise. | |
| +@result The rejection reason, or NULL if the promise is not rejected. | |
| +*/ | |
| +JS_EXPORT JSC_NULL_UNSPECIFIED JSValueRef JSValueGetPromiseRejectionReason(JSC_NULL_UNSPECIFIED JSContextRef ctx, JSC_NULL_UNSPECIFIED JSValueRef promise, JSC_NULL_UNSPECIFIED JSValueRef* JSC_NULL_UNSPECIFIED exception) JSC_API_AVAILABLE(macos(13.3), ios(16.4)); | |
| + | |
| #ifdef __cplusplus | |
| } | |
| #endif | |
| -#endif /* JSValueRef_h */ | |
| +#endif /* JSValueRef_h */ | |
| \ No newline at end of file | |
| diff --git forkSrcPrefix/Source/JavaScriptCore/API/JSContextRef.cpp forkDstPrefix/Source/JavaScriptCore/API/JSContextRef.cpp | |
| index 84df90637a8b82ee2a5cdc895671030b819f7f84..3b790d26d693739497d5b443ab7244dca1a44c79 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/API/JSContextRef.cpp | |
| +++ forkDstPrefix/Source/JavaScriptCore/API/JSContextRef.cpp | |
| @@ -25,21 +25,48 @@ | |
| #include "config.h" | |
| #include "JSContextRef.h" | |
| +#include "JSCJSValue.h" | |
| #include "JSContextRefInternal.h" | |
| #include "APICast.h" | |
| #include "CallFrame.h" | |
| +#include "Completion.h" | |
| +#include "GlobalObjectMethodTable.h" | |
| #include "InitializeThreading.h" | |
| #include "IntegrityInlines.h" | |
| #include "JSAPIGlobalObject.h" | |
| #include "JSAPIWrapperObject.h" | |
| #include "JSCallbackObject.h" | |
| #include "JSClassRef.h" | |
| +#include "JSGlobalObject.h" | |
| +#include "JSInternalPromise.h" | |
| +#include "JSMap.h" | |
| +#include "JSModuleLoader.h" | |
| +#include "JSModuleRecord.h" | |
| +#include "JSNativeStdFunction.h" | |
| #include "JSObjectInlines.h" | |
| +#include "JSPromise.h" | |
| +#include "JSScriptFetchParameters.h" | |
| +#include "JSSourceCode.h" | |
| +#include "JSString.h" | |
| +#include "JSStringRef.h" | |
| +#include "JSWebAssemblyHelpers.h" | |
| +#include "ModuleAnalyzer.h" | |
| +#include "ObjectConstructor.h" | |
| +#include "ParserError.h" | |
| +#include "ScriptFetchParameters.h" | |
| +#include "SourceCode.h" | |
| +#include "SourceOrigin.h" | |
| +#include "SourceProvider.h" | |
| #include "StackVisitor.h" | |
| #include "StrongInlines.h" | |
| #include "StructureInlines.h" | |
| +#include "JSModuleNamespaceObject.h" | |
| #include "Watchdog.h" | |
| +#include <cstdio> | |
| +#include <wtf/HashMap.h> | |
| +#include <wtf/HashSet.h> | |
| +#include <wtf/URL.h> | |
| #include <wtf/text/StringBuilder.h> | |
| #if ENABLE(REMOTE_INSPECTOR) | |
| @@ -60,6 +87,331 @@ static constexpr int32_t webkitFirstVersionWithConcurrentGlobalContexts = 0x2100 | |
| using namespace JSC; | |
| +struct JSModuleLoaderContext { | |
| + JSModuleLoaderResolveCallback resolveCallback; | |
| + JSModuleLoaderFetchCallback fetchCallback; | |
| + JSModuleLoaderImportMetaCallback importMetaCallback; | |
| + JSModuleLoaderEvaluateCallback evaluateCallback; | |
| + void* userData; | |
| + JSContextRef ctx; | |
| + WTF::HashMap<String, Strong<JSInternalPromise>> modulePromises; | |
| + WTF::HashSet<String> syntheticModuleKeys; | |
| +}; | |
| + | |
| +class CAPIGlobalObject final : public JSGlobalObject { | |
| +public: | |
| + using Base = JSGlobalObject; | |
| + static constexpr unsigned StructureFlags = Base::StructureFlags; | |
| + | |
| + static CAPIGlobalObject* create(VM& vm, Structure* structure, JSModuleLoaderContext* context) | |
| + { | |
| + CAPIGlobalObject* object = new (NotNull, allocateCell<CAPIGlobalObject>(vm)) CAPIGlobalObject(vm, structure); | |
| + object->finishCreation(vm, context); | |
| + return object; | |
| + } | |
| + | |
| + DECLARE_INFO; | |
| + static const GlobalObjectMethodTable s_globalObjectMethodTable; | |
| + | |
| + static Structure* createStructure(VM& vm, JSValue prototype) | |
| + { | |
| + return Structure::create(vm, nullptr, prototype, TypeInfo(GlobalObjectType, StructureFlags), info()); | |
| + } | |
| + | |
| + static RuntimeFlags javaScriptRuntimeFlags(const JSGlobalObject*) | |
| + { | |
| + return RuntimeFlags::createAllEnabled(); | |
| + } | |
| + | |
| + bool isSyntheticModule(const String& moduleKey) const { | |
| + return m_moduleLoaderContext && m_moduleLoaderContext->syntheticModuleKeys.contains(moduleKey); | |
| + } | |
| + | |
| + JSModuleLoaderContext* moduleLoaderContext() const { return m_moduleLoaderContext; } | |
| + | |
| +private: | |
| + CAPIGlobalObject(VM&, Structure*); | |
| + | |
| + void finishCreation(VM& vm, JSModuleLoaderContext* context) | |
| + { | |
| + Base::finishCreation(vm); | |
| + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); | |
| + m_moduleLoaderContext = context; | |
| + } | |
| + | |
| + static Identifier moduleLoaderResolve(JSGlobalObject*, JSModuleLoader*, JSValue keyValue, JSValue referrerValue, JSValue); | |
| + static JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, JSModuleLoader*, JSValue keyValue, JSValue parametersValue, JSValue); | |
| + static JSObject* moduleLoaderCreateImportMetaProperties(JSGlobalObject*, JSModuleLoader*, JSValue keyValue, JSModuleRecord*, JSValue); | |
| + static JSInternalPromise* moduleLoaderImportModule(JSGlobalObject*, JSModuleLoader*, JSString* moduleNameValue, JSValue parameters, const SourceOrigin& sourceOrigin); | |
| + static JSValue moduleLoaderEvaluate(JSGlobalObject*, JSModuleLoader*, JSValue, JSValue, JSValue, JSValue, JSValue); | |
| + static void queueMicrotaskToEventLoop(JSGlobalObject&, QueuedTask&&); | |
| + JSModuleLoaderContext* m_moduleLoaderContext; | |
| +}; | |
| + | |
| +const ClassInfo CAPIGlobalObject::s_info = { "CAPIGlobalObject"_s, &JSGlobalObject::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(CAPIGlobalObject) }; | |
| + | |
| +const GlobalObjectMethodTable CAPIGlobalObject::s_globalObjectMethodTable = { | |
| + &supportsRichSourceInfo, | |
| + &shouldInterruptScript, | |
| + &javaScriptRuntimeFlags, | |
| + nullptr, | |
| + &shouldInterruptScriptBeforeTimeout, | |
| + &moduleLoaderImportModule, | |
| + &moduleLoaderResolve, | |
| + &moduleLoaderFetch, | |
| + &moduleLoaderCreateImportMetaProperties, | |
| + &moduleLoaderEvaluate, // Now implemented for synthetic modules | |
| + nullptr, // promiseRejectionTracker | |
| + &reportUncaughtExceptionAtEventLoop, | |
| + ¤tScriptExecutionOwner, | |
| + &scriptExecutionStatus, | |
| + &reportViolationForUnsafeEval, | |
| + nullptr, // defaultLanguage | |
| + nullptr, // compileStreaming | |
| + nullptr, // instantiateStreaming | |
| + &deriveShadowRealmGlobalObject, | |
| + &codeForEval, | |
| + &canCompileStrings, | |
| + &trustedScriptStructure, | |
| +}; | |
| + | |
| +CAPIGlobalObject::CAPIGlobalObject(VM& vm, Structure* structure) | |
| + : JSGlobalObject(vm, structure, &s_globalObjectMethodTable) | |
| +{ | |
| +} | |
| + | |
| + | |
| + | |
| +Identifier CAPIGlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, JSModuleLoader*, JSValue keyValue, JSValue referrerValue, JSValue) | |
| +{ | |
| + VM& vm = globalObject->vm(); | |
| + auto scope = DECLARE_THROW_SCOPE(vm); | |
| + | |
| + CAPIGlobalObject* thisObject = jsCast<CAPIGlobalObject*>(globalObject); | |
| + JSModuleLoaderContext* context = thisObject->moduleLoaderContext(); | |
| + | |
| + if (!context || !context->resolveCallback) { | |
| + const Identifier key = keyValue.toPropertyKey(globalObject); | |
| + RETURN_IF_EXCEPTION(scope, { }); | |
| + return key; | |
| + } | |
| + | |
| + const Identifier key = keyValue.toPropertyKey(globalObject); | |
| + RETURN_IF_EXCEPTION(scope, { }); | |
| + | |
| + String specifier = key.string(); | |
| + String referrer = referrerValue.isUndefined() ? String() : referrerValue.toWTFString(globalObject); | |
| + RETURN_IF_EXCEPTION(scope, { }); | |
| + | |
| + JSStringRef specifierRef = OpaqueJSString::tryCreate(specifier).leakRef(); | |
| + JSStringRef referrerRef = referrer.isEmpty() ? nullptr : OpaqueJSString::tryCreate(referrer).leakRef(); | |
| + | |
| + JSStringRef resolvedRef = context->resolveCallback(context->ctx, specifierRef, referrerRef, context->userData); | |
| + | |
| + if (specifierRef) | |
| + JSStringRelease(specifierRef); | |
| + if (referrerRef) | |
| + JSStringRelease(referrerRef); | |
| + | |
| + if (!resolvedRef) { | |
| + throwTypeError(globalObject, scope, makeString("Failed to resolve module: "_s, specifier)); | |
| + return { }; | |
| + } | |
| + | |
| + String resolved = resolvedRef->string(); | |
| + JSStringRelease(resolvedRef); | |
| + | |
| + return Identifier::fromString(vm, resolved); | |
| +} | |
| + | |
| +JSInternalPromise* CAPIGlobalObject::moduleLoaderFetch(JSGlobalObject* globalObject, JSModuleLoader*, JSValue keyValue, JSValue parametersValue, JSValue) | |
| +{ | |
| + VM& vm = globalObject->vm(); | |
| + auto scope = DECLARE_THROW_SCOPE(vm); | |
| + | |
| + CAPIGlobalObject* thisObject = jsCast<CAPIGlobalObject*>(globalObject); | |
| + JSModuleLoaderContext* context = thisObject->moduleLoaderContext(); | |
| + JSInternalPromise* promise = JSInternalPromise::create(vm, globalObject->internalPromiseStructure()); | |
| + | |
| + if (!context || !context->fetchCallback) { | |
| + promise->reject(globalObject, createTypeError(globalObject, "No module fetch callback provided"_s)); | |
| + return promise; | |
| + } | |
| + | |
| + String moduleKey = keyValue.toWTFString(globalObject); | |
| + RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); | |
| + | |
| + auto it = context->modulePromises.find(moduleKey); | |
| + if (it != context->modulePromises.end()) | |
| + return it->value.get(); | |
| + | |
| + JSObjectRef attributesRef = nullptr; | |
| + if (JSScriptFetchParameters* parameters = jsDynamicCast<JSScriptFetchParameters*>(parametersValue)) { | |
| + JSObject* attributesObj = constructEmptyObject(globalObject); | |
| + | |
| + if (parameters->parameters().type() != ScriptFetchParameters::Type::JavaScript) { | |
| + String typeString; | |
| + switch (parameters->parameters().type()) { | |
| + case ScriptFetchParameters::Type::JSON: | |
| + typeString = "json"_s; | |
| + break; | |
| +#if ENABLE(WEBASSEMBLY) | |
| + case ScriptFetchParameters::Type::WebAssembly: | |
| + typeString = "wasm"_s; | |
| + break; | |
| +#endif | |
| + default: | |
| + break; | |
| + } | |
| + if (!typeString.isEmpty()) | |
| + attributesObj->putDirect(vm, vm.propertyNames->type, jsString(vm, typeString)); | |
| + } | |
| + attributesRef = toRef(attributesObj); | |
| + } | |
| + | |
| + JSStringRef keyRef = OpaqueJSString::tryCreate(moduleKey).leakRef(); | |
| + | |
| + JSValueRef sourceCodeRef = context->fetchCallback(context->ctx, keyRef, attributesRef, context->userData); | |
| + JSStringRelease(keyRef); | |
| + | |
| + if (!sourceCodeRef) { | |
| + promise->reject(globalObject, createError(globalObject, makeString("Failed to fetch module: "_s, moduleKey))); | |
| + return promise; | |
| + } | |
| + | |
| + JSValue sourceCodeValue = toJS(globalObject, sourceCodeRef); | |
| + | |
| + if (!sourceCodeValue.isCell() || !jsDynamicCast<JSSourceCode*>(sourceCodeValue.asCell())) { | |
| + promise->reject(globalObject, createTypeError(globalObject, "Fetch callback must return a JSSourceCode object"_s)); | |
| + return promise; | |
| + } | |
| + | |
| + context->modulePromises.set(moduleKey, Strong<JSInternalPromise>(vm, promise)); | |
| + promise->resolve(globalObject, sourceCodeValue); | |
| + return promise; | |
| +} | |
| + | |
| +JSObject* CAPIGlobalObject::moduleLoaderCreateImportMetaProperties(JSGlobalObject* globalObject, JSModuleLoader*, JSValue keyValue, JSModuleRecord*, JSValue) | |
| +{ | |
| + VM& vm = globalObject->vm(); | |
| + auto scope = DECLARE_THROW_SCOPE(vm); | |
| + | |
| + CAPIGlobalObject* thisObject = jsCast<CAPIGlobalObject*>(globalObject); | |
| + JSModuleLoaderContext* context = thisObject->moduleLoaderContext(); | |
| + | |
| + JSObject* metaProperties = constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure()); | |
| + RETURN_IF_EXCEPTION(scope, nullptr); | |
| + | |
| + metaProperties->putDirect(vm, Identifier::fromString(vm, "url"_s), keyValue); | |
| + | |
| + if (context && context->importMetaCallback) { | |
| + String moduleKey = keyValue.toWTFString(globalObject); | |
| + RETURN_IF_EXCEPTION(scope, nullptr); | |
| + | |
| + JSStringRef keyRef = OpaqueJSString::tryCreate(moduleKey).leakRef(); | |
| + JSObjectRef userProperties = context->importMetaCallback(context->ctx, keyRef, context->userData); | |
| + JSStringRelease(keyRef); | |
| + | |
| + if (userProperties) { | |
| + JSObject* userObj = toJS(userProperties); | |
| + PropertyNameArray propertyNames(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude); | |
| + userObj->getOwnPropertyNames(userObj, globalObject, propertyNames, DontEnumPropertiesMode::Exclude); | |
| + | |
| + for (const auto& propertyName : propertyNames) { | |
| + JSValue value = userObj->get(globalObject, propertyName); | |
| + RETURN_IF_EXCEPTION(scope, nullptr); | |
| + metaProperties->putDirect(vm, propertyName, value); | |
| + } | |
| + } | |
| + } | |
| + | |
| + return metaProperties; | |
| +} | |
| + | |
| +JSInternalPromise* CAPIGlobalObject::moduleLoaderImportModule(JSGlobalObject* globalObject, JSModuleLoader*, JSString* moduleNameValue, JSValue parameters, const SourceOrigin& sourceOrigin) | |
| +{ | |
| + VM& vm = globalObject->vm(); | |
| + auto scope = DECLARE_THROW_SCOPE(vm); | |
| + | |
| + auto* promise = JSInternalPromise::create(vm, globalObject->internalPromiseStructure()); | |
| + | |
| + auto rejectWithError = [&](JSValue error) { | |
| + promise->reject(globalObject, error); | |
| + return promise; | |
| + }; | |
| + | |
| + auto referrer = sourceOrigin.url(); | |
| + auto specifier = moduleNameValue->value(globalObject); | |
| + RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); | |
| + | |
| + if (!referrer.protocolIsFile()) | |
| + RELEASE_AND_RETURN(scope, rejectWithError(createError(globalObject, makeString("Could not resolve the referrer's path '"_s, referrer.string(), "', while trying to resolve module '"_s, specifier.data, "'."_s)))); | |
| + | |
| + auto attributes = JSC::retrieveImportAttributesFromDynamicImportOptions(globalObject, parameters, { vm.propertyNames->type.impl() }); | |
| + RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); | |
| + | |
| + auto type = JSC::retrieveTypeImportAttribute(globalObject, attributes); | |
| + RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); | |
| + | |
| + parameters = jsUndefined(); | |
| + if (type) | |
| + parameters = JSScriptFetchParameters::create(vm, ScriptFetchParameters::create(type.value())); | |
| + | |
| + auto result = JSC::importModule(globalObject, Identifier::fromString(vm, specifier), jsString(vm, referrer.string()), parameters, jsUndefined()); | |
| + RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); | |
| + | |
| + return result; | |
| +} | |
| + | |
| +void CAPIGlobalObject::queueMicrotaskToEventLoop(JSGlobalObject& object, QueuedTask&& task) | |
| +{ | |
| + VM& vm = object.vm(); | |
| + vm.queueMicrotask(std::move(task)); | |
| +} | |
| + | |
| +JSValue CAPIGlobalObject::moduleLoaderEvaluate(JSGlobalObject* globalObject, JSModuleLoader*, JSValue keyValue, JSValue moduleRecordValue, JSValue scriptFetcherValue, JSValue sentValue, JSValue resumeMode) | |
| +{ | |
| + VM& vm = globalObject->vm(); | |
| + auto scope = DECLARE_THROW_SCOPE(vm); | |
| + | |
| + CAPIGlobalObject* thisObject = jsCast<CAPIGlobalObject*>(globalObject); | |
| + JSModuleLoaderContext* context = thisObject->moduleLoaderContext(); | |
| + | |
| + if (!context || !context->evaluateCallback) { | |
| + return { }; | |
| + } | |
| + | |
| + String moduleKey = keyValue.toWTFString(globalObject); | |
| + RETURN_IF_EXCEPTION(scope, { }); | |
| + | |
| + // Check if we're being called from isSyntheticModule (all params except key are undefined) | |
| + if (moduleRecordValue.isUndefined() && scriptFetcherValue.isUndefined() && | |
| + sentValue.isUndefined() && resumeMode.isUndefined()) { | |
| + bool isSynthetic = context && context->syntheticModuleKeys.contains(moduleKey); | |
| + return jsBoolean(isSynthetic); | |
| + } | |
| + | |
| + // Check for parseModule requesting synthetic exports (scriptFetcher is true) | |
| + if (moduleRecordValue.isUndefined() && scriptFetcherValue.isBoolean() && scriptFetcherValue.asBoolean()) { | |
| + | |
| + if (context->syntheticModuleKeys.contains(moduleKey)) { | |
| + JSStringRef keyRef = OpaqueJSString::tryCreate(moduleKey).leakRef(); | |
| + JSObjectRef exportsRef = context->evaluateCallback(context->ctx, keyRef, context->userData); | |
| + JSStringRelease(keyRef); | |
| + | |
| + if (!exportsRef) { | |
| + | |
| + throwException(globalObject, scope, createError(globalObject, makeString("Failed to evaluate synthetic module: "_s, moduleKey))); | |
| + return { }; | |
| + } | |
| + JSObject* exportsObject = toJS(exportsRef); | |
| + return JSValue(exportsObject); | |
| + } | |
| + } | |
| + | |
| + return { }; | |
| +} | |
| + | |
| // From the API's perspective, a context group remains alive iff | |
| // (a) it has been JSContextGroupRetained | |
| // OR | |
| @@ -162,6 +514,49 @@ JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClass | |
| return JSGlobalContextRetain(toGlobalRef(globalObject)); | |
| } | |
| +JSGlobalContextRef JSGlobalContextCreateWithModuleLoader( | |
| + JSContextGroupRef group, | |
| + JSModuleLoaderResolveCallback resolveCallback, | |
| + JSModuleLoaderFetchCallback fetchCallback, | |
| + JSModuleLoaderImportMetaCallback importMetaCallback, | |
| + void* userInfo) | |
| +{ | |
| + return JSGlobalContextCreateWithModuleLoaderEx(group, resolveCallback, fetchCallback, importMetaCallback, nullptr, userInfo); | |
| +} | |
| + | |
| +JSGlobalContextRef JSGlobalContextCreateWithModuleLoaderEx( | |
| + JSContextGroupRef group, | |
| + JSModuleLoaderResolveCallback resolveCallback, | |
| + JSModuleLoaderFetchCallback fetchCallback, | |
| + JSModuleLoaderImportMetaCallback importMetaCallback, | |
| + JSModuleLoaderEvaluateCallback evaluateCallback, | |
| + void* userInfo) | |
| +{ | |
| + JSC::initialize(); | |
| + | |
| + Ref<VM> vm = group ? Ref<VM>(*toJS(group)) : VM::createContextGroup(); | |
| + | |
| + JSModuleLoaderContext* context = new JSModuleLoaderContext(); | |
| + context->resolveCallback = resolveCallback; | |
| + context->fetchCallback = fetchCallback; | |
| + context->importMetaCallback = importMetaCallback; | |
| + context->evaluateCallback = evaluateCallback; | |
| + context->userData = userInfo; | |
| + | |
| + JSLockHolder locker(vm.ptr()); | |
| + | |
| + Structure* structure = CAPIGlobalObject::createStructure(vm.get(), jsNull()); | |
| + CAPIGlobalObject* globalObject = CAPIGlobalObject::create(vm.get(), structure, context); | |
| + | |
| + context->ctx = toGlobalRef(globalObject); | |
| + | |
| +#if ENABLE(REMOTE_INSPECTOR) | |
| + globalObject->setInspectable(JSRemoteInspectorGetInspectionEnabledByDefault()); | |
| +#endif | |
| + | |
| + return JSGlobalContextRetain(toGlobalRef(globalObject)); | |
| +} | |
| + | |
| JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx) | |
| { | |
| JSGlobalObject* globalObject = toJS(ctx); | |
| @@ -177,11 +572,20 @@ void JSGlobalContextRelease(JSGlobalContextRef ctx) | |
| { | |
| JSGlobalObject* globalObject = toJS(ctx); | |
| VM& vm = globalObject->vm(); | |
| - JSLockHolder locker(vm); | |
| + JSLockHolder locker(&vm); | |
| + | |
| bool protectCountIsZero = vm.heap.unprotect(globalObject); | |
| - if (protectCountIsZero) | |
| + if (protectCountIsZero) { | |
| + if (CAPIGlobalObject* capiGlobalObject = jsDynamicCast<CAPIGlobalObject*>(globalObject)) { | |
| + if (JSModuleLoaderContext* context = capiGlobalObject->moduleLoaderContext()) { | |
| + context->modulePromises.clear(); | |
| + context->syntheticModuleKeys.clear(); | |
| + delete context; | |
| + } | |
| + } | |
| vm.heap.reportAbandonedObjectGraph(); | |
| + } | |
| vm.derefSuppressingSaferCPPChecking(); | |
| } | |
| @@ -479,6 +883,231 @@ Inspector::AugmentableInspectorController* JSGlobalContextGetAugmentableInspecto | |
| } | |
| #endif | |
| +// Module API implementations | |
| + | |
| +JSObjectRef JSEvaluateModule(JSContextRef ctx, JSStringRef moduleKey, JSValueRef* exception) | |
| +{ | |
| + if (!ctx) { | |
| + ASSERT_NOT_REACHED(); | |
| + return nullptr; | |
| + } | |
| + | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + auto scope = DECLARE_CATCH_SCOPE(vm); | |
| + | |
| + String moduleKeyString = moduleKey ? moduleKey->string() : "<module>"_s; | |
| + | |
| + // Get the module loader | |
| + JSModuleLoader* loader = globalObject->moduleLoader(); | |
| + | |
| + // Use requestImportModule which returns a promise that resolves with the namespace object | |
| + JSInternalPromise* internalPromise = loader->requestImportModule( | |
| + globalObject, | |
| + Identifier::fromString(vm, moduleKeyString), | |
| + jsUndefined(), // referrer | |
| + jsUndefined(), // parameters | |
| + jsUndefined() // scriptFetcher | |
| + ); | |
| + | |
| + if (scope.exception()) { | |
| + if (exception) | |
| + *exception = toRef(globalObject, scope.exception()->value()); | |
| + scope.clearException(); | |
| + return nullptr; | |
| + } | |
| + | |
| + JSPromise* externalPromise = JSPromise::create(vm, globalObject->promiseStructure()); | |
| + | |
| + auto* fulfillHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), | |
| + [externalPromise](JSGlobalObject* globalObject, CallFrame* callFrame) { | |
| + externalPromise->resolve(globalObject, callFrame->argument(0)); | |
| + return JSValue::encode(jsUndefined()); | |
| + }); | |
| + | |
| + auto* rejectHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), | |
| + [externalPromise](JSGlobalObject* globalObject, CallFrame* callFrame) { | |
| + externalPromise->reject(globalObject, callFrame->argument(0)); | |
| + return JSValue::encode(jsUndefined()); | |
| + }); | |
| + | |
| + internalPromise->then(globalObject, fulfillHandler, rejectHandler); | |
| + | |
| + return toRef(externalPromise); | |
| +} | |
| + | |
| +JSObjectRef JSImportModule(JSContextRef ctx, JSStringRef specifier, JSStringRef referrer, JSObjectRef attributes, JSValueRef* exception) | |
| +{ | |
| + if (!ctx) { | |
| + ASSERT_NOT_REACHED(); | |
| + return nullptr; | |
| + } | |
| + | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + auto scope = DECLARE_CATCH_SCOPE(vm); | |
| + | |
| + String referrerString = referrer ? referrer->string() : String(); | |
| + JSValue referrerValue = referrerString.isEmpty() ? jsUndefined() : jsString(vm, referrerString); | |
| + | |
| + JSValue parameters = jsUndefined(); | |
| + if (attributes) { | |
| + JSObject* attributesObj = toJS(attributes); | |
| + JSValue typeValue = attributesObj->get(globalObject, vm.propertyNames->type); | |
| + | |
| + if (!typeValue.isUndefinedOrNull()) { | |
| + String typeString = typeValue.toWTFString(globalObject); | |
| + RETURN_IF_EXCEPTION(scope, nullptr); | |
| + | |
| + ScriptFetchParameters::Type type = ScriptFetchParameters::Type::JavaScript; | |
| + if (typeString == "json"_s) | |
| + type = ScriptFetchParameters::Type::JSON; | |
| +#if ENABLE(WEBASSEMBLY) | |
| + else if (typeString == "wasm"_s || typeString == "webassembly"_s) | |
| + type = ScriptFetchParameters::Type::WebAssembly; | |
| +#endif | |
| + | |
| + if (type != ScriptFetchParameters::Type::JavaScript) | |
| + parameters = JSScriptFetchParameters::create(vm, ScriptFetchParameters::create(type)); | |
| + } | |
| + } | |
| + | |
| + JSInternalPromise* promise = JSC::importModule(globalObject, Identifier::fromString(vm, specifier->string()), referrerValue, parameters, jsUndefined()); | |
| + | |
| + if (scope.exception()) { | |
| + if (exception) | |
| + *exception = toRef(globalObject, scope.exception()->value()); | |
| + scope.clearException(); | |
| + return nullptr; | |
| + } | |
| + | |
| + JSPromise* externalPromise = JSPromise::create(vm, globalObject->promiseStructure()); | |
| + | |
| + auto* fulfillHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), | |
| + [externalPromise](JSGlobalObject* globalObject, CallFrame* callFrame) { | |
| + externalPromise->resolve(globalObject, callFrame->argument(0)); | |
| + return JSValue::encode(jsUndefined()); | |
| + }); | |
| + | |
| + auto* rejectHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), | |
| + [externalPromise](JSGlobalObject* globalObject, CallFrame* callFrame) { | |
| + externalPromise->reject(globalObject, callFrame->argument(0)); | |
| + return JSValue::encode(jsUndefined()); | |
| + }); | |
| + | |
| + promise->then(globalObject, fulfillHandler, rejectHandler); | |
| + | |
| + return toRef(externalPromise); | |
| +} | |
| + | |
| +bool JSCheckModuleSyntax(JSContextRef ctx, JSStringRef source, JSStringRef sourceURL, JSValueRef* exception) | |
| +{ | |
| + if (!ctx) { | |
| + ASSERT_NOT_REACHED(); | |
| + return false; | |
| + } | |
| + | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + auto scope = DECLARE_CATCH_SCOPE(vm); | |
| + | |
| + String sourceURLString = sourceURL ? sourceURL->string() : "<module>"_s; | |
| + URL url = URL(URL(), sourceURLString); | |
| + | |
| + SourceCode sourceCode = makeSource(source->string(), SourceOrigin { url }, SourceTaintedOrigin::Untainted, sourceURLString, TextPosition(), SourceProviderSourceType::Module); | |
| + | |
| + ParserError error; | |
| + bool validSyntax = JSC::checkModuleSyntax(globalObject, sourceCode, error); | |
| + | |
| + if (!validSyntax) { | |
| + JSValue errorValue = error.toErrorObject(globalObject, sourceCode); | |
| + if (exception) | |
| + *exception = toRef(globalObject, errorValue); | |
| + return false; | |
| + } | |
| + | |
| + if (scope.exception()) { | |
| + if (exception) | |
| + *exception = toRef(globalObject, scope.exception()->value()); | |
| + scope.clearException(); | |
| + return false; | |
| + } | |
| + | |
| + return true; | |
| +} | |
| + | |
| +void JSRegisterSyntheticModule(JSContextRef ctx, const char* moduleKey) | |
| +{ | |
| + if (!ctx || !moduleKey) { | |
| + return; | |
| + } | |
| + | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + | |
| + CAPIGlobalObject* capiGlobal = jsCast<CAPIGlobalObject*>(globalObject); | |
| + JSModuleLoaderContext* context = capiGlobal->moduleLoaderContext(); | |
| + | |
| + if (!context) { | |
| + return; | |
| + } | |
| + context->syntheticModuleKeys.add(String::fromUTF8(moduleKey)); | |
| +} | |
| + | |
| + | |
| +JSValueRef JSModuleSourceCreate(JSContextRef ctx, JSStringRef source, JSStringRef sourceURL, int sourceType) | |
| +{ | |
| + if (!ctx) { | |
| + ASSERT_NOT_REACHED(); | |
| + return nullptr; | |
| + } | |
| + | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + | |
| + String sourceURLString = sourceURL ? sourceURL->string() : String(); | |
| + URL url = URL(URL(), sourceURLString); | |
| + | |
| + SourceProviderSourceType providerType = SourceProviderSourceType::Program; | |
| + SourceCode sourceCode; | |
| + | |
| + switch (sourceType) { | |
| + case 1: // Module | |
| + providerType = SourceProviderSourceType::Module; | |
| + sourceCode = makeSource(source->string(), SourceOrigin { url }, SourceTaintedOrigin::Untainted, sourceURLString, TextPosition(), providerType); | |
| + break; | |
| +#if ENABLE(WEBASSEMBLY) | |
| + case 2: // WebAssembly | |
| + { | |
| + String sourceString = source->string(); | |
| + Vector<uint8_t> bytes; | |
| + bytes.reserveInitialCapacity(sourceString.length()); | |
| + for (unsigned i = 0; i < sourceString.length(); ++i) | |
| + bytes.append(static_cast<uint8_t>(sourceString[i])); | |
| + | |
| + sourceCode = SourceCode(WebAssemblySourceProvider::create(WTFMove(bytes), SourceOrigin { url }, sourceURLString)); | |
| + break; | |
| + } | |
| +#endif | |
| + case 3: // JSON | |
| + providerType = SourceProviderSourceType::JSON; | |
| + sourceCode = makeSource(source->string(), SourceOrigin { url }, SourceTaintedOrigin::Untainted, sourceURLString, TextPosition(), providerType); | |
| + break; | |
| + default: // Script | |
| + sourceCode = makeSource(source->string(), SourceOrigin { url }, SourceTaintedOrigin::Untainted, sourceURLString, TextPosition(), providerType); | |
| + break; | |
| + } | |
| + | |
| + auto* jsSourceCode = JSSourceCode::create(vm, WTFMove(sourceCode)); | |
| + | |
| + return toRef(globalObject, JSValue(jsSourceCode)); | |
| +} | |
| + | |
| bool JSContextGroupEnableSamplingProfiler(JSContextGroupRef group) | |
| { | |
| VM& vm = *toJS(group); | |
| @@ -520,5 +1149,4 @@ JSStringRef JSContextGroupTakeSamplesFromSamplingProfiler(JSContextGroupRef grou | |
| #else | |
| return nullptr; | |
| #endif | |
| -} | |
| - | |
| +} | |
| \ No newline at end of file | |
| diff --git forkSrcPrefix/Source/JavaScriptCore/API/JSTypedArray.cpp forkDstPrefix/Source/JavaScriptCore/API/JSTypedArray.cpp | |
| index 0cadcc32ec06520c897aeab0114e72a550ac75b9..5c0d97fae3b2445a7d377e80f465b9945d6b39af 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/API/JSTypedArray.cpp | |
| +++ forkDstPrefix/Source/JavaScriptCore/API/JSTypedArray.cpp | |
| @@ -329,6 +329,78 @@ JSObjectRef JSObjectMakeArrayBufferWithBytesNoCopy(JSContextRef ctx, void* bytes | |
| return toRef(jsBuffer); | |
| } | |
| +void* JSValueGetTypedArrayBytesPtrFromValue(JSContextRef ctx, JSValueRef valueRef, JSValueRef* exception, size_t* offset, size_t* length) | |
| +{ | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + | |
| + JSValue value = toJS(globalObject, valueRef); | |
| + JSObject* object = value.getObject(); | |
| + | |
| + if (JSArrayBufferView* typedArray = jsDynamicCast<JSArrayBufferView*>(object)) { | |
| + if (ArrayBuffer* buffer = typedArray->possiblySharedBuffer()) { | |
| + buffer->pinAndLock(); | |
| + if (offset) | |
| + *offset = typedArray->byteOffset(); | |
| + if (length) | |
| + *length = typedArray->byteLength(); | |
| + return buffer->data(); | |
| + } | |
| + | |
| + setException(ctx, exception, createOutOfMemoryError(globalObject)); | |
| + } | |
| + return nullptr; | |
| +} | |
| + | |
| +bool JSObjectIsDetachedBuffer(JSContextRef ctx, JSObjectRef objectRef, JSValueRef* exception) | |
| +{ | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + JSObject* object = toJS(objectRef); | |
| + | |
| + JSArrayBuffer* thisObject = jsDynamicCast<JSArrayBuffer*>(object); | |
| + if (!thisObject) { | |
| + setException(ctx, exception, createTypeError(globalObject, "JSObjectIsDetachedBuffer expects object to be an Array Buffer object"_s)); | |
| + return false; | |
| + } | |
| + | |
| + return thisObject->impl()->isDetached(); | |
| +} | |
| + | |
| +JSValueRef JSValueFastUFT8Encoding(JSContextRef ctx, JSValueRef value, JSValueRef* exception) | |
| +{ | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + auto scope = DECLARE_CATCH_SCOPE(vm); | |
| + | |
| + JSValue jsValue = toJS(globalObject, value); | |
| + auto string = jsValue.toWTFString(globalObject); | |
| + if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) | |
| + return nullptr; | |
| + | |
| + auto expectedUtf8 = string.tryGetUTF8([&](std::span<const char8_t> span) { | |
| + return spanReinterpretCast<const uint8_t>(span); | |
| + }); | |
| + | |
| + if (!expectedUtf8) { | |
| + setException(ctx, exception, createTypeError(globalObject, "Cannot convert the value to UTF-8"_s)); | |
| + return nullptr; | |
| + } | |
| + | |
| + // Return array buffer with the UTF-8 encoded string. | |
| + auto span = expectedUtf8.value(); | |
| + auto buffer = ArrayBuffer::tryCreate(span); | |
| + if (!buffer) { | |
| + setException(ctx, exception, createOutOfMemoryError(globalObject)); | |
| + return nullptr; | |
| + } | |
| + | |
| + return toRef(JSArrayBuffer::create(vm, globalObject->arrayBufferStructure(ArrayBufferSharingMode::Default), WTFMove(buffer))); | |
| +} | |
| + | |
| void* JSObjectGetArrayBufferBytesPtr(JSContextRef ctx, JSObjectRef objectRef, JSValueRef* exception) | |
| { | |
| JSGlobalObject* globalObject = toJS(ctx); | |
| diff --git forkSrcPrefix/Source/JavaScriptCore/API/JSTypedArray.h forkDstPrefix/Source/JavaScriptCore/API/JSTypedArray.h | |
| index 7eaf76c5e1ede8e6bf0283a97312353b42ef69dd..cdd6ae7db350a80d2f20bf20853325aac492805c 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/API/JSTypedArray.h | |
| +++ forkDstPrefix/Source/JavaScriptCore/API/JSTypedArray.h | |
| @@ -97,6 +97,19 @@ JS_EXPORT JSObjectRef JSObjectMakeTypedArrayWithArrayBufferAndOffset(JSContextRe | |
| */ | |
| JS_EXPORT void* JSObjectGetTypedArrayBytesPtr(JSContextRef ctx, JSObjectRef object, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0)); | |
| +/*! | |
| + @function | |
| + @abstract Returns a temporary pointer to the backing store of a JavaScript Typed Array object. | |
| + @param ctx The execution context to use. | |
| + @param value The JSValueRef whose Typed Array type data pointer to obtain. | |
| + @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception. | |
| + @param offset A pointer to a size_t in which to store the byte offset of the Typed Array object. | |
| + @param length A pointer to a size_t in which to store the byte length of the Typed Array object. | |
| + @result A pointer to the raw data buffer that serves as object's backing store or NULL if object is not a Typed Array object. | |
| + @discussion The pointer returned by this function is temporary and is not guaranteed to remain valid across JavaScriptCore API calls. | |
| + */ | |
| +JS_EXPORT void* JSValueGetTypedArrayBytesPtrFromValue(JSContextRef ctx, JSValueRef value, JSValueRef* exception, size_t* offset, size_t* length) JSC_API_AVAILABLE(macos(10.12), ios(10.0)); | |
| + | |
| /*! | |
| @function | |
| @abstract Returns the length of a JavaScript Typed Array object. | |
| @@ -153,6 +166,27 @@ JS_EXPORT JSObjectRef JSObjectGetTypedArrayBuffer(JSContextRef ctx, JSObjectRef | |
| */ | |
| JS_EXPORT JSObjectRef JSObjectMakeArrayBufferWithBytesNoCopy(JSContextRef ctx, void* bytes, size_t byteLength, JSTypedArrayBytesDeallocator bytesDeallocator, void* deallocatorContext, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0)); | |
| +/*! | |
| + @function | |
| + @abstract Returns a pointer to the data buffer that serves as the backing store for a JavaScript Array Buffer object. | |
| + @param ctx The execution context to use. | |
| + @param value The Array Buffer object whose internal backing store pointer to return. | |
| + @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception. | |
| + @result A pointer to the raw data buffer that serves as object's backing store or NULL if object is not an Array Buffer object. | |
| + @discussion The pointer returned by this function is temporary and is not guaranteed to remain valid across JavaScriptCore API calls. | |
| +*/ | |
| +JS_EXPORT JSValueRef JSValueFastUFT8Encoding(JSContextRef ctx, JSValueRef value, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0)); | |
| + | |
| +/*! | |
| + @function | |
| + @abstract Returns a boolean value indicating whether or not a JavaScript value is a detached Typed Array object. | |
| + @param ctx The execution context to use. | |
| + @param objectRef The JSObjectRef whose Typed Array type data pointer to obtain. | |
| + @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception. | |
| + @result A boolean value indicating whether or not objectRef is a detached Typed Array object. | |
| + */ | |
| +JS_EXPORT bool JSObjectIsDetachedBuffer(JSContextRef ctx, JSObjectRef objectRef, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.12), ios(10.0)); | |
| + | |
| /*! | |
| @function | |
| @abstract Returns a pointer to the data buffer that serves as the backing store for a JavaScript Typed Array object. | |
| diff --git forkSrcPrefix/Source/JavaScriptCore/API/JSObjectRef.h forkDstPrefix/Source/JavaScriptCore/API/JSObjectRef.h | |
| index 6f1a7ba6c9062e937944047ae740859f38b6fc2a..6e287ccb567f41bd350fad9dc9b9291d407cff96 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/API/JSObjectRef.h | |
| +++ forkDstPrefix/Source/JavaScriptCore/API/JSObjectRef.h | |
| @@ -467,6 +467,17 @@ JS_EXPORT JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, c | |
| */ | |
| JS_EXPORT JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) JSC_API_AVAILABLE(macos(10.6), ios(7.0)); | |
| +/*! | |
| + @function | |
| + @abstract Creates a JavaScript TypeError object, as if by invoking the built-in TypeError constructor. | |
| + @param ctx The execution context to use. | |
| + @param message A JSString containing the message for the TypeError's 'message' property. | |
| + @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception. | |
| + @result A JSObject that is an TypeError. | |
| + */ | |
| +JS_EXPORT JSObjectRef JSObjectMakeTypeError(JSContextRef ctx, JSStringRef message, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.6), ios(7.0)); | |
| + | |
| + | |
| /*! | |
| @function | |
| @abstract Creates a JavaScript RegExp object, as if by invoking the built-in RegExp constructor. | |
| @@ -614,6 +625,28 @@ JS_EXPORT void JSObjectSetPropertyForKey(JSContextRef ctx, JSObjectRef object, J | |
| */ | |
| JS_EXPORT bool JSObjectDeletePropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef propertyKey, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.15), ios(13.0)); | |
| +/*! | |
| + @function | |
| + @abstract Implement the async iterable protocol on an object. | |
| + @param ctx The execution context to use. | |
| + @param object The JSObject to implement the async iterable protocol on. | |
| + @param value A zero-argument function that returns an object, conforming to the async iterator protocol. | |
| + @param attributes A logically ORed set of JSPropertyAttributes to give to the property. | |
| + @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception. | |
| + */ | |
| +JS_EXPORT void JSObjectSetAsyncIterator(JSContextRef ctx, JSObjectRef object, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.15), ios(13.0)); | |
| + | |
| +/*! | |
| + @function | |
| + @abstract Implement the iterator protocol on an object. | |
| + @param ctx The execution context to use. | |
| + @param object The JSObject to implement the iterator protocol on. | |
| + @param value A zero-argument function that returns an object, conforming to the iterator protocol. | |
| + @param attributes A logically ORed set of JSPropertyAttributes to give to the property. | |
| + @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception. | |
| + */ | |
| +JS_EXPORT void JSObjectSetIterator(JSContextRef ctx, JSObjectRef object, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.15), ios(13.0)); | |
| + | |
| /*! | |
| @function | |
| @abstract Gets a property from an object by numeric index. | |
| diff --git forkSrcPrefix/Source/JavaScriptCore/runtime/SyntheticModuleRecord.h forkDstPrefix/Source/JavaScriptCore/runtime/SyntheticModuleRecord.h | |
| index c26d7e9123d090e0d6ca1f0770bd730ee74fe013..a5093206ace498f06d93b463b283eb7ad9a1efc2 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/runtime/SyntheticModuleRecord.h | |
| +++ forkDstPrefix/Source/JavaScriptCore/runtime/SyntheticModuleRecord.h | |
| @@ -58,15 +58,16 @@ public: | |
| static SyntheticModuleRecord* parseJSONModule(JSGlobalObject*, const Identifier& moduleKey, SourceCode&&); | |
| + static SyntheticModuleRecord* tryCreateDefaultExportSyntheticModule(JSGlobalObject*, const Identifier& moduleKey, JSValue); | |
| + static SyntheticModuleRecord* tryCreateWithExportNamesAndValues(JSGlobalObject*, const Identifier& moduleKey, const Vector<Identifier, 4>& exportNames, const MarkedArgumentBuffer& exportValues); | |
| + | |
| + | |
| Synchronousness link(JSGlobalObject*, JSValue scriptFetcher); | |
| JS_EXPORT_PRIVATE JSValue evaluate(JSGlobalObject*); | |
| private: | |
| SyntheticModuleRecord(VM&, Structure*, const Identifier& moduleKey); | |
| - static SyntheticModuleRecord* tryCreateDefaultExportSyntheticModule(JSGlobalObject*, const Identifier& moduleKey, JSValue); | |
| - static SyntheticModuleRecord* tryCreateWithExportNamesAndValues(JSGlobalObject*, const Identifier& moduleKey, const Vector<Identifier, 4>& exportNames, const MarkedArgumentBuffer& exportValues); | |
| - | |
| void finishCreation(JSGlobalObject*, VM&); | |
| }; | |
| diff --git forkSrcPrefix/Source/JavaScriptCore/API/JSObjectRef.cpp forkDstPrefix/Source/JavaScriptCore/API/JSObjectRef.cpp | |
| index c07011ca7a53334c5926959eac9d8b7e90cb9ef1..9ef7fb04c9015ac692ca38d2498fd3cb7fc781de 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/API/JSObjectRef.cpp | |
| +++ forkDstPrefix/Source/JavaScriptCore/API/JSObjectRef.cpp | |
| @@ -247,6 +247,26 @@ JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSVa | |
| return toRef(result); | |
| } | |
| +JSObjectRef JSObjectMakeTypeError(JSContextRef ctx, JSStringRef message, JSValueRef* exception) | |
| +{ | |
| + if (!ctx) { | |
| + ASSERT_NOT_REACHED(); | |
| + return nullptr; | |
| + } | |
| + | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + auto scope = DECLARE_CATCH_SCOPE(vm); | |
| + | |
| + JSObject* result = createTypeError(globalObject, message ? message->string() : String()); | |
| + | |
| + if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) | |
| + result = nullptr; | |
| + | |
| + return toRef(result); | |
| +} | |
| + | |
| JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) | |
| { | |
| if (!ctx) { | |
| @@ -466,6 +486,52 @@ void JSObjectSetPropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef | |
| handleExceptionIfNeeded(scope, ctx, exception); | |
| } | |
| +void JSObjectSetAsyncIterator(JSContextRef ctx, JSObjectRef object, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception) | |
| +{ | |
| + if (!ctx) { | |
| + ASSERT_NOT_REACHED(); | |
| + return; | |
| + } | |
| + | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + auto scope = DECLARE_CATCH_SCOPE(vm); | |
| + | |
| + JSObject* jsObject = toJS(object); | |
| + JSValue jsValue = toJS(globalObject, value); | |
| + | |
| + if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) | |
| + return; | |
| + | |
| + jsObject->putDirect(vm, vm.propertyNames->asyncIteratorSymbol, jsValue, attributes); | |
| + | |
| + handleExceptionIfNeeded(scope, ctx, exception); | |
| +} | |
| + | |
| +void JSObjectSetIterator(JSContextRef ctx, JSObjectRef object, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception) | |
| +{ | |
| + if (!ctx) { | |
| + ASSERT_NOT_REACHED(); | |
| + return; | |
| + } | |
| + | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + auto scope = DECLARE_CATCH_SCOPE(vm); | |
| + | |
| + JSObject* jsObject = toJS(object); | |
| + JSValue jsValue = toJS(globalObject, value); | |
| + | |
| + if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) | |
| + return; | |
| + | |
| + jsObject->putDirect(vm, vm.propertyNames->iteratorSymbol, jsValue, attributes); | |
| + | |
| + handleExceptionIfNeeded(scope, ctx, exception); | |
| +} | |
| + | |
| bool JSObjectDeletePropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef key, JSValueRef* exception) | |
| { | |
| if (!ctx) { | |
| @@ -561,6 +627,9 @@ void* JSObjectGetPrivate(JSObjectRef object) | |
| { | |
| JSObject* jsObject = uncheckedToJS(object); | |
| + if (!jsObject) | |
| + return nullptr; | |
| + | |
| const ClassInfo* classInfo = classInfoPrivate(jsObject); | |
| // Get wrapped object if proxied | |
| diff --git forkSrcPrefix/Source/WTF/wtf/WTFConfig.cpp forkDstPrefix/Source/WTF/wtf/WTFConfig.cpp | |
| index 97a5382cba1cdab0d34b96db021adb0d5dfe698d..530b2debbab1a48893d28eb575eb826add77f9d6 100644 | |
| --- forkSrcPrefix/Source/WTF/wtf/WTFConfig.cpp | |
| +++ forkDstPrefix/Source/WTF/wtf/WTFConfig.cpp | |
| @@ -210,6 +210,8 @@ void Config::permanentlyFreeze() | |
| void permanentlyFreezePages(void* base, size_t size, FreezePagePermission permission) | |
| { | |
| + (void)base; | |
| + (void)permission; | |
| RELEASE_ASSERT(roundUpToMultipleOf(pageSize(), size) == size); | |
| int result = 0; | |
| diff --git forkSrcPrefix/Source/JavaScriptCore/builtins/ModuleLoader.js forkDstPrefix/Source/JavaScriptCore/builtins/ModuleLoader.js | |
| index 611f5b8f794e0d7ebc9f53daf35db0ade5ab0d08..f43bd3319f4cf260a36492fbc09126bc265051d7 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/builtins/ModuleLoader.js | |
| +++ forkDstPrefix/Source/JavaScriptCore/builtins/ModuleLoader.js | |
| @@ -102,6 +102,7 @@ function newRegistryEntry(key, type) | |
| evaluated: false, | |
| then: @undefined, | |
| isAsync: false, | |
| + isSynthetic: false, | |
| }; | |
| } | |
| @@ -127,6 +128,7 @@ function ensureRegistered(key, type) | |
| } | |
| entry = @newRegistryEntry(key, type); | |
| + entry.isSynthetic = this.isSyntheticModule(key); | |
| entryMap.@set(type, entry); | |
| return entry; | |
| @@ -200,6 +202,17 @@ function requestInstantiate(entry, parameters, fetcher) | |
| return entry.instantiate; | |
| var instantiatePromise = (async () => { | |
| + if (entry.isSynthetic) { | |
| + if (entry.satisfy) | |
| + return entry; | |
| + | |
| + entry.instantiate = instantiatePromise; | |
| + var moduleRecord = await this.parseModule(entry.key, @undefined); | |
| + entry.module = moduleRecord; | |
| + entry.dependencies = []; | |
| + @setStateToMax(entry, @ModuleSatisfy); | |
| + return entry; | |
| + } | |
| var source = await this.requestFetch(entry, parameters, fetcher); | |
| // https://html.spec.whatwg.org/#fetch-a-single-module-script | |
| // Now fetching request succeeds. Then even if instantiation fails, we should cache it. | |
| diff --git forkSrcPrefix/Source/JavaScriptCore/API/JSValueRef.cpp forkDstPrefix/Source/JavaScriptCore/API/JSValueRef.cpp | |
| index 17cff8d1791e4960a9b3ae8b71b25aaeceb025eb..a3865de110072c13cb9b5a8ae56f43fabe56e8a9 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/API/JSValueRef.cpp | |
| +++ forkDstPrefix/Source/JavaScriptCore/API/JSValueRef.cpp | |
| @@ -31,6 +31,8 @@ | |
| #include "DateInstance.h" | |
| #include "JSAPIWrapperObject.h" | |
| #include "JSCInlines.h" | |
| +#include "JSPromise.h" | |
| +#include "JSStringRef.h" | |
| #include "JSCallbackObject.h" | |
| #include "JSONObject.h" | |
| #include "LiteralParser.h" | |
| @@ -817,3 +819,126 @@ void JSValueUnprotect(JSContextRef ctx, JSValueRef value) | |
| JSValue jsValue = toJSForGC(globalObject, value); | |
| gcUnprotect(jsValue); | |
| } | |
| + | |
| +bool JSValueIsPromise(JSContextRef ctx, JSValueRef value) | |
| +{ | |
| + if (!ctx) { | |
| + ASSERT_NOT_REACHED(); | |
| + return false; | |
| + } | |
| + | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + JSLockHolder locker(globalObject); | |
| + JSValue jsValue = toJS(globalObject, value); | |
| + | |
| + return jsValue.inherits<JSPromise>(); | |
| +} | |
| + | |
| +JSPromiseState JSValueGetPromiseState(JSContextRef ctx, JSValueRef promise, JSValueRef* exception) | |
| +{ | |
| + if (!ctx) { | |
| + ASSERT_NOT_REACHED(); | |
| + return kJSPromiseStatePending; | |
| + } | |
| + | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + | |
| + JSValue jsValue = toJS(globalObject, promise); | |
| + | |
| + if (!jsValue.inherits<JSPromise>()) { | |
| + if (exception) { | |
| + JSStringRef errStr = JSStringCreateWithUTF8CString("Value is not a Promise"); | |
| + *exception = JSValueMakeString(ctx, errStr); | |
| + JSStringRelease(errStr); | |
| + } | |
| + return kJSPromiseStatePending; | |
| + } | |
| + | |
| + JSPromise* jsPromise = jsCast<JSPromise*>(jsValue); | |
| + | |
| + switch (jsPromise->status(vm)) { | |
| + case JSPromise::Status::Pending: | |
| + return kJSPromiseStatePending; | |
| + case JSPromise::Status::Fulfilled: | |
| + return kJSPromiseStateFulfilled; | |
| + case JSPromise::Status::Rejected: | |
| + return kJSPromiseStateRejected; | |
| + default: | |
| + ASSERT_NOT_REACHED(); | |
| + return kJSPromiseStatePending; | |
| + } | |
| +} | |
| + | |
| +JSValueRef JSValueGetPromiseResult(JSContextRef ctx, JSValueRef promise, JSValueRef* exception) | |
| +{ | |
| + if (!ctx) { | |
| + ASSERT_NOT_REACHED(); | |
| + return nullptr; | |
| + } | |
| + | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + | |
| + JSValue jsValue = toJS(globalObject, promise); | |
| + | |
| + if (!jsValue.inherits<JSPromise>()) { | |
| + if (exception) { | |
| + JSStringRef errStr = JSStringCreateWithUTF8CString("Value is not a Promise"); | |
| + *exception = JSValueMakeString(ctx, errStr); | |
| + JSStringRelease(errStr); | |
| + } | |
| + return nullptr; | |
| + } | |
| + | |
| + JSPromise* jsPromise = jsCast<JSPromise*>(jsValue); | |
| + | |
| + if (jsPromise->status(vm) != JSPromise::Status::Fulfilled) { | |
| + if (exception) { | |
| + JSStringRef errStr = JSStringCreateWithUTF8CString("Promise is not fulfilled"); | |
| + *exception = JSValueMakeString(ctx, errStr); | |
| + JSStringRelease(errStr); | |
| + } | |
| + return nullptr; | |
| + } | |
| + | |
| + return toRef(globalObject, jsPromise->result(vm)); | |
| +} | |
| + | |
| +JSValueRef JSValueGetPromiseRejectionReason(JSContextRef ctx, JSValueRef promise, JSValueRef* exception) | |
| +{ | |
| + if (!ctx) { | |
| + ASSERT_NOT_REACHED(); | |
| + return nullptr; | |
| + } | |
| + | |
| + JSGlobalObject* globalObject = toJS(ctx); | |
| + VM& vm = globalObject->vm(); | |
| + JSLockHolder locker(vm); | |
| + | |
| + JSValue jsValue = toJS(globalObject, promise); | |
| + | |
| + if (!jsValue.inherits<JSPromise>()) { | |
| + if (exception) { | |
| + JSStringRef errStr = JSStringCreateWithUTF8CString("Value is not a Promise"); | |
| + *exception = JSValueMakeString(ctx, errStr); | |
| + JSStringRelease(errStr); | |
| + } | |
| + return nullptr; | |
| + } | |
| + | |
| + JSPromise* jsPromise = jsCast<JSPromise*>(jsValue); | |
| + | |
| + if (jsPromise->status(vm) != JSPromise::Status::Rejected) { | |
| + if (exception) { | |
| + JSStringRef errStr = JSStringCreateWithUTF8CString("Promise is not rejected"); | |
| + *exception = JSValueMakeString(ctx, errStr); | |
| + JSStringRelease(errStr); | |
| + } | |
| + return nullptr; | |
| + } | |
| + | |
| + return toRef(globalObject, jsPromise->result(vm)); | |
| +} | |
| \ No newline at end of file | |
| diff --git forkSrcPrefix/Source/JavaScriptCore/API/JSBase.h forkDstPrefix/Source/JavaScriptCore/API/JSBase.h | |
| index 2eaed1ff19b33e27d5df34ff444e8ab2a82b6058..e4dd233861688c0c96a7623461f7792be2bf62d7 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/API/JSBase.h | |
| +++ forkDstPrefix/Source/JavaScriptCore/API/JSBase.h | |
| @@ -139,6 +139,24 @@ JS_EXPORT bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStrin | |
| */ | |
| JS_EXPORT void JSGarbageCollect(JSContextRef ctx); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Produces an object with various statistics about current memory usage. | |
| +@param ctx The execution context to use. | |
| +@result An object containing GC heap status data. | |
| +@discussion Specifically, the result object has the following integer-valued fields: | |
| + heapSize: current size of heap | |
| + heapCapacity: current capacity of heap | |
| + extraMemorySize: amount of non-GC memory referenced by GC objects (included in heap size / capacity) | |
| + objectCount: current count of GC objects | |
| + protectedObjectCount: current count of protected GC objects | |
| + globalObjectCount: current count of global GC objects | |
| + protectedGlobalObjectCount: current count of protected global GC objects | |
| + objectTypeCounts: object with GC object types as keys and their current counts as values | |
| +*/ | |
| +JS_EXPORT JSObjectRef JSGetMemoryUsageStatistics(JSContextRef ctx); | |
| + | |
| #ifdef __cplusplus | |
| } | |
| #endif | |
| diff --git forkSrcPrefix/Source/JavaScriptCore/API/JSContextRef.h forkDstPrefix/Source/JavaScriptCore/API/JSContextRef.h | |
| index 5c09aa330061200e7578d41895ec5fd87bd72ff2..951a2d0204f4ee7b24999428831d852655e7f350 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/API/JSContextRef.h | |
| +++ forkDstPrefix/Source/JavaScriptCore/API/JSContextRef.h | |
| @@ -38,6 +38,50 @@ | |
| extern "C" { | |
| #endif | |
| +/* Module Support Types */ | |
| + | |
| +/*! | |
| +@typedef JSModuleLoaderResolveCallback | |
| +@abstract Callback to resolve module specifiers to module keys (typically URLs). | |
| +@param ctx The execution context. | |
| +@param specifier The import specifier (e.g., "./module.js", "lodash"). | |
| +@param referrer The module key of the importing module, or NULL for top-level. | |
| +@param userInfo User data passed when setting up module loading. | |
| +@result The resolved module key (typically URL), or NULL if resolution fails. The caller takes ownership. | |
| +*/ | |
| +typedef JSStringRef (*JSModuleLoaderResolveCallback)(JSContextRef ctx, JSStringRef specifier, JSStringRef referrer, void* userInfo); | |
| + | |
| +/*! | |
| +@typedef JSModuleLoaderFetchCallback | |
| +@abstract Callback to fetch module source code given a module key. | |
| +@param ctx The execution context. | |
| +@param moduleKey The resolved module key (typically URL) to fetch. | |
| +@param attributes A JSObjectRef containing import attributes (e.g., { type: "json" }), or NULL. | |
| +@param userInfo User data passed when setting up module loading. | |
| +@result A JSValueRef representing a JSSourceCode object for regular modules, or JSModuleSyntheticSourceCreate for synthetic modules, or NULL if fetching fails. | |
| +*/ | |
| +typedef JSValueRef (*JSModuleLoaderFetchCallback)(JSContextRef ctx, JSStringRef moduleKey, JSObjectRef attributes, void* userInfo); | |
| + | |
| +/*! | |
| +@typedef JSModuleLoaderImportMetaCallback | |
| +@abstract Callback to create import.meta properties for a module. | |
| +@param ctx The execution context. | |
| +@param moduleKey The module key for which to create import.meta. | |
| +@param userInfo User data passed when setting up module loading. | |
| +@result A JSObjectRef containing properties to be added to import.meta, or NULL. | |
| +*/ | |
| +typedef JSObjectRef (*JSModuleLoaderImportMetaCallback)(JSContextRef ctx, JSStringRef moduleKey, void* userInfo); | |
| + | |
| +/*! | |
| +@typedef JSModuleLoaderEvaluateCallback | |
| +@abstract Callback to evaluate synthetic modules programmatically. | |
| +@param ctx The execution context. | |
| +@param moduleKey The module key to evaluate. | |
| +@param userInfo User data passed when setting up module loading. | |
| +@result A JSObjectRef representing the module namespace object with exports, or NULL if evaluation fails. | |
| +*/ | |
| +typedef JSObjectRef (*JSModuleLoaderEvaluateCallback)(JSContextRef ctx, JSStringRef moduleKey, void* userInfo); | |
| + | |
| /*! | |
| @function | |
| @abstract Creates a JavaScript context group. | |
| @@ -99,6 +143,42 @@ JS_EXPORT JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass) | |
| */ | |
| JS_EXPORT JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass) JSC_API_AVAILABLE(macos(10.6), ios(7.0)); | |
| +/*! | |
| +@function | |
| +@abstract Creates a global JavaScript execution context with module loading support. | |
| +@param group The context group to use. Pass NULL to create a unique group. | |
| +@param resolveCallback Callback for resolving import specifiers to module keys. | |
| +@param fetchCallback Callback for fetching module source code. | |
| +@param importMetaCallback Optional callback for creating import.meta properties. | |
| +@param userInfo User data to pass to the callbacks. | |
| +@result A JSGlobalContext with module loading support. Retain this value if you want to keep it. | |
| +*/ | |
| +JS_EXPORT JSGlobalContextRef JSGlobalContextCreateWithModuleLoader( | |
| + JSContextGroupRef group, | |
| + JSModuleLoaderResolveCallback resolveCallback, | |
| + JSModuleLoaderFetchCallback fetchCallback, | |
| + JSModuleLoaderImportMetaCallback importMetaCallback, | |
| + void* userInfo) JSC_API_AVAILABLE(macos(13.3), ios(16.4)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Creates a global JavaScript execution context with full module loading support including synthetic modules. | |
| +@param group The context group to use. Pass NULL to create a unique group. | |
| +@param resolveCallback Callback for resolving import specifiers to module keys. | |
| +@param fetchCallback Callback for fetching module source code. Can return JSModuleSyntheticSourceCreate for synthetic modules. | |
| +@param importMetaCallback Optional callback for creating import.meta properties. | |
| +@param evaluateCallback Optional callback for evaluating synthetic modules. | |
| +@param userInfo User data to pass to the callbacks. | |
| +@result A JSGlobalContext with full module loading support including synthetic modules. | |
| +*/ | |
| +JS_EXPORT JSGlobalContextRef JSGlobalContextCreateWithModuleLoaderEx( | |
| + JSContextGroupRef group, | |
| + JSModuleLoaderResolveCallback resolveCallback, | |
| + JSModuleLoaderFetchCallback fetchCallback, | |
| + JSModuleLoaderImportMetaCallback importMetaCallback, | |
| + JSModuleLoaderEvaluateCallback evaluateCallback, | |
| + void* userInfo) JSC_API_AVAILABLE(macos(13.3), ios(16.4)); | |
| + | |
| /*! | |
| @function | |
| @abstract Retains a global JavaScript execution context. | |
| @@ -171,8 +251,179 @@ JS_EXPORT bool JSGlobalContextIsInspectable(JSGlobalContextRef ctx) JSC_API_AVAI | |
| */ | |
| JS_EXPORT void JSGlobalContextSetInspectable(JSGlobalContextRef ctx, bool inspectable) JSC_API_AVAILABLE(macos(13.3), ios(16.4)); | |
| +/*! | |
| +@function | |
| +@abstract Gets a Backtrace for the existing context | |
| +@param ctx The JSContext whose backtrace you want to get | |
| +@param maxStackSize The maximum number of stack frames to include | |
| +@result A string containing the backtrace | |
| +*/ | |
| +JS_EXPORT JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) JSC_API_AVAILABLE(macos(10.6), ios(7.0)); | |
| + | |
| +/*! | |
| +@typedef JSShouldTerminateCallback | |
| +@abstract The callback invoked when script execution has exceeded the allowed | |
| + time limit previously specified via JSContextGroupSetExecutionTimeLimit. | |
| +@param ctx The execution context to use. | |
| +@param context User specified context data previously passed to | |
| + JSContextGroupSetExecutionTimeLimit. | |
| +@discussion If you named your function Callback, you would declare it like this: | |
| + | |
| + bool Callback(JSContextRef ctx, void* context); | |
| + | |
| + If you return true, the timed out script will terminate. | |
| + If you return false, the script will run for another period of the allowed | |
| + time limit specified via JSContextGroupSetExecutionTimeLimit. | |
| + | |
| + Within this callback function, you may call JSContextGroupSetExecutionTimeLimit | |
| + to set a new time limit, or JSContextGroupClearExecutionTimeLimit to cancel the | |
| + timeout. | |
| +*/ | |
| +typedef bool (*JSShouldTerminateCallback)(JSContextRef ctx, void* context); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Sets the script execution time limit. | |
| +@param group The JavaScript context group that this time limit applies to. | |
| +@param limit The time limit of allowed script execution time in seconds. | |
| +@param callback The callback function that will be invoked when the time limit | |
| + has been reached. This will give you a chance to decide if you want to | |
| + terminate the script or not. If you pass a NULL callback, the script will be | |
| + terminated unconditionally when the time limit has been reached. | |
| +@param context User data that you can provide to be passed back to you | |
| + in your callback. | |
| +@discussion In order to guarantee that the execution time limit will take effect, you will | |
| + need to call JSContextGroupSetExecutionTimeLimit before you start executing | |
| + any scripts. | |
| +*/ | |
| +JS_EXPORT void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* context) JSC_API_AVAILABLE(macos(10.6), ios(7.0)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Clears the script execution time limit. | |
| +@param group The JavaScript context group that the time limit is cleared on. | |
| +*/ | |
| +JS_EXPORT void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group) JSC_API_AVAILABLE(macos(10.6), ios(7.0)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Enables sampling profiler. | |
| +@param group The JavaScript context group to start sampling. | |
| +@result The value of the enablement, true if the sampling profiler gets enabled, otherwise false. | |
| +*/ | |
| +JS_EXPORT bool JSContextGroupEnableSamplingProfiler(JSContextGroupRef group) JSC_API_AVAILABLE(macos(14.2), ios(17.2)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Disables sampling profiler. | |
| +@param group The JavaScript context group to stop sampling. | |
| +*/ | |
| +JS_EXPORT void JSContextGroupDisableSamplingProfiler(JSContextGroupRef group) JSC_API_AVAILABLE(macos(14.2), ios(17.2)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Gets sampling profiler output in JSON form and clears the sampling profiler records. | |
| +@param group The JavaScript context group whose sampling profile output is taken. | |
| +@result The sampling profiler output in JSON form. NULL if sampling profiler is not enabled ever before. | |
| +@discussion Calling this function clears the sampling data accumulated so far. | |
| +*/ | |
| +JS_EXPORT JSStringRef JSContextGroupTakeSamplesFromSamplingProfiler(JSContextGroupRef group) JSC_API_AVAILABLE(macos(14.2), ios(17.2)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Gets the include native call stack when reporting exceptions setting for a context. | |
| +@param ctx The JSGlobalContext whose setting you want to get. | |
| +@result The value of the setting, true if native call stack is included, otherwise false. | |
| +@discussion This setting is true by default. | |
| +*/ | |
| +JS_EXPORT bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx) JSC_API_AVAILABLE(macos(10.10), ios(8.0)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Sets the include native call stack when reporting exceptions setting for a context. | |
| +@param ctx The JSGlobalContext that you want to change. | |
| +@param includesNativeCallStack The new value of the setting for the context. | |
| +*/ | |
| +JS_EXPORT void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx, bool includesNativeCallStack) JSC_API_AVAILABLE(macos(10.10), ios(8.0)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Sets the unhandled promise rejection callback for a context. | |
| +@discussion Similar to window.addEventListener('unhandledrejection'), but for contexts not associated with a web view. | |
| +@param ctx The JSGlobalContext to set the callback on. | |
| +@param function The callback function to set, which receives the promise and rejection reason as arguments. | |
| +@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception. | |
| +*/ | |
| +JS_EXPORT void JSGlobalContextSetUnhandledRejectionCallback(JSGlobalContextRef ctx, JSObjectRef function, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.15.4), ios(13.4)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Sets whether a context allows use of eval (or the Function constructor). | |
| +@param ctx The JSGlobalContext that you want to change. | |
| +@param enabled The new eval enabled setting for the context. | |
| +@param message The error message to display when user attempts to call eval (or the Function constructor). Pass NULL when setting enabled to true. | |
| +*/ | |
| +JS_EXPORT void JSGlobalContextSetEvalEnabled(JSGlobalContextRef ctx, bool enabled, JSStringRef message) JSC_API_AVAILABLE(macos(12.3), ios(15.4)); | |
| + | |
| +/* Module Loading API */ | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Evaluates a JavaScript module by its key. | |
| +@param ctx The execution context to use. | |
| +@param moduleKey A JSString containing the module key/URL to evaluate. | |
| +@param exception A pointer to store an exception if evaluation fails. | |
| +@result A promise that resolves when the module and its dependencies are loaded. | |
| +@discussion The module source will be fetched through the module loader's fetch callback. | |
| +*/ | |
| +JS_EXPORT JSObjectRef JSEvaluateModule(JSContextRef ctx, JSStringRef moduleKey, JSValueRef* exception) JSC_API_AVAILABLE(macos(13.3), ios(16.4)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Dynamically imports a module (equivalent to import()). | |
| +@param ctx The execution context to use. | |
| +@param specifier A JSString containing the module specifier to import. | |
| +@param referrer Optional JSString containing the importing module's key. | |
| +@param attributes Optional JSObject containing import attributes. | |
| +@param exception A pointer to store an exception if import fails. | |
| +@result A promise that resolves to the module namespace object. | |
| +*/ | |
| +JS_EXPORT JSObjectRef JSImportModule(JSContextRef ctx, JSStringRef specifier, JSStringRef referrer, JSObjectRef attributes, JSValueRef* exception) JSC_API_AVAILABLE(macos(13.3), ios(16.4)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Checks module source code for syntax errors. | |
| +@param ctx The execution context to use. | |
| +@param source A JSString containing the module source to check. | |
| +@param sourceURL A JSString containing a URL for error reporting. | |
| +@param exception A pointer to store a syntax error exception if any. | |
| +@result true if the module syntax is valid, false otherwise. | |
| +*/ | |
| +JS_EXPORT bool JSCheckModuleSyntax(JSContextRef ctx, JSStringRef source, JSStringRef sourceURL, JSValueRef* exception) JSC_API_AVAILABLE(macos(13.3), ios(16.4)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Creates a JSSourceCode object for use with module loading. | |
| +@param ctx The execution context to use. | |
| +@param source A JSString containing the source code. | |
| +@param sourceURL A JSString containing the source URL. | |
| +@param sourceType The type of source: 0 for Script, 1 for Module, 2 for WebAssembly, 3 for JSON. | |
| +@result A JSValueRef representing a JSSourceCode object. | |
| +*/ | |
| +JS_EXPORT JSValueRef JSModuleSourceCreate(JSContextRef ctx, JSStringRef source, JSStringRef sourceURL, int sourceType) JSC_API_AVAILABLE(macos(13.3), ios(16.4)); | |
| + | |
| +/*! | |
| +@function | |
| +@abstract Registers a module key as synthetic. | |
| +@param ctx The execution context to use. | |
| +@param moduleKey A C string containing the module key to mark as synthetic. | |
| +@discussion Call this before loading modules to indicate which modules should be treated as synthetic. | |
| + Call multiple times to register multiple synthetic modules. | |
| +*/ | |
| +JS_EXPORT void JSRegisterSyntheticModule(JSContextRef ctx, const char* moduleKey) JSC_API_AVAILABLE(macos(13.3), ios(16.4)); | |
| + | |
| #ifdef __cplusplus | |
| } | |
| #endif | |
| -#endif /* JSContextRef_h */ | |
| +#endif /* JSContextRef_h */ | |
| \ No newline at end of file | |
| diff --git forkSrcPrefix/Source/JavaScriptCore/API/JSContextRefPrivate.h forkDstPrefix/Source/JavaScriptCore/API/JSContextRefPrivate.h | |
| index 3f833c910ccfb72813debb3461e7b48769508a89..f20cdbc4f1d709c8b3562631325bcca1830bfa17 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/API/JSContextRefPrivate.h | |
| +++ forkDstPrefix/Source/JavaScriptCore/API/JSContextRefPrivate.h | |
| @@ -38,139 +38,6 @@ | |
| extern "C" { | |
| #endif | |
| -/*! | |
| -@function | |
| -@abstract Gets a Backtrace for the existing context | |
| -@param ctx The JSContext whose backtrace you want to get | |
| -@result A string containing the backtrace | |
| -*/ | |
| -JS_EXPORT JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) JSC_API_AVAILABLE(macos(10.6), ios(7.0)); | |
| - | |
| - | |
| -/*! | |
| -@typedef JSShouldTerminateCallback | |
| -@abstract The callback invoked when script execution has exceeded the allowed | |
| - time limit previously specified via JSContextGroupSetExecutionTimeLimit. | |
| -@param ctx The execution context to use. | |
| -@param context User specified context data previously passed to | |
| - JSContextGroupSetExecutionTimeLimit. | |
| -@discussion If you named your function Callback, you would declare it like this: | |
| - | |
| - bool Callback(JSContextRef ctx, void* context); | |
| - | |
| - If you return true, the timed out script will terminate. | |
| - If you return false, the script will run for another period of the allowed | |
| - time limit specified via JSContextGroupSetExecutionTimeLimit. | |
| - | |
| - Within this callback function, you may call JSContextGroupSetExecutionTimeLimit | |
| - to set a new time limit, or JSContextGroupClearExecutionTimeLimit to cancel the | |
| - timeout. | |
| -*/ | |
| -typedef bool | |
| -(*JSShouldTerminateCallback) (JSContextRef ctx, void* context); | |
| - | |
| -/*! | |
| -@function | |
| -@abstract Sets the script execution time limit. | |
| -@param group The JavaScript context group that this time limit applies to. | |
| -@param limit The time limit of allowed script execution time in seconds. | |
| -@param callback The callback function that will be invoked when the time limit | |
| - has been reached. This will give you a chance to decide if you want to | |
| - terminate the script or not. If you pass a NULL callback, the script will be | |
| - terminated unconditionally when the time limit has been reached. | |
| -@param context User data that you can provide to be passed back to you | |
| - in your callback. | |
| - | |
| - In order to guarantee that the execution time limit will take effect, you will | |
| - need to call JSContextGroupSetExecutionTimeLimit before you start executing | |
| - any scripts. | |
| -*/ | |
| -JS_EXPORT void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* context) JSC_API_AVAILABLE(macos(10.6), ios(7.0)); | |
| - | |
| -/*! | |
| -@function | |
| -@abstract Clears the script execution time limit. | |
| -@param group The JavaScript context group that the time limit is cleared on. | |
| -*/ | |
| -JS_EXPORT void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group) JSC_API_AVAILABLE(macos(10.6), ios(7.0)); | |
| - | |
| -/*! | |
| -@function | |
| -@abstract Enables sampling profiler. | |
| -@param group The JavaScript context group to start sampling. | |
| -@result The value of the enablement, true if the sampling profiler gets enabled, otherwise false. | |
| -@discussion Remote inspection is true by default. | |
| -*/ | |
| -JS_EXPORT bool JSContextGroupEnableSamplingProfiler(JSContextGroupRef group) JSC_API_AVAILABLE(macos(14.2), ios(17.2)); | |
| - | |
| -/*! | |
| -@function | |
| -@abstract Disables sampling profiler. | |
| -@param group The JavaScript context group to stop sampling. | |
| -*/ | |
| -JS_EXPORT void JSContextGroupDisableSamplingProfiler(JSContextGroupRef group) JSC_API_AVAILABLE(macos(14.2), ios(17.2)); | |
| - | |
| -/*! | |
| -@function | |
| -@abstract Gets sampling profiler output in JSON form and clears the sampling profiler records. | |
| -@param group The JavaScript context group whose sampling profile output is taken. | |
| -@result The sampling profiler output in JSON form. NULL if sampling profiler is not enabled ever before. | |
| -@discussion Calling this function clears the sampling data accumulated so far. | |
| -*/ | |
| -JS_EXPORT JSStringRef JSContextGroupTakeSamplesFromSamplingProfiler(JSContextGroupRef group) JSC_API_AVAILABLE(macos(14.2), ios(17.2)); | |
| - | |
| -/*! | |
| -@function | |
| -@abstract Gets a whether or not remote inspection is enabled on the context. | |
| -@param ctx The JSGlobalContext whose setting you want to get. | |
| -@result The value of the setting, true if remote inspection is enabled, otherwise false. | |
| -@discussion Remote inspection is true by default. | |
| -*/ | |
| -JS_EXPORT bool JSGlobalContextGetRemoteInspectionEnabled(JSGlobalContextRef ctx) JSC_API_DEPRECATED_WITH_REPLACEMENT("JSGlobalContextIsInspectable", macos(10.10, 13.3), ios(8.0, 16.4)); | |
| - | |
| -/*! | |
| -@function | |
| -@abstract Sets the remote inspection setting for a context. | |
| -@param ctx The JSGlobalContext that you want to change. | |
| -@param enabled The new remote inspection enabled setting for the context. | |
| -*/ | |
| -JS_EXPORT void JSGlobalContextSetRemoteInspectionEnabled(JSGlobalContextRef ctx, bool enabled) JSC_API_DEPRECATED_WITH_REPLACEMENT("JSGlobalContextSetInspectable", macos(10.10, 13.3), ios(8.0, 16.4)); | |
| - | |
| -/*! | |
| -@function | |
| -@abstract Gets the include native call stack when reporting exceptions setting for a context. | |
| -@param ctx The JSGlobalContext whose setting you want to get. | |
| -@result The value of the setting, true if remote inspection is enabled, otherwise false. | |
| -@discussion This setting is true by default. | |
| -*/ | |
| -JS_EXPORT bool JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx) JSC_API_AVAILABLE(macos(10.10), ios(8.0)); | |
| - | |
| -/*! | |
| -@function | |
| -@abstract Sets the include native call stack when reporting exceptions setting for a context. | |
| -@param ctx The JSGlobalContext that you want to change. | |
| -@param includesNativeCallStack The new value of the setting for the context. | |
| -*/ | |
| -JS_EXPORT void JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions(JSGlobalContextRef ctx, bool includesNativeCallStack) JSC_API_AVAILABLE(macos(10.10), ios(8.0)); | |
| - | |
| -/*! | |
| -@function | |
| -@abstract Sets the unhandled promise rejection callback for a context. | |
| -@discussion Similar to window.addEventListener('unhandledrejection'), but for contexts not associated with a web view. | |
| -@param ctx The JSGlobalContext to set the callback on. | |
| -@param function The callback function to set, which receives the promise and rejection reason as arguments. | |
| -@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception. | |
| -*/ | |
| -JS_EXPORT void JSGlobalContextSetUnhandledRejectionCallback(JSGlobalContextRef ctx, JSObjectRef function, JSValueRef* exception) JSC_API_AVAILABLE(macos(10.15.4), ios(13.4)); | |
| - | |
| -/*! | |
| -@function | |
| -@abstract Sets whether a context allows use of eval (or the Function constructor). | |
| -@param ctx The JSGlobalContext that you want to change. | |
| -@param enabled The new eval enabled setting for the context. | |
| -@param message The error message to display when user attempts to call eval (or the Function constructor). Pass NULL when setting enabled to true. | |
| -*/ | |
| -JS_EXPORT void JSGlobalContextSetEvalEnabled(JSGlobalContextRef ctx, bool enabled, JSStringRef message) JSC_API_AVAILABLE(macos(12.3), ios(15.4)); | |
| #ifdef __cplusplus | |
| } | |
| diff --git forkSrcPrefix/Source/JavaScriptCore/API/JSBasePrivate.h forkDstPrefix/Source/JavaScriptCore/API/JSBasePrivate.h | |
| index 6b79783ba007ff102f8ab1b69bbd3f90dda36c6b..485aeaf87b3b3c496b580a2c3d61565c5fb5e81c 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/API/JSBasePrivate.h | |
| +++ forkDstPrefix/Source/JavaScriptCore/API/JSBasePrivate.h | |
| @@ -58,23 +58,6 @@ JS_EXPORT void JSDisableGCTimer(void); | |
| JS_EXPORT bool JSConfigureSignalForGC(int signal); | |
| #endif | |
| -/*! | |
| -@function | |
| -@abstract Produces an object with various statistics about current memory usage. | |
| -@param ctx The execution context to use. | |
| -@result An object containing GC heap status data. | |
| -@discussion Specifically, the result object has the following integer-valued fields: | |
| - heapSize: current size of heap | |
| - heapCapacity: current capacity of heap | |
| - extraMemorySize: amount of non-GC memory referenced by GC objects (included in heap size / capacity) | |
| - objectCount: current count of GC objects | |
| - protectedObjectCount: current count of protected GC objects | |
| - globalObjectCount: current count of global GC objects | |
| - protectedGlobalObjectCount: current count of protected global GC objects | |
| - objectTypeCounts: object with GC object types as keys and their current counts as values | |
| -*/ | |
| -JS_EXPORT JSObjectRef JSGetMemoryUsageStatistics(JSContextRef ctx); | |
| - | |
| #ifdef __cplusplus | |
| } | |
| #endif | |
| diff --git forkSrcPrefix/Source/JavaScriptCore/runtime/JSModuleLoader.cpp forkDstPrefix/Source/JavaScriptCore/runtime/JSModuleLoader.cpp | |
| index ac80b970a51175662013097d6a61f9e8ec220fef..2e4498c7569a76fb53d66168ed554e490e07f72d 100644 | |
| --- forkSrcPrefix/Source/JavaScriptCore/runtime/JSModuleLoader.cpp | |
| +++ forkDstPrefix/Source/JavaScriptCore/runtime/JSModuleLoader.cpp | |
| @@ -59,6 +59,7 @@ static JSC_DECLARE_HOST_FUNCTION(moduleLoaderFetch); | |
| static JSC_DECLARE_HOST_FUNCTION(moduleLoaderGetModuleNamespaceObject); | |
| static JSC_DECLARE_HOST_FUNCTION(moduleLoaderTypeFromParameters); | |
| static JSC_DECLARE_HOST_FUNCTION(moduleLoaderCreateTypeErrorCopy); | |
| +static JSC_DECLARE_HOST_FUNCTION(moduleLoaderIsSyntheticModule); | |
| } | |
| @@ -90,6 +91,7 @@ void JSModuleLoader::finishCreation(JSGlobalObject* globalObject, VM& vm) | |
| JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("evaluate"_s, moduleLoaderEvaluate, static_cast<unsigned>(PropertyAttribute::DontEnum), 3, ImplementationVisibility::Private); | |
| JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("typeFromParameters"_s, moduleLoaderTypeFromParameters, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, ImplementationVisibility::Private); | |
| JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("createTypeErrorCopy"_s, moduleLoaderCreateTypeErrorCopy, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, ImplementationVisibility::Private); | |
| + JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("isSyntheticModule"_s, moduleLoaderIsSyntheticModule, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, ImplementationVisibility::Private); | |
| JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().ensureRegisteredPublicName(), moduleLoaderEnsureRegisteredCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | |
| JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().requestFetchPublicName(), moduleLoaderRequestFetchCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | |
| @@ -329,6 +331,29 @@ JSModuleNamespaceObject* JSModuleLoader::getModuleNamespaceObject(JSGlobalObject | |
| // ------------------------------ Functions -------------------------------- | |
| +JSC_DEFINE_HOST_FUNCTION(moduleLoaderIsSyntheticModule, (JSGlobalObject* globalObject, CallFrame* callFrame)) | |
| +{ | |
| + JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(callFrame->thisValue()); | |
| + if (!loader) | |
| + return JSValue::encode(jsBoolean(false)); | |
| + | |
| + if (globalObject->globalObjectMethodTable()->moduleLoaderEvaluate) { | |
| + VM& vm = globalObject->vm(); | |
| + auto scope = DECLARE_THROW_SCOPE(vm); | |
| + | |
| + JSValue keyValue = callFrame->argument(0); | |
| + JSValue result = globalObject->globalObjectMethodTable()->moduleLoaderEvaluate( | |
| + globalObject, loader, keyValue, jsUndefined(), jsUndefined(), jsUndefined(), jsUndefined()); | |
| + | |
| + RETURN_IF_EXCEPTION(scope, encodedJSValue()); | |
| + | |
| + if (result.isBoolean()) | |
| + return JSValue::encode(result); | |
| + } | |
| + | |
| + return JSValue::encode(jsBoolean(false)); | |
| +} | |
| + | |
| JSC_DEFINE_HOST_FUNCTION(moduleLoaderParseModule, (JSGlobalObject* globalObject, CallFrame* callFrame)) | |
| { | |
| VM& vm = globalObject->vm(); | |
| @@ -348,6 +373,46 @@ JSC_DEFINE_HOST_FUNCTION(moduleLoaderParseModule, (JSGlobalObject* globalObject, | |
| dataLogLnIf(Options::dumpModuleLoadingState(), "loader [parsing] ", moduleKey); | |
| JSValue source = callFrame->argument(1); | |
| + if (source.isUndefined()) { | |
| + if (globalObject->globalObjectMethodTable()->moduleLoaderEvaluate) { | |
| + JSValue exports = globalObject->globalObjectMethodTable()->moduleLoaderEvaluate( | |
| + globalObject, | |
| + jsCast<JSModuleLoader*>(callFrame->thisValue()), | |
| + callFrame->argument(0), // key | |
| + jsUndefined(), // moduleRecord | |
| + jsBoolean(true), // scriptFetcher - USE AS FLAG! | |
| + jsUndefined(), // awaitedValue | |
| + jsUndefined() // resumeMode | |
| + ); | |
| + | |
| + if (exports.isObject()) { | |
| + JSObject* exportsObj = exports.getObject(); | |
| + PropertyNameArray propertyNames(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude); | |
| + exportsObj->getOwnPropertyNames(exportsObj, globalObject, propertyNames, DontEnumPropertiesMode::Exclude); | |
| + | |
| + Vector<Identifier, 4> exportNames; | |
| + MarkedArgumentBuffer exportValues; | |
| + | |
| + for (const auto& propertyName : propertyNames) { | |
| + JSValue value = exportsObj->get(globalObject, propertyName); | |
| + RETURN_IF_EXCEPTION(scope, JSValue::encode(promise->rejectWithCaughtException(globalObject, scope))); | |
| + exportNames.append(propertyName); | |
| + exportValues.append(value); | |
| + } | |
| + | |
| + SyntheticModuleRecord* moduleRecord = SyntheticModuleRecord::tryCreateWithExportNamesAndValues( | |
| + globalObject, moduleKey, exportNames, exportValues); | |
| + | |
| + RETURN_IF_EXCEPTION(scope, JSValue::encode(promise->rejectWithCaughtException(globalObject, scope))); | |
| + | |
| + scope.release(); | |
| + promise->resolve(globalObject, moduleRecord); | |
| + return JSValue::encode(promise); | |
| + } | |
| + } | |
| + | |
| + RELEASE_AND_RETURN(scope, JSValue::encode(rejectWithError(createError(globalObject, makeString("No source provided for module"_s))))); | |
| + } | |
| auto* jsSourceCode = jsCast<JSSourceCode*>(source); | |
| SourceCode sourceCode = jsSourceCode->sourceCode(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment