diff options
| author | 2021-08-05 19:48:36 -0700 | |
|---|---|---|
| committer | 2021-08-05 19:48:36 -0700 | |
| commit | c0273a09f19e0757711592c6ad3b3b5de7acca67 (patch) | |
| tree | b0af7c1c4cc4c0c5a03c198a338275e139a6fc37 | |
| parent | 56c689d684467694a51db5aa9e765146718e6c1a (diff) | |
| download | bun-c0273a09f19e0757711592c6ad3b3b5de7acca67.tar.gz bun-c0273a09f19e0757711592c6ad3b3b5de7acca67.tar.zst bun-c0273a09f19e0757711592c6ad3b3b5de7acca67.zip | |
alright server-side reloading code works
Former-commit-id: a49ef52eec1037014e3c9cda1a09f387a01116b8
| -rw-r--r-- | .vscode/launch.json | 4 | ||||
| -rw-r--r-- | .vscode/settings.json | 3 | ||||
| -rw-r--r-- | demos/css-stress-test/framework.tsx | 5 | ||||
| -rw-r--r-- | src/bundler.zig | 24 | ||||
| -rw-r--r-- | src/cli.zig | 1 | ||||
| -rw-r--r-- | src/feature_flags.zig | 2 | ||||
| -rw-r--r-- | src/http.zig | 52 | ||||
| -rw-r--r-- | src/javascript/jsc/JavascriptCore.zig | 7 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/ZigGlobalObject.cpp | 64 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/ZigSourceProvider.cpp | 6 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/ZigSourceProvider.h | 13 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/bindings.cpp | 84 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/bindings.zig | 9 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/exports.zig | 10 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/headers-cpp.h | 2 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/headers-handwritten.h | 3 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/headers.h | 5 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/headers.zig | 3 | ||||
| -rw-r--r-- | src/javascript/jsc/webcore/response.zig | 17 | ||||
| -rw-r--r-- | src/runtime/hmr.ts | 2 | ||||
| -rw-r--r-- | src/watcher.zig | 3 |
21 files changed, 268 insertions, 51 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json index 184131251..034d61941 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -70,9 +70,7 @@ "name": "Eval", "program": "${workspaceFolder}/build/debug/macos-x86_64/spjs", "args": [ - "src/index.tsx", - "--resolve=dev", - "--outdir=outcss" + "./src/index.tsx" // "--public-url=https://localhost:9000/" ], "cwd": "${workspaceFolder}/demos/css-stress-test", diff --git a/.vscode/settings.json b/.vscode/settings.json index 2ae7aa2d6..bc6b1d516 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -113,6 +113,7 @@ "map": "cpp", "numeric": "cpp", "set": "cpp", - "__memory": "cpp" + "__memory": "cpp", + "memory_resource": "cpp" } } diff --git a/demos/css-stress-test/framework.tsx b/demos/css-stress-test/framework.tsx index 0d1e5d18c..c07f032bc 100644 --- a/demos/css-stress-test/framework.tsx +++ b/demos/css-stress-test/framework.tsx @@ -1,7 +1,8 @@ import ReactDOMServer from "react-dom/server.browser"; -import { Base } from "./src/index"; -addEventListener("fetch", (event: FetchEvent) => { +addEventListener("fetch", async (event: FetchEvent) => { + const { Base } = await import("./src/index"); + const response = new Response(` <!DOCTYPE html> <html> diff --git a/src/bundler.zig b/src/bundler.zig index 161aeb6c0..769cb4cb0 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -229,6 +229,26 @@ pub fn NewBundler(cache_files: bool) type { framework.entry_point = try this.allocator.dupe(u8, resolved.path_pair.primary.text); } } + + pub fn configureFrameworkWithResolveResult(this: *ThisBundler) ?_resolver.Result { + if (this.options.framework) |*framework| { + var framework_file = this.normalizeEntryPointPath(framework.entry_point); + const result = this.resolver.resolve( + this.fs.top_level_dir, + framework_file, + .entry_point, + ) catch |err| { + Output.prettyErrorln("Failed to load framework: {s}", .{@errorName(err)}); + Output.flush(); + this.options.framework = null; + return null; + }; + framework.entry_point = result.path_pair.primary.text; + return result; + } + + return null; + } pub fn configureRouter(this: *ThisBundler) !void { try this.configureFramework(); @@ -381,6 +401,10 @@ pub fn NewBundler(cache_files: bool) type { bundler.resolver.debug_logs = try DebugLogs.init(allocator); } + if (bundler.configureFrameworkWithResolveResult()) |result| { + try this.resolve_queue.writeItem(result); + } + for (bundler.options.entry_points) |entry_point| { const entry_point_path = bundler.normalizeEntryPointPath(entry_point); const source_dir = bundler.fs.top_level_dir; diff --git a/src/cli.zig b/src/cli.zig index c0210f373..cf1791d1e 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -382,6 +382,7 @@ pub const Cli = struct { this_bundler.configureLinker(); var filepath = "node_modules.jsb"; var node_modules = try bundler.ServeBundler.GenerateNodeModuleBundle.generate(&this_bundler, allocator, filepath); + var elapsed = @divTrunc(std.time.nanoTimestamp() - start_time, @as(i128, std.time.ns_per_ms)); var bundle = NodeModuleBundle.init(node_modules, allocator); diff --git a/src/feature_flags.zig b/src/feature_flags.zig index b5fc7cb5e..191222e31 100644 --- a/src/feature_flags.zig +++ b/src/feature_flags.zig @@ -32,7 +32,7 @@ pub const verbose_watcher = true; pub const css_supports_fence = true; pub const disable_entry_cache = false; -pub const enable_bytecode_caching = true; +pub const enable_bytecode_caching = false; pub const CSSModulePolyfill = enum { // When you import a .css file and you reference the import in JavaScript diff --git a/src/http.zig b/src/http.zig index 8fff01048..2e944f859 100644 --- a/src/http.zig +++ b/src/http.zig @@ -33,18 +33,18 @@ const Header = picohttp.Header; const Request = picohttp.Request; const Response = picohttp.Response; pub const Headers = picohttp.Headers; -pub const MimeType = @import("http/mime_type.zig"); +pub const MimeType = @import("./http/mime_type.zig"); const Bundler = bundler.ServeBundler; const Websocket = @import("./http/websocket.zig"); -const js_printer = @import("js_printer.zig"); +const js_printer = @import("./js_printer.zig"); const SOCKET_FLAGS = os.SOCK_CLOEXEC; const watcher = @import("./watcher.zig"); threadlocal var req_headers_buf: [100]picohttp.Header = undefined; threadlocal var res_headers_buf: [100]picohttp.Header = undefined; const sync = @import("./sync.zig"); const JavaScript = @import("./javascript/jsc/javascript.zig"); -const js = @import("javascript/jsc/javascript.zig"); -usingnamespace @import("javascript/jsc/bindings/bindings.zig"); +usingnamespace @import("./javascript/jsc/bindings/bindings.zig"); +usingnamespace @import("./javascript/jsc/bindings/exports.zig"); const Router = @import("./router.zig"); pub const Watcher = watcher.NewWatcher(*Server); @@ -649,6 +649,7 @@ pub const RequestContext = struct { framework: Options.Framework, existing_bundle: ?*NodeModuleBundle, log: ?*logger.Log = null, + watcher: *Watcher, }; pub const Channel = sync.Channel(*JavaScriptHandler, .{ .Static = 100 }); @@ -657,7 +658,7 @@ pub const RequestContext = struct { pub var javascript_disabled = false; pub fn spawnThread(handler: HandlerThread) !void { var thread = try std.Thread.spawn(.{}, spawn, .{handler}); - // thread.detach(); + thread.detach(); } pub fn spawn(handler: HandlerThread) void { @@ -697,14 +698,13 @@ pub const RequestContext = struct { const boot = handler.framework.entry_point; std.debug.assert(boot.len > 0); defer vm.deinit(); - + vm.watcher = handler.watcher; var resolved_entry_point = try vm.bundler.resolver.resolve( std.fs.path.dirname(boot) orelse vm.bundler.fs.top_level_dir, vm.bundler.normalizeEntryPointPath(boot), .entry_point, ); var load_result = try vm.loadEntryPoint(resolved_entry_point.path_pair.primary.text); - switch (load_result.status(vm.global.vm())) { JSPromise.Status.Fulfilled => {}, else => { @@ -712,7 +712,14 @@ pub const RequestContext = struct { "JavaScript VM failed to start", .{}, ); - Output.flush(); + var result = load_result.result(vm.global.vm()); + + vm.defaultErrorHandler(result); + + if (channel.tryReadItem() catch null) |item| { + item.ctx.sendInternalError(error.JSFailedToStart) catch {}; + item.ctx.arena.deinit(); + } return; }, } @@ -729,10 +736,14 @@ pub const RequestContext = struct { } pub fn runLoop(vm: *JavaScript.VirtualMachine) !void { + var module_map = ZigGlobalObject.getModuleRegistryMap(vm.global); + while (true) { defer { + std.debug.assert(ZigGlobalObject.resetModuleRegistryMap(vm.global, module_map)); js_ast.Stmt.Data.Store.reset(); js_ast.Expr.Data.Store.reset(); + } var handler: *JavaScriptHandler = try channel.readItem(); try JavaScript.EventListenerMixin.emitFetchEvent(vm, &handler.ctx); @@ -755,6 +766,7 @@ pub const RequestContext = struct { .framework = server.bundler.options.framework.?, .existing_bundle = server.bundler.options.node_modules_bundle, .log = &server.log, + .watcher = server.watcher, }, ); } @@ -1159,7 +1171,7 @@ pub const RequestContext = struct { return try ctx.sendJSB(); } - if (strings.eqlComptime(ctx.url.path, "_api")) { + if (strings.eqlComptime(ctx.url.path, "_api.hmr")) { try ctx.handleWebsocket(); return; } @@ -1230,6 +1242,10 @@ pub const RequestContext = struct { return bytes.len; } + pub fn slice(_ctx: *SocketPrinterInternal) string { + return buffer.list.items; + } + pub fn getLastByte(_ctx: *const SocketPrinterInternal) u8 { return if (buffer.list.items.len > 0) buffer.list.items[buffer.list.items.len - 1] else 0; } @@ -1540,6 +1556,8 @@ pub const Server = struct { var header = fbs.getWritten(); for (events) |event| { const file_path = watchlist.items(.file_path)[event.index]; + const update_count = watchlist.items(.count)[event.index] + 1; + watchlist.items(.count)[event.index] = update_count; // so it's consistent with the rest // if we use .extname we might run into an issue with whether or not the "." is included. @@ -1550,9 +1568,7 @@ pub const Server = struct { defer { if (comptime is_javascript_enabled) { // TODO: does this need a lock? - if (RequestContext.JavaScriptHandler.javascript_vm.require_cache.get(id)) |module| { - module.reload_pending = true; - } + RequestContext.JavaScriptHandler.javascript_vm.incrementUpdateCounter(id, update_count); } } const change_message = Api.WebsocketMessageFileChangeNotification{ @@ -1672,8 +1688,16 @@ pub const Server = struct { if (req_ctx.url.extname.len == 0 and !RequestContext.JavaScriptHandler.javascript_disabled) { if (server.bundler.options.framework != null) { - RequestContext.JavaScriptHandler.enqueue(&req_ctx, server) catch unreachable; - server.javascript_enabled = !RequestContext.JavaScriptHandler.javascript_disabled; + server.javascript_enabled = true; + + // We want to start this on the main thread + if (server.watcher.watchloop_handle == null) { + server.watcher.start() catch {}; + } + + RequestContext.JavaScriptHandler.enqueue(&req_ctx, server) catch { + server.javascript_enabled = false; + }; } } diff --git a/src/javascript/jsc/JavascriptCore.zig b/src/javascript/jsc/JavascriptCore.zig index 6c4da3297..4e9bbf4c4 100644 --- a/src/javascript/jsc/JavascriptCore.zig +++ b/src/javascript/jsc/JavascriptCore.zig @@ -1,3 +1,4 @@ +const cpp = @import("./bindings/bindings.zig"); const generic = opaque {}; pub const Private = c_void; pub const struct_OpaqueJSContextGroup = generic; @@ -243,7 +244,11 @@ pub const OpaqueJSClass = struct_OpaqueJSClass; pub const OpaqueJSPropertyNameArray = struct_OpaqueJSPropertyNameArray; pub const OpaqueJSPropertyNameAccumulator = struct_OpaqueJSPropertyNameAccumulator; -// const JSProcessID = ; +// This is a workaround for not receiving a JSException* object +// This function lets us use the C API but returns a plain old JSValue +// allowing us to have exceptions that include stack traces +pub extern "c" fn JSObjectCallAsFunctionReturnValue(ctx: JSContextRef, object: JSObjectRef, thisObject: JSObjectRef, argumentCount: usize, arguments: [*c]const JSValueRef) cpp.JSValue; + pub extern fn JSRemoteInspectorDisableAutoStart() void; pub extern fn JSRemoteInspectorStart() void; // JS_EXPORT void JSRemoteInspectorSetParentProcessInformation(JSProcessID, const uint8_t* auditData, size_t auditLength) JSC_API_AVAILABLE(macos(10.11), ios(9.0)); diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp index f09281fa7..2a26e44cb 100644 --- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp +++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp @@ -8,11 +8,14 @@ #include <JavaScriptCore/Completion.h> #include <JavaScriptCore/Error.h> #include <JavaScriptCore/Exception.h> +#include <JavaScriptCore/HashMapImpl.h> +#include <JavaScriptCore/HashMapImplInlines.h> #include <JavaScriptCore/Identifier.h> #include <JavaScriptCore/InitializeThreading.h> #include <JavaScriptCore/JSCast.h> #include <JavaScriptCore/JSContextInternal.h> #include <JavaScriptCore/JSInternalPromise.h> +#include <JavaScriptCore/JSMap.h> #include <JavaScriptCore/JSModuleLoader.h> #include <JavaScriptCore/JSNativeStdFunction.h> #include <JavaScriptCore/JSPromise.h> @@ -33,6 +36,7 @@ #include <exception> #include <iostream> +// #include <JavaScriptCore/CachedType.h> #include <JavaScriptCore/JSCallbackObject.h> #include <JavaScriptCore/JSClassRef.h> @@ -184,6 +188,59 @@ JSC::JSInternalPromise *GlobalObject::moduleLoaderImportModule(JSGlobalObject *g return result; } +extern "C" void *Zig__GlobalObject__getModuleRegistryMap(JSC__JSGlobalObject *arg0) { + if (JSC::JSObject *loader = + JSC::jsDynamicCast<JSC::JSObject *>(arg0->vm(), arg0->moduleLoader())) { + JSC::JSMap *map = JSC::jsDynamicCast<JSC::JSMap *>( + arg0->vm(), + loader->getDirect(arg0->vm(), JSC::Identifier::fromString(arg0->vm(), "registry"))); + + JSC::JSMap *cloned = map->clone(arg0, arg0->vm(), arg0->mapStructure()); + JSC::gcProtect(cloned); + + return cloned; + } + + return nullptr; +} + +extern "C" bool Zig__GlobalObject__resetModuleRegistryMap(JSC__JSGlobalObject *globalObject, + void *map_ptr) { + if (map_ptr == nullptr) return false; + JSC::JSMap *map = reinterpret_cast<JSC::JSMap *>(map_ptr); + + if (JSC::JSObject *obj = + JSC::jsDynamicCast<JSC::JSObject *>(globalObject->vm(), globalObject->moduleLoader())) { + auto identifier = JSC::Identifier::fromString(globalObject->vm(), "registry"); + + if (JSC::JSMap *oldMap = JSC::jsDynamicCast<JSC::JSMap *>( + globalObject->vm(), obj->getDirect(globalObject->vm(), identifier))) { + // Help the GC by releasing the old map. + oldMap->clear(globalObject); + // forEachInIterable( + // globalObject, oldMap, [&](VM &vm, JSGlobalObject *globalObject, JSValue nextValue) { + // auto scope = DECLARE_THROW_SCOPE(vm); + // JSC::JSValue key = nextObject->getIndex(globalObject, static_cast<unsigned>(0)); + // RETURN_IF_EXCEPTION(scope, void()); + + // if (!map->has(globalObject, key)) { + + // JSC::JSValue value = nextObject->getIndex(globalObject, static_cast<unsigned>(1)); + // RETURN_IF_EXCEPTION(scope, void()); + + // } + // scope.release(); + // }); + }; + + return obj->putDirect( + globalObject->vm(), identifier, + map->clone(globalObject, globalObject->vm(), globalObject->mapStructure())); + } + + return false; +} + JSC::JSInternalPromise *GlobalObject::moduleLoaderFetch(JSGlobalObject *globalObject, JSModuleLoader *loader, JSValue key, JSValue value1, JSValue value2) { @@ -214,14 +271,13 @@ JSC::JSInternalPromise *GlobalObject::moduleLoaderFetch(JSGlobalObject *globalOb RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); } - auto code = Zig::toString(res.result.value.source_code); auto provider = Zig::SourceProvider::create(res.result.value); auto jsSourceCode = JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)); - // if (provider.ptr()->isBytecodeCacheEnabled()) { - // provider.ptr()->readOrGenerateByteCodeCache(vm, jsSourceCode->sourceCode()); - // } + if (provider.ptr()->isBytecodeCacheEnabled()) { + provider.ptr()->readOrGenerateByteCodeCache(vm, jsSourceCode->sourceCode()); + } scope.release(); promise->resolve(globalObject, jsSourceCode); diff --git a/src/javascript/jsc/bindings/ZigSourceProvider.cpp b/src/javascript/jsc/bindings/ZigSourceProvider.cpp index 6a08e1057..63bf1dcfd 100644 --- a/src/javascript/jsc/bindings/ZigSourceProvider.cpp +++ b/src/javascript/jsc/bindings/ZigSourceProvider.cpp @@ -33,8 +33,7 @@ Ref<SourceProvider> SourceProvider::create(ResolvedSource resolvedSource) { unsigned SourceProvider::getHash() { if (m_hash) { return m_hash; } - m_hash = WTF::StringHash::hash(WTF::String(WTF::StringImpl::createWithoutCopying( - m_resolvedSource.source_code.ptr, m_resolvedSource.source_code.len))); + m_hash = WTF::StringHash::hash(m_source.get()); return m_hash; } @@ -104,6 +103,9 @@ void SourceProvider::readOrGenerateByteCodeCache(JSC::VM &vm, const JSC::SourceC m_cachedBytecode = JSC::CachedBytecode::create(); } } + // TODO: read the bytecode into a JSC::SourceCode object here + case 1: { + } } } int SourceProvider::readCache(JSC::VM &vm, const JSC::SourceCode &sourceCode) { diff --git a/src/javascript/jsc/bindings/ZigSourceProvider.h b/src/javascript/jsc/bindings/ZigSourceProvider.h index 2012b45b6..11e89310a 100644 --- a/src/javascript/jsc/bindings/ZigSourceProvider.h +++ b/src/javascript/jsc/bindings/ZigSourceProvider.h @@ -6,6 +6,7 @@ namespace JSC { class Structure; class Identifier; +class SourceCodeKey; } // namespace JSC @@ -13,6 +14,7 @@ class Identifier; #include <JavaScriptCore/CachedBytecode.h> #include <JavaScriptCore/JSGlobalObject.h> #include <JavaScriptCore/JSTypeInfo.h> +// #include <JavaScriptCore/SourceCodeKey.h> #include <JavaScriptCore/SourceProvider.h> #include <JavaScriptCore/Structure.h> #include <wtf/FileSystem.h> @@ -35,9 +37,7 @@ class SourceProvider final : public JSC::SourceProvider { ~SourceProvider() { commitCachedBytecode(); } unsigned hash() const { return m_hash; }; - StringView source() const { - return StringView(m_resolvedSource.source_code.ptr, m_resolvedSource.source_code.len); - } + StringView source() const { return StringView(m_source.get()); } RefPtr<JSC::CachedBytecode> cachedBytecode() { if (m_resolvedSource.bytecodecache_fd == 0) { return nullptr; } @@ -57,7 +57,10 @@ class SourceProvider final : public JSC::SourceProvider { SourceProvider(ResolvedSource resolvedSource, const SourceOrigin &sourceOrigin, WTF::String &&sourceURL, const TextPosition &startPosition, JSC::SourceProviderSourceType sourceType) - : Base(sourceOrigin, WTFMove(sourceURL), startPosition, sourceType) { + : Base(sourceOrigin, WTFMove(sourceURL), startPosition, sourceType), + m_source( + *WTF::String(resolvedSource.source_code.ptr, resolvedSource.source_code.len).impl()) { + m_resolvedSource = resolvedSource; m_hash = resolvedSource.hash; getHash(); @@ -65,6 +68,8 @@ class SourceProvider final : public JSC::SourceProvider { unsigned m_hash; unsigned getHash(); RefPtr<JSC::CachedBytecode> m_cachedBytecode; + Ref<WTF::StringImpl> m_source; + // JSC::SourceCodeKey key; }; } // namespace Zig
\ No newline at end of file diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp index 6d08f3854..4d8d13483 100644 --- a/src/javascript/jsc/bindings/bindings.cpp +++ b/src/javascript/jsc/bindings/bindings.cpp @@ -15,6 +15,7 @@ #include <JavaScriptCore/JSClassRef.h> #include <JavaScriptCore/JSInternalPromise.h> #include <JavaScriptCore/JSMap.h> +#include <JavaScriptCore/JSModuleLoader.h> #include <JavaScriptCore/JSModuleRecord.h> #include <JavaScriptCore/JSNativeStdFunction.h> #include <JavaScriptCore/JSObject.h> @@ -34,6 +35,70 @@ #include <wtf/text/WTFString.h> extern "C" { +// This is very naive! +JSC__JSInternalPromise *JSC__VM__reloadModule(JSC__VM *vm, JSC__JSGlobalObject *arg1, + ZigString arg2) { + return nullptr; + // JSC::JSMap *map = JSC::jsDynamicCast<JSC::JSMap *>( + // arg1->vm(), arg1->moduleLoader()->getDirect( + // arg1->vm(), JSC::Identifier::fromString(arg1->vm(), "registry"))); + + // const JSC::Identifier identifier = Zig::toIdentifier(arg2, arg1); + // JSC::JSValue val = JSC::identifierToJSValue(arg1->vm(), identifier); + + // if (!map->has(arg1, val)) return nullptr; + + // if (JSC::JSObject *registryEntry = + // JSC::jsDynamicCast<JSC::JSObject *>(arg1->vm(), map->get(arg1, val))) { + // auto moduleIdent = JSC::Identifier::fromString(arg1->vm(), "module"); + // if (JSC::JSModuleRecord *record = JSC::jsDynamicCast<JSC::JSModuleRecord *>( + // arg1->vm(), registryEntry->getDirect(arg1->vm(), moduleIdent))) { + // registryEntry->putDirect(arg1->vm(), moduleIdent, JSC::jsUndefined()); + // JSC::JSModuleRecord::destroy(static_cast<JSC::JSCell *>(record)); + // } + // map->remove(arg1, val); + // return JSC__JSModuleLoader__loadAndEvaluateModule(arg1, arg2); + // } + + // return nullptr; +} + +// This is the same as the C API version, except it returns a JSValue which may be a *Exception +// We want that so we can return stack traces. +JSC__JSValue JSObjectCallAsFunctionReturnValue(JSContextRef ctx, JSObjectRef object, + JSObjectRef thisObject, size_t argumentCount, + const JSValueRef *arguments); + +JSC__JSValue JSObjectCallAsFunctionReturnValue(JSContextRef ctx, JSObjectRef object, + JSObjectRef thisObject, size_t argumentCount, + const JSValueRef *arguments) { + JSC::JSGlobalObject *globalObject = toJS(ctx); + JSC::VM &vm = globalObject->vm(); + + if (!object) return JSC::JSValue::encode(JSC::JSValue()); + + JSC::JSObject *jsObject = toJS(object); + JSC::JSObject *jsThisObject = toJS(thisObject); + + if (!jsThisObject) jsThisObject = globalObject->globalThis(); + + JSC::MarkedArgumentBuffer argList; + for (size_t i = 0; i < argumentCount; i++) argList.append(toJS(globalObject, arguments[i])); + + auto callData = getCallData(vm, jsObject); + if (callData.type == JSC::CallData::Type::None) return JSC::JSValue::encode(JSC::JSValue()); + + NakedPtr<JSC::Exception> returnedException = nullptr; + auto result = + JSC::call(globalObject, jsObject, callData, jsThisObject, argList, returnedException); + + if (returnedException.get()) { + return JSC::JSValue::encode(JSC::JSValue(returnedException.get())); + } + + return JSC::JSValue::encode(result); +} + #pragma mark - JSC::Exception JSC__Exception *JSC__Exception__create(JSC__JSGlobalObject *arg0, JSC__JSObject *arg1, @@ -95,6 +160,7 @@ size_t JSC__JSString__length(const JSC__JSString *arg0) { return arg0->length(); JSC__JSObject *JSC__JSString__toObject(JSC__JSString *arg0, JSC__JSGlobalObject *arg1) { return arg0->toObject(arg1); } + bWTF__String JSC__JSString__value(JSC__JSString *arg0, JSC__JSGlobalObject *arg1) { return Wrap<WTF__String, bWTF__String>::wrap(arg0->value(arg1)); } @@ -1239,14 +1305,22 @@ JSC__VM *JSC__VM__create(unsigned char HeapType0) { return vm; } -void JSC__VM__deinit(JSC__VM *arg1, JSC__JSGlobalObject *globalObject) { - JSC::VM &vm = reinterpret_cast<JSC::VM &>(arg1); - bool protectCountIsZero = vm.heap.unprotect(globalObject); - if (protectCountIsZero) vm.heap.reportAbandonedObjectGraph(); +void JSC__VM__deleteAllCode(JSC__VM *arg1, JSC__JSGlobalObject *globalObject) { + JSC::JSLockHolder locker(globalObject->vm()); - vm.deref(); + arg1->drainMicrotasks(); + if (JSC::JSObject *obj = + JSC::jsDynamicCast<JSC::JSObject *>(globalObject->vm(), globalObject->moduleLoader())) { + auto id = JSC::Identifier::fromString(globalObject->vm(), "registry"); + JSC::JSMap *map = + JSC::JSMap::create(globalObject, globalObject->vm(), globalObject->mapStructure()); + obj->putDirect(globalObject->vm(), id, map); + } + arg1->deleteAllCode(JSC::DeleteAllCodeEffort::PreventCollectionAndDeleteAllCode); + arg1->heap.reportAbandonedObjectGraph(); } +void JSC__VM__deinit(JSC__VM *arg1, JSC__JSGlobalObject *globalObject) {} void JSC__VM__drainMicrotasks(JSC__VM *arg0) { arg0->drainMicrotasks(); } bool JSC__VM__executionForbidden(JSC__VM *arg0) { return (*arg0).executionForbidden(); } diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig index 1ae5c1236..9373a00a5 100644 --- a/src/javascript/jsc/bindings/bindings.zig +++ b/src/javascript/jsc/bindings/bindings.zig @@ -1480,6 +1480,13 @@ pub const VM = extern struct { return cppFn("deinit", .{ vm, global_object }); } + pub fn deleteAllCode( + vm: *VM, + global_object: *JSGlobalObject, + ) void { + return cppFn("deleteAllCode", .{ vm, global_object }); + } + pub fn setExecutionForbidden(vm: *VM, forbidden: bool) void { cppFn("setExecutionForbidden", .{ vm, forbidden }); } @@ -1522,7 +1529,7 @@ pub const VM = extern struct { }); } - pub const Extern = [_][]const u8{ "apiLock", "create", "deinit", "setExecutionForbidden", "executionForbidden", "isEntered", "throwError", "drainMicrotasks" }; + pub const Extern = [_][]const u8{ "deleteAllCode", "apiLock", "create", "deinit", "setExecutionForbidden", "executionForbidden", "isEntered", "throwError", "drainMicrotasks" }; }; pub const ThrowScope = extern struct { diff --git a/src/javascript/jsc/bindings/exports.zig b/src/javascript/jsc/bindings/exports.zig index 861b65e2b..89297aaf6 100644 --- a/src/javascript/jsc/bindings/exports.zig +++ b/src/javascript/jsc/bindings/exports.zig @@ -35,6 +35,14 @@ pub const ZigGlobalObject = extern struct { return shim.cppFn("create", .{ class_ref, count, console }); } + pub fn getModuleRegistryMap(global: *JSGlobalObject) *c_void { + return shim.cppFn("getModuleRegistryMap", .{global}); + } + + pub fn resetModuleRegistryMap(global: *JSGlobalObject, map: *c_void) bool { + return shim.cppFn("resetModuleRegistryMap", .{ global, map }); + } + pub fn import(global: *JSGlobalObject, specifier: ZigString, source: ZigString) callconv(.C) ErrorableZigString { if (comptime is_bindgen) { unreachable; @@ -94,7 +102,7 @@ pub const ZigGlobalObject = extern struct { .@"onCrash" = onCrash, }); - pub const Extern = [_][]const u8{"create"}; + pub const Extern = [_][]const u8{ "create", "getModuleRegistryMap", "resetModuleRegistryMap" }; comptime { @export(import, .{ .name = Export[0].symbol_name }); diff --git a/src/javascript/jsc/bindings/headers-cpp.h b/src/javascript/jsc/bindings/headers-cpp.h index e4bc40fbe..1e578bd0a 100644 --- a/src/javascript/jsc/bindings/headers-cpp.h +++ b/src/javascript/jsc/bindings/headers-cpp.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1628059111 +//-- AUTOGENERATED FILE -- 1628213116 // clang-format off #pragma once diff --git a/src/javascript/jsc/bindings/headers-handwritten.h b/src/javascript/jsc/bindings/headers-handwritten.h index 6768a7d64..10bf85a52 100644 --- a/src/javascript/jsc/bindings/headers-handwritten.h +++ b/src/javascript/jsc/bindings/headers-handwritten.h @@ -92,4 +92,5 @@ const JSErrorCode JSErrorCodeUserErrorCode = 254; #ifdef __cplusplus extern "C" ZigErrorCode Zig_ErrorCodeParserError; -#endif
\ No newline at end of file + +#endif diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h index 02afc9cc9..813a01750 100644 --- a/src/javascript/jsc/bindings/headers.h +++ b/src/javascript/jsc/bindings/headers.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1628059111 +//-- AUTOGENERATED FILE -- 1628213116 // clang-format: off #pragma once @@ -481,6 +481,7 @@ CPP_DECL JSC__JSValue JSC__Exception__value(JSC__Exception* arg0); CPP_DECL JSC__JSLock* JSC__VM__apiLock(JSC__VM* arg0); CPP_DECL JSC__VM* JSC__VM__create(unsigned char HeapType0); CPP_DECL void JSC__VM__deinit(JSC__VM* arg0, JSC__JSGlobalObject* arg1); +CPP_DECL void JSC__VM__deleteAllCode(JSC__VM* arg0, JSC__JSGlobalObject* arg1); CPP_DECL void JSC__VM__drainMicrotasks(JSC__VM* arg0); CPP_DECL bool JSC__VM__executionForbidden(JSC__VM* arg0); CPP_DECL bool JSC__VM__isEntered(JSC__VM* arg0); @@ -562,6 +563,8 @@ CPP_DECL size_t WTF__StringView__length(const WTF__StringView* arg0); #pragma mark - Zig::GlobalObject CPP_DECL JSC__JSGlobalObject* Zig__GlobalObject__create(JSClassRef* arg0, int32_t arg1, void* arg2); +CPP_DECL void* Zig__GlobalObject__getModuleRegistryMap(JSC__JSGlobalObject* arg0); +CPP_DECL bool Zig__GlobalObject__resetModuleRegistryMap(JSC__JSGlobalObject* arg0, void* arg1); #ifdef __cplusplus diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig index cb223c3ce..901422733 100644 --- a/src/javascript/jsc/bindings/headers.zig +++ b/src/javascript/jsc/bindings/headers.zig @@ -295,6 +295,7 @@ pub extern fn JSC__Exception__value(arg0: [*c]JSC__Exception) JSC__JSValue; pub extern fn JSC__VM__apiLock(arg0: [*c]JSC__VM) [*c]JSC__JSLock; pub extern fn JSC__VM__create(HeapType0: u8) [*c]JSC__VM; pub extern fn JSC__VM__deinit(arg0: [*c]JSC__VM, arg1: [*c]JSC__JSGlobalObject) void; +pub extern fn JSC__VM__deleteAllCode(arg0: [*c]JSC__VM, arg1: [*c]JSC__JSGlobalObject) void; pub extern fn JSC__VM__drainMicrotasks(arg0: [*c]JSC__VM) void; pub extern fn JSC__VM__executionForbidden(arg0: [*c]JSC__VM) bool; pub extern fn JSC__VM__isEntered(arg0: [*c]JSC__VM) bool; @@ -352,4 +353,6 @@ pub extern fn WTF__StringView__is8Bit(arg0: [*c]const WTF__StringView) bool; pub extern fn WTF__StringView__isEmpty(arg0: [*c]const WTF__StringView) bool; pub extern fn WTF__StringView__length(arg0: [*c]const WTF__StringView) usize; pub extern fn Zig__GlobalObject__create(arg0: [*c]JSClassRef, arg1: i32, arg2: ?*c_void) [*c]JSC__JSGlobalObject; +pub extern fn Zig__GlobalObject__getModuleRegistryMap(arg0: [*c]JSC__JSGlobalObject) ?*c_void; +pub extern fn Zig__GlobalObject__resetModuleRegistryMap(arg0: [*c]JSC__JSGlobalObject, arg1: ?*c_void) bool; pub extern fn ZigException__fromException(arg0: [*c]JSC__Exception) ZigException; diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig index 579a8a9fe..0ae53a120 100644 --- a/src/javascript/jsc/webcore/response.zig +++ b/src/javascript/jsc/webcore/response.zig @@ -775,17 +775,14 @@ pub const Body = struct { } else |err| {} } - var str_ref = js.JSValueToStringCopy(ctx, body_ref, exception); - defer js.JSStringRelease(str_ref); - const len = js.JSStringGetMaximumUTF8CStringSize(str_ref); + var str = JSValue.fromRef(body_ref).toWTFString(VirtualMachine.vm.global); + const len = str.length(); if (len == 0) { body.value = .{ .String = "" }; return body; } - var str = allocator.alloc(u8, len + 1) catch unreachable; - - body.value = Value{ .String = str[0 .. js.JSStringGetUTF8CString(str_ref, str.ptr, len) - 1] }; + body.value = Value{ .String = str.characters8()[0..len] }; return body; }, .kJSTypeObject => { @@ -1123,6 +1120,8 @@ pub const FetchEvent = struct { return js.JSValueMakeUndefined(ctx); }; + defer this.request_context.arena.deinit(); + var needs_mime_type = true; var content_length: ?usize = null; if (response.body.init.headers) |*headers| { @@ -1166,7 +1165,10 @@ pub const FetchEvent = struct { }, .String => |str| { const did_send = this.request_context.writeETag(str) catch false; - if (did_send) return js.JSValueMakeUndefined(ctx); + if (did_send) { + // defer getAllocator(ctx).destroy(str.ptr); + return js.JSValueMakeUndefined(ctx); + } }, else => unreachable, } @@ -1182,6 +1184,7 @@ pub const FetchEvent = struct { this.request_context.writeBodyBuf(buf.ptr[buf.offset..buf.byte_len]) catch return js.JSValueMakeUndefined(ctx); }, .String => |str| { + // defer getAllocator(ctx).destroy(str.ptr); this.request_context.writeBodyBuf(str) catch return js.JSValueMakeUndefined(ctx); }, else => unreachable, diff --git a/src/runtime/hmr.ts b/src/runtime/hmr.ts index 7260f28a0..8f661e6f9 100644 --- a/src/runtime/hmr.ts +++ b/src/runtime/hmr.ts @@ -396,7 +396,7 @@ var __HMRModule, __FastRefreshModule, __HMRClient; this.reconnect = 0; } - const baseURL = new URL(location.origin + "/_api"); + const baseURL = new URL(location.origin + "/_api.hmr"); baseURL.protocol = location.protocol === "https" ? "wss" : "ws"; this.socket = new WebSocket(baseURL.toString(), ["speedy-hmr"]); this.socket.binaryType = "arraybuffer"; diff --git a/src/watcher.zig b/src/watcher.zig index 82ff530f6..1ce5320a2 100644 --- a/src/watcher.zig +++ b/src/watcher.zig @@ -14,6 +14,7 @@ pub const WatchItem = struct { eventlist_index: u32, loader: options.Loader, fd: StoredFileDescriptorType, + count: u32, }; pub const WatchEvent = struct { @@ -54,7 +55,6 @@ pub fn NewWatcher(comptime ContextType: type) type { // Internal changelist: [128]KEvent = undefined, - changed_count: u8 = 0, // User-facing watch_events: [128]WatchEvent = undefined, @@ -235,6 +235,7 @@ pub fn NewWatcher(comptime ContextType: type) type { .file_path = if (copy_file_path) try this.allocator.dupe(u8, file_path) else file_path, .fd = fd, .hash = hash, + .count = 0, .eventlist_index = @truncate(u32, index), .loader = loader, }); |
