Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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/. */
7 #include "vm/GlobalObject.h"
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 #include "jsworkers.h"
19 #include "builtin/Eval.h"
20 #if EXPOSE_INTL_API
21 # include "builtin/Intl.h"
22 #endif
23 #include "builtin/MapObject.h"
24 #include "builtin/Object.h"
25 #include "builtin/RegExp.h"
26 #include "builtin/SIMD.h"
27 #include "builtin/TypedObject.h"
28 #include "vm/PIC.h"
29 #include "vm/RegExpStatics.h"
30 #include "vm/StopIterationObject.h"
31 #include "vm/WeakMapObject.h"
33 #include "jscompartmentinlines.h"
34 #include "jsobjinlines.h"
35 #include "jsscriptinlines.h"
37 #include "vm/ObjectImpl-inl.h"
39 using namespace js;
41 struct ProtoTableEntry {
42 const Class *clasp;
43 ClassInitializerOp init;
44 };
46 #define DECLARE_PROTOTYPE_CLASS_INIT(name,code,init,clasp) \
47 extern JSObject *init(JSContext *cx, Handle<JSObject*> obj);
48 JS_FOR_EACH_PROTOTYPE(DECLARE_PROTOTYPE_CLASS_INIT)
49 #undef DECLARE_PROTOTYPE_CLASS_INIT
51 JSObject *
52 js_InitViaClassSpec(JSContext *cx, Handle<JSObject*> obj)
53 {
54 MOZ_ASSUME_UNREACHABLE();
55 }
57 static const ProtoTableEntry protoTable[JSProto_LIMIT] = {
58 #define INIT_FUNC(name,code,init,clasp) { clasp, init },
59 #define INIT_FUNC_DUMMY(name,code,init,clasp) { nullptr, nullptr },
60 JS_FOR_PROTOTYPES(INIT_FUNC, INIT_FUNC_DUMMY)
61 #undef INIT_FUNC_DUMMY
62 #undef INIT_FUNC
63 };
65 const js::Class *
66 js::ProtoKeyToClass(JSProtoKey key)
67 {
68 MOZ_ASSERT(key < JSProto_LIMIT);
69 return protoTable[key].clasp;
70 }
72 // This method is not in the header file to avoid having to include
73 // TypedObject.h from GlobalObject.h. It is not generally perf
74 // sensitive.
75 TypedObjectModuleObject&
76 js::GlobalObject::getTypedObjectModule() const {
77 Value v = getConstructor(JSProto_TypedObject);
78 // only gets called from contexts where TypedObject must be initialized
79 JS_ASSERT(v.isObject());
80 return v.toObject().as<TypedObjectModuleObject>();
81 }
83 JSObject *
84 js_InitObjectClass(JSContext *cx, HandleObject obj)
85 {
86 JS_ASSERT(obj->isNative());
88 return obj->as<GlobalObject>().getOrCreateObjectPrototype(cx);
89 }
91 JSObject *
92 js_InitFunctionClass(JSContext *cx, HandleObject obj)
93 {
94 JS_ASSERT(obj->isNative());
96 return obj->as<GlobalObject>().getOrCreateFunctionPrototype(cx);
97 }
99 static bool
100 ThrowTypeError(JSContext *cx, unsigned argc, Value *vp)
101 {
102 JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, nullptr,
103 JSMSG_THROW_TYPE_ERROR);
104 return false;
105 }
107 static bool
108 TestProtoThis(HandleValue v)
109 {
110 return !v.isNullOrUndefined();
111 }
113 static bool
114 ProtoGetterImpl(JSContext *cx, CallArgs args)
115 {
116 JS_ASSERT(TestProtoThis(args.thisv()));
118 HandleValue thisv = args.thisv();
119 if (thisv.isPrimitive() && !BoxNonStrictThis(cx, args))
120 return false;
122 RootedObject obj(cx, &args.thisv().toObject());
123 RootedObject proto(cx);
124 if (!JSObject::getProto(cx, obj, &proto))
125 return false;
126 args.rval().setObjectOrNull(proto);
127 return true;
128 }
130 static bool
131 ProtoGetter(JSContext *cx, unsigned argc, Value *vp)
132 {
133 CallArgs args = CallArgsFromVp(argc, vp);
134 return CallNonGenericMethod(cx, TestProtoThis, ProtoGetterImpl, args);
135 }
137 namespace js {
138 size_t sSetProtoCalled = 0;
139 } // namespace js
141 static bool
142 ProtoSetterImpl(JSContext *cx, CallArgs args)
143 {
144 JS_ASSERT(TestProtoThis(args.thisv()));
146 HandleValue thisv = args.thisv();
147 if (thisv.isPrimitive()) {
148 JS_ASSERT(!thisv.isNullOrUndefined());
150 // Mutating a boxed primitive's [[Prototype]] has no side effects.
151 args.rval().setUndefined();
152 return true;
153 }
155 if (!cx->runningWithTrustedPrincipals())
156 ++sSetProtoCalled;
158 Rooted<JSObject*> obj(cx, &args.thisv().toObject());
160 /* Do nothing if __proto__ isn't being set to an object or null. */
161 if (args.length() == 0 || !args[0].isObjectOrNull()) {
162 args.rval().setUndefined();
163 return true;
164 }
166 Rooted<JSObject*> newProto(cx, args[0].toObjectOrNull());
168 bool success;
169 if (!JSObject::setProto(cx, obj, newProto, &success))
170 return false;
172 if (!success) {
173 js_ReportValueError(cx, JSMSG_SETPROTOTYPEOF_FAIL, JSDVG_IGNORE_STACK, thisv, js::NullPtr());
174 return false;
175 }
177 args.rval().setUndefined();
178 return true;
179 }
181 static bool
182 ProtoSetter(JSContext *cx, unsigned argc, Value *vp)
183 {
184 CallArgs args = CallArgsFromVp(argc, vp);
186 // Do this here, rather than in |ProtoSetterImpl|, so even likely-buggy
187 // use of the __proto__ setter on unacceptable values, where no subsequent
188 // use occurs on an acceptable value, will trigger a warning.
189 RootedObject callee(cx, &args.callee());
190 if (!GlobalObject::warnOnceAboutPrototypeMutation(cx, callee))
191 return false;
193 return CallNonGenericMethod(cx, TestProtoThis, ProtoSetterImpl, args);
194 }
196 JSObject *
197 GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
198 {
199 Rooted<GlobalObject*> self(cx, this);
201 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
202 JS_ASSERT(isNative());
204 cx->setDefaultCompartmentObjectIfUnset(self);
206 RootedObject objectProto(cx);
208 /*
209 * Create |Object.prototype| first, mirroring CreateBlankProto but for the
210 * prototype of the created object.
211 */
212 objectProto = NewObjectWithGivenProto(cx, &JSObject::class_, nullptr, self, SingletonObject);
213 if (!objectProto)
214 return nullptr;
216 /*
217 * The default 'new' type of Object.prototype is required by type inference
218 * to have unknown properties, to simplify handling of e.g. heterogenous
219 * objects in JSON and script literals.
220 */
221 if (!setNewTypeUnknown(cx, &JSObject::class_, objectProto))
222 return nullptr;
224 /* Create |Function.prototype| next so we can create other functions. */
225 RootedFunction functionProto(cx);
226 {
227 JSObject *functionProto_ = NewObjectWithGivenProto(cx, &JSFunction::class_,
228 objectProto, self, SingletonObject);
229 if (!functionProto_)
230 return nullptr;
231 functionProto = &functionProto_->as<JSFunction>();
233 /*
234 * Bizarrely, |Function.prototype| must be an interpreted function, so
235 * give it the guts to be one.
236 */
237 {
238 JSObject *proto = NewFunction(cx, functionProto, nullptr, 0, JSFunction::INTERPRETED,
239 self, NullPtr());
240 if (!proto)
241 return nullptr;
242 JS_ASSERT(proto == functionProto);
243 functionProto->setIsFunctionPrototype();
244 }
246 const char *rawSource = "() {\n}";
247 size_t sourceLen = strlen(rawSource);
248 jschar *source = InflateString(cx, rawSource, &sourceLen);
249 if (!source)
250 return nullptr;
251 ScriptSource *ss =
252 cx->new_<ScriptSource>();
253 if (!ss) {
254 js_free(source);
255 return nullptr;
256 }
257 ScriptSourceHolder ssHolder(ss);
258 ss->setSource(source, sourceLen);
259 CompileOptions options(cx);
260 options.setNoScriptRval(true)
261 .setVersion(JSVERSION_DEFAULT);
262 RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss, options));
263 if (!sourceObject)
264 return nullptr;
266 RootedScript script(cx, JSScript::Create(cx,
267 /* enclosingScope = */ NullPtr(),
268 /* savedCallerFun = */ false,
269 options,
270 /* staticLevel = */ 0,
271 sourceObject,
272 0,
273 ss->length()));
274 if (!script || !JSScript::fullyInitTrivial(cx, script))
275 return nullptr;
277 functionProto->initScript(script);
278 types::TypeObject* protoType = functionProto->getType(cx);
279 if (!protoType)
280 return nullptr;
281 protoType->interpretedFunction = functionProto;
282 script->setFunction(functionProto);
284 /*
285 * The default 'new' type of Function.prototype is required by type
286 * inference to have unknown properties, to simplify handling of e.g.
287 * CloneFunctionObject.
288 */
289 if (!setNewTypeUnknown(cx, &JSFunction::class_, functionProto))
290 return nullptr;
291 }
293 /* Create the Object function now that we have a [[Prototype]] for it. */
294 RootedFunction objectCtor(cx);
295 {
296 RootedObject ctor(cx, NewObjectWithGivenProto(cx, &JSFunction::class_, functionProto,
297 self, SingletonObject));
298 if (!ctor)
299 return nullptr;
300 RootedAtom objectAtom(cx, cx->names().Object);
301 objectCtor = NewFunction(cx, ctor, obj_construct, 1, JSFunction::NATIVE_CTOR, self,
302 objectAtom);
303 if (!objectCtor)
304 return nullptr;
305 }
307 /*
308 * Install |Object| and |Object.prototype| for the benefit of subsequent
309 * code that looks for them.
310 */
311 self->setObjectClassDetails(objectCtor, objectProto);
313 /* Create |Function| so it and |Function.prototype| can be installed. */
314 RootedFunction functionCtor(cx);
315 {
316 // Note that ctor is rooted purely for the JS_ASSERT at the end
317 RootedObject ctor(cx, NewObjectWithGivenProto(cx, &JSFunction::class_, functionProto,
318 self, SingletonObject));
319 if (!ctor)
320 return nullptr;
321 RootedAtom functionAtom(cx, cx->names().Function);
322 functionCtor = NewFunction(cx, ctor, Function, 1, JSFunction::NATIVE_CTOR, self,
323 functionAtom);
324 if (!functionCtor)
325 return nullptr;
326 JS_ASSERT(ctor == functionCtor);
327 }
329 /*
330 * Install |Function| and |Function.prototype| so that we can freely create
331 * functions and objects without special effort.
332 */
333 self->setFunctionClassDetails(functionCtor, functionProto);
335 /*
336 * The hard part's done: now go back and add all the properties these
337 * primordial values have.
338 */
339 if (!LinkConstructorAndPrototype(cx, objectCtor, objectProto) ||
340 !DefinePropertiesAndBrand(cx, objectProto, nullptr, object_methods))
341 {
342 return nullptr;
343 }
345 /*
346 * Add an Object.prototype.__proto__ accessor property to implement that
347 * extension (if it's actually enabled). Cache the getter for this
348 * function so that cross-compartment [[Prototype]]-getting is implemented
349 * in one place.
350 */
351 RootedFunction getter(cx, NewFunction(cx, NullPtr(), ProtoGetter, 0, JSFunction::NATIVE_FUN,
352 self, NullPtr()));
353 if (!getter)
354 return nullptr;
355 #if JS_HAS_OBJ_PROTO_PROP
356 RootedFunction setter(cx, NewFunction(cx, NullPtr(), ProtoSetter, 0, JSFunction::NATIVE_FUN,
357 self, NullPtr()));
358 if (!setter)
359 return nullptr;
360 if (!JSObject::defineProperty(cx, objectProto,
361 cx->names().proto, UndefinedHandleValue,
362 JS_DATA_TO_FUNC_PTR(PropertyOp, getter.get()),
363 JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setter.get()),
364 JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED))
365 {
366 return nullptr;
367 }
368 #endif /* JS_HAS_OBJ_PROTO_PROP */
369 self->setProtoGetter(getter);
372 if (!DefinePropertiesAndBrand(cx, objectCtor, nullptr, object_static_methods) ||
373 !LinkConstructorAndPrototype(cx, functionCtor, functionProto) ||
374 !DefinePropertiesAndBrand(cx, functionProto, nullptr, function_methods) ||
375 !DefinePropertiesAndBrand(cx, functionCtor, nullptr, nullptr))
376 {
377 return nullptr;
378 }
380 /* Add the global Function and Object properties now. */
381 if (!self->addDataProperty(cx, cx->names().Object, constructorPropertySlot(JSProto_Object), 0))
382 return nullptr;
383 if (!self->addDataProperty(cx, cx->names().Function, constructorPropertySlot(JSProto_Function), 0))
384 return nullptr;
386 /* Heavy lifting done, but lingering tasks remain. */
388 /* ES5 15.1.2.1. */
389 RootedId evalId(cx, NameToId(cx->names().eval));
390 JSObject *evalobj = DefineFunction(cx, self, evalId, IndirectEval, 1, JSFUN_STUB_GSOPS);
391 if (!evalobj)
392 return nullptr;
393 self->setOriginalEval(evalobj);
395 /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
396 RootedFunction throwTypeError(cx, NewFunction(cx, NullPtr(), ThrowTypeError, 0,
397 JSFunction::NATIVE_FUN, self, NullPtr()));
398 if (!throwTypeError)
399 return nullptr;
400 if (!JSObject::preventExtensions(cx, throwTypeError))
401 return nullptr;
402 self->setThrowTypeError(throwTypeError);
404 RootedObject intrinsicsHolder(cx);
405 if (cx->runtime()->isSelfHostingGlobal(self)) {
406 intrinsicsHolder = self;
407 } else {
408 RootedObject proto(cx, self->getOrCreateObjectPrototype(cx));
409 if (!proto)
410 return nullptr;
411 intrinsicsHolder = NewObjectWithGivenProto(cx, &JSObject::class_, proto, self,
412 TenuredObject);
413 if (!intrinsicsHolder)
414 return nullptr;
415 }
416 self->setIntrinsicsHolder(intrinsicsHolder);
417 /* Define a property 'global' with the current global as its value. */
418 RootedValue global(cx, ObjectValue(*self));
419 if (!JSObject::defineProperty(cx, intrinsicsHolder, cx->names().global,
420 global, JS_PropertyStub, JS_StrictPropertyStub,
421 JSPROP_PERMANENT | JSPROP_READONLY))
422 {
423 return nullptr;
424 }
426 /*
427 * The global object should have |Object.prototype| as its [[Prototype]].
428 * Eventually we'd like to have standard classes be there from the start,
429 * and thus we would know we were always setting what had previously been a
430 * null [[Prototype]], but right now some code assumes it can set the
431 * [[Prototype]] before standard classes have been initialized. For now,
432 * only set the [[Prototype]] if it hasn't already been set.
433 */
434 Rooted<TaggedProto> tagged(cx, TaggedProto(objectProto));
435 if (self->shouldSplicePrototype(cx) && !self->splicePrototype(cx, self->getClass(), tagged))
436 return nullptr;
438 /*
439 * Notify any debuggers about the creation of the script for
440 * |Function.prototype| -- after all initialization, for simplicity.
441 */
442 RootedScript functionProtoScript(cx, functionProto->nonLazyScript());
443 CallNewScriptHook(cx, functionProtoScript, functionProto);
444 return functionProto;
445 }
447 /* static */ bool
448 GlobalObject::ensureConstructor(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey key)
449 {
450 if (global->isStandardClassResolved(key))
451 return true;
452 return resolveConstructor(cx, global, key);
453 }
455 /* static*/ bool
456 GlobalObject::resolveConstructor(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey key)
457 {
458 MOZ_ASSERT(!global->isStandardClassResolved(key));
460 // There are two different kinds of initialization hooks. One of them is
461 // the class js_InitFoo hook, defined in a JSProtoKey-keyed table at the
462 // top of this file. The other lives in the ClassSpec for classes that
463 // define it. Classes may use one or the other, but not both.
464 ClassInitializerOp init = protoTable[key].init;
465 if (init == js_InitViaClassSpec)
466 init = nullptr;
468 const Class *clasp = ProtoKeyToClass(key);
470 // Some classes have no init routine, which means that they're disabled at
471 // compile-time. We could try to enforce that callers never pass such keys
472 // to resolveConstructor, but that would cramp the style of consumers like
473 // GlobalObject::initStandardClasses that want to just carpet-bomb-call
474 // ensureConstructor with every JSProtoKey. So it's easier to just handle
475 // it here.
476 bool haveSpec = clasp && clasp->spec.defined();
477 if (!init && !haveSpec)
478 return true;
480 // See if there's an old-style initialization hook.
481 if (init) {
482 MOZ_ASSERT(!haveSpec);
483 return init(cx, global);
484 }
486 //
487 // Ok, we're doing it with a class spec.
488 //
490 // Create the constructor.
491 RootedObject ctor(cx, clasp->spec.createConstructor(cx, key));
492 if (!ctor)
493 return false;
495 // Define any specified functions.
496 if (const JSFunctionSpec *funs = clasp->spec.constructorFunctions) {
497 if (!JS_DefineFunctions(cx, ctor, funs))
498 return false;
499 }
501 // We don't always have a prototype (i.e. Math and JSON). If we don't,
502 // |createPrototype| and |prototypeFunctions| should both be null.
503 RootedObject proto(cx);
504 if (clasp->spec.createPrototype) {
505 proto = clasp->spec.createPrototype(cx, key);
506 if (!proto)
507 return false;
508 }
509 if (const JSFunctionSpec *funs = clasp->spec.prototypeFunctions) {
510 if (!JS_DefineFunctions(cx, proto, funs))
511 return false;
512 }
514 // If the prototype exists, link it with the constructor.
515 if (proto && !LinkConstructorAndPrototype(cx, ctor, proto))
516 return false;
518 // Call the post-initialization hook, if provided.
519 if (clasp->spec.finishInit && !clasp->spec.finishInit(cx, ctor, proto))
520 return false;
522 // Stash things in the right slots and define the constructor on the global.
523 return initBuiltinConstructor(cx, global, key, ctor, proto);
524 }
526 /* static */ bool
527 GlobalObject::initBuiltinConstructor(JSContext *cx, Handle<GlobalObject*> global,
528 JSProtoKey key, HandleObject ctor, HandleObject proto)
529 {
530 JS_ASSERT(!global->nativeEmpty()); // reserved slots already allocated
531 JS_ASSERT(key != JSProto_Null);
532 JS_ASSERT(ctor);
533 JS_ASSERT(proto);
535 RootedId id(cx, NameToId(ClassName(key, cx)));
536 JS_ASSERT(!global->nativeLookup(cx, id));
538 if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
539 return false;
541 global->setConstructor(key, ObjectValue(*ctor));
542 global->setPrototype(key, ObjectValue(*proto));
543 global->setConstructorPropertySlot(key, ObjectValue(*ctor));
545 types::AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
546 return true;
547 }
549 GlobalObject *
550 GlobalObject::create(JSContext *cx, const Class *clasp)
551 {
552 JS_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
553 JS_ASSERT(clasp->trace == JS_GlobalObjectTraceHook);
555 JSObject *obj = NewObjectWithGivenProto(cx, clasp, nullptr, nullptr, SingletonObject);
556 if (!obj)
557 return nullptr;
559 Rooted<GlobalObject *> global(cx, &obj->as<GlobalObject>());
561 cx->compartment()->initGlobal(*global);
563 if (!global->setVarObj(cx))
564 return nullptr;
565 if (!global->setDelegate(cx))
566 return nullptr;
568 /* Construct a regexp statics object for this global object. */
569 JSObject *res = RegExpStatics::create(cx, global);
570 if (!res)
571 return nullptr;
573 global->initSlot(REGEXP_STATICS, ObjectValue(*res));
574 return global;
575 }
577 /* static */ bool
578 GlobalObject::getOrCreateEval(JSContext *cx, Handle<GlobalObject*> global,
579 MutableHandleObject eval)
580 {
581 if (!global->getOrCreateObjectPrototype(cx))
582 return false;
583 eval.set(&global->getSlot(EVAL).toObject());
584 return true;
585 }
587 bool
588 GlobalObject::valueIsEval(Value val)
589 {
590 Value eval = getSlot(EVAL);
591 return eval.isObject() && eval == val;
592 }
594 /* static */ bool
595 GlobalObject::initStandardClasses(JSContext *cx, Handle<GlobalObject*> global)
596 {
597 /* Define a top-level property 'undefined' with the undefined value. */
598 if (!JSObject::defineProperty(cx, global, cx->names().undefined, UndefinedHandleValue,
599 JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY))
600 {
601 return false;
602 }
604 for (size_t k = 0; k < JSProto_LIMIT; ++k) {
605 if (!ensureConstructor(cx, global, static_cast<JSProtoKey>(k)))
606 return false;
607 }
608 return true;
609 }
611 /* static */ bool
612 GlobalObject::isRuntimeCodeGenEnabled(JSContext *cx, Handle<GlobalObject*> global)
613 {
614 HeapSlot &v = global->getSlotRef(RUNTIME_CODEGEN_ENABLED);
615 if (v.isUndefined()) {
616 /*
617 * If there are callbacks, make sure that the CSP callback is installed
618 * and that it permits runtime code generation, then cache the result.
619 */
620 JSCSPEvalChecker allows = cx->runtime()->securityCallbacks->contentSecurityPolicyAllows;
621 Value boolValue = BooleanValue(!allows || allows(cx));
622 v.set(global, HeapSlot::Slot, RUNTIME_CODEGEN_ENABLED, boolValue);
623 }
624 return !v.isFalse();
625 }
627 /* static */ bool
628 GlobalObject::warnOnceAbout(JSContext *cx, HandleObject obj, uint32_t slot, unsigned errorNumber)
629 {
630 Rooted<GlobalObject*> global(cx, &obj->global());
631 HeapSlot &v = global->getSlotRef(slot);
632 if (v.isUndefined()) {
633 if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr,
634 errorNumber))
635 {
636 return false;
637 }
638 v.init(global, HeapSlot::Slot, slot, BooleanValue(true));
639 }
640 return true;
641 }
643 JSFunction *
644 GlobalObject::createConstructor(JSContext *cx, Native ctor, JSAtom *nameArg, unsigned length,
645 gc::AllocKind kind)
646 {
647 RootedAtom name(cx, nameArg);
648 RootedObject self(cx, this);
649 return NewFunction(cx, NullPtr(), ctor, length, JSFunction::NATIVE_CTOR, self, name, kind);
650 }
652 static JSObject *
653 CreateBlankProto(JSContext *cx, const Class *clasp, JSObject &proto, GlobalObject &global)
654 {
655 JS_ASSERT(clasp != &JSObject::class_);
656 JS_ASSERT(clasp != &JSFunction::class_);
658 RootedObject blankProto(cx, NewObjectWithGivenProto(cx, clasp, &proto, &global, SingletonObject));
659 if (!blankProto || !blankProto->setDelegate(cx))
660 return nullptr;
662 return blankProto;
663 }
665 JSObject *
666 GlobalObject::createBlankPrototype(JSContext *cx, const Class *clasp)
667 {
668 Rooted<GlobalObject*> self(cx, this);
669 JSObject *objectProto = getOrCreateObjectPrototype(cx);
670 if (!objectProto)
671 return nullptr;
673 return CreateBlankProto(cx, clasp, *objectProto, *self.get());
674 }
676 JSObject *
677 GlobalObject::createBlankPrototypeInheriting(JSContext *cx, const Class *clasp, JSObject &proto)
678 {
679 return CreateBlankProto(cx, clasp, proto, *this);
680 }
682 bool
683 js::LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor_, JSObject *proto_)
684 {
685 RootedObject ctor(cx, ctor_), proto(cx, proto_);
687 RootedValue protoVal(cx, ObjectValue(*proto));
688 RootedValue ctorVal(cx, ObjectValue(*ctor));
690 return JSObject::defineProperty(cx, ctor, cx->names().prototype,
691 protoVal, JS_PropertyStub, JS_StrictPropertyStub,
692 JSPROP_PERMANENT | JSPROP_READONLY) &&
693 JSObject::defineProperty(cx, proto, cx->names().constructor,
694 ctorVal, JS_PropertyStub, JS_StrictPropertyStub, 0);
695 }
697 bool
698 js::DefinePropertiesAndBrand(JSContext *cx, JSObject *obj_,
699 const JSPropertySpec *ps, const JSFunctionSpec *fs)
700 {
701 RootedObject obj(cx, obj_);
703 if (ps && !JS_DefineProperties(cx, obj, ps))
704 return false;
705 if (fs && !JS_DefineFunctions(cx, obj, fs))
706 return false;
707 return true;
708 }
710 static void
711 GlobalDebuggees_finalize(FreeOp *fop, JSObject *obj)
712 {
713 fop->delete_((GlobalObject::DebuggerVector *) obj->getPrivate());
714 }
716 static const Class
717 GlobalDebuggees_class = {
718 "GlobalDebuggee", JSCLASS_HAS_PRIVATE,
719 JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
720 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, GlobalDebuggees_finalize
721 };
723 GlobalObject::DebuggerVector *
724 GlobalObject::getDebuggers()
725 {
726 Value debuggers = getReservedSlot(DEBUGGERS);
727 if (debuggers.isUndefined())
728 return nullptr;
729 JS_ASSERT(debuggers.toObject().getClass() == &GlobalDebuggees_class);
730 return (DebuggerVector *) debuggers.toObject().getPrivate();
731 }
733 /* static */ GlobalObject::DebuggerVector *
734 GlobalObject::getOrCreateDebuggers(JSContext *cx, Handle<GlobalObject*> global)
735 {
736 assertSameCompartment(cx, global);
737 DebuggerVector *debuggers = global->getDebuggers();
738 if (debuggers)
739 return debuggers;
741 JSObject *obj = NewObjectWithGivenProto(cx, &GlobalDebuggees_class, nullptr, global);
742 if (!obj)
743 return nullptr;
744 debuggers = cx->new_<DebuggerVector>();
745 if (!debuggers)
746 return nullptr;
747 obj->setPrivate(debuggers);
748 global->setReservedSlot(DEBUGGERS, ObjectValue(*obj));
749 return debuggers;
750 }
752 /* static */ bool
753 GlobalObject::addDebugger(JSContext *cx, Handle<GlobalObject*> global, Debugger *dbg)
754 {
755 DebuggerVector *debuggers = getOrCreateDebuggers(cx, global);
756 if (!debuggers)
757 return false;
758 #ifdef DEBUG
759 for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++)
760 JS_ASSERT(*p != dbg);
761 #endif
762 if (debuggers->empty() && !global->compartment()->addDebuggee(cx, global))
763 return false;
764 if (!debuggers->append(dbg)) {
765 (void) global->compartment()->removeDebuggee(cx, global);
766 return false;
767 }
768 return true;
769 }
771 /* static */ JSObject *
772 GlobalObject::getOrCreateForOfPICObject(JSContext *cx, Handle<GlobalObject *> global)
773 {
774 assertSameCompartment(cx, global);
775 JSObject *forOfPIC = global->getForOfPICObject();
776 if (forOfPIC)
777 return forOfPIC;
779 forOfPIC = ForOfPIC::createForOfPICObject(cx, global);
780 if (!forOfPIC)
781 return nullptr;
782 global->setReservedSlot(FOR_OF_PIC_CHAIN, ObjectValue(*forOfPIC));
783 return forOfPIC;
784 }
786 bool
787 GlobalObject::getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, HandleAtom name,
788 unsigned nargs, MutableHandleValue funVal)
789 {
790 RootedId shId(cx, AtomToId(selfHostedName));
791 RootedObject holder(cx, cx->global()->intrinsicsHolder());
793 if (cx->global()->maybeGetIntrinsicValue(shId, funVal.address()))
794 return true;
796 JSFunction *fun = NewFunction(cx, NullPtr(), nullptr, nargs, JSFunction::INTERPRETED_LAZY,
797 holder, name, JSFunction::ExtendedFinalizeKind, SingletonObject);
798 if (!fun)
799 return false;
800 fun->setIsSelfHostedBuiltin();
801 fun->setExtendedSlot(0, StringValue(selfHostedName));
802 funVal.setObject(*fun);
804 return cx->global()->addIntrinsicValue(cx, shId, funVal);
805 }
807 bool
808 GlobalObject::addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value)
809 {
810 RootedObject holder(cx, intrinsicsHolder());
812 uint32_t slot = holder->slotSpan();
813 RootedShape last(cx, holder->lastProperty());
814 Rooted<UnownedBaseShape*> base(cx, last->base()->unowned());
816 StackShape child(base, id, slot, 0, 0);
817 RootedShape shape(cx, cx->compartment()->propertyTree.getChild(cx, last, child));
818 if (!shape)
819 return false;
821 if (!JSObject::setLastProperty(cx, holder, shape))
822 return false;
824 holder->setSlot(shape->slot(), value);
825 return true;
826 }