aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bun.js/api/bun.zig154
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp60
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);
}