Skip to content

Commit

Permalink
src: port defineLazyProperties to native code
Browse files Browse the repository at this point in the history
This allows us to have getters not observable from JS side.

PR-URL: #57081
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Chengzhong Wu <[email protected]>
Reviewed-By: Joyee Cheung <[email protected]>
  • Loading branch information
aduh95 authored Feb 18, 2025
1 parent 7a6b128 commit 2086877
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 81 deletions.
14 changes: 2 additions & 12 deletions lib/internal/bootstrap/web/exposed-wildcard.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@ const {

const {
exposeInterface,
lazyDOMExceptionClass,
exposeLazyInterfaces,
exposeGetterAndSetter,
exposeNamespace,
} = require('internal/util');
const config = internalBinding('config');
const { exposeLazyDOMExceptionProperty } = internalBinding('messaging');

// https://console.spec.whatwg.org/#console-namespace
exposeNamespace(globalThis, 'console',
Expand All @@ -28,16 +27,7 @@ const { URL, URLSearchParams } = require('internal/url');
exposeInterface(globalThis, 'URL', URL);
// https://url.spec.whatwg.org/#urlsearchparams
exposeInterface(globalThis, 'URLSearchParams', URLSearchParams);
exposeGetterAndSetter(globalThis,
'DOMException',
() => {
const DOMException = lazyDOMExceptionClass();
exposeInterface(globalThis, 'DOMException', DOMException);
return DOMException;
},
(value) => {
exposeInterface(globalThis, 'DOMException', value);
});
exposeLazyDOMExceptionProperty(globalThis);

// https://dom.spec.whatwg.org/#interface-abortcontroller
// Lazy ones.
Expand Down
41 changes: 1 addition & 40 deletions lib/internal/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const {
const { signals } = internalBinding('constants').os;
const {
guessHandleType: _guessHandleType,
defineLazyProperties,
privateSymbols: {
arrow_message_private_symbol,
decorated_private_symbol,
Expand Down Expand Up @@ -610,46 +611,6 @@ function exposeGetterAndSetter(target, name, getter, setter = undefined) {
});
}

function defineLazyProperties(target, id, keys, enumerable = true) {
const descriptors = { __proto__: null };
let mod;
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
let lazyLoadedValue;
function set(value) {
ObjectDefineProperty(target, key, {
__proto__: null,
writable: true,
value,
});
}
ObjectDefineProperty(set, 'name', {
__proto__: null,
value: `set ${key}`,
});
function get() {
mod ??= require(id);
if (lazyLoadedValue === undefined) {
lazyLoadedValue = mod[key];
set(lazyLoadedValue);
}
return lazyLoadedValue;
}
ObjectDefineProperty(get, 'name', {
__proto__: null,
value: `get ${key}`,
});
descriptors[key] = {
__proto__: null,
configurable: true,
enumerable,
get,
set,
};
}
ObjectDefineProperties(target, descriptors);
}

function defineReplaceableLazyAttribute(target, id, keys, writable = true, check) {
let mod;
for (let i = 0; i < keys.length; i++) {
Expand Down
36 changes: 36 additions & 0 deletions src/node_messaging.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1645,6 +1645,36 @@ static void BroadcastChannel(const FunctionCallbackInfo<Value>& args) {
}
}

static void ExposeLazyDOMExceptionPropertyGetter(
Local<v8::Name> name, const v8::PropertyCallbackInfo<Value>& info) {
auto context = info.GetIsolate()->GetCurrentContext();
Local<Function> domexception;
if (!GetDOMException(context).ToLocal(&domexception)) {
// V8 will have scheduled an error to be thrown.
return;
}
info.GetReturnValue().Set(domexception);
}
static void ExposeLazyDOMExceptionProperty(
const FunctionCallbackInfo<Value>& args) {
CHECK_GE(args.Length(), 1);
CHECK(args[0]->IsObject());

Isolate* isolate = args.GetIsolate();
auto target = args[0].As<Object>();

if (target
->SetLazyDataProperty(isolate->GetCurrentContext(),
FIXED_ONE_BYTE_STRING(isolate, "DOMException"),
ExposeLazyDOMExceptionPropertyGetter,
Local<Value>(),
v8::DontEnum)
.IsNothing()) {
// V8 will have scheduled an error to be thrown.
return;
}
}

static void CreatePerIsolateProperties(IsolateData* isolate_data,
Local<ObjectTemplate> target) {
Isolate* isolate = isolate_data->isolate();
Expand All @@ -1669,6 +1699,10 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
isolate_data->message_port_constructor_string(),
GetMessagePortConstructorTemplate(isolate_data));

SetMethod(isolate,
target,
"exposeLazyDOMExceptionProperty",
ExposeLazyDOMExceptionProperty);
// These are not methods on the MessagePort prototype, because
// the browser equivalents do not provide them.
SetMethod(isolate, target, "stopMessagePort", MessagePort::Stop);
Expand Down Expand Up @@ -1714,6 +1748,8 @@ static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(MessagePort::MoveToContext);
registry->Register(SetDeserializerCreateObjectFunction);
registry->Register(StructuredClone);
registry->Register(ExposeLazyDOMExceptionProperty);
registry->Register(ExposeLazyDOMExceptionPropertyGetter);
}

} // anonymous namespace
Expand Down
66 changes: 66 additions & 0 deletions src/node_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,69 @@ static void IsInsideNodeModules(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(result);
}

static void DefineLazyPropertiesGetter(
Local<v8::Name> name, const v8::PropertyCallbackInfo<Value>& info) {
Realm* realm = Realm::GetCurrent(info);
Isolate* isolate = realm->isolate();
auto context = isolate->GetCurrentContext();
Local<Value> arg = info.Data();
Local<Value> require_result;
if (!realm->builtin_module_require()
->Call(context, Null(isolate), 1, &arg)
.ToLocal(&require_result)) {
// V8 will have scheduled an error to be thrown.
return;
}
Local<Value> ret;
if (!require_result.As<v8::Object>()->Get(context, name).ToLocal(&ret)) {
// V8 will have scheduled an error to be thrown.
return;
}
info.GetReturnValue().Set(ret);
}
static void DefineLazyProperties(const FunctionCallbackInfo<Value>& args) {
// target: object, id: string, keys: string[][, enumerable = true]
CHECK_GE(args.Length(), 3);
// target: Object where to define the lazy properties.
CHECK(args[0]->IsObject());
// id: Internal module to lazy-load where the API to expose are implemented.
CHECK(args[1]->IsString());
// keys: Keys to map from `require(id)` and `target`.
CHECK(args[2]->IsArray());
// enumerable: Whether the property should be enumerable.
CHECK(args.Length() == 3 || args[3]->IsBoolean());

Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();
auto context = isolate->GetCurrentContext();

auto target = args[0].As<Object>();
Local<Value> id = args[1];
v8::PropertyAttribute attribute =
args.Length() == 3 || args[3]->IsTrue() ? v8::None : v8::DontEnum;

const Local<Array> keys = args[2].As<Array>();
size_t length = keys->Length();
for (size_t i = 0; i < length; i++) {
Local<Value> key;
if (!keys->Get(context, i).ToLocal(&key)) {
// V8 will have scheduled an error to be thrown.
return;
}
CHECK(key->IsString());
if (target
->SetLazyDataProperty(context,
key.As<String>(),
DefineLazyPropertiesGetter,
id,
attribute)
.IsNothing()) {
// V8 will have scheduled an error to be thrown.
return;
};
}
}

void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(GetPromiseDetails);
registry->Register(GetProxyDetails);
Expand All @@ -364,6 +427,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(fast_guess_handle_type_.GetTypeInfo());
registry->Register(ParseEnv);
registry->Register(IsInsideNodeModules);
registry->Register(DefineLazyProperties);
registry->Register(DefineLazyPropertiesGetter);
}

