1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ModuleEnvironmentProxy.h"
9 #include "mozilla/Assertions.h" // MOZ_ASSERT
10 #include "mozilla/Maybe.h" // mozilla::Maybe
12 #include <stddef.h> // size_t
14 #include "js/Class.h" // JS::ObjectOpResult
15 #include "js/ErrorReport.h" // JS_ReportOutOfMemory
16 #include "js/GCVector.h" // JS::RootedVector
17 #include "js/Id.h" // JS::PropertyKey
18 #include "js/PropertyAndElement.h" // JS::IdVector, JS_HasPropertyById, JS_GetPropertyById, JS_Enumerate
19 #include "js/PropertyDescriptor.h" // JS::PropertyDescriptor, JS_GetOwnPropertyDescriptorById
20 #include "js/Proxy.h" // js::ProxyOptions, js::NewProxyObject, js::GetProxyPrivate
21 #include "js/RootingAPI.h" // JS::Rooted, JS::Handle, JS::MutableHandle
22 #include "js/TypeDecls.h" // JSContext, JSObject, JS::MutableHandleVector
23 #include "js/Value.h" // JS::Value
24 #include "js/friend/ErrorMessages.h" // JSMSG_*
25 #include "js/String.h"
26 #include "js/Modules.h"
31 struct ModuleEnvironmentProxyHandler
: public js::BaseProxyHandler
{
32 ModuleEnvironmentProxyHandler() : js::BaseProxyHandler(&gFamily
, false) {}
34 bool defineProperty(JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
35 JS::Handle
<JS::PropertyKey
> aId
,
36 JS::Handle
<JS::PropertyDescriptor
> aDesc
,
37 JS::ObjectOpResult
& aResult
) const override
{
38 return aResult
.fail(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE
);
41 bool getPrototype(JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
42 JS::MutableHandle
<JSObject
*> aProtop
) const override
{
47 bool setPrototype(JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
48 JS::Handle
<JSObject
*> aProto
,
49 JS::ObjectOpResult
& aResult
) const override
{
51 return aResult
.succeed();
53 return aResult
.failCantSetProto();
56 bool getPrototypeIfOrdinary(
57 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
, bool* aIsOrdinary
,
58 JS::MutableHandle
<JSObject
*> aProtop
) const override
{
63 bool setImmutablePrototype(JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
64 bool* aSucceeded
) const override
{
69 bool preventExtensions(JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
70 JS::ObjectOpResult
& aResult
) const override
{
75 bool isExtensible(JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
76 bool* aExtensible
) const override
{
81 bool set(JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
82 JS::Handle
<JS::PropertyKey
> aId
, JS::Handle
<JS::Value
> aValue
,
83 JS::Handle
<JS::Value
> aReceiver
,
84 JS::ObjectOpResult
& aResult
) const override
{
85 return aResult
.failReadOnly();
88 bool delete_(JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
89 JS::Handle
<JS::PropertyKey
> aId
,
90 JS::ObjectOpResult
& aResult
) const override
{
91 return aResult
.failCantDelete();
94 bool getOwnPropertyDescriptor(
95 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
96 JS::Handle
<JS::PropertyKey
> aId
,
97 JS::MutableHandle
<mozilla::Maybe
<JS::PropertyDescriptor
>> aDesc
)
99 bool has(JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
100 JS::Handle
<JS::PropertyKey
> aId
, bool* aBp
) const override
;
101 bool get(JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
102 JS::Handle
<JS::Value
> receiver
, JS::Handle
<JS::PropertyKey
> aId
,
103 JS::MutableHandle
<JS::Value
> aVp
) const override
;
104 bool ownPropertyKeys(
105 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
106 JS::MutableHandleVector
<JS::PropertyKey
> aProps
) const override
;
109 static JSObject
* getEnvironment(JS::Handle
<JSObject
*> aProxy
) {
110 return &js::GetProxyPrivate(aProxy
).toObject();
113 static bool equalsNamespace(JSContext
* aCx
, JS::Handle
<JS::PropertyKey
> aId
,
115 if (!aId
.isString()) {
119 return JS_StringEqualsLiteral(aCx
, aId
.toString(), "*namespace*", aMatch
);
123 static const char gFamily
;
124 static const ModuleEnvironmentProxyHandler gHandler
;
127 MOZ_RUNINIT
const ModuleEnvironmentProxyHandler
128 ModuleEnvironmentProxyHandler::gHandler
;
129 const char ModuleEnvironmentProxyHandler::gFamily
= 0;
131 bool ModuleEnvironmentProxyHandler::getOwnPropertyDescriptor(
132 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
133 JS::Handle
<JS::PropertyKey
> aId
,
134 JS::MutableHandle
<mozilla::Maybe
<JS::PropertyDescriptor
>> aDesc
) const {
136 if (!equalsNamespace(aCx
, aId
, &isNamespace
)) {
144 JS::Rooted
<JSObject
*> envObj(aCx
, getEnvironment(aProxy
));
145 if (!JS_GetOwnPropertyDescriptorById(aCx
, envObj
, aId
, aDesc
)) {
149 if (aDesc
.get().isNothing()) {
153 JS::PropertyDescriptor
& desc
= *aDesc
.get();
155 desc
.setConfigurable(false);
156 desc
.setWritable(false);
157 desc
.setEnumerable(true);
162 bool ModuleEnvironmentProxyHandler::has(JSContext
* aCx
,
163 JS::Handle
<JSObject
*> aProxy
,
164 JS::Handle
<JS::PropertyKey
> aId
,
167 if (!equalsNamespace(aCx
, aId
, &isNamespace
)) {
175 JS::Rooted
<JSObject
*> envObj(aCx
, getEnvironment(aProxy
));
176 return JS_HasOwnPropertyById(aCx
, envObj
, aId
, aBp
);
179 bool ModuleEnvironmentProxyHandler::get(
180 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
181 JS::Handle
<JS::Value
> aReceiver
, JS::Handle
<JS::PropertyKey
> aId
,
182 JS::MutableHandle
<JS::Value
> aVp
) const {
184 if (!equalsNamespace(aCx
, aId
, &isNamespace
)) {
192 JS::Rooted
<JSObject
*> envObj(aCx
, getEnvironment(aProxy
));
193 return JS_GetPropertyById(aCx
, envObj
, aId
, aVp
);
196 bool ModuleEnvironmentProxyHandler::ownPropertyKeys(
197 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
198 JS::MutableHandleVector
<JS::PropertyKey
> aProps
) const {
199 JS::Rooted
<JSObject
*> envObj(aCx
, getEnvironment(aProxy
));
200 JS::Rooted
<JS::IdVector
> ids(aCx
, JS::IdVector(aCx
));
201 if (!JS_Enumerate(aCx
, envObj
, &ids
)) {
205 for (size_t i
= 0; i
< ids
.length(); i
++) {
207 if (!equalsNamespace(aCx
, ids
[i
], &isNamespace
)) {
213 if (!aProps
.append(ids
[i
])) {
214 JS_ReportOutOfMemory(aCx
);
222 JSObject
* CreateModuleEnvironmentProxy(JSContext
* aCx
,
223 JS::Handle
<JSObject
*> aModuleObj
) {
224 js::ProxyOptions options
;
225 options
.setLazyProto(true);
227 JS::Rooted
<JSObject
*> envObj(aCx
, JS::GetModuleEnvironment(aCx
, aModuleObj
));
232 JS::Rooted
<JS::Value
> envVal(aCx
, JS::ObjectValue(*envObj
));
233 return NewProxyObject(aCx
, &ModuleEnvironmentProxyHandler::gHandler
, envVal
,
237 } // namespace loader
238 } // namespace mozilla