diff options
| -rw-r--r-- | src/bun.js/bindings/ModuleLoader.cpp | 2 | ||||
| -rw-r--r-- | src/bun.js/bindings/ScriptExecutionContext.cpp | 14 | ||||
| -rw-r--r-- | src/js_ast.zig | 157 | ||||
| -rw-r--r-- | src/js_parser.zig | 38 | 
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; | 
