aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bun.js/bindings/ModuleLoader.cpp2
-rw-r--r--src/bun.js/bindings/ScriptExecutionContext.cpp14
-rw-r--r--src/js_ast.zig157
-rw-r--r--src/js_parser.zig38
4 files changed, 160 insertions, 51 deletions
diff --git a/src/bun.js/bindings/ModuleLoader.cpp b/src/bun.js/bindings/ModuleLoader.cpp
index 40e41b083..75981f5b3 100644
--- a/src/bun.js/bindings/ModuleLoader.cpp
+++ b/src/bun.js/bindings/ModuleLoader.cpp
@@ -457,7 +457,7 @@ static JSValue fetchSourceCode(
}
default: {
auto provider = Zig::SourceProvider::create(res->result.value);
- return rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
+ return rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(WTFMove(provider))));
}
}
}
diff --git a/src/bun.js/bindings/ScriptExecutionContext.cpp b/src/bun.js/bindings/ScriptExecutionContext.cpp
index 08e8e11ef..e8cae5e33 100644
--- a/src/bun.js/bindings/ScriptExecutionContext.cpp
+++ b/src/bun.js/bindings/ScriptExecutionContext.cpp
@@ -10,7 +10,7 @@ extern "C" void Bun__startLoop(us_loop_t* loop);
namespace WebCore {
-static unsigned lastUniqueIdentifier = 0;
+static std::atomic<unsigned> lastUniqueIdentifier = 0;
static Lock allScriptExecutionContextsMapLock;
static HashMap<ScriptExecutionContextIdentifier, ScriptExecutionContext*>& allScriptExecutionContextsMap() WTF_REQUIRES_LOCK(allScriptExecutionContextsMapLock)
@@ -41,7 +41,7 @@ us_socket_context_t* ScriptExecutionContext::webSocketContextSSL()
us_bun_socket_context_options_t opts;
memset(&opts, 0, sizeof(us_bun_socket_context_options_t));
// adds root ca
- opts.request_cert = true;
+ opts.request_cert = true;
// but do not reject unauthorized
opts.reject_unauthorized = false;
this->m_ssl_client_websockets_ctx = us_create_bun_socket_context(1, loop, sizeof(size_t), opts);
@@ -108,12 +108,12 @@ void ScriptExecutionContext::regenerateIdentifier()
{
Locker locker { allScriptExecutionContextsMapLock };
- ASSERT(allScriptExecutionContextsMap().contains(m_identifier));
- allScriptExecutionContextsMap().remove(m_identifier);
+ // ASSERT(allScriptExecutionContextsMap().contains(m_identifier));
+ // allScriptExecutionContextsMap().remove(m_identifier);
m_identifier = ++lastUniqueIdentifier;
- ASSERT(!allScriptExecutionContextsMap().contains(m_identifier));
+ // ASSERT(!allScriptExecutionContextsMap().contains(m_identifier));
allScriptExecutionContextsMap().add(m_identifier, this);
}
@@ -121,14 +121,14 @@ void ScriptExecutionContext::addToContextsMap()
{
Locker locker { allScriptExecutionContextsMapLock };
ASSERT(!allScriptExecutionContextsMap().contains(m_identifier));
- allScriptExecutionContextsMap().add(m_identifier, this);
+ // allScriptExecutionContextsMap().add(m_identifier, this);
}
void ScriptExecutionContext::removeFromContextsMap()
{
Locker locker { allScriptExecutionContextsMapLock };
ASSERT(allScriptExecutionContextsMap().contains(m_identifier));
- allScriptExecutionContextsMap().remove(m_identifier);
+ // allScriptExecutionContextsMap().remove(m_identifier);
}
}
diff --git a/src/js_ast.zig b/src/js_ast.zig
index 133ae9aa5..9bf76a37f 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -1435,21 +1435,16 @@ pub const E = struct {
return ExprNodeList.init(out[0 .. out.len - remain.len]);
}
- pub fn toJS(this: @This(), ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.C.JSValueRef {
- var stack = std.heap.stackFallback(32 * @sizeOf(ExprNodeList), JSC.getAllocator(ctx));
- var allocator = stack.get();
- var results = allocator.alloc(JSC.C.JSValueRef, this.items.len) catch {
- return JSC.C.JSValueMakeUndefined(ctx);
- };
- defer if (stack.fixed_buffer_allocator.end_index >= stack.fixed_buffer_allocator.buffer.len - 1) allocator.free(results);
-
- var i: usize = 0;
+ pub fn toJS(this: @This(), allocator: std.mem.Allocator, globalObject: *JSC.JSGlobalObject) ToJSError!JSC.JSValue {
const items = this.items.slice();
- while (i < results.len) : (i += 1) {
- results[i] = items[i].toJS(ctx, exception);
+ var array = JSC.JSValue.createEmptyArray(globalObject, items.len);
+ array.protect();
+ defer array.unprotect();
+ for (items, 0..) |expr, j| {
+ array.putIndex(globalObject, @truncate(u32, j), try expr.data.toJS(allocator, globalObject));
}
- return JSC.C.JSObjectMakeArray(ctx, results.len, results.ptr, exception);
+ return array;
}
};
@@ -1762,8 +1757,8 @@ pub const E = struct {
return try std.json.stringify(self.value, opts, o);
}
- pub fn toJS(this: @This(), _: JSC.C.JSContextRef, _: JSC.C.ExceptionRef) JSC.C.JSValueRef {
- return JSC.JSValue.jsNumber(this.value).asObjectRef();
+ pub fn toJS(this: @This()) JSC.JSValue {
+ return JSC.JSValue.jsNumber(this.value);
}
};
@@ -1776,7 +1771,7 @@ pub const E = struct {
return try std.json.stringify(self.value, opts, o);
}
- pub fn toJS(_: @This(), _: JSC.C.JSContextRef, _: JSC.C.ExceptionRef) JSC.C.JSValueRef {
+ pub fn toJS(_: @This()) JSC.JSValue {
// TODO:
return JSC.JSValue.jsNumber(0);
}
@@ -1840,6 +1835,22 @@ pub const E = struct {
return if (asProperty(self, key)) |query| query.expr else @as(?Expr, null);
}
+ pub fn toJS(this: *Object, allocator: std.mem.Allocator, globalObject: *JSC.JSGlobalObject) ToJSError!JSC.JSValue {
+ var obj = JSC.JSValue.createEmptyObject(globalObject, this.properties.len);
+ obj.protect();
+ defer obj.unprotect();
+ const props: []const G.Property = this.properties.slice();
+ for (props) |prop| {
+ if (prop.kind != .normal or prop.class_static_block != null or prop.key == null or prop.key.?.data != .e_string or prop.value == null) {
+ return error.@"Cannot convert argument type to JS";
+ }
+ var key = prop.key.?.data.e_string.toZigString(allocator);
+ obj.put(globalObject, &key, try prop.value.?.toJS(allocator, globalObject));
+ }
+
+ return obj;
+ }
+
pub fn put(self: *Object, allocator: std.mem.Allocator, key: string, expr: Expr) !void {
if (asProperty(self, key)) |query| {
self.properties.ptr[query.i].value = expr;
@@ -2339,6 +2350,18 @@ pub const E = struct {
}
}
+ pub fn toJS(s: *String, allocator: std.mem.Allocator, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
+ return s.toZigString(allocator).toValueGC(globalObject);
+ }
+
+ pub fn toZigString(s: *String, allocator: std.mem.Allocator) JSC.ZigString {
+ if (s.isUTF8()) {
+ return JSC.ZigString.fromUTF8(s.slice(allocator));
+ } else {
+ return JSC.ZigString.init16(s.slice16());
+ }
+ }
+
pub fn jsonStringify(s: *const String, options: anytype, writer: anytype) !void {
var buf = [_]u8{0} ** 4096;
var i: usize = 0;
@@ -3090,8 +3113,8 @@ pub const Expr = struct {
return false;
}
- pub fn toJS(this: Expr, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.C.JSValueRef {
- return this.data.toJS(ctx, exception);
+ pub fn toJS(this: Expr, allocator: std.mem.Allocator, globalObject: *JSC.JSGlobalObject) ToJSError!JSC.JSValue {
+ return this.data.toJS(allocator, globalObject);
}
pub fn get(expr: *const Expr, name: string) ?Expr {
@@ -5203,18 +5226,35 @@ pub const Expr = struct {
return equality;
}
- pub fn toJS(this: Data, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.C.JSValueRef {
+ pub fn toJS(this: Data, allocator: std.mem.Allocator, globalObject: *JSC.JSGlobalObject) ToJSError!JSC.JSValue {
return switch (this) {
- .e_array => |e| e.toJS(ctx, exception),
- .e_null => |e| e.toJS(ctx, exception),
- .e_undefined => |e| e.toJS(ctx, exception),
- .e_object => |e| e.toJS(ctx, exception),
- .e_boolean => |e| e.toJS(ctx, exception),
- .e_number => |e| e.toJS(ctx, exception),
- .e_big_int => |e| e.toJS(ctx, exception),
- .e_string => |e| e.toJS(ctx, exception),
+ .e_array => |e| e.toJS(allocator, globalObject),
+ .e_object => |e| e.toJS(allocator, globalObject),
+ .e_string => |e| e.toJS(allocator, globalObject),
+ .e_null => JSC.JSValue.null,
+ .e_undefined => JSC.JSValue.undefined,
+ .e_boolean => |boolean| if (boolean.value)
+ JSC.JSValue.true
+ else
+ JSC.JSValue.false,
+ .e_number => |e| e.toJS(),
+ // .e_big_int => |e| e.toJS(ctx, exception),
+
+ .e_identifier,
+ .e_import_identifier,
+ .inline_identifier,
+ .e_private_identifier,
+ .e_commonjs_export_identifier,
+ => error.@"Cannot convert identifier to JS. Try a statically-known value",
+
+ // brk: {
+ // // var node = try allocator.create(Macro.JSNode);
+ // // node.* = Macro.JSNode.initExpr(Expr{ .data = this, .loc = logger.Loc.Empty });
+ // // break :brk JSC.JSValue.c(Macro.JSNode.Class.make(globalObject, node));
+ // },
+
else => {
- return JSC.C.JSValueMakeUndefined(ctx);
+ return error.@"Cannot convert argument type to JS";
},
};
}
@@ -9585,7 +9625,7 @@ pub const Macro = struct {
threadlocal var args_buf: [3]js.JSObjectRef = undefined;
threadlocal var expr_nodes_buf: [1]JSNode = undefined;
threadlocal var exception_holder: Zig.ZigException.Holder = undefined;
- pub const MacroError = error{MacroFailed};
+ pub const MacroError = error{ MacroFailed, OutOfMemory } || ToJSError;
pub fn NewRun(comptime Visitor: type) type {
return struct {
@@ -9609,6 +9649,7 @@ pub const Macro = struct {
function_name: string,
caller: Expr,
args_count: usize,
+ args_ptr: [*]JSC.JSValue,
source: *const logger.Source,
id: i32,
visitor: Visitor,
@@ -9621,7 +9662,7 @@ pub const Macro = struct {
macro_callback,
null,
args_count,
- &args_buf,
+ @ptrCast([*]js.JSObjectRef, args_ptr),
);
var runner = Run{
@@ -9936,13 +9977,47 @@ pub const Macro = struct {
if (comptime Environment.isDebug) Output.prettyln("<r><d>[macro]<r> call <d><b>{s}<r>", .{function_name});
exception_holder = Zig.ZigException.Holder.init();
- expr_nodes_buf[0] = JSNode.initExpr(caller);
- args_buf[0] = JSNode.Class.make(
- macro.vm.global,
- &expr_nodes_buf[0],
- );
- args_buf[1] = if (javascript_object.isEmpty()) null else javascript_object.asObjectRef();
- args_buf[2] = null;
+ var js_args: []JSC.JSValue = &.{};
+ defer {
+ for (js_args[0 .. js_args.len - @as(usize, @boolToInt(!javascript_object.isEmpty()))]) |arg| {
+ arg.unprotect();
+ }
+
+ allocator.free(js_args);
+ }
+
+ var globalObject = JSC.VirtualMachine.get().global;
+
+ switch (caller.data) {
+ .e_call => |call| {
+ const call_args: []Expr = call.args.slice();
+ js_args = try allocator.alloc(JSC.JSValue, call_args.len + @as(usize, @boolToInt(!javascript_object.isEmpty())));
+
+ for (call_args, js_args[0..call_args.len]) |in, *out| {
+ const value = try in.toJS(
+ allocator,
+ globalObject,
+ );
+ value.protect();
+ out.* = value;
+ }
+ },
+ .e_template => {
+ @panic("TODO: support template literals in macros");
+ },
+ else => {
+ @panic("Unexpected caller type");
+ },
+ }
+
+ if (!javascript_object.isEmpty()) {
+ if (js_args.len == 0) {
+ js_args = try allocator.alloc(JSC.JSValue, 1);
+ }
+
+ js_args[js_args.len - 1] = javascript_object;
+ }
+
const Run = NewRun(Visitor);
const CallFunction = @TypeOf(Run.runAsync);
@@ -9970,7 +10045,8 @@ pub const Macro = struct {
allocator,
function_name,
caller,
- 2 + @as(usize, @boolToInt(!javascript_object.isEmpty())),
+ js_args.len,
+ js_args.ptr,
source,
id,
visitor,
@@ -10301,3 +10377,10 @@ pub const GlobalStoreHandle = struct {
// Stmt | 192
// STry | 384
// -- ESBuild bit sizes
+
+const ToJSError = error{
+ @"Cannot convert argument type to JS",
+ @"Cannot convert identifier to JS. Try a statically-known value",
+ MacroError,
+ OutOfMemory,
+};
diff --git a/src/js_parser.zig b/src/js_parser.zig
index dea2f044f..13d4b06de 100644
--- a/src/js_parser.zig
+++ b/src/js_parser.zig
@@ -2300,7 +2300,11 @@ const ThenCatchChain = struct {
has_catch: bool = false,
};
-const ParsedPath = struct { loc: logger.Loc, text: string };
+const ParsedPath = struct {
+ loc: logger.Loc,
+ text: string,
+ is_macro: bool,
+};
const StrictModeFeature = enum {
with_statement,
@@ -8058,7 +8062,7 @@ fn NewParser_(
}
fn processImportStatement(p: *P, stmt_: S.Import, path: ParsedPath, loc: logger.Loc, was_originally_bare_import: bool) anyerror!Stmt {
- const is_macro = FeatureFlags.is_macro_enabled and js_ast.Macro.isMacroPath(path.text);
+ const is_macro = FeatureFlags.is_macro_enabled and (path.is_macro or js_ast.Macro.isMacroPath(path.text));
var stmt = stmt_;
if (is_macro) {
const id = p.addImportRecord(.stmt, path.loc, path.text);
@@ -8884,6 +8888,10 @@ fn NewParser_(
// path.assertions
);
+ if (path.is_macro) {
+ try p.log.addError(p.source, path.loc, "cannot use macro in export statement");
+ }
+
if (comptime track_symbol_usage_during_parse_pass) {
// In the scan pass, we need _some_ way of knowing *not* to mark as unused
p.import_records.items[import_record_index].calls_runtime_re_export_fn = true;
@@ -8919,6 +8927,10 @@ fn NewParser_(
}
}
+ if (parsedPath.is_macro) {
+ try p.log.addError(p.source, loc, "export from cannot be used with \"type\": \"macro\"");
+ }
+
const import_record_index = p.addImportRecord(.stmt, parsedPath.loc, parsedPath.text);
const path_name = fs.PathName.init(parsedPath.text);
const namespace_ref = p.storeNameInRef(
@@ -10913,6 +10925,7 @@ fn NewParser_(
var path = ParsedPath{
.loc = p.lexer.loc(),
.text = p.lexer.string_literal_slice,
+ .is_macro = false,
};
if (p.lexer.token == .t_no_substitution_template_literal) {
@@ -10934,15 +10947,28 @@ fn NewParser_(
try p.lexer.expect(.t_open_brace);
while (p.lexer.token != .t_close_brace) {
- // Parse the key
- if (p.lexer.isIdentifierOrKeyword()) {} else if (p.lexer.token == .t_string_literal) {} else {
- try p.lexer.expect(.t_identifier);
- }
+ const is_type_flag = brk: {
+ // Parse the key
+ if (p.lexer.isIdentifierOrKeyword()) {
+ break :brk strings.eqlComptime(p.lexer.identifier, "type");
+ } else if (p.lexer.token == .t_string_literal) {
+ break :brk p.lexer.string_literal_is_ascii and strings.eqlComptime(p.lexer.string_literal_slice, "type");
+ } else {
+ try p.lexer.expect(.t_identifier);
+ }
+
+ break :brk false;
+ };
try p.lexer.next();
try p.lexer.expect(.t_colon);
try p.lexer.expect(.t_string_literal);
+ if (is_type_flag and
+ p.lexer.string_literal_is_ascii and strings.eqlComptime(p.lexer.string_literal_slice, "macro"))
+ {
+ path.is_macro = true;
+ }
if (p.lexer.token != .t_comma) {
break;