aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-08-05 19:48:36 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-08-05 19:48:36 -0700
commitc0273a09f19e0757711592c6ad3b3b5de7acca67 (patch)
treeb0af7c1c4cc4c0c5a03c198a338275e139a6fc37
parent56c689d684467694a51db5aa9e765146718e6c1a (diff)
downloadbun-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.json4
-rw-r--r--.vscode/settings.json3
-rw-r--r--demos/css-stress-test/framework.tsx5
-rw-r--r--src/bundler.zig24
-rw-r--r--src/cli.zig1
-rw-r--r--src/feature_flags.zig2
-rw-r--r--src/http.zig52
-rw-r--r--src/javascript/jsc/JavascriptCore.zig7
-rw-r--r--src/javascript/jsc/bindings/ZigGlobalObject.cpp64
-rw-r--r--src/javascript/jsc/bindings/ZigSourceProvider.cpp6
-rw-r--r--src/javascript/jsc/bindings/ZigSourceProvider.h13
-rw-r--r--src/javascript/jsc/bindings/bindings.cpp84
-rw-r--r--src/javascript/jsc/bindings/bindings.zig9
-rw-r--r--src/javascript/jsc/bindings/exports.zig10
-rw-r--r--src/javascript/jsc/bindings/headers-cpp.h2
-rw-r--r--src/javascript/jsc/bindings/headers-handwritten.h3
-rw-r--r--src/javascript/jsc/bindings/headers.h5
-rw-r--r--src/javascript/jsc/bindings/headers.zig3
-rw-r--r--src/javascript/jsc/webcore/response.zig17
-rw-r--r--src/runtime/hmr.ts2
-rw-r--r--src/watcher.zig3
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,
});