Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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/. */
6 :
7 : #include "vm/GlobalObject.h"
8 :
9 : #include "jscntxt.h"
10 : #include "jsdate.h"
11 : #include "jsexn.h"
12 : #include "jsfriendapi.h"
13 : #include "jsmath.h"
14 : #include "json.h"
15 : #include "jsprototypes.h"
16 : #include "jsweakmap.h"
17 :
18 : #include "builtin/AtomicsObject.h"
19 : #include "builtin/DataViewObject.h"
20 : #include "builtin/Eval.h"
21 : #if EXPOSE_INTL_API
22 : # include "builtin/Intl.h"
23 : #endif
24 : #include "builtin/MapObject.h"
25 : #include "builtin/ModuleObject.h"
26 : #include "builtin/Object.h"
27 : #include "builtin/Promise.h"
28 : #include "builtin/RegExp.h"
29 : #include "builtin/SelfHostingDefines.h"
30 : #include "builtin/SymbolObject.h"
31 : #include "builtin/TypedObject.h"
32 : #include "builtin/WeakMapObject.h"
33 : #include "builtin/WeakSetObject.h"
34 : #include "vm/Debugger.h"
35 : #include "vm/EnvironmentObject.h"
36 : #include "vm/HelperThreads.h"
37 : #include "vm/PIC.h"
38 : #include "vm/RegExpStatics.h"
39 : #include "vm/RegExpStaticsObject.h"
40 : #include "vm/StopIterationObject.h"
41 : #include "wasm/WasmJS.h"
42 :
43 : #include "jscompartmentinlines.h"
44 : #include "jsobjinlines.h"
45 : #include "jsscriptinlines.h"
46 :
47 : #include "vm/NativeObject-inl.h"
48 :
49 : using namespace js;
50 :
51 : struct ProtoTableEntry {
52 : const Class* clasp;
53 : ClassInitializerOp init;
54 : };
55 :
56 : namespace js {
57 :
58 : #define DECLARE_PROTOTYPE_CLASS_INIT(name,code,init,clasp) \
59 : extern JSObject* init(JSContext* cx, Handle<JSObject*> obj);
60 : JS_FOR_EACH_PROTOTYPE(DECLARE_PROTOTYPE_CLASS_INIT)
61 : #undef DECLARE_PROTOTYPE_CLASS_INIT
62 :
63 : } // namespace js
64 :
65 : JSObject*
66 0 : js::InitViaClassSpec(JSContext* cx, Handle<JSObject*> obj)
67 : {
68 0 : MOZ_CRASH("InitViaClassSpec() should not be called.");
69 : }
70 :
71 : static const ProtoTableEntry protoTable[JSProto_LIMIT] = {
72 : #define INIT_FUNC(name,code,init,clasp) { clasp, init },
73 : #define INIT_FUNC_DUMMY(name,code,init,clasp) { nullptr, nullptr },
74 : JS_FOR_PROTOTYPES(INIT_FUNC, INIT_FUNC_DUMMY)
75 : #undef INIT_FUNC_DUMMY
76 : #undef INIT_FUNC
77 3 : };
78 :
79 : JS_FRIEND_API(const js::Class*)
80 2166 : js::ProtoKeyToClass(JSProtoKey key)
81 : {
82 2166 : MOZ_ASSERT(key < JSProto_LIMIT);
83 2166 : return protoTable[key].clasp;
84 : }
85 :
86 : // This method is not in the header file to avoid having to include
87 : // TypedObject.h from GlobalObject.h. It is not generally perf
88 : // sensitive.
89 : TypedObjectModuleObject&
90 0 : js::GlobalObject::getTypedObjectModule() const {
91 0 : Value v = getConstructor(JSProto_TypedObject);
92 : // only gets called from contexts where TypedObject must be initialized
93 0 : MOZ_ASSERT(v.isObject());
94 0 : return v.toObject().as<TypedObjectModuleObject>();
95 : }
96 :
97 : /* static */ bool
98 1970 : GlobalObject::skipDeselectedConstructor(JSContext* cx, JSProtoKey key)
99 : {
100 1970 : if (key == JSProto_WebAssembly)
101 6 : return !wasm::HasSupport(cx);
102 :
103 : #ifdef ENABLE_SHARED_ARRAY_BUFFER
104 : // Return true if the given constructor has been disabled at run-time.
105 1964 : switch (key) {
106 : case JSProto_Atomics:
107 : case JSProto_SharedArrayBuffer:
108 12 : return !cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled();
109 : default:
110 1952 : return false;
111 : }
112 : #else
113 : return false;
114 : #endif
115 : }
116 :
117 : /* static */ bool
118 4695 : GlobalObject::ensureConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key)
119 : {
120 4695 : if (global->isStandardClassResolved(key))
121 3362 : return true;
122 1333 : return resolveConstructor(cx, global, key);
123 : }
124 :
125 : /* static*/ bool
126 1709 : GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key)
127 : {
128 1709 : MOZ_ASSERT(!global->isStandardClassResolved(key));
129 :
130 : // Prohibit collection of allocation metadata. Metadata builders shouldn't
131 : // need to observe lazily-constructed prototype objects coming into
132 : // existence. And assertions start to fail when the builder itself attempts
133 : // an allocation that re-entrantly tries to create the same prototype.
134 3419 : AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
135 :
136 : // Constructor resolution may execute self-hosted scripts. These
137 : // self-hosted scripts do not call out to user code by construction. Allow
138 : // all scripts to execute, even in debuggee compartments that are paused.
139 3419 : AutoSuppressDebuggeeNoExecuteChecks suppressNX(cx);
140 :
141 : // There are two different kinds of initialization hooks. One of them is
142 : // the class js::InitFoo hook, defined in a JSProtoKey-keyed table at the
143 : // top of this file. The other lives in the ClassSpec for classes that
144 : // define it. Classes may use one or the other, but not both.
145 1709 : ClassInitializerOp init = protoTable[key].init;
146 1709 : if (init == InitViaClassSpec)
147 1418 : init = nullptr;
148 :
149 1709 : const Class* clasp = ProtoKeyToClass(key);
150 1709 : if (!init && !clasp)
151 30 : return true; // JSProto_Null or a compile-time-disabled feature.
152 :
153 1679 : if (skipDeselectedConstructor(cx, key))
154 0 : return true;
155 :
156 : // Some classes have no init routine, which means that they're disabled at
157 : // compile-time. We could try to enforce that callers never pass such keys
158 : // to resolveConstructor, but that would cramp the style of consumers like
159 : // GlobalObject::initStandardClasses that want to just carpet-bomb-call
160 : // ensureConstructor with every JSProtoKey. So it's easier to just handle
161 : // it here.
162 1679 : bool haveSpec = clasp && clasp->specDefined();
163 1679 : if (!init && !haveSpec)
164 0 : return true;
165 :
166 : // See if there's an old-style initialization hook.
167 1679 : if (init) {
168 261 : MOZ_ASSERT(!haveSpec);
169 261 : return init(cx, global);
170 : }
171 :
172 : //
173 : // Ok, we're doing it with a class spec.
174 : //
175 :
176 1418 : bool isObjectOrFunction = key == JSProto_Function || key == JSProto_Object;
177 :
178 : // We need to create the prototype first, and immediately stash it in the
179 : // slot. This is so the following bootstrap ordering is possible:
180 : // * Object.prototype
181 : // * Function.prototype
182 : // * Function
183 : // * Object
184 : //
185 : // We get the above when Object is resolved before Function. If Function
186 : // is resolved before Object, we'll end up re-entering resolveConstructor
187 : // for Function, which is a problem. So if Function is being resolved
188 : // before Object.prototype exists, we just resolve Object instead, since we
189 : // know that Function will also be resolved before we return.
190 1418 : if (key == JSProto_Function && global->getPrototype(JSProto_Object).isUndefined())
191 16 : return resolveConstructor(cx, global, JSProto_Object);
192 :
193 : // We don't always have a prototype (i.e. Math and JSON). If we don't,
194 : // |createPrototype|, |prototypeFunctions|, and |prototypeProperties|
195 : // should all be null.
196 2805 : RootedObject proto(cx);
197 1402 : if (ClassObjectCreationOp createPrototype = clasp->specCreatePrototypeHook()) {
198 1402 : proto = createPrototype(cx, key);
199 1402 : if (!proto)
200 0 : return false;
201 :
202 1402 : if (isObjectOrFunction) {
203 : // Make sure that creating the prototype didn't recursively resolve
204 : // our own constructor. We can't just assert that there's no
205 : // prototype; OOMs can result in incomplete resolutions in which
206 : // the prototype is saved but not the constructor. So use the same
207 : // criteria that protects entry into this function.
208 622 : MOZ_ASSERT(!global->isStandardClassResolved(key));
209 :
210 622 : global->setPrototype(key, ObjectValue(*proto));
211 : }
212 : }
213 :
214 : // Create the constructor.
215 2805 : RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, key));
216 1402 : if (!ctor)
217 0 : return false;
218 :
219 2805 : RootedId id(cx, NameToId(ClassName(key, cx)));
220 1402 : if (isObjectOrFunction) {
221 622 : if (clasp->specShouldDefineConstructor()) {
222 1244 : RootedValue ctorValue(cx, ObjectValue(*ctor));
223 622 : if (!DefineProperty(cx, global, id, ctorValue, nullptr, nullptr, JSPROP_RESOLVING))
224 0 : return false;
225 : }
226 :
227 622 : global->setConstructor(key, ObjectValue(*ctor));
228 : }
229 :
230 : // If we're operating on the self-hosting global, we don't want any
231 : // functions and properties on the builtins and their prototypes.
232 1402 : if (!cx->runtime()->isSelfHostingGlobal(global)) {
233 1396 : if (const JSFunctionSpec* funs = clasp->specPrototypeFunctions()) {
234 1274 : if (!JS_DefineFunctions(cx, proto, funs))
235 0 : return false;
236 : }
237 1396 : if (const JSPropertySpec* props = clasp->specPrototypeProperties()) {
238 1083 : if (!JS_DefineProperties(cx, proto, props))
239 0 : return false;
240 : }
241 1396 : if (const JSFunctionSpec* funs = clasp->specConstructorFunctions()) {
242 747 : if (!JS_DefineFunctions(cx, ctor, funs))
243 0 : return false;
244 : }
245 1397 : if (const JSPropertySpec* props = clasp->specConstructorProperties()) {
246 605 : if (!JS_DefineProperties(cx, ctor, props))
247 0 : return false;
248 : }
249 : }
250 :
251 : // If the prototype exists, link it with the constructor.
252 1403 : if (proto && !LinkConstructorAndPrototype(cx, ctor, proto))
253 0 : return false;
254 :
255 : // Call the post-initialization hook, if provided.
256 1403 : if (FinishClassInitOp finishInit = clasp->specFinishInitHook()) {
257 687 : if (!finishInit(cx, ctor, proto))
258 0 : return false;
259 : }
260 :
261 1403 : if (!isObjectOrFunction) {
262 : // Any operations that modifies the global object should be placed
263 : // after any other fallible operations.
264 :
265 : // Fallible operation that modifies the global object.
266 781 : if (clasp->specShouldDefineConstructor()) {
267 1378 : RootedValue ctorValue(cx, ObjectValue(*ctor));
268 689 : if (!DefineProperty(cx, global, id, ctorValue, nullptr, nullptr, JSPROP_RESOLVING))
269 0 : return false;
270 : }
271 :
272 : // Infallible operations that modify the global object.
273 781 : global->setConstructor(key, ObjectValue(*ctor));
274 781 : if (proto)
275 781 : global->setPrototype(key, ObjectValue(*proto));
276 : }
277 :
278 1403 : return true;
279 : }
280 :
281 : /* static */ bool
282 194 : GlobalObject::initBuiltinConstructor(JSContext* cx, Handle<GlobalObject*> global,
283 : JSProtoKey key, HandleObject ctor, HandleObject proto)
284 : {
285 194 : MOZ_ASSERT(!global->empty()); // reserved slots already allocated
286 194 : MOZ_ASSERT(key != JSProto_Null);
287 194 : MOZ_ASSERT(ctor);
288 194 : MOZ_ASSERT(proto);
289 :
290 388 : RootedId id(cx, NameToId(ClassName(key, cx)));
291 194 : MOZ_ASSERT(!global->lookup(cx, id));
292 :
293 388 : RootedValue ctorValue(cx, ObjectValue(*ctor));
294 194 : if (!DefineProperty(cx, global, id, ctorValue, nullptr, nullptr, JSPROP_RESOLVING))
295 0 : return false;
296 :
297 194 : global->setConstructor(key, ObjectValue(*ctor));
298 194 : global->setPrototype(key, ObjectValue(*proto));
299 194 : return true;
300 : }
301 :
302 : GlobalObject*
303 311 : GlobalObject::createInternal(JSContext* cx, const Class* clasp)
304 : {
305 311 : MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
306 311 : MOZ_ASSERT(clasp->isTrace(JS_GlobalObjectTraceHook));
307 :
308 311 : JSObject* obj = NewObjectWithGivenProto(cx, clasp, nullptr, SingletonObject);
309 311 : if (!obj)
310 0 : return nullptr;
311 :
312 622 : Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
313 311 : MOZ_ASSERT(global->isUnqualifiedVarObj());
314 :
315 : // Initialize the private slot to null if present, as GC can call class
316 : // hooks before the caller gets to set this to a non-garbage value.
317 311 : if (clasp->flags & JSCLASS_HAS_PRIVATE)
318 284 : global->setPrivate(nullptr);
319 :
320 : Rooted<LexicalEnvironmentObject*> lexical(cx,
321 622 : LexicalEnvironmentObject::createGlobal(cx, global));
322 311 : if (!lexical)
323 0 : return nullptr;
324 311 : global->setReservedSlot(LEXICAL_ENVIRONMENT, ObjectValue(*lexical));
325 :
326 622 : Rooted<GlobalScope*> emptyGlobalScope(cx, GlobalScope::createEmpty(cx, ScopeKind::Global));
327 311 : if (!emptyGlobalScope)
328 0 : return nullptr;
329 311 : global->setReservedSlot(EMPTY_GLOBAL_SCOPE, PrivateGCThingValue(emptyGlobalScope));
330 :
331 311 : cx->compartment()->initGlobal(*global);
332 :
333 311 : if (!JSObject::setQualifiedVarObj(cx, global))
334 0 : return nullptr;
335 311 : if (!JSObject::setDelegate(cx, global))
336 0 : return nullptr;
337 :
338 311 : return global;
339 : }
340 :
341 : /* static */ GlobalObject*
342 308 : GlobalObject::new_(JSContext* cx, const Class* clasp, JSPrincipals* principals,
343 : JS::OnNewGlobalHookOption hookOption,
344 : const JS::CompartmentOptions& options)
345 : {
346 308 : MOZ_ASSERT(!cx->isExceptionPending());
347 308 : MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
348 :
349 308 : JSCompartment* compartment = NewCompartment(cx, principals, options);
350 308 : if (!compartment)
351 0 : return nullptr;
352 :
353 616 : Rooted<GlobalObject*> global(cx);
354 : {
355 616 : AutoCompartmentUnchecked ac(cx, compartment);
356 308 : global = GlobalObject::createInternal(cx, clasp);
357 308 : if (!global)
358 0 : return nullptr;
359 :
360 308 : if (hookOption == JS::FireOnNewGlobalHook)
361 16 : JS_FireOnNewGlobalObject(cx, global);
362 : }
363 :
364 308 : return global;
365 : }
366 :
367 : LexicalEnvironmentObject&
368 53013 : GlobalObject::lexicalEnvironment() const
369 : {
370 53013 : return getReservedSlot(LEXICAL_ENVIRONMENT).toObject().as<LexicalEnvironmentObject>();
371 : }
372 :
373 : GlobalScope&
374 4879 : GlobalObject::emptyGlobalScope() const
375 : {
376 4879 : const Value& v = getReservedSlot(EMPTY_GLOBAL_SCOPE);
377 4879 : MOZ_ASSERT(v.isPrivateGCThing() && v.traceKind() == JS::TraceKind::Scope);
378 4879 : return static_cast<Scope*>(v.toGCThing())->as<GlobalScope>();
379 : }
380 :
381 : /* static */ bool
382 0 : GlobalObject::getOrCreateEval(JSContext* cx, Handle<GlobalObject*> global,
383 : MutableHandleObject eval)
384 : {
385 0 : if (!getOrCreateObjectPrototype(cx, global))
386 0 : return false;
387 0 : eval.set(&global->getSlot(EVAL).toObject());
388 0 : return true;
389 : }
390 :
391 : bool
392 2 : GlobalObject::valueIsEval(const Value& val)
393 : {
394 2 : Value eval = getSlot(EVAL);
395 2 : return eval.isObject() && eval == val;
396 : }
397 :
398 : /* static */ bool
399 6 : GlobalObject::initStandardClasses(JSContext* cx, Handle<GlobalObject*> global)
400 : {
401 : /* Define a top-level property 'undefined' with the undefined value. */
402 6 : if (!DefineProperty(cx, global, cx->names().undefined, UndefinedHandleValue,
403 : nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING))
404 : {
405 0 : return false;
406 : }
407 :
408 342 : for (size_t k = 0; k < JSProto_LIMIT; ++k) {
409 336 : if (!ensureConstructor(cx, global, static_cast<JSProtoKey>(k)))
410 0 : return false;
411 : }
412 6 : return true;
413 : }
414 :
415 : /**
416 : * Initializes a builtin constructor and its prototype without defining any
417 : * properties or functions on it.
418 : *
419 : * Used in self-hosting to install the few builtin constructors required by
420 : * self-hosted builtins.
421 : */
422 : static bool
423 12 : InitBareBuiltinCtor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey protoKey)
424 : {
425 12 : MOZ_ASSERT(cx->runtime()->isSelfHostingGlobal(global));
426 12 : const Class* clasp = ProtoKeyToClass(protoKey);
427 24 : RootedObject proto(cx);
428 12 : proto = clasp->specCreatePrototypeHook()(cx, protoKey);
429 12 : if (!proto)
430 0 : return false;
431 :
432 24 : RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, protoKey));
433 12 : if (!ctor)
434 0 : return false;
435 :
436 12 : return GlobalObject::initBuiltinConstructor(cx, global, protoKey, ctor, proto);
437 : }
438 :
439 : /**
440 : * The self-hosting global only gets a small subset of all standard classes.
441 : * Even those are only created as bare constructors without any properties
442 : * or functions.
443 : */
444 : /* static */ bool
445 3 : GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> global,
446 : const JSFunctionSpec* builtins)
447 : {
448 : // Define a top-level property 'undefined' with the undefined value.
449 3 : if (!DefineProperty(cx, global, cx->names().undefined, UndefinedHandleValue,
450 : nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY))
451 : {
452 0 : return false;
453 : }
454 :
455 6 : RootedValue std_isConcatSpreadable(cx);
456 3 : std_isConcatSpreadable.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::isConcatSpreadable));
457 3 : if (!JS_DefineProperty(cx, global, "std_isConcatSpreadable", std_isConcatSpreadable,
458 : JSPROP_PERMANENT | JSPROP_READONLY))
459 : {
460 0 : return false;
461 : }
462 :
463 : // Define a top-level property 'std_iterator' with the name of the method
464 : // used by for-of loops to create an iterator.
465 6 : RootedValue std_iterator(cx);
466 3 : std_iterator.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::iterator));
467 3 : if (!JS_DefineProperty(cx, global, "std_iterator", std_iterator,
468 : JSPROP_PERMANENT | JSPROP_READONLY))
469 : {
470 0 : return false;
471 : }
472 :
473 6 : RootedValue std_match(cx);
474 3 : std_match.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::match));
475 3 : if (!JS_DefineProperty(cx, global, "std_match", std_match,
476 : JSPROP_PERMANENT | JSPROP_READONLY))
477 : {
478 0 : return false;
479 : }
480 :
481 6 : RootedValue std_replace(cx);
482 3 : std_replace.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::replace));
483 3 : if (!JS_DefineProperty(cx, global, "std_replace", std_replace,
484 : JSPROP_PERMANENT | JSPROP_READONLY))
485 : {
486 0 : return false;
487 : }
488 :
489 6 : RootedValue std_search(cx);
490 3 : std_search.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::search));
491 3 : if (!JS_DefineProperty(cx, global, "std_search", std_search,
492 : JSPROP_PERMANENT | JSPROP_READONLY))
493 : {
494 0 : return false;
495 : }
496 :
497 6 : RootedValue std_species(cx);
498 3 : std_species.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::species));
499 3 : if (!JS_DefineProperty(cx, global, "std_species", std_species,
500 : JSPROP_PERMANENT | JSPROP_READONLY))
501 : {
502 0 : return false;
503 : }
504 :
505 6 : RootedValue std_split(cx);
506 3 : std_split.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::split));
507 3 : if (!JS_DefineProperty(cx, global, "std_split", std_split,
508 : JSPROP_PERMANENT | JSPROP_READONLY))
509 : {
510 0 : return false;
511 : }
512 :
513 6 : return InitBareBuiltinCtor(cx, global, JSProto_Array) &&
514 6 : InitBareBuiltinCtor(cx, global, JSProto_TypedArray) &&
515 6 : InitBareBuiltinCtor(cx, global, JSProto_Uint8Array) &&
516 9 : InitBareBuiltinCtor(cx, global, JSProto_Int32Array) &&
517 18 : InitBareSymbolCtor(cx, global) &&
518 15 : InitBareWeakMapCtor(cx, global) &&
519 21 : InitStopIterationClass(cx, global) &&
520 9 : DefineFunctions(cx, global, builtins, AsIntrinsic);
521 : }
522 :
523 : /* static */ bool
524 6 : GlobalObject::isRuntimeCodeGenEnabled(JSContext* cx, Handle<GlobalObject*> global)
525 : {
526 6 : HeapSlot& v = global->getSlotRef(RUNTIME_CODEGEN_ENABLED);
527 6 : if (v.isUndefined()) {
528 : /*
529 : * If there are callbacks, make sure that the CSP callback is installed
530 : * and that it permits runtime code generation, then cache the result.
531 : */
532 2 : JSCSPEvalChecker allows = cx->runtime()->securityCallbacks->contentSecurityPolicyAllows;
533 2 : Value boolValue = BooleanValue(!allows || allows(cx));
534 2 : v.set(global, HeapSlot::Slot, RUNTIME_CODEGEN_ENABLED, boolValue);
535 : }
536 6 : return !v.isFalse();
537 : }
538 :
539 : /* static */ bool
540 0 : GlobalObject::warnOnceAbout(JSContext* cx, HandleObject obj, WarnOnceFlag flag,
541 : unsigned errorNumber)
542 : {
543 0 : Rooted<GlobalObject*> global(cx, &obj->global());
544 0 : HeapSlot& v = global->getSlotRef(WARNED_ONCE_FLAGS);
545 0 : MOZ_ASSERT_IF(!v.isUndefined(), v.toInt32());
546 0 : int32_t flags = v.isUndefined() ? 0 : v.toInt32();
547 0 : if (!(flags & flag)) {
548 0 : if (!JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
549 : errorNumber))
550 : {
551 0 : return false;
552 : }
553 0 : if (v.isUndefined())
554 0 : v.init(global, HeapSlot::Slot, WARNED_ONCE_FLAGS, Int32Value(flags | flag));
555 : else
556 0 : v.set(global, HeapSlot::Slot, WARNED_ONCE_FLAGS, Int32Value(flags | flag));
557 : }
558 0 : return true;
559 : }
560 :
561 : /* static */ JSFunction*
562 869 : GlobalObject::createConstructor(JSContext* cx, Native ctor, JSAtom* nameArg, unsigned length,
563 : gc::AllocKind kind, const JSJitInfo* jitInfo)
564 : {
565 1738 : RootedAtom name(cx, nameArg);
566 869 : JSFunction* fun = NewNativeConstructor(cx, ctor, length, name, kind);
567 869 : if (!fun)
568 0 : return nullptr;
569 :
570 869 : if (jitInfo)
571 346 : fun->setJitInfo(jitInfo);
572 :
573 869 : return fun;
574 : }
575 :
576 : static NativeObject*
577 979 : CreateBlankProto(JSContext* cx, const Class* clasp, HandleObject proto, HandleObject global)
578 : {
579 979 : MOZ_ASSERT(clasp != &JSFunction::class_);
580 :
581 1958 : RootedNativeObject blankProto(cx, NewNativeObjectWithGivenProto(cx, clasp, proto,
582 1958 : SingletonObject));
583 979 : if (!blankProto || !JSObject::setDelegate(cx, blankProto))
584 0 : return nullptr;
585 :
586 979 : return blankProto;
587 : }
588 :
589 : /* static */ NativeObject*
590 600 : GlobalObject::createBlankPrototype(JSContext* cx, Handle<GlobalObject*> global, const Class* clasp)
591 : {
592 1200 : RootedObject objectProto(cx, getOrCreateObjectPrototype(cx, global));
593 600 : if (!objectProto)
594 0 : return nullptr;
595 :
596 600 : return CreateBlankProto(cx, clasp, objectProto, global);
597 : }
598 :
599 : /* static */ NativeObject*
600 379 : GlobalObject::createBlankPrototypeInheriting(JSContext* cx, Handle<GlobalObject*> global,
601 : const Class* clasp, HandleObject proto)
602 : {
603 379 : return CreateBlankProto(cx, clasp, proto, global);
604 : }
605 :
606 : bool
607 2342 : js::LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor_, JSObject* proto_,
608 : unsigned prototypeAttrs, unsigned constructorAttrs)
609 : {
610 4684 : RootedObject ctor(cx, ctor_), proto(cx, proto_);
611 :
612 4684 : RootedValue protoVal(cx, ObjectValue(*proto));
613 4684 : RootedValue ctorVal(cx, ObjectValue(*ctor));
614 :
615 11710 : return DefineProperty(cx, ctor, cx->names().prototype, protoVal, nullptr, nullptr,
616 16394 : prototypeAttrs) &&
617 9368 : DefineProperty(cx, proto, cx->names().constructor, ctorVal, nullptr, nullptr,
618 4684 : constructorAttrs);
619 : }
620 :
621 : bool
622 646 : js::DefinePropertiesAndFunctions(JSContext* cx, HandleObject obj,
623 : const JSPropertySpec* ps, const JSFunctionSpec* fs)
624 : {
625 646 : if (ps && !JS_DefineProperties(cx, obj, ps))
626 0 : return false;
627 646 : if (fs && !JS_DefineFunctions(cx, obj, fs))
628 0 : return false;
629 646 : return true;
630 : }
631 :
632 : bool
633 504 : js::DefineToStringTag(JSContext* cx, HandleObject obj, JSAtom* tag)
634 : {
635 1008 : RootedId toStringTagId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().toStringTag));
636 1008 : RootedValue tagString(cx, StringValue(tag));
637 1008 : return DefineProperty(cx, obj, toStringTagId, tagString, nullptr, nullptr, JSPROP_READONLY);
638 : }
639 :
640 : static void
641 0 : GlobalDebuggees_finalize(FreeOp* fop, JSObject* obj)
642 : {
643 0 : MOZ_ASSERT(fop->maybeOnHelperThread());
644 0 : fop->delete_((GlobalObject::DebuggerVector*) obj->as<NativeObject>().getPrivate());
645 0 : }
646 :
647 : static const ClassOps
648 : GlobalDebuggees_classOps = {
649 : nullptr,
650 : nullptr,
651 : nullptr,
652 : nullptr,
653 : nullptr,
654 : nullptr,
655 : nullptr,
656 : nullptr,
657 : GlobalDebuggees_finalize
658 : };
659 :
660 : static const Class
661 : GlobalDebuggees_class = {
662 : "GlobalDebuggee",
663 : JSCLASS_HAS_PRIVATE |
664 : JSCLASS_BACKGROUND_FINALIZE,
665 : &GlobalDebuggees_classOps
666 : };
667 :
668 : GlobalObject::DebuggerVector*
669 13051 : GlobalObject::getDebuggers() const
670 : {
671 13051 : Value debuggers = getReservedSlot(DEBUGGERS);
672 13051 : if (debuggers.isUndefined())
673 13051 : return nullptr;
674 0 : MOZ_ASSERT(debuggers.toObject().getClass() == &GlobalDebuggees_class);
675 0 : return (DebuggerVector*) debuggers.toObject().as<NativeObject>().getPrivate();
676 : }
677 :
678 : /* static */ GlobalObject::DebuggerVector*
679 0 : GlobalObject::getOrCreateDebuggers(JSContext* cx, Handle<GlobalObject*> global)
680 : {
681 0 : assertSameCompartment(cx, global);
682 0 : DebuggerVector* debuggers = global->getDebuggers();
683 0 : if (debuggers)
684 0 : return debuggers;
685 :
686 0 : NativeObject* obj = NewNativeObjectWithGivenProto(cx, &GlobalDebuggees_class, nullptr);
687 0 : if (!obj)
688 0 : return nullptr;
689 0 : debuggers = cx->new_<DebuggerVector>();
690 0 : if (!debuggers)
691 0 : return nullptr;
692 0 : obj->setPrivate(debuggers);
693 0 : global->setReservedSlot(DEBUGGERS, ObjectValue(*obj));
694 0 : return debuggers;
695 : }
696 :
697 : /* static */ NativeObject*
698 18 : GlobalObject::getOrCreateForOfPICObject(JSContext* cx, Handle<GlobalObject*> global)
699 : {
700 18 : assertSameCompartment(cx, global);
701 18 : NativeObject* forOfPIC = global->getForOfPICObject();
702 18 : if (forOfPIC)
703 0 : return forOfPIC;
704 :
705 18 : forOfPIC = ForOfPIC::createForOfPICObject(cx, global);
706 18 : if (!forOfPIC)
707 0 : return nullptr;
708 18 : global->setReservedSlot(FOR_OF_PIC_CHAIN, ObjectValue(*forOfPIC));
709 18 : return forOfPIC;
710 : }
711 :
712 : bool
713 0 : GlobalObject::hasRegExpStatics() const
714 : {
715 0 : return !getSlot(REGEXP_STATICS).isUndefined();
716 : }
717 :
718 : /* static */ RegExpStatics*
719 264 : GlobalObject::getRegExpStatics(JSContext* cx, Handle<GlobalObject*> global)
720 : {
721 264 : MOZ_ASSERT(cx);
722 264 : RegExpStaticsObject* resObj = nullptr;
723 264 : const Value& val = global->getSlot(REGEXP_STATICS);
724 264 : if (!val.isObject()) {
725 13 : MOZ_ASSERT(val.isUndefined());
726 13 : resObj = RegExpStatics::create(cx, global);
727 13 : if (!resObj)
728 0 : return nullptr;
729 :
730 13 : global->initSlot(REGEXP_STATICS, ObjectValue(*resObj));
731 : } else {
732 251 : resObj = &val.toObject().as<RegExpStaticsObject>();
733 : }
734 264 : return static_cast<RegExpStatics*>(resObj->getPrivate(/* nfixed = */ 1));
735 : }
736 :
737 : RegExpStatics*
738 0 : GlobalObject::getAlreadyCreatedRegExpStatics() const
739 : {
740 0 : const Value& val = this->getSlot(REGEXP_STATICS);
741 0 : MOZ_ASSERT(val.isObject());
742 0 : return static_cast<RegExpStatics*>(val.toObject().as<RegExpStaticsObject>().getPrivate(/* nfixed = */ 1));
743 : }
744 :
745 : /* static */ NativeObject*
746 61816 : GlobalObject::getIntrinsicsHolder(JSContext* cx, Handle<GlobalObject*> global)
747 : {
748 61816 : Value slot = global->getReservedSlot(INTRINSICS);
749 61816 : MOZ_ASSERT(slot.isUndefined() || slot.isObject());
750 :
751 61816 : if (slot.isObject())
752 61505 : return &slot.toObject().as<NativeObject>();
753 :
754 622 : Rooted<NativeObject*> intrinsicsHolder(cx);
755 311 : bool isSelfHostingGlobal = cx->runtime()->isSelfHostingGlobal(global);
756 311 : if (isSelfHostingGlobal) {
757 3 : intrinsicsHolder = global;
758 : } else {
759 308 : intrinsicsHolder = NewObjectWithGivenProto<PlainObject>(cx, nullptr, TenuredObject);
760 308 : if (!intrinsicsHolder)
761 0 : return nullptr;
762 : }
763 :
764 : /* Define a property 'global' with the current global as its value. */
765 622 : RootedValue globalValue(cx, ObjectValue(*global));
766 311 : if (!DefineProperty(cx, intrinsicsHolder, cx->names().global, globalValue,
767 : nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY))
768 : {
769 0 : return nullptr;
770 : }
771 :
772 : // Install the intrinsics holder in the intrinsics.
773 311 : global->setReservedSlot(INTRINSICS, ObjectValue(*intrinsicsHolder));
774 311 : return intrinsicsHolder;
775 : }
776 :
777 : /* static */ bool
778 20912 : GlobalObject::getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global,
779 : HandlePropertyName selfHostedName, HandleAtom name,
780 : unsigned nargs, MutableHandleValue funVal)
781 : {
782 20912 : bool exists = false;
783 20912 : if (!GlobalObject::maybeGetIntrinsicValue(cx, global, selfHostedName, funVal, &exists))
784 0 : return false;
785 20912 : if (exists) {
786 2124 : RootedFunction fun(cx, &funVal.toObject().as<JSFunction>());
787 1062 : if (fun->explicitName() == name)
788 883 : return true;
789 :
790 179 : if (fun->explicitName() == selfHostedName) {
791 : // This function was initially cloned because it was called by
792 : // other self-hosted code, so the clone kept its self-hosted name,
793 : // instead of getting the name it's intended to have in content
794 : // compartments. This can happen when a lazy builtin is initialized
795 : // after self-hosted code for another builtin used the same
796 : // function. In that case, we need to change the function's name,
797 : // which is ok because it can't have been exposed to content
798 : // before.
799 0 : fun->initAtom(name);
800 0 : return true;
801 : }
802 :
803 :
804 : // The function might be installed multiple times on the same or
805 : // different builtins, under different property names, so its name
806 : // might be neither "selfHostedName" nor "name". In that case, its
807 : // canonical name must've been set using the `_SetCanonicalName`
808 : // intrinsic.
809 179 : cx->runtime()->assertSelfHostedFunctionHasCanonicalName(cx, selfHostedName);
810 179 : return true;
811 : }
812 :
813 39701 : RootedFunction fun(cx);
814 19850 : if (!cx->runtime()->createLazySelfHostedFunctionClone(cx, selfHostedName, name, nargs,
815 : /* proto = */ nullptr,
816 : SingletonObject, &fun))
817 : {
818 0 : return false;
819 : }
820 19851 : funVal.setObject(*fun);
821 :
822 19851 : return GlobalObject::addIntrinsicValue(cx, global, selfHostedName, funVal);
823 : }
824 :
825 : /* static */ bool
826 22132 : GlobalObject::addIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
827 : HandlePropertyName name, HandleValue value)
828 : {
829 44264 : RootedNativeObject holder(cx, GlobalObject::getIntrinsicsHolder(cx, global));
830 22132 : if (!holder)
831 0 : return false;
832 :
833 22132 : uint32_t slot = holder->slotSpan();
834 44264 : RootedShape last(cx, holder->lastProperty());
835 44264 : Rooted<UnownedBaseShape*> base(cx, last->base()->unowned());
836 :
837 44264 : RootedId id(cx, NameToId(name));
838 44264 : Rooted<StackShape> child(cx, StackShape(base, id, slot, 0, 0));
839 22132 : Shape* shape = cx->zone()->propertyTree().getChild(cx, last, child);
840 22132 : if (!shape)
841 0 : return false;
842 :
843 22132 : if (!holder->setLastProperty(cx, shape))
844 0 : return false;
845 :
846 22132 : holder->setSlot(shape->slot(), value);
847 22132 : return true;
848 : }
849 :
850 : /* static */ bool
851 0 : GlobalObject::ensureModulePrototypesCreated(JSContext *cx, Handle<GlobalObject*> global)
852 : {
853 0 : return getOrCreateObject(cx, global, MODULE_PROTO, initModuleProto) &&
854 0 : getOrCreateObject(cx, global, IMPORT_ENTRY_PROTO, initImportEntryProto) &&
855 0 : getOrCreateObject(cx, global, EXPORT_ENTRY_PROTO, initExportEntryProto);
856 : }
|