void Initialize(Local<Object> target,
Expand Down Expand Up @@ -448,6 +513,7 @@ void Initialize(Local<Object> target,
}

SetMethod(context, target, "isInsideNodeModules", IsInsideNodeModules);
SetMethod(context, target, "defineLazyProperties", DefineLazyProperties);
SetMethodNoSideEffect(
context, target, "getPromiseDetails", GetPromiseDetails);
SetMethodNoSideEffect(context, target, "getProxyDetails", GetProxyDetails);
Expand Down
27 changes: 0 additions & 27 deletions test/common/wpt.js
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,6 @@ class WPTRunner {
switch (name) {
case 'Window': {
this.globalThisInitScripts.push('globalThis.Window = Object.getPrototypeOf(globalThis).constructor;');
this.loadLazyGlobals();
break;
}

Expand All @@ -609,32 +608,6 @@ class WPTRunner {
}
}

loadLazyGlobals() {
const lazyProperties = [
'DOMException',
'Performance', 'PerformanceEntry', 'PerformanceMark', 'PerformanceMeasure',
'PerformanceObserver', 'PerformanceObserverEntryList', 'PerformanceResourceTiming',
'Blob', 'atob', 'btoa',
'MessageChannel', 'MessagePort', 'MessageEvent',
'EventTarget', 'Event',
'AbortController', 'AbortSignal',
'performance',
'TransformStream', 'TransformStreamDefaultController',
'WritableStream', 'WritableStreamDefaultController', 'WritableStreamDefaultWriter',
'ReadableStream', 'ReadableStreamDefaultReader',
'ReadableStreamBYOBReader', 'ReadableStreamBYOBRequest',
'ReadableByteStreamController', 'ReadableStreamDefaultController',
'ByteLengthQueuingStrategy', 'CountQueuingStrategy',
'TextEncoder', 'TextDecoder', 'TextEncoderStream', 'TextDecoderStream',
'CompressionStream', 'DecompressionStream',
];
if (Boolean(process.versions.openssl) && !process.env.NODE_SKIP_CRYPTO) {
lazyProperties.push('crypto', 'Crypto', 'CryptoKey', 'SubtleCrypto');
}
const script = lazyProperties.map((name) => `globalThis.${name};`).join('\n');
this.globalThisInitScripts.push(script);
}

// TODO(joyeecheung): work with the upstream to port more tests in .html
// to .js.
async runJsTests() {
Expand Down
2 changes: 0 additions & 2 deletions test/wpt/test-domexception.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@ const { WPTRunner } = require('../common/wpt');

const runner = new WPTRunner('webidl/ecmascript-binding/es-exceptions');

runner.loadLazyGlobals();

runner.runJsTests();

0 comments on commit 2086877

Please sign in to comment.