aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-05-09 04:11:48 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-05-09 04:11:48 -0700
commit8ac108ba06fff666ce3257d3c64b694b7a2c6338 (patch)
tree8c52be68968228535fba0883b38c36f9b8eea30e /src
parent8014a0b8d8f5d9f7c20ad25f1ee7045bd2ca384a (diff)
downloadbun-8ac108ba06fff666ce3257d3c64b694b7a2c6338.tar.gz
bun-8ac108ba06fff666ce3257d3c64b694b7a2c6338.tar.zst
bun-8ac108ba06fff666ce3257d3c64b694b7a2c6338.zip
[napi] Move some code to C++ for perf
Diffstat (limited to 'src')
-rw-r--r--src/javascript/jsc/bindings/napi.cpp172
-rw-r--r--src/napi/napi.zig167
2 files changed, 181 insertions, 158 deletions
diff --git a/src/javascript/jsc/bindings/napi.cpp b/src/javascript/jsc/bindings/napi.cpp
index 94c18ebac..f8f4e1011 100644
--- a/src/javascript/jsc/bindings/napi.cpp
+++ b/src/javascript/jsc/bindings/napi.cpp
@@ -227,7 +227,6 @@ static void defineNapiProperty(Zig::GlobalObject* globalObject, JSC::JSObject* t
JSC::JSObject* setter = nullptr;
if (property.getter) {
- auto callGetter = property.getter;
auto function = Zig::JSFFIFunction::create(vm, globalObject, 0, nameStr, reinterpret_cast<Zig::FFIFunction>(property.getter));
function->dataPtr = dataPtr;
@@ -239,7 +238,6 @@ static void defineNapiProperty(Zig::GlobalObject* globalObject, JSC::JSObject* t
}
if (property.setter) {
- auto callGetter = property.setter;
auto function = Zig::JSFFIFunction::create(vm, globalObject, 1, nameStr, reinterpret_cast<Zig::FFIFunction>(property.setter));
function->dataPtr = dataPtr;
// if (isInstance) {
@@ -264,6 +262,176 @@ static void defineNapiProperty(Zig::GlobalObject* globalObject, JSC::JSObject* t
}
}
+extern "C" napi_status napi_set_property(napi_env env, napi_value target,
+ napi_value key, napi_value value)
+{
+ auto globalObject = toJS(env);
+ auto& vm = globalObject->vm();
+ auto* object = toJS(target).getObject();
+ if (!object) {
+ return napi_object_expected;
+ }
+
+ auto keyProp = toJS(key);
+ auto scope = DECLARE_CATCH_SCOPE(vm);
+ object->putDirect(globalObject->vm(), keyProp.toPropertyKey(globalObject), toJS(value));
+ RETURN_IF_EXCEPTION(scope, napi_generic_failure);
+
+ scope.clearException();
+ return napi_ok;
+}
+extern "C" napi_status napi_has_property(napi_env env, napi_value object,
+ napi_value key, bool* result)
+{
+ auto globalObject = toJS(env);
+ auto& vm = globalObject->vm();
+ auto* target = toJS(object).getObject();
+ if (!target) {
+ return napi_object_expected;
+ }
+
+ auto keyProp = toJS(key);
+ auto scope = DECLARE_CATCH_SCOPE(vm);
+ // TODO: use the slot directly?
+ *result = !!target->getIfPropertyExists(globalObject, keyProp.toPropertyKey(globalObject));
+ RETURN_IF_EXCEPTION(scope, napi_generic_failure);
+
+ scope.clearException();
+ return napi_ok;
+}
+extern "C" napi_status napi_get_property(napi_env env, napi_value object,
+ napi_value key, napi_value* result)
+{
+ auto globalObject = toJS(env);
+ auto& vm = globalObject->vm();
+
+ auto* target = toJS(object).getObject();
+ if (!target) {
+ return napi_object_expected;
+ }
+
+ auto keyProp = toJS(key);
+ auto scope = DECLARE_CATCH_SCOPE(vm);
+ *result = toNapi(target->getIfPropertyExists(globalObject, keyProp.toPropertyKey(globalObject)));
+ RETURN_IF_EXCEPTION(scope, napi_generic_failure);
+
+ scope.clearException();
+ return napi_ok;
+}
+
+extern "C" napi_status napi_delete_property(napi_env env, napi_value object,
+ napi_value key, bool* result)
+{
+ auto globalObject = toJS(env);
+ auto& vm = globalObject->vm();
+
+ auto* target = toJS(object).getObject();
+ if (!target) {
+ return napi_object_expected;
+ }
+
+ auto keyProp = toJS(key);
+ auto scope = DECLARE_CATCH_SCOPE(vm);
+ *result = toNapi(target->deleteProperty(globalObject, JSC::PropertyName(keyProp.toPropertyKey(globalObject))));
+ RETURN_IF_EXCEPTION(scope, napi_generic_failure);
+
+ scope.clearException();
+ return napi_ok;
+}
+extern "C" napi_status napi_has_own_property(napi_env env, napi_value object,
+ napi_value key, bool* result)
+{
+ auto globalObject = toJS(env);
+ auto& vm = globalObject->vm();
+
+ auto* target = toJS(object).getObject();
+ if (!target) {
+ return napi_object_expected;
+ }
+
+ auto keyProp = toJS(key);
+ auto scope = DECLARE_CATCH_SCOPE(vm);
+ *result = toNapi(target->hasOwnProperty(globalObject, JSC::PropertyName(keyProp.toPropertyKey(globalObject))));
+ RETURN_IF_EXCEPTION(scope, napi_generic_failure);
+
+ scope.clearException();
+ return napi_ok;
+}
+
+extern "C" napi_status napi_set_named_property(napi_env env, napi_value object,
+ const char* utf8name,
+ napi_value value)
+{
+ auto globalObject = toJS(env);
+ auto target = toJS(object).getObject();
+ auto& vm = globalObject->vm();
+ if (!UNLIKELY(target)) {
+ return napi_object_expected;
+ }
+
+ // In this case, we should clone the property name
+ auto name = JSC::PropertyName(JSC::Identifier::fromString(vm, WTF::String::fromUTF8(utf8name, strlen(utf8name))));
+
+ auto scope = DECLARE_CATCH_SCOPE(vm);
+ target->putDirect(globalObject->vm(), name, toJS(value), 0);
+ RETURN_IF_EXCEPTION(scope, napi_generic_failure);
+ scope.clearException();
+ return napi_ok;
+}
+
+// This is more efficient than using WTF::String::FromUTF8
+// it doesn't copy the string
+// but it's only safe to use if we are not setting a property
+// because we can't gurantee the lifetime of it
+#define PROPERTY_NAME_FROM_UTF8(identifierName) \
+ size_t utf8Len = strlen(utf8name); \
+ JSC::PropertyName identifierName = LIKELY(charactersAreAllASCII(reinterpret_cast<const LChar*>(utf8name), utf8Len)) ? JSC::PropertyName(JSC::Identifier::fromString(vm, WTF::String(WTF::StringImpl::createWithoutCopying(utf8name, utf8Len)))) : JSC::PropertyName(JSC::Identifier::fromString(vm, WTF::String::fromUTF8(utf8name)));
+
+extern "C" napi_status napi_has_named_property(napi_env env, napi_value object,
+ const char* utf8name,
+ bool* result)
+{
+
+ auto globalObject = toJS(env);
+ auto& vm = globalObject->vm();
+
+ auto* target = toJS(object).getObject();
+ if (UNLIKELY(!target)) {
+ return napi_object_expected;
+ }
+
+ PROPERTY_NAME_FROM_UTF8(name);
+
+ auto scope = DECLARE_CATCH_SCOPE(vm);
+ *result = !!target->getIfPropertyExists(globalObject, name);
+ RETURN_IF_EXCEPTION(scope, napi_generic_failure);
+
+ scope.clearException();
+ return napi_ok;
+}
+extern "C" napi_status napi_get_named_property(napi_env env, napi_value object,
+ const char* utf8name,
+ napi_value* result)
+{
+
+ auto globalObject = toJS(env);
+ auto& vm = globalObject->vm();
+
+ auto* target = toJS(object).getObject();
+ if (UNLIKELY(!target)) {
+ return napi_object_expected;
+ }
+
+ PROPERTY_NAME_FROM_UTF8(name);
+
+ auto scope = DECLARE_CATCH_SCOPE(vm);
+ *result = toNapi(target->getIfPropertyExists(globalObject, name));
+ RETURN_IF_EXCEPTION(scope, napi_generic_failure);
+
+ scope.clearException();
+ return napi_ok;
+}
+
extern "C" void napi_module_register(napi_module* mod)
{
auto* globalObject = Bun__getDefaultGlobal();
diff --git a/src/napi/napi.zig b/src/napi/napi.zig
index 9189d4c94..788e9f377 100644
--- a/src/napi/napi.zig
+++ b/src/napi/napi.zig
@@ -411,12 +411,14 @@ pub export fn napi_get_value_string_latin1(env: napi_env, value: napi_value, buf
if (wrote < 0) {
return .generic_failure;
}
- result.* = @intCast(usize, wrote);
+ // if zero terminated, report the length of the string without the null
+ result.* = @intCast(@TypeOf(result.*), wrote - @as(@TypeOf(wrote), @boolToInt(bufsize == 0)));
return .ok;
}
const to_copy = @minimum(zig_str.len, buf_.len);
@memcpy(buf, zig_str.slice().ptr, to_copy);
- result.* = to_copy;
+ // if zero terminated, report the length of the string without the null
+ result.* = to_copy - @as(usize, @boolToInt(bufsize == 0));
return .ok;
}
pub export fn napi_get_value_string_utf8(env: napi_env, value: napi_value, buf_ptr: [*c]u8, bufsize: usize, result: *usize) napi_status {
@@ -449,13 +451,15 @@ pub export fn napi_get_value_string_utf8(env: napi_env, value: napi_value, buf_p
if (wrote < 0) {
return .generic_failure;
}
- result.* = @intCast(usize, wrote);
+ // if zero terminated, report the length of the string without the null
+ result.* = @intCast(@TypeOf(result.*), wrote - @as(@TypeOf(wrote), @boolToInt(bufsize == 0)));
return .ok;
}
const to_copy = @minimum(zig_str.len, buf_.len);
@memcpy(buf, zig_str.slice().ptr, to_copy);
- result.* = to_copy;
+ // if zero terminated, report the length of the string without the null
+ result.* = to_copy - @as(usize, @boolToInt(bufsize == 0));
return .ok;
}
pub export fn napi_get_value_string_utf16(env: napi_env, value: napi_value, buf_ptr: [*c]char16_t, bufsize: usize, result: *usize) napi_status {
@@ -491,7 +495,8 @@ pub export fn napi_get_value_string_utf16(env: napi_env, value: napi_value, buf_
const to_copy = @minimum(zig_str.len, buf_.len);
@memcpy(std.mem.sliceAsBytes(buf[0..bufsize]).ptr, std.mem.sliceAsBytes(zig_str.utf16SliceAligned()).ptr, to_copy * 2);
- result.* = to_copy;
+ // if zero terminated, report the length of the string without the null
+ result.* = to_copy - @as(usize, @boolToInt(bufsize == 0));
return .ok;
}
pub export fn napi_coerce_to_bool(_: napi_env, value: napi_value, result: *napi_value) napi_status {
@@ -527,141 +532,6 @@ pub export fn napi_get_prototype(env: napi_env, object: napi_value, result: *nap
// result.* =
// }
-pub export fn napi_set_property(env: napi_env, object: napi_value, key: napi_value, value: napi_value) napi_status {
- if (!object.isObject()) {
- return .object_expected;
- }
- var name = key.getZigString(env);
- if (name.len == 0 or value.isEmpty()) {
- return .invalid_arg;
- }
- var exception = [_]JSC.C.JSValueRef{null};
- JSC.C.JSObjectSetPropertyForKey(
- env.ref(),
- object.asObjectRef(),
- key.asObjectRef(),
- value.asObjectRef(),
- JSC.C.JSPropertyAttributes.kJSPropertyAttributeNone,
- &exception,
- );
- return if (exception[0] == null)
- .ok
- else
- .generic_failure;
-}
-pub export fn napi_has_property(env: napi_env, object: napi_value, key: napi_value, result: *bool) napi_status {
- if (!object.isObject()) {
- return .object_expected;
- }
- var name = key.getZigString(env);
- var name_slice = name.toSlice(JSC.VirtualMachine.vm.allocator);
- defer name_slice.deinit();
- if (name.len == 0) {
- return .invalid_arg;
- }
- // TODO: bind hasOwnProperty
- result.* = object.get(env, name_slice.slice()) != null;
- return .ok;
-}
-pub export fn napi_get_property(env: napi_env, object: napi_value, key: napi_value, result: *napi_value) napi_status {
- if (!object.isObject()) {
- return .object_expected;
- }
-
- if (!key.isString()) {
- return .invalid_arg;
- }
-
- var name = key.getZigString(env);
- var name_slice = name.toSlice(JSC.VirtualMachine.vm.allocator);
- defer name_slice.deinit();
- if (name.len == 0) {
- return .invalid_arg;
- }
- // TODO: DECLARE_THROW_SCOPE
- result.* = object.get(env, name_slice.slice()) orelse JSC.JSValue.@"undefined";
- return .ok;
-}
-pub export fn napi_delete_property(env: napi_env, object: napi_value, key: napi_value, result: *bool) napi_status {
- if (!object.isObject()) {
- return .object_expected;
- }
-
- if (!key.isString()) {
- return .invalid_arg;
- }
-
- result.* = JSC.C.JSObjectDeletePropertyForKey(env.ref(), object.asObjectRef(), key.asObjectRef(), null);
- return .ok;
-}
-pub export fn napi_has_own_property(env: napi_env, object: napi_value, key: napi_value, result: *bool) napi_status {
- if (!object.isObject()) {
- return .object_expected;
- }
-
- if (!key.isString()) {
- return .invalid_arg;
- }
-
- result.* = JSC.C.JSObjectHasPropertyForKey(env.ref(), object.asObjectRef(), key.asObjectRef(), null);
- return .ok;
-}
-
-fn noop_finalizer(_: ?*anyopaque, _: JSC.C.JSStringRef, _: *anyopaque, _: usize) callconv(.C) void {}
-pub export fn napi_set_named_property(env: napi_env, object: napi_value, utf8name: [*c]const u8, value: napi_value) napi_status {
- if (!object.isObject()) {
- return .object_expected;
- }
-
- if (utf8name == null) {
- return .invalid_arg;
- }
-
- const str = std.mem.span(utf8name);
- if (str.len == 0)
- return .invalid_arg;
-
- var ext = JSC.C.JSStringCreateExternal(utf8name, str.len, null, noop_finalizer);
- defer JSC.C.JSStringRelease(ext);
- JSC.C.JSObjectSetProperty(env.ref(), object.asObjectRef(), ext, value.asObjectRef(), 0, TODO_EXCEPTION);
- return .ok;
-}
-pub export fn napi_has_named_property(env: napi_env, object: napi_value, utf8name: [*c]const u8, result: *bool) napi_status {
- if (!object.isObject()) {
- return .object_expected;
- }
-
- if (utf8name == null) {
- return .invalid_arg;
- }
-
- const str = std.mem.span(utf8name);
- if (str.len == 0)
- return .invalid_arg;
-
- var ext = JSC.C.JSStringCreateExternal(utf8name, str.len, null, noop_finalizer);
- defer JSC.C.JSStringRelease(ext);
- result.* = JSC.C.JSObjectHasProperty(env.ref(), object.asObjectRef(), ext);
- return .ok;
-}
-pub export fn napi_get_named_property(env: napi_env, object: napi_value, utf8name: [*c]const u8, result: *napi_value) napi_status {
- if (!object.isObject()) {
- return .object_expected;
- }
-
- if (utf8name == null) {
- return .invalid_arg;
- }
-
- const str = std.mem.span(utf8name);
- if (str.len == 0)
- return .invalid_arg;
-
- var ext = JSC.C.JSStringCreateExternal(utf8name, str.len, null, noop_finalizer);
- defer JSC.C.JSStringRelease(ext);
- result.* = JSValue.c(JSC.C.JSObjectGetProperty(env.ref(), object.asObjectRef(), ext, TODO_EXCEPTION));
- return .ok;
-}
pub export fn napi_set_element(env: napi_env, object: napi_value, index: c_uint, value: napi_value) napi_status {
if (!object.jsType().isIndexable()) {
return .array_expected;
@@ -1546,14 +1416,6 @@ pub fn fixDeadCodeElimination() void {
// std.mem.doNotOptimizeAway(&napi_coerce_to_string);
std.mem.doNotOptimizeAway(&napi_get_prototype);
// std.mem.doNotOptimizeAway(&napi_get_property_names);
- std.mem.doNotOptimizeAway(&napi_set_property);
- std.mem.doNotOptimizeAway(&napi_has_property);
- std.mem.doNotOptimizeAway(&napi_get_property);
- std.mem.doNotOptimizeAway(&napi_delete_property);
- std.mem.doNotOptimizeAway(&napi_has_own_property);
- std.mem.doNotOptimizeAway(&napi_set_named_property);
- std.mem.doNotOptimizeAway(&napi_has_named_property);
- std.mem.doNotOptimizeAway(&napi_get_named_property);
std.mem.doNotOptimizeAway(&napi_set_element);
std.mem.doNotOptimizeAway(&napi_has_element);
std.mem.doNotOptimizeAway(&napi_get_element);
@@ -1649,14 +1511,7 @@ comptime {
// _ = napi_coerce_to_string;
_ = napi_get_prototype;
// _ = napi_get_property_names;
- _ = napi_set_property;
- _ = napi_has_property;
- _ = napi_get_property;
- _ = napi_delete_property;
- _ = napi_has_own_property;
- _ = napi_set_named_property;
- _ = napi_has_named_property;
- _ = napi_get_named_property;
+
_ = napi_set_element;
_ = napi_has_element;
_ = napi_get_element;