Bug 1805288 - Part 1: Add ChromeUtils.defineLazyGetter. r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D171319
This commit is contained in:
Tooru Fujisawa
2023-03-03 06:29:16 +00:00
parent f6899e9f8b
commit 6ba113a0b1
4 changed files with 97 additions and 7 deletions

View File

@@ -7,6 +7,7 @@
#include "ChromeUtils.h"
#include "JSOracleParent.h"
#include "js/CallAndConstruct.h" // JS::Call
#include "js/CharacterEncoding.h"
#include "js/Object.h" // JS::GetClass
#include "js/PropertyAndElement.h" // JS_DefineProperty, JS_DefinePropertyById, JS_Enumerate, JS_GetProperty, JS_GetPropertyById, JS_SetProperty, JS_SetPropertyById, JS::IdVector
@@ -634,10 +635,11 @@ void ChromeUtils::ImportESModule(
aRetval.set(moduleNamespace);
}
namespace module_getter {
namespace lazy_getter {
static const size_t SLOT_ID = 0;
static const size_t SLOT_URI = 1;
static const size_t SLOT_LAMBDA = 1;
static bool ExtractArgs(JSContext* aCx, JS::CallArgs& aArgs,
JS::MutableHandle<JSObject*> aCallee,
@@ -659,6 +661,56 @@ static bool ExtractArgs(JSContext* aCx, JS::CallArgs& aArgs,
return true;
}
static bool JSLazyGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
JS::Rooted<JSObject*> callee(aCx);
JS::Rooted<JSObject*> thisObj(aCx);
JS::Rooted<jsid> id(aCx);
if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
return false;
}
JS::Rooted<JS::Value> lambda(
aCx, js::GetFunctionNativeReserved(callee, SLOT_LAMBDA));
JS::Rooted<JS::Value> value(aCx);
if (!JS::Call(aCx, thisObj, lambda, JS::HandleValueArray::empty(), &value)) {
return false;
}
if (!JS_DefinePropertyById(aCx, thisObj, id, value, JSPROP_ENUMERATE)) {
return false;
}
args.rval().set(value);
return true;
}
static bool DefineLazyGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
JS::Handle<JS::Value> aName,
JS::Handle<JSObject*> aLambda) {
JS::Rooted<jsid> id(aCx);
if (!JS_ValueToId(aCx, aName, &id)) {
return false;
}
JS::Rooted<JSObject*> getter(
aCx, JS_GetFunctionObject(
js::NewFunctionByIdWithReserved(aCx, JSLazyGetter, 0, 0, id)));
if (!getter) {
JS_ReportOutOfMemory(aCx);
return false;
}
js::SetFunctionNativeReserved(getter, SLOT_ID, aName);
JS::Rooted<JS::Value> lambdaValue(aCx, JS::ObjectValue(*aLambda));
js::SetFunctionNativeReserved(getter, SLOT_LAMBDA, lambdaValue);
return JS_DefinePropertyById(aCx, aTarget, id, getter, nullptr,
JSPROP_ENUMERATE);
}
enum class ModuleType { JSM, ESM };
static bool ModuleGetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
@@ -820,7 +872,21 @@ static bool DefineESModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
return JS_DefinePropertyById(aCx, aTarget, aId, getter, setter,
JSPROP_ENUMERATE);
}
} // namespace module_getter
} // namespace lazy_getter
/* static */
void ChromeUtils::DefineLazyGetter(const GlobalObject& aGlobal,
JS::Handle<JSObject*> aTarget,
JS::Handle<JS::Value> aName,
JS::Handle<JSObject*> aLambda,
ErrorResult& aRv) {
JSContext* cx = aGlobal.Context();
if (!lazy_getter::DefineLazyGetter(cx, aTarget, aName, aLambda)) {
aRv.NoteJSContextException(cx);
return;
}
}
/* static */
void ChromeUtils::DefineModuleGetter(const GlobalObject& global,
@@ -828,8 +894,8 @@ void ChromeUtils::DefineModuleGetter(const GlobalObject& global,
const nsAString& id,
const nsAString& resourceURI,
ErrorResult& aRv) {
if (!module_getter::DefineJSModuleGetter(global.Context(), target, id,
resourceURI)) {
if (!lazy_getter::DefineJSModuleGetter(global.Context(), target, id,
resourceURI)) {
aRv.NoteJSContextException(global.Context());
}
}
@@ -839,7 +905,7 @@ void ChromeUtils::DefineESModuleGetters(const GlobalObject& global,
JS::Handle<JSObject*> target,
JS::Handle<JSObject*> modules,
ErrorResult& aRv) {
auto cx = global.Context();
JSContext* cx = global.Context();
JS::Rooted<JS::IdVector> props(cx, JS::IdVector(cx));
if (!JS_Enumerate(cx, modules, &props)) {
@@ -862,8 +928,7 @@ void ChromeUtils::DefineESModuleGetters(const GlobalObject& global,
return;
}
if (!module_getter::DefineESModuleGetter(cx, target, prop,
resourceURIVal)) {
if (!lazy_getter::DefineESModuleGetter(cx, target, prop, resourceURIVal)) {
aRv.NoteJSContextException(cx);
return;
}