aboutsummaryrefslogtreecommitdiff
path: root/src/javascript/jsc/bindings/bindings.cpp
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-09-19 03:43:17 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-09-19 03:43:17 -0700
commit60b5fb95b19b2f96dcfd851663b40e1155c9cc0e (patch)
tree483c76e2ff7b87e5a1fdf510b1cc577826055df8 /src/javascript/jsc/bindings/bindings.cpp
parent9ae35ec5811f7395f98988ccdcd07395cd731bb0 (diff)
downloadbun-60b5fb95b19b2f96dcfd851663b40e1155c9cc0e.tar.gz
bun-60b5fb95b19b2f96dcfd851663b40e1155c9cc0e.tar.zst
bun-60b5fb95b19b2f96dcfd851663b40e1155c9cc0e.zip
WIP macros
Diffstat (limited to 'src/javascript/jsc/bindings/bindings.cpp')
-rw-r--r--src/javascript/jsc/bindings/bindings.cpp537
1 files changed, 300 insertions, 237 deletions
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