js/src/vm/GlobalObject.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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 }

mercurial