diff options
Diffstat (limited to 'src/javascript/jsc')
-rw-r--r-- | src/javascript/jsc/base.zig | 7 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/bindings.cpp | 537 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/bindings.zig | 20 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/headers-cpp.h | 2 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/headers.h | 11 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/headers.zig | 54 | ||||
-rw-r--r-- | src/javascript/jsc/config.zig | 2 | ||||
-rw-r--r-- | src/javascript/jsc/javascript.zig | 13 |
8 files changed, 365 insertions, 281 deletions
diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig index 4acd688c1..2b73da905 100644 --- a/src/javascript/jsc/base.zig +++ b/src/javascript/jsc/base.zig @@ -4,6 +4,7 @@ pub usingnamespace @import("../../global.zig"); usingnamespace @import("./javascript.zig"); usingnamespace @import("./webcore/response.zig"); const Router = @import("./api/router.zig"); +const JSExpr = @import("../../js_ast.zig").Macro.JSExpr; const TaggedPointerTypes = @import("../../tagged_pointer.zig"); const TaggedPointerUnion = TaggedPointerTypes.TaggedPointerUnion; @@ -839,6 +840,10 @@ pub fn NewClass( } pub fn customHasInstance(ctx: js.JSContextRef, obj: js.JSObjectRef, value: js.JSValueRef, exception: js.ExceptionRef) callconv(.C) bool { + if (comptime @typeInfo(ZigType) == .Struct and @hasDecl(ZigType, "isInstanceOf")) { + return ZigType.isInstanceOf(ctx, obj, value, exception); + } + return js.JSValueIsObjectOfClass(ctx, value, get().*); } @@ -1449,6 +1454,7 @@ pub fn NewClass( if (!singleton) def.hasInstance = customHasInstance; + return def; } }; @@ -1509,6 +1515,7 @@ pub const JSPrivateDataPtr = TaggedPointerUnion(.{ Headers, Body, Router, + JSExpr, }); pub inline fn GetJSPrivateData(comptime Type: type, ref: js.JSObjectRef) ?*Type { diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp index 50e6978b5..407b452d2 100644 --- a/src/javascript/jsc/bindings/bindings.cpp +++ b/src/javascript/jsc/bindings/bindings.cpp @@ -7,6 +7,7 @@ #include <JavaScriptCore/ErrorInstance.h> #include <JavaScriptCore/ExceptionScope.h> #include <JavaScriptCore/FunctionConstructor.h> +#include <JavaScriptCore/HashMapImplInlines.h> #include <JavaScriptCore/Identifier.h> #include <JavaScriptCore/IteratorOperations.h> #include <JavaScriptCore/JSArray.h> @@ -15,7 +16,9 @@ #include <JavaScriptCore/JSClassRef.h> #include <JavaScriptCore/JSInternalPromise.h> #include <JavaScriptCore/JSMap.h> +#include <JavaScriptCore/JSModuleEnvironment.h> #include <JavaScriptCore/JSModuleLoader.h> +#include <JavaScriptCore/JSModuleNamespaceObject.h> #include <JavaScriptCore/JSModuleRecord.h> #include <JavaScriptCore/JSNativeStdFunction.h> #include <JavaScriptCore/JSObject.h> @@ -27,6 +30,7 @@ #include <JavaScriptCore/StackFrame.h> #include <JavaScriptCore/StackVisitor.h> #include <JavaScriptCore/VM.h> +#include <JavaScriptCore/VMEntryScope.h> #include <JavaScriptCore/WasmFaultSignalHandler.h> #include <wtf/text/ExternalStringImpl.h> #include <wtf/text/StringCommon.h> @@ -92,6 +96,243 @@ void JSC__JSObject__putRecord(JSC__JSObject *object, JSC__JSGlobalObject *global object->putDirect(global->vm(), ident, descriptor.value()); scope.release(); } + +static void populateStackFrameMetadata(const JSC::StackFrame *stackFrame, ZigStackFrame *frame) { + frame->source_url = Zig::toZigString(stackFrame->sourceURL()); + + if (stackFrame->isWasmFrame()) { + frame->code_type = ZigStackFrameCodeWasm; + return; + } + + auto m_codeBlock = stackFrame->codeBlock(); + if (m_codeBlock) { + switch (m_codeBlock->codeType()) { + case JSC::EvalCode: { + frame->code_type = ZigStackFrameCodeEval; + return; + } + case JSC::ModuleCode: { + frame->code_type = ZigStackFrameCodeModule; + return; + } + case JSC::GlobalCode: { + frame->code_type = ZigStackFrameCodeGlobal; + return; + } + case JSC::FunctionCode: { + frame->code_type = + !m_codeBlock->isConstructor() ? ZigStackFrameCodeFunction : ZigStackFrameCodeConstructor; + break; + } + default: ASSERT_NOT_REACHED(); + } + } + + auto calleeCell = stackFrame->callee(); + if (!calleeCell || !calleeCell->isObject()) return; + + JSC::JSObject *callee = JSC::jsCast<JSC::JSObject *>(calleeCell); + // Does the code block have a user-defined name property? + JSC::JSValue name = callee->getDirect(m_codeBlock->vm(), m_codeBlock->vm().propertyNames->name); + if (name && name.isString()) { + auto str = name.toWTFString(m_codeBlock->globalObject()); + frame->function_name = Zig::toZigString(str); + return; + } + + /* For functions (either JSFunction or InternalFunction), fallback to their "native" name + * property. Based on JSC::getCalculatedDisplayName, "inlining" the + * JSFunction::calculatedDisplayName\InternalFunction::calculatedDisplayName calls */ + if (JSC::JSFunction *function = + JSC::jsDynamicCast<JSC::JSFunction *>(m_codeBlock->vm(), callee)) { + + WTF::String actualName = function->name(m_codeBlock->vm()); + if (!actualName.isEmpty() || function->isHostOrBuiltinFunction()) { + frame->function_name = Zig::toZigString(actualName); + return; + } + + auto inferred_name = function->jsExecutable()->name(); + frame->function_name = Zig::toZigString(inferred_name.string()); + } + + if (JSC::InternalFunction *function = + JSC::jsDynamicCast<JSC::InternalFunction *>(m_codeBlock->vm(), callee)) { + // Based on JSC::InternalFunction::calculatedDisplayName, skipping the "displayName" property + frame->function_name = Zig::toZigString(function->name()); + } +} +// Based on +// https://github.com/mceSystems/node-jsc/blob/master/deps/jscshim/src/shim/JSCStackTrace.cpp#L298 +static void populateStackFramePosition(const JSC::StackFrame *stackFrame, ZigString *source_lines, + int32_t *source_line_numbers, uint8_t source_lines_count, + ZigStackFramePosition *position) { + auto m_codeBlock = stackFrame->codeBlock(); + if (!m_codeBlock) return; + + JSC::BytecodeIndex bytecodeOffset = + stackFrame->hasBytecodeIndex() ? stackFrame->bytecodeIndex() : JSC::BytecodeIndex(); + + /* Get the "raw" position info. + * Note that we're using m_codeBlock->unlinkedCodeBlock()->expressionRangeForBytecodeOffset + * rather than m_codeBlock->expressionRangeForBytecodeOffset in order get the "raw" offsets and + * avoid the CodeBlock's expressionRangeForBytecodeOffset modifications to the line and column + * numbers, (we don't need the column number from it, and we'll calculate the line "fixes" + * ourselves). */ + int startOffset = 0; + int endOffset = 0; + int divotPoint = 0; + unsigned line = 0; + unsigned unusedColumn = 0; + m_codeBlock->unlinkedCodeBlock()->expressionRangeForBytecodeIndex( + bytecodeOffset, divotPoint, startOffset, endOffset, line, unusedColumn); + divotPoint += m_codeBlock->sourceOffset(); + + // TODO: evaluate if using the API from UnlinkedCodeBlock can be used instead of iterating + // through source text. + + /* On the first line of the source code, it seems that we need to "fix" the column with the + * starting offset. We currently use codeBlock->source()->startPosition().m_column.oneBasedInt() + * as the offset in the first line rather than codeBlock->firstLineColumnOffset(), which seems + * simpler (and what CodeBlock::expressionRangeForBytecodeOffset does). This is because + * firstLineColumnOffset values seems different from what we expect (according to v8's tests) + * and I haven't dove into the relevant parts in JSC (yet) to figure out why. */ + unsigned columnOffset = line ? 0 : m_codeBlock->source().startColumn().zeroBasedInt(); + + // "Fix" the line number + JSC::ScriptExecutable *executable = m_codeBlock->ownerExecutable(); + if (std::optional<int> overrideLine = executable->overrideLineNumber(m_codeBlock->vm())) { + line = overrideLine.value(); + } else { + line += executable->firstLine(); + } + + // Calculate the staring\ending offsets of the entire expression + int expressionStart = divotPoint - startOffset; + int expressionStop = divotPoint + endOffset; + + // Make sure the range is valid + WTF::StringView sourceString = m_codeBlock->source().provider()->source(); + if (!expressionStop || expressionStart > static_cast<int>(sourceString.length())) { return; } + + // Search for the beginning of the line + unsigned int lineStart = expressionStart; + while ((lineStart > 0) && ('\n' != sourceString[lineStart - 1])) { lineStart--; } + // Search for the end of the line + unsigned int lineStop = expressionStop; + unsigned int sourceLength = sourceString.length(); + while ((lineStop < sourceLength) && ('\n' != sourceString[lineStop])) { lineStop++; } + if (source_lines_count > 1 && source_lines != nullptr) { + auto chars = sourceString.characters8(); + + // Most of the time, when you look at a stack trace, you want a couple lines above + + source_lines[0] = {&chars[lineStart], lineStop - lineStart}; + source_line_numbers[0] = line; + + if (lineStart > 0) { + auto byte_offset_in_source_string = lineStart - 1; + uint8_t source_line_i = 1; + auto remaining_lines_to_grab = source_lines_count - 1; + + while (byte_offset_in_source_string > 0 && remaining_lines_to_grab > 0) { + unsigned int end_of_line_offset = byte_offset_in_source_string; + + // This should probably be code points instead of newlines + while (byte_offset_in_source_string > 0 && chars[byte_offset_in_source_string] != '\n') { + byte_offset_in_source_string--; + } + + // We are at the beginning of the line + source_lines[source_line_i] = {&chars[byte_offset_in_source_string], + end_of_line_offset - byte_offset_in_source_string + 1}; + + source_line_numbers[source_line_i] = line - source_line_i; + source_line_i++; + + remaining_lines_to_grab--; + + byte_offset_in_source_string -= byte_offset_in_source_string > 0; + } + } + } + + /* Finally, store the source "positions" info. + * Notes: + * - The retrieved column seem to point the "end column". To make sure we're current, we'll + *calculate the columns ourselves, since we've already found where the line starts. Note that in + *v8 it should be 0-based here (in contrast the 1-based column number in v8::StackFrame). + * - The static_casts are ugly, but comes from differences between JSC and v8's api, and should + *be OK since no source should be longer than "max int" chars. + * TODO: If expressionStart == expressionStop, then m_endColumn will be equal to m_startColumn. + *Should we handle this case? + */ + position->expression_start = expressionStart; + position->expression_stop = expressionStop; + position->line = WTF::OrdinalNumber::fromOneBasedInt(static_cast<int>(line)).zeroBasedInt(); + position->column_start = (expressionStart - lineStart) + columnOffset; + position->column_stop = position->column_start + (expressionStop - expressionStart); + position->line_start = lineStart; + position->line_stop = lineStop; + + return; +} +static void populateStackFrame(ZigStackTrace *trace, const JSC::StackFrame *stackFrame, + ZigStackFrame *frame, bool is_top) { + populateStackFrameMetadata(stackFrame, frame); + populateStackFramePosition(stackFrame, is_top ? trace->source_lines_ptr : nullptr, + is_top ? trace->source_lines_numbers : nullptr, + is_top ? trace->source_lines_to_collect : 0, &frame->position); +} +static void populateStackTrace(const WTF::Vector<JSC::StackFrame> &frames, ZigStackTrace *trace) { + uint8_t frame_i = 0; + size_t stack_frame_i = 0; + const size_t total_frame_count = frames.size(); + const uint8_t frame_count = + total_frame_count < trace->frames_len ? total_frame_count : trace->frames_len; + + while (frame_i < frame_count && stack_frame_i < total_frame_count) { + // Skip native frames + while (stack_frame_i < total_frame_count && !(&frames.at(stack_frame_i))->codeBlock() && + !(&frames.at(stack_frame_i))->isWasmFrame()) { + stack_frame_i++; + } + if (stack_frame_i >= total_frame_count) break; + + ZigStackFrame *frame = &trace->frames_ptr[frame_i]; + populateStackFrame(trace, &frames[stack_frame_i], frame, frame_i == 0); + stack_frame_i++; + frame_i++; + } + trace->frames_len = frame_i; +} +static void fromErrorInstance(ZigException *except, JSC::JSGlobalObject *global, + JSC::ErrorInstance *err, const Vector<JSC::StackFrame> *stackTrace, + JSC::JSValue val) { + JSC::JSObject *obj = JSC::jsDynamicCast<JSC::JSObject *>(global->vm(), val); + if (stackTrace != nullptr && stackTrace->size() > 0) { + populateStackTrace(*stackTrace, &except->stack); + } else if (err->stackTrace() != nullptr && err->stackTrace()->size() > 0) { + populateStackTrace(*err->stackTrace(), &except->stack); + } + + except->code = (unsigned char)err->errorType(); + if (err->isStackOverflowError()) { except->code = 253; } + if (err->isOutOfMemoryError()) { except->code = 8; } + + if (obj->hasProperty(global, global->vm().propertyNames->message)) { + except->message = Zig::toZigString( + obj->getDirect(global->vm(), global->vm().propertyNames->message).toWTFString(global)); + + } else { + except->message = Zig::toZigString(err->sanitizedMessageString(global)); + } + except->name = Zig::toZigString(err->sanitizedNameString(global)); + except->runtime_type = err->runtimeTypeForCause(); + + except->exception = err; +} void JSC__JSValue__putRecord(JSC__JSValue objectValue, JSC__JSGlobalObject *global, ZigString *key, ZigString *values, size_t valuesLen) { JSC::JSValue objValue = JSC::JSValue::decode(objectValue); @@ -268,6 +509,65 @@ bWTF__String JSC__JSString__value(JSC__JSString *arg0, JSC__JSGlobalObject *arg1 #pragma mark - JSC::JSModuleLoader +JSC__JSValue JSC__JSModuleLoader__callExportedFunction(JSC__JSGlobalObject *globalObject, + ZigString specifier, ZigString functionName, + JSC__JSValue *arguments, + unsigned char args_len, + ZigException *zig_exception) { + JSC::VM &vm = globalObject->vm(); + JSC::JSLockHolder lock(vm); + + JSC::JSObject *loader = JSC::jsDynamicCast<JSC::JSObject *>(vm, globalObject->moduleLoader()); + JSC::JSMap *registry = JSC::jsDynamicCast<JSC::JSMap *>( + vm, loader->getDirect(vm, JSC::Identifier::fromString(vm, "registry"))); + auto specifier_impl = WTF::ExternalStringImpl::createStatic(specifier.ptr, specifier.len); + auto specifier_ident = + JSC::jsOwnedString(vm, reinterpret_cast<WTF::UniquedStringImpl *>(specifier_impl.ptr())); + auto entry_cell = registry->get(globalObject, specifier_ident); + + if (JSC::JSObject *entry = JSC::jsDynamicCast<JSC::JSObject *>(vm, entry_cell)) { + auto recordIdentifier = JSC::Identifier::fromString(vm, "module"); + + if (JSC::JSModuleRecord *record = + JSC::jsDynamicCast<JSC::JSModuleRecord *>(vm, entry->getDirect(vm, recordIdentifier))) { + auto fn_impl = WTF::ExternalStringImpl::createStatic(functionName.ptr, functionName.len); + auto fn_ident = reinterpret_cast<WTF::UniquedStringImpl *>(specifier_impl.ptr()); + auto env = record->getModuleNamespace(globalObject); + + if (JSC::JSValue macroFunctionExport = + env->getIfPropertyExists(globalObject, JSC::PropertyName(fn_ident))) { + + if (JSC::JSObject *macroFunction = JSC::asObject(macroFunctionExport.asCell())) { + // auto functionNameImpl = + // WTF::ExternalStringImpl::createStatic(functionName.ptr, functionName.len); + JSC::VMEntryScope entryScope(vm, globalObject); + + auto callData = JSC::getCallData(vm, macroFunction); + if (callData.type == JSC::CallData::Type::None) return JSC::JSValue::encode({}); + + JSC::MarkedArgumentBuffer argList; + for (size_t i = 0; i < args_len; i++) argList.append(JSC::JSValue::decode(arguments[i])); + + NakedPtr<JSC::Exception> uncaughtException; + JSC::JSValue reval = JSC::call(globalObject, macroFunction, callData, + globalObject->globalThis(), argList, uncaughtException); + if (uncaughtException) { + if (JSC::ErrorInstance *error = + JSC::jsDynamicCast<JSC::ErrorInstance *>(vm, uncaughtException->value())) { + fromErrorInstance(zig_exception, globalObject, error, &uncaughtException->stack(), + JSC::JSValue(uncaughtException)); + return JSC::JSValue::encode({}); + } + } + return JSC::JSValue::encode(reval); + } + } + } + } + + return JSC::JSValue::encode({}); +} + // JSC__JSValue // JSC__JSModuleLoader__dependencyKeysIfEvaluated(JSC__JSModuleLoader* arg0, // JSC__JSGlobalObject* arg1, JSC__JSModuleRecord* arg2) { @@ -1032,243 +1332,6 @@ bWTF__String JSC__JSValue__toWTFString(JSC__JSValue JSValue0, JSC__JSGlobalObjec return Wrap<WTF::String, bWTF__String>::wrap(value.toWTFString(arg1)); }; -static void populateStackFrameMetadata(const JSC::StackFrame *stackFrame, ZigStackFrame *frame) { - frame->source_url = Zig::toZigString(stackFrame->sourceURL()); - - if (stackFrame->isWasmFrame()) { - frame->code_type = ZigStackFrameCodeWasm; - return; - } - - auto m_codeBlock = stackFrame->codeBlock(); - if (m_codeBlock) { - switch (m_codeBlock->codeType()) { - case JSC::EvalCode: { - frame->code_type = ZigStackFrameCodeEval; - return; - } - case JSC::ModuleCode: { - frame->code_type = ZigStackFrameCodeModule; - return; - } - case JSC::GlobalCode: { - frame->code_type = ZigStackFrameCodeGlobal; - return; - } - case JSC::FunctionCode: { - frame->code_type = - !m_codeBlock->isConstructor() ? ZigStackFrameCodeFunction : ZigStackFrameCodeConstructor; - break; - } - default: ASSERT_NOT_REACHED(); - } - } - - auto calleeCell = stackFrame->callee(); - if (!calleeCell || !calleeCell->isObject()) return; - - JSC::JSObject *callee = JSC::jsCast<JSC::JSObject *>(calleeCell); - // Does the code block have a user-defined name property? - JSC::JSValue name = callee->getDirect(m_codeBlock->vm(), m_codeBlock->vm().propertyNames->name); - if (name && name.isString()) { - auto str = name.toWTFString(m_codeBlock->globalObject()); - frame->function_name = Zig::toZigString(str); - return; - } - - /* For functions (either JSFunction or InternalFunction), fallback to their "native" name - * property. Based on JSC::getCalculatedDisplayName, "inlining" the - * JSFunction::calculatedDisplayName\InternalFunction::calculatedDisplayName calls */ - if (JSC::JSFunction *function = - JSC::jsDynamicCast<JSC::JSFunction *>(m_codeBlock->vm(), callee)) { - - WTF::String actualName = function->name(m_codeBlock->vm()); - if (!actualName.isEmpty() || function->isHostOrBuiltinFunction()) { - frame->function_name = Zig::toZigString(actualName); - return; - } - - auto inferred_name = function->jsExecutable()->name(); - frame->function_name = Zig::toZigString(inferred_name.string()); - } - - if (JSC::InternalFunction *function = - JSC::jsDynamicCast<JSC::InternalFunction *>(m_codeBlock->vm(), callee)) { - // Based on JSC::InternalFunction::calculatedDisplayName, skipping the "displayName" property - frame->function_name = Zig::toZigString(function->name()); - } -} -// Based on -// https://github.com/mceSystems/node-jsc/blob/master/deps/jscshim/src/shim/JSCStackTrace.cpp#L298 -static void populateStackFramePosition(const JSC::StackFrame *stackFrame, ZigString *source_lines, - int32_t *source_line_numbers, uint8_t source_lines_count, - ZigStackFramePosition *position) { - auto m_codeBlock = stackFrame->codeBlock(); - if (!m_codeBlock) return; - - JSC::BytecodeIndex bytecodeOffset = - stackFrame->hasBytecodeIndex() ? stackFrame->bytecodeIndex() : JSC::BytecodeIndex(); - - /* Get the "raw" position info. - * Note that we're using m_codeBlock->unlinkedCodeBlock()->expressionRangeForBytecodeOffset - * rather than m_codeBlock->expressionRangeForBytecodeOffset in order get the "raw" offsets and - * avoid the CodeBlock's expressionRangeForBytecodeOffset modifications to the line and column - * numbers, (we don't need the column number from it, and we'll calculate the line "fixes" - * ourselves). */ - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - unsigned line = 0; - unsigned unusedColumn = 0; - m_codeBlock->unlinkedCodeBlock()->expressionRangeForBytecodeIndex( - bytecodeOffset, divotPoint, startOffset, endOffset, line, unusedColumn); - divotPoint += m_codeBlock->sourceOffset(); - - // TODO: evaluate if using the API from UnlinkedCodeBlock can be used instead of iterating - // through source text. - - /* On the first line of the source code, it seems that we need to "fix" the column with the - * starting offset. We currently use codeBlock->source()->startPosition().m_column.oneBasedInt() - * as the offset in the first line rather than codeBlock->firstLineColumnOffset(), which seems - * simpler (and what CodeBlock::expressionRangeForBytecodeOffset does). This is because - * firstLineColumnOffset values seems different from what we expect (according to v8's tests) - * and I haven't dove into the relevant parts in JSC (yet) to figure out why. */ - unsigned columnOffset = line ? 0 : m_codeBlock->source().startColumn().zeroBasedInt(); - - // "Fix" the line number - JSC::ScriptExecutable *executable = m_codeBlock->ownerExecutable(); - if (std::optional<int> overrideLine = executable->overrideLineNumber(m_codeBlock->vm())) { - line = overrideLine.value(); - } else { - line += executable->firstLine(); - } - - // Calculate the staring\ending offsets of the entire expression - int expressionStart = divotPoint - startOffset; - int expressionStop = divotPoint + endOffset; - - // Make sure the range is valid - WTF::StringView sourceString = m_codeBlock->source().provider()->source(); - if (!expressionStop || expressionStart > static_cast<int>(sourceString.length())) { return; } - - // Search for the beginning of the line - unsigned int lineStart = expressionStart; - while ((lineStart > 0) && ('\n' != sourceString[lineStart - 1])) { lineStart--; } - // Search for the end of the line - unsigned int lineStop = expressionStop; - unsigned int sourceLength = sourceString.length(); - while ((lineStop < sourceLength) && ('\n' != sourceString[lineStop])) { lineStop++; } - if (source_lines_count > 1 && source_lines != nullptr) { - auto chars = sourceString.characters8(); - - // Most of the time, when you look at a stack trace, you want a couple lines above - - source_lines[0] = {&chars[lineStart], lineStop - lineStart}; - source_line_numbers[0] = line; - - if (lineStart > 0) { - auto byte_offset_in_source_string = lineStart - 1; - uint8_t source_line_i = 1; - auto remaining_lines_to_grab = source_lines_count - 1; - - while (byte_offset_in_source_string > 0 && remaining_lines_to_grab > 0) { - unsigned int end_of_line_offset = byte_offset_in_source_string; - - // This should probably be code points instead of newlines - while (byte_offset_in_source_string > 0 && chars[byte_offset_in_source_string] != '\n') { - byte_offset_in_source_string--; - } - - // We are at the beginning of the line - source_lines[source_line_i] = {&chars[byte_offset_in_source_string], - end_of_line_offset - byte_offset_in_source_string + 1}; - - source_line_numbers[source_line_i] = line - source_line_i; - source_line_i++; - - remaining_lines_to_grab--; - - byte_offset_in_source_string -= byte_offset_in_source_string > 0; - } - } - } - - /* Finally, store the source "positions" info. - * Notes: - * - The retrieved column seem to point the "end column". To make sure we're current, we'll - *calculate the columns ourselves, since we've already found where the line starts. Note that in - *v8 it should be 0-based here (in contrast the 1-based column number in v8::StackFrame). - * - The static_casts are ugly, but comes from differences between JSC and v8's api, and should - *be OK since no source should be longer than "max int" chars. - * TODO: If expressionStart == expressionStop, then m_endColumn will be equal to m_startColumn. - *Should we handle this case? - */ - position->expression_start = expressionStart; - position->expression_stop = expressionStop; - position->line = WTF::OrdinalNumber::fromOneBasedInt(static_cast<int>(line)).zeroBasedInt(); - position->column_start = (expressionStart - lineStart) + columnOffset; - position->column_stop = position->column_start + (expressionStop - expressionStart); - position->line_start = lineStart; - position->line_stop = lineStop; - - return; -} -static void populateStackFrame(ZigStackTrace *trace, const JSC::StackFrame *stackFrame, - ZigStackFrame *frame, bool is_top) { - populateStackFrameMetadata(stackFrame, frame); - populateStackFramePosition(stackFrame, is_top ? trace->source_lines_ptr : nullptr, - is_top ? trace->source_lines_numbers : nullptr, - is_top ? trace->source_lines_to_collect : 0, &frame->position); -} -static void populateStackTrace(const WTF::Vector<JSC::StackFrame> &frames, ZigStackTrace *trace) { - uint8_t frame_i = 0; - size_t stack_frame_i = 0; - const size_t total_frame_count = frames.size(); - const uint8_t frame_count = - total_frame_count < trace->frames_len ? total_frame_count : trace->frames_len; - - while (frame_i < frame_count && stack_frame_i < total_frame_count) { - // Skip native frames - while (stack_frame_i < total_frame_count && !(&frames.at(stack_frame_i))->codeBlock() && - !(&frames.at(stack_frame_i))->isWasmFrame()) { - stack_frame_i++; - } - if (stack_frame_i >= total_frame_count) break; - - ZigStackFrame *frame = &trace->frames_ptr[frame_i]; - populateStackFrame(trace, &frames[stack_frame_i], frame, frame_i == 0); - stack_frame_i++; - frame_i++; - } - trace->frames_len = frame_i; -} -static void fromErrorInstance(ZigException *except, JSC::JSGlobalObject *global, - JSC::ErrorInstance *err, const Vector<JSC::StackFrame> *stackTrace, - JSC::JSValue val) { - JSC::JSObject *obj = JSC::jsDynamicCast<JSC::JSObject *>(global->vm(), val); - if (stackTrace != nullptr && stackTrace->size() > 0) { - populateStackTrace(*stackTrace, &except->stack); - } else if (err->stackTrace() != nullptr && err->stackTrace()->size() > 0) { - populateStackTrace(*err->stackTrace(), &except->stack); - } - - except->code = (unsigned char)err->errorType(); - if (err->isStackOverflowError()) { except->code = 253; } - if (err->isOutOfMemoryError()) { except->code = 8; } - - if (obj->hasProperty(global, global->vm().propertyNames->message)) { - except->message = Zig::toZigString( - obj->getDirect(global->vm(), global->vm().propertyNames->message).toWTFString(global)); - - } else { - except->message = Zig::toZigString(err->sanitizedMessageString(global)); - } - except->name = Zig::toZigString(err->sanitizedNameString(global)); - except->runtime_type = err->runtimeTypeForCause(); - - except->exception = err; -} - void exceptionFromString(ZigException *except, JSC::JSValue value, JSC::JSGlobalObject *global) { // Fallback case for when it's a user-defined ErrorLike-object that doesn't inherit from // ErrorInstance diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig index f9cc9bad3..96c1767b4 100644 --- a/src/javascript/jsc/bindings/bindings.zig +++ b/src/javascript/jsc/bindings/bindings.zig @@ -373,12 +373,30 @@ pub const JSModuleLoader = extern struct { }); } + pub fn callExportedFunction( + globalObject: *JSGlobalObject, + specifier: ZigString, + function_name: ZigString, + arguments_ptr: [*]JSValue, + arguments_len: u8, + exception: *ZigException, + ) JSValue { + return shim.cppFn("callExportedFunction", .{ + globalObject, + specifier, + function_name, + arguments_ptr, + arguments_len, + exception, + }); + } // pub fn dependencyKeysIfEvaluated(this: *JSModuleLoader, globalObject: *JSGlobalObject, moduleRecord: *JSModuleRecord) *JSValue { // return shim.cppFn("dependencyKeysIfEvaluated", .{ this, globalObject, moduleRecord }); // } pub const Extern = [_][]const u8{ // "dependencyKeysIfEvaluated", + "callExportedFunction", "evaluate", "loadAndEvaluateModuleEntryPoint", "loadAndEvaluateModule", @@ -821,7 +839,7 @@ pub const JSGlobalObject = extern struct { const cppFn = shim.cppFn; - pub fn ref(this: *JSGlobalObject) C_API.JSContextRef { + pub inline fn ref(this: *JSGlobalObject) C_API.JSContextRef { return @ptrCast(C_API.JSContextRef, this); } pub const ctx = ref; diff --git a/src/javascript/jsc/bindings/headers-cpp.h b/src/javascript/jsc/bindings/headers-cpp.h index 7ea94d875..f10b9571d 100644 --- a/src/javascript/jsc/bindings/headers-cpp.h +++ b/src/javascript/jsc/bindings/headers-cpp.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1631749917 +//-- AUTOGENERATED FILE -- 1632030969 // clang-format off #pragma once diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h index e40651476..f057a7c17 100644 --- a/src/javascript/jsc/bindings/headers.h +++ b/src/javascript/jsc/bindings/headers.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1631749917 +//-- AUTOGENERATED FILE -- 1632030969 // clang-format: off #pragma once @@ -100,10 +100,10 @@ typedef void* JSClassRef; typedef bJSC__JSGlobalObject JSC__JSGlobalObject; // JSC::JSGlobalObject typedef bJSC__JSFunction JSC__JSFunction; // JSC::JSFunction typedef struct JSC__ArrayPrototype JSC__ArrayPrototype; // JSC::ArrayPrototype + typedef ZigException ZigException; typedef struct JSC__AsyncFunctionPrototype JSC__AsyncFunctionPrototype; // JSC::AsyncFunctionPrototype - typedef bJSC__Identifier JSC__Identifier; // JSC::Identifier typedef bJSC__JSPromise JSC__JSPromise; // JSC::JSPromise - typedef ZigException ZigException; + typedef bJSC__Identifier JSC__Identifier; // JSC::Identifier typedef struct JSC__SetIteratorPrototype JSC__SetIteratorPrototype; // JSC::SetIteratorPrototype typedef bJSC__SourceCode JSC__SourceCode; // JSC::SourceCode typedef bJSC__JSCell JSC__JSCell; // JSC::JSCell @@ -139,8 +139,8 @@ typedef void* JSClassRef; class JSObject; class AsyncIteratorPrototype; class AsyncGeneratorFunctionPrototype; - class Identifier; class JSPromise; + class Identifier; class RegExpPrototype; class AsyncFunctionPrototype; class CatchScope; @@ -193,8 +193,8 @@ typedef void* JSClassRef; using JSC__JSObject = JSC::JSObject; using JSC__AsyncIteratorPrototype = JSC::AsyncIteratorPrototype; using JSC__AsyncGeneratorFunctionPrototype = JSC::AsyncGeneratorFunctionPrototype; - using JSC__Identifier = JSC::Identifier; using JSC__JSPromise = JSC::JSPromise; + using JSC__Identifier = JSC::Identifier; using JSC__RegExpPrototype = JSC::RegExpPrototype; using JSC__AsyncFunctionPrototype = JSC::AsyncFunctionPrototype; using JSC__CatchScope = JSC::CatchScope; @@ -267,6 +267,7 @@ CPP_DECL void Inspector__ScriptArguments__release(Inspector__ScriptArguments* ar #pragma mark - JSC::JSModuleLoader +CPP_DECL JSC__JSValue JSC__JSModuleLoader__callExportedFunction(JSC__JSGlobalObject* arg0, ZigString arg1, ZigString arg2, JSC__JSValue* arg3, unsigned char arg4, ZigException* arg5); CPP_DECL bool JSC__JSModuleLoader__checkSyntax(JSC__JSGlobalObject* arg0, const JSC__SourceCode* arg1, bool arg2); CPP_DECL JSC__JSValue JSC__JSModuleLoader__evaluate(JSC__JSGlobalObject* arg0, const unsigned char* arg1, size_t arg2, const unsigned char* arg3, size_t arg4, JSC__JSValue JSValue5, JSC__JSValue* arg6); CPP_DECL JSC__JSInternalPromise* JSC__JSModuleLoader__importModule(JSC__JSGlobalObject* arg0, const JSC__Identifier* arg1); diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig index 1b295fbad..5fbe63371 100644 --- a/src/javascript/jsc/bindings/headers.zig +++ b/src/javascript/jsc/bindings/headers.zig @@ -37,64 +37,65 @@ pub const __mbstate_t = extern union { pub const __darwin_mbstate_t = __mbstate_t; pub const __darwin_ptrdiff_t = c_long; pub const __darwin_size_t = c_ulong; - + pub const JSC__RegExpPrototype = struct_JSC__RegExpPrototype; - + pub const JSC__GeneratorPrototype = struct_JSC__GeneratorPrototype; - + pub const JSC__ArrayIteratorPrototype = struct_JSC__ArrayIteratorPrototype; - + pub const JSC__StringPrototype = struct_JSC__StringPrototype; pub const WTF__StringView = bWTF__StringView; - + pub const JSC__JSPromisePrototype = struct_JSC__JSPromisePrototype; pub const JSC__CatchScope = bJSC__CatchScope; pub const JSC__ThrowScope = bJSC__ThrowScope; pub const JSC__PropertyName = bJSC__PropertyName; pub const JSC__JSObject = bJSC__JSObject; pub const WTF__ExternalStringImpl = bWTF__ExternalStringImpl; - + pub const JSC__AsyncIteratorPrototype = struct_JSC__AsyncIteratorPrototype; pub const WTF__StringImpl = bWTF__StringImpl; pub const JSC__JSLock = bJSC__JSLock; pub const JSC__JSModuleLoader = bJSC__JSModuleLoader; pub const JSC__VM = bJSC__VM; - + pub const JSC__AsyncGeneratorPrototype = struct_JSC__AsyncGeneratorPrototype; - + pub const JSC__AsyncGeneratorFunctionPrototype = struct_JSC__AsyncGeneratorFunctionPrototype; pub const JSC__JSGlobalObject = bJSC__JSGlobalObject; pub const JSC__JSFunction = bJSC__JSFunction; - + pub const JSC__ArrayPrototype = struct_JSC__ArrayPrototype; - + pub const JSC__AsyncFunctionPrototype = struct_JSC__AsyncFunctionPrototype; -pub const JSC__Identifier = bJSC__Identifier; pub const JSC__JSPromise = bJSC__JSPromise; - +pub const JSC__Identifier = bJSC__Identifier; + pub const JSC__SetIteratorPrototype = struct_JSC__SetIteratorPrototype; pub const JSC__SourceCode = bJSC__SourceCode; pub const JSC__JSCell = bJSC__JSCell; - + pub const JSC__BigIntPrototype = struct_JSC__BigIntPrototype; - + pub const JSC__GeneratorFunctionPrototype = struct_JSC__GeneratorFunctionPrototype; pub const JSC__SourceOrigin = bJSC__SourceOrigin; pub const JSC__JSModuleRecord = bJSC__JSModuleRecord; pub const WTF__String = bWTF__String; pub const WTF__URL = bWTF__URL; - + + pub const JSC__IteratorPrototype = struct_JSC__IteratorPrototype; pub const JSC__JSInternalPromise = bJSC__JSInternalPromise; - + pub const JSC__FunctionPrototype = struct_JSC__FunctionPrototype; pub const Inspector__ScriptArguments = bInspector__ScriptArguments; pub const JSC__Exception = bJSC__Exception; pub const JSC__JSString = bJSC__JSString; - + pub const JSC__ObjectPrototype = struct_JSC__ObjectPrototype; pub const JSC__CallFrame = bJSC__CallFrame; - + pub const JSC__MapIteratorPrototype = struct_JSC__MapIteratorPrototype; pub extern fn JSC__JSObject__create(arg0: [*c]JSC__JSGlobalObject, arg1: usize, arg2: ?*c_void, ArgFn3: ?fn (?*c_void, [*c]JSC__JSObject, [*c]JSC__JSGlobalObject) callconv(.C) void) JSC__JSValue; pub extern fn JSC__JSObject__getArrayLength(arg0: [*c]JSC__JSObject) usize; @@ -120,6 +121,7 @@ pub extern fn Inspector__ScriptArguments__argumentCount(arg0: [*c]Inspector__Scr pub extern fn Inspector__ScriptArguments__getFirstArgumentAsString(arg0: [*c]Inspector__ScriptArguments) bWTF__String; pub extern fn Inspector__ScriptArguments__isEqual(arg0: [*c]Inspector__ScriptArguments, arg1: [*c]Inspector__ScriptArguments) bool; pub extern fn Inspector__ScriptArguments__release(arg0: [*c]Inspector__ScriptArguments) void; +pub extern fn JSC__JSModuleLoader__callExportedFunction(arg0: [*c]JSC__JSGlobalObject, arg1: ZigString, arg2: ZigString, arg3: [*c]JSC__JSValue, arg4: u8, arg5: [*c]ZigException) JSC__JSValue; pub extern fn JSC__JSModuleLoader__checkSyntax(arg0: [*c]JSC__JSGlobalObject, arg1: [*c]const JSC__SourceCode, arg2: bool) bool; pub extern fn JSC__JSModuleLoader__evaluate(arg0: [*c]JSC__JSGlobalObject, arg1: [*c]const u8, arg2: usize, arg3: [*c]const u8, arg4: usize, JSValue5: JSC__JSValue, arg6: [*c]JSC__JSValue) JSC__JSValue; pub extern fn JSC__JSModuleLoader__importModule(arg0: [*c]JSC__JSGlobalObject, arg1: [*c]const JSC__Identifier) [*c]JSC__JSInternalPromise; @@ -154,14 +156,14 @@ pub extern fn JSC__JSInternalPromise__then(arg0: [*c]JSC__JSInternalPromise, arg pub extern fn JSC__SourceOrigin__fromURL(arg0: [*c]const WTF__URL) bJSC__SourceOrigin; pub extern fn JSC__SourceCode__fromString(arg0: [*c]JSC__SourceCode, arg1: [*c]const WTF__String, arg2: [*c]const JSC__SourceOrigin, arg3: [*c]WTF__String, SourceType4: u8) void; pub extern fn JSC__JSFunction__calculatedDisplayName(arg0: [*c]JSC__JSFunction, arg1: [*c]JSC__VM) bWTF__String; -pub extern fn JSC__JSFunction__callWithArguments(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]JSC__JSValue, arg3: usize, arg4: *?*JSC__Exception, arg5: [*c]const u8) JSC__JSValue; -pub extern fn JSC__JSFunction__callWithArgumentsAndThis(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: [*c]JSC__JSGlobalObject, arg3: [*c]JSC__JSValue, arg4: usize, arg5: *?*JSC__Exception, arg6: [*c]const u8) JSC__JSValue; -pub extern fn JSC__JSFunction__callWithoutAnyArgumentsOrThis(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: *?*JSC__Exception, arg3: [*c]const u8) JSC__JSValue; -pub extern fn JSC__JSFunction__callWithThis(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, JSValue2: JSC__JSValue, arg3: *?*JSC__Exception, arg4: [*c]const u8) JSC__JSValue; -pub extern fn JSC__JSFunction__constructWithArguments(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]JSC__JSValue, arg3: usize, arg4: *?*JSC__Exception, arg5: [*c]const u8) JSC__JSValue; -pub extern fn JSC__JSFunction__constructWithArgumentsAndNewTarget(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: [*c]JSC__JSGlobalObject, arg3: [*c]JSC__JSValue, arg4: usize, arg5: *?*JSC__Exception, arg6: [*c]const u8) JSC__JSValue; -pub extern fn JSC__JSFunction__constructWithNewTarget(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, JSValue2: JSC__JSValue, arg3: *?*JSC__Exception, arg4: [*c]const u8) JSC__JSValue; -pub extern fn JSC__JSFunction__constructWithoutAnyArgumentsOrNewTarget(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: *?*JSC__Exception, arg3: [*c]const u8) JSC__JSValue; +pub extern fn JSC__JSFunction__callWithArguments(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]JSC__JSValue, arg3: usize, arg4: *?*JSC__Exception , arg5: [*c]const u8) JSC__JSValue; +pub extern fn JSC__JSFunction__callWithArgumentsAndThis(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: [*c]JSC__JSGlobalObject, arg3: [*c]JSC__JSValue, arg4: usize, arg5: *?*JSC__Exception , arg6: [*c]const u8) JSC__JSValue; +pub extern fn JSC__JSFunction__callWithoutAnyArgumentsOrThis(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: *?*JSC__Exception , arg3: [*c]const u8) JSC__JSValue; +pub extern fn JSC__JSFunction__callWithThis(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, JSValue2: JSC__JSValue, arg3: *?*JSC__Exception , arg4: [*c]const u8) JSC__JSValue; +pub extern fn JSC__JSFunction__constructWithArguments(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]JSC__JSValue, arg3: usize, arg4: *?*JSC__Exception , arg5: [*c]const u8) JSC__JSValue; +pub extern fn JSC__JSFunction__constructWithArgumentsAndNewTarget(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: [*c]JSC__JSGlobalObject, arg3: [*c]JSC__JSValue, arg4: usize, arg5: *?*JSC__Exception , arg6: [*c]const u8) JSC__JSValue; +pub extern fn JSC__JSFunction__constructWithNewTarget(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, JSValue2: JSC__JSValue, arg3: *?*JSC__Exception , arg4: [*c]const u8) JSC__JSValue; +pub extern fn JSC__JSFunction__constructWithoutAnyArgumentsOrNewTarget(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: *?*JSC__Exception , arg3: [*c]const u8) JSC__JSValue; pub extern fn JSC__JSFunction__createFromNative(arg0: [*c]JSC__JSGlobalObject, arg1: u16, arg2: [*c]const WTF__String, arg3: ?*c_void, ArgFn4: ?fn (?*c_void, [*c]JSC__JSGlobalObject, [*c]JSC__CallFrame) callconv(.C) JSC__JSValue) [*c]JSC__JSFunction; pub extern fn JSC__JSFunction__displayName(arg0: [*c]JSC__JSFunction, arg1: [*c]JSC__VM) bWTF__String; pub extern fn JSC__JSFunction__getName(arg0: [*c]JSC__JSFunction, arg1: [*c]JSC__VM) bWTF__String; diff --git a/src/javascript/jsc/config.zig b/src/javascript/jsc/config.zig index 2f91e433d..3a24f200e 100644 --- a/src/javascript/jsc/config.zig +++ b/src/javascript/jsc/config.zig @@ -8,7 +8,7 @@ const NodeModuleBundle = @import("../../node_module_bundle.zig").NodeModuleBundl const logger = @import("../../logger.zig"); const Api = @import("../../api/schema.zig").Api; const options = @import("../../options.zig"); -const Bundler = @import("../../bundler.zig").ServeBundler; +const Bundler = @import("../../bundler.zig").Bundler; const js_printer = @import("../../js_printer.zig"); const hash_map = @import("../../hash_map.zig"); const http = @import("../../http.zig"); diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig index bd9b470a9..9e6f5defd 100644 --- a/src/javascript/jsc/javascript.zig +++ b/src/javascript/jsc/javascript.zig @@ -7,7 +7,7 @@ const NodeModuleBundle = @import("../../node_module_bundle.zig").NodeModuleBundl const logger = @import("../../logger.zig"); const Api = @import("../../api/schema.zig").Api; const options = @import("../../options.zig"); -const Bundler = @import("../../bundler.zig").ServeBundler; +const Bundler = @import("../../bundler.zig").Bundler; const ServerEntryPoint = @import("../../bundler.zig").ServerEntryPoint; const js_printer = @import("../../js_printer.zig"); const js_parser = @import("../../js_parser.zig"); @@ -359,22 +359,16 @@ pub const Bun = struct { const bun_file_import_path = "/node_modules.server.bun"; pub const LazyClasses = [_]type{}; -pub const Module = struct { - reload_pending: bool = false, -}; - // If you read JavascriptCore/API/JSVirtualMachine.mm - https://github.com/WebKit/WebKit/blob/acff93fb303baa670c055cb24c2bad08691a01a0/Source/JavaScriptCore/API/JSVirtualMachine.mm#L101 // We can see that it's sort of like std.mem.Allocator but for JSGlobalContextRef, to support Automatic Reference Counting // Its unavailable on Linux pub const VirtualMachine = struct { - const RequireCacheType = std.AutoHashMap(u32, *Module); global: *JSGlobalObject, allocator: *std.mem.Allocator, node_modules: ?*NodeModuleBundle = null, bundler: Bundler, watcher: ?*http.Watcher = null, console: *ZigConsoleClient, - require_cache: RequireCacheType, log: *logger.Log, event_listeners: EventListenerMixin.Map, main: string = "", @@ -389,8 +383,8 @@ pub const VirtualMachine = struct { transpiled_count: usize = 0, resolved_count: usize = 0, had_errors: bool = false, - pub var vm_loaded = false; - pub var vm: *VirtualMachine = undefined; + pub threadlocal var vm_loaded = false; + pub threadlocal var vm: *VirtualMachine = undefined; pub fn init( allocator: *std.mem.Allocator, @@ -421,7 +415,6 @@ pub const VirtualMachine = struct { .global = undefined, .allocator = allocator, .entry_point = ServerEntryPoint{}, - .require_cache = RequireCacheType.init(allocator), .event_listeners = EventListenerMixin.Map.init(allocator), .bundler = bundler, .console = console, |