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:
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "js/Object.h" // JS::GetReservedSlot, JS::SetReservedSlot
9 #include "js/PropertyAndElement.h" // JS_DefineProperty, JS_DefinePropertyById
10 #include "jsapi-tests/tests.h"
13 * Test that resolve hook recursion for the same object and property is
16 BEGIN_TEST(testResolveRecursion
) {
17 static const JSClassOps my_resolve_classOps
= {
18 nullptr, // addProperty
19 nullptr, // delProperty
21 nullptr, // newEnumerate
22 my_resolve
, // resolve
23 nullptr, // mayResolve
30 static const JSClass my_resolve_class
= {
31 "MyResolve", JSCLASS_HAS_RESERVED_SLOTS(SlotCount
), &my_resolve_classOps
};
33 obj1
.init(cx
, JS_NewObject(cx
, &my_resolve_class
));
35 obj2
.init(cx
, JS_NewObject(cx
, &my_resolve_class
));
37 JS::SetReservedSlot(obj1
, TestSlot
, JS::PrivateValue(this));
38 JS::SetReservedSlot(obj2
, TestSlot
, JS::PrivateValue(this));
40 JS::RootedValue
obj1Val(cx
, JS::ObjectValue(*obj1
));
41 JS::RootedValue
obj2Val(cx
, JS::ObjectValue(*obj2
));
42 CHECK(JS_DefineProperty(cx
, global
, "obj1", obj1Val
, 0));
43 CHECK(JS_DefineProperty(cx
, global
, "obj2", obj2Val
, 0));
45 resolveEntryCount
= 0;
48 /* Start the essence of the test via invoking the first resolve hook. */
49 JS::RootedValue
v(cx
);
52 CHECK_EQUAL(resolveEntryCount
, 4);
53 CHECK_EQUAL(resolveExitCount
, 4);
60 enum Slots
{ TestSlot
, SlotCount
};
62 JS::PersistentRootedObject obj1
;
63 JS::PersistentRootedObject obj2
;
64 int resolveEntryCount
;
67 struct AutoIncrCounters
{
68 explicit AutoIncrCounters(cls_testResolveRecursion
* t
) : t(t
) {
69 t
->resolveEntryCount
++;
72 ~AutoIncrCounters() { t
->resolveExitCount
++; }
74 cls_testResolveRecursion
* t
;
77 bool doResolve(JS::HandleObject obj
, JS::HandleId id
, bool* resolvedp
) {
78 CHECK_EQUAL(resolveExitCount
, 0);
79 AutoIncrCounters
incr(this);
80 CHECK(obj
== obj1
|| obj
== obj2
);
84 JSLinearString
* str
= JS_EnsureLinearString(cx
, id
.toString());
86 JS::RootedValue
v(cx
);
87 if (JS_LinearStringEqualsLiteral(str
, "x")) {
89 /* First resolve hook invocation. */
90 CHECK_EQUAL(resolveEntryCount
, 1);
91 EVAL("obj2.y = true", &v
);
93 CHECK(JS_DefinePropertyById(cx
, obj
, id
, JS::FalseHandleValue
,
99 CHECK_EQUAL(resolveEntryCount
, 4);
103 } else if (JS_LinearStringEqualsLiteral(str
, "y")) {
105 CHECK_EQUAL(resolveEntryCount
, 2);
106 CHECK(JS_DefinePropertyById(cx
, obj
, id
, JS::NullHandleValue
,
109 CHECK(v
.isUndefined());
116 CHECK_EQUAL(resolveEntryCount
, 3);
118 CHECK(v
.isUndefined());
120 CHECK(v
.isUndefined());
124 CHECK(v
.isUndefined());
125 EVAL("obj1.y = 0", &v
);
135 static bool my_resolve(JSContext
* cx
, JS::HandleObject obj
, JS::HandleId id
,
137 void* p
= JS::GetReservedSlot(obj
, TestSlot
).toPrivate();
138 return static_cast<cls_testResolveRecursion
*>(p
)->doResolve(obj
, id
,
141 END_TEST(testResolveRecursion
)
144 * Test that JS_InitStandardClasses does not cause resolve hooks to be called.
146 * (XPConnect apparently does have global classes, such as the one created by
147 * nsMessageManagerScriptExecutor::InitChildGlobalInternal(), that have resolve
148 * hooks which can call back into JS, and on which JS_InitStandardClasses is
149 * called. Calling back into JS in the middle of resolving `undefined` is bad.)
151 BEGIN_TEST(testResolveRecursion_InitStandardClasses
) {
152 CHECK(JS::InitRealmStandardClasses(cx
));
156 const JSClass
* getGlobalClass() override
{
157 static const JSClassOps myGlobalClassOps
= {
158 nullptr, // addProperty
159 nullptr, // delProperty
160 nullptr, // enumerate
161 nullptr, // newEnumerate
162 my_resolve
, // resolve
163 nullptr, // mayResolve
166 nullptr, // construct
167 JS_GlobalObjectTraceHook
, // trace
170 static const JSClass myGlobalClass
= {
171 "testResolveRecursion_InitStandardClasses_myGlobalClass",
172 JSCLASS_GLOBAL_FLAGS
, &myGlobalClassOps
};
174 return &myGlobalClass
;
177 static bool my_resolve(JSContext
* cx
, JS::HandleObject obj
, JS::HandleId id
,
179 MOZ_ASSERT_UNREACHABLE(
180 "resolve hook should not be called from InitStandardClasses");
181 JS_ReportErrorASCII(cx
, "FAIL");
184 END_TEST(testResolveRecursion_InitStandardClasses
)