Skip to content

Instantly share code, notes, and snippets.

@andrewmd5
Created August 25, 2025 13:55
Show Gist options
  • Save andrewmd5/70b98411a34bbeb63d2cf3402f0465cb to your computer and use it in GitHub Desktop.
Save andrewmd5/70b98411a34bbeb63d2cf3402f0465cb to your computer and use it in GitHub Desktop.
JavaScriptCore ECMAScript modules (C API)
#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;
}
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,
+ &currentScriptExecutionOwner,
+ &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