diff options
Diffstat (limited to 'src/bun.js')
-rw-r--r-- | src/bun.js/api/bun.zig | 154 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.cpp | 60 |
2 files changed, 134 insertions, 80 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index 9ddf309cc..105add52c 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -1542,95 +1542,95 @@ pub fn serve( unreachable; } -pub export fn Bun__escapeHTML( - globalObject: *JSGlobalObject, - callframe: *JSC.CallFrame, -) JSC.JSValue { - const arguments = callframe.arguments(2); - if (arguments.len < 1) { - return ZigString.Empty.toValue(globalObject); +pub export fn Bun__escapeHTML16(globalObject: *JSC.JSGlobalObject, input_value: JSValue, ptr: [*]const u16, len: usize) JSValue { + std.debug.assert(len > 0); + const input_slice = ptr[0..len]; + const escaped = strings.escapeHTMLForUTF16Input(globalObject.bunVM().allocator, input_slice) catch { + globalObject.vm().throwError(globalObject, ZigString.init("Out of memory").toValue(globalObject)); + return JSC.JSValue.jsUndefined(); + }; + + switch (escaped) { + .static => |val| { + return ZigString.init(val).toValue(globalObject); + }, + .original => return input_value, + .allocated => |escaped_html| { + if (comptime Environment.allow_assert) { + // assert that re-encoding the string produces the same result + std.debug.assert( + std.mem.eql( + u16, + (strings.toUTF16Alloc(bun.default_allocator, strings.toUTF8Alloc(bun.default_allocator, escaped_html) catch unreachable, false) catch unreachable).?, + escaped_html, + ), + ); + + // assert we do not allocate a new string unnecessarily + std.debug.assert( + !std.mem.eql( + u16, + input_slice, + escaped_html, + ), + ); + + // the output should always be longer than the input + std.debug.assert(escaped_html.len > input_slice.len); + } + + return ZigString.from16(escaped_html.ptr, escaped_html.len).toExternalValue(globalObject); + }, } +} - const input_value = arguments.ptr[0]; - const zig_str = input_value.getZigString(globalObject); - if (zig_str.len == 0) - return ZigString.Empty.toValue(globalObject); +pub export fn Bun__escapeHTML8(globalObject: *JSC.JSGlobalObject, input_value: JSValue, ptr: [*]const u8, len: usize) JSValue { + std.debug.assert(len > 0); - if (zig_str.is16Bit()) { - const input_slice = zig_str.utf16SliceAligned(); - const escaped = strings.escapeHTMLForUTF16Input(globalObject.bunVM().allocator, input_slice) catch { - globalObject.vm().throwError(globalObject, ZigString.init("Out of memory").toValue(globalObject)); - return JSC.JSValue.jsUndefined(); - }; + const input_slice = ptr[0..len]; + var stack_allocator = std.heap.stackFallback(256, globalObject.bunVM().allocator); + const allocator = if (input_slice.len <= 32) stack_allocator.get() else stack_allocator.fallback_allocator; - switch (escaped) { - .static => |val| { - return ZigString.init(val).toValue(globalObject); - }, - .original => return input_value, - .allocated => |escaped_html| { - if (comptime Environment.allow_assert) { - // assert that re-encoding the string produces the same result - std.debug.assert( - std.mem.eql( - u16, - (strings.toUTF16Alloc(bun.default_allocator, strings.toUTF8Alloc(bun.default_allocator, escaped_html) catch unreachable, false) catch unreachable).?, - escaped_html, - ), - ); - - // assert we do not allocate a new string unnecessarily - std.debug.assert( - !std.mem.eql( - u16, - input_slice, - escaped_html, - ), - ); - - // the output should always be longer than the input - std.debug.assert(escaped_html.len > input_slice.len); - } + const escaped = strings.escapeHTMLForLatin1Input(allocator, input_slice) catch { + globalObject.vm().throwError(globalObject, ZigString.init("Out of memory").toValue(globalObject)); + return JSC.JSValue.jsUndefined(); + }; - return ZigString.from16(escaped_html.ptr, escaped_html.len).toExternalValue(globalObject); - }, - } - } else { - const input_slice = zig_str.slice(); - const escaped = strings.escapeHTMLForLatin1Input(globalObject.bunVM().allocator, input_slice) catch { - globalObject.vm().throwError(globalObject, ZigString.init("Out of memory").toValue(globalObject)); - return JSC.JSValue.jsUndefined(); - }; + switch (escaped) { + .static => |val| { + return ZigString.init(val).toValue(globalObject); + }, + .original => return input_value, + .allocated => |escaped_html| { + if (comptime Environment.allow_assert) { + // the output should always be longer than the input + std.debug.assert(escaped_html.len > input_slice.len); + + // assert we do not allocate a new string unnecessarily + std.debug.assert( + !std.mem.eql( + u8, + input_slice, + escaped_html, + ), + ); + } - switch (escaped) { - .static => |val| { - return ZigString.init(val).toValue(globalObject); - }, - .original => return input_value, - .allocated => |escaped_html| { - if (comptime Environment.allow_assert) { - // the output should always be longer than the input - std.debug.assert(escaped_html.len > input_slice.len); - - // assert we do not allocate a new string unnecessarily - std.debug.assert( - !std.mem.eql( - u8, - input_slice, - escaped_html, - ), - ); - } + if (input_slice.len <= 32) { + const zig_str = ZigString.init(escaped_html); + const out = zig_str.toAtomicValue(globalObject); + return out; + } - return ZigString.init(escaped_html).toExternalValue(globalObject); - }, - } + return ZigString.init(escaped_html).toExternalValue(globalObject); + }, } } comptime { if (!JSC.is_bindgen) { - _ = Bun__escapeHTML; + _ = Bun__escapeHTML8; + _ = Bun__escapeHTML16; } } diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 5ad12624a..d8db25e9a 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -346,6 +346,9 @@ extern "C" JSC__JSValue JSC__JSValue__makeWithNameAndPrototype(JSC__JSGlobalObje return JSC::JSValue::encode(JSC::JSValue(object)); } +extern "C" EncodedJSValue Bun__escapeHTML8(JSGlobalObject* globalObject, EncodedJSValue input, const LChar* ptr, size_t length); +extern "C" EncodedJSValue Bun__escapeHTML16(JSGlobalObject* globalObject, EncodedJSValue input, const UChar* ptr, size_t length); + const JSC::GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &supportsRichSourceInfo, &shouldInterruptScript, @@ -1572,6 +1575,7 @@ class JSPerformanceObject; static JSC_DECLARE_HOST_FUNCTION(functionPerformanceNow); static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(functionPerformanceNowWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject*, JSPerformanceObject*)); static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(functionBunNanosecondsWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject*, JSObject*)); +static JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(functionBunEscapeHTMLWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject*, JSObject*, JSString*)); } class JSPerformanceObject final : public JSC::JSNonFinalObject { @@ -1638,6 +1642,51 @@ JSC_DEFINE_JIT_OPERATION(functionPerformanceNowWithoutTypeCheck, JSC::EncodedJSV return functionPerformanceNowBody(lexicalGlobalObject); } +JSC_DEFINE_JIT_OPERATION(functionBunEscapeHTMLWithoutTypeCheck, JSC::EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, JSObject* castedThis, JSString* string)) +{ + JSC::VM& vm = JSC::getVM(lexicalGlobalObject); + IGNORE_WARNINGS_BEGIN("frame-address") + CallFrame* callFrame = DECLARE_CALL_FRAME(vm); + IGNORE_WARNINGS_END + JSC::JITOperationPrologueCallFrameTracer tracer(vm, callFrame); + size_t length = string->length(); + if (!length) + return JSValue::encode(string); + + auto resolvedString = string->value(lexicalGlobalObject); + if (!resolvedString.is8Bit()) { + return Bun__escapeHTML16(lexicalGlobalObject, JSValue::encode(string), resolvedString.characters16(), length); + } else { + return Bun__escapeHTML8(lexicalGlobalObject, JSValue::encode(string), resolvedString.characters8(), length); + } +} + +JSC_DECLARE_HOST_FUNCTION(functionBunEscapeHTML); +JSC_DEFINE_HOST_FUNCTION(functionBunEscapeHTML, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame)) +{ + JSC::VM& vm = JSC::getVM(lexicalGlobalObject); + JSC::JSValue argument = callFrame->argument(0); + if (argument.isEmpty()) + return JSValue::encode(jsEmptyString(vm)); + if (argument.isNumber() || argument.isBoolean()) + return JSValue::encode(argument.toString(lexicalGlobalObject)); + + auto scope = DECLARE_THROW_SCOPE(vm); + auto string = argument.toString(lexicalGlobalObject); + RETURN_IF_EXCEPTION(scope, {}); + size_t length = string->length(); + if (!length) + RELEASE_AND_RETURN(scope, JSValue::encode(string)); + + auto resolvedString = string->value(lexicalGlobalObject); + EncodedJSValue encodedInput = JSValue::encode(string); + if (!resolvedString.is8Bit()) { + RELEASE_AND_RETURN(scope, Bun__escapeHTML16(lexicalGlobalObject, encodedInput, resolvedString.characters16(), length)); + } else { + RELEASE_AND_RETURN(scope, Bun__escapeHTML8(lexicalGlobalObject, encodedInput, resolvedString.characters8(), length)); + } +} + JSC_DECLARE_HOST_FUNCTION(functionBunNanoseconds); JSC_DEFINE_HOST_FUNCTION(functionBunNanoseconds, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) @@ -1938,8 +1987,6 @@ void GlobalObject::finishCreation(VM& vm) RELEASE_ASSERT(classInfo()); } -extern "C" EncodedJSValue Bun__escapeHTML(JSGlobalObject* globalObject, CallFrame* callFrame); - // This implementation works the same as setTimeout(myFunction, 0) // TODO: make it more efficient // https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate @@ -2248,7 +2295,14 @@ void GlobalObject::installAPIGlobals(JSClassRef* globals, int count, JSC::VM& vm { JSC::Identifier identifier = JSC::Identifier::fromString(vm, "escapeHTML"_s); - object->putDirectNativeFunction(vm, this, identifier, 1, Bun__escapeHTML, ImplementationVisibility::Public, NoIntrinsic, + static ClassInfo escapeHTMLClassInfo = *object->classInfo(); + static const JSC::DOMJIT::Signature DOMJITSignatureForEscapeHTML( + functionBunEscapeHTMLWithoutTypeCheck, + object->classInfo(), + JSC::DOMJIT::Effect::forPure(), + SpecString, + SpecString); + object->putDirectNativeFunction(vm, this, identifier, 1, functionBunEscapeHTML, ImplementationVisibility::Public, NoIntrinsic, &DOMJITSignatureForEscapeHTML, JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); } |