js/src/vm/GlobalObject.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/vm/GlobalObject.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,826 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "vm/GlobalObject.h"
    1.11 +
    1.12 +#include "jscntxt.h"
    1.13 +#include "jsdate.h"
    1.14 +#include "jsexn.h"
    1.15 +#include "jsfriendapi.h"
    1.16 +#include "jsmath.h"
    1.17 +#include "json.h"
    1.18 +#include "jsprototypes.h"
    1.19 +#include "jsweakmap.h"
    1.20 +#include "jsworkers.h"
    1.21 +
    1.22 +#include "builtin/Eval.h"
    1.23 +#if EXPOSE_INTL_API
    1.24 +# include "builtin/Intl.h"
    1.25 +#endif
    1.26 +#include "builtin/MapObject.h"
    1.27 +#include "builtin/Object.h"
    1.28 +#include "builtin/RegExp.h"
    1.29 +#include "builtin/SIMD.h"
    1.30 +#include "builtin/TypedObject.h"
    1.31 +#include "vm/PIC.h"
    1.32 +#include "vm/RegExpStatics.h"
    1.33 +#include "vm/StopIterationObject.h"
    1.34 +#include "vm/WeakMapObject.h"
    1.35 +
    1.36 +#include "jscompartmentinlines.h"
    1.37 +#include "jsobjinlines.h"
    1.38 +#include "jsscriptinlines.h"
    1.39 +
    1.40 +#include "vm/ObjectImpl-inl.h"
    1.41 +
    1.42 +using namespace js;
    1.43 +
    1.44 +struct ProtoTableEntry {
    1.45 +    const Class *clasp;
    1.46 +    ClassInitializerOp init;
    1.47 +};
    1.48 +
    1.49 +#define DECLARE_PROTOTYPE_CLASS_INIT(name,code,init,clasp) \
    1.50 +    extern JSObject *init(JSContext *cx, Handle<JSObject*> obj);
    1.51 +JS_FOR_EACH_PROTOTYPE(DECLARE_PROTOTYPE_CLASS_INIT)
    1.52 +#undef DECLARE_PROTOTYPE_CLASS_INIT
    1.53 +
    1.54 +JSObject *
    1.55 +js_InitViaClassSpec(JSContext *cx, Handle<JSObject*> obj)
    1.56 +{
    1.57 +    MOZ_ASSUME_UNREACHABLE();
    1.58 +}
    1.59 +
    1.60 +static const ProtoTableEntry protoTable[JSProto_LIMIT] = {
    1.61 +#define INIT_FUNC(name,code,init,clasp) { clasp, init },
    1.62 +#define INIT_FUNC_DUMMY(name,code,init,clasp) { nullptr, nullptr },
    1.63 +    JS_FOR_PROTOTYPES(INIT_FUNC, INIT_FUNC_DUMMY)
    1.64 +#undef INIT_FUNC_DUMMY
    1.65 +#undef INIT_FUNC
    1.66 +};
    1.67 +
    1.68 +const js::Class *
    1.69 +js::ProtoKeyToClass(JSProtoKey key)
    1.70 +{
    1.71 +    MOZ_ASSERT(key < JSProto_LIMIT);
    1.72 +    return protoTable[key].clasp;
    1.73 +}
    1.74 +
    1.75 +// This method is not in the header file to avoid having to include
    1.76 +// TypedObject.h from GlobalObject.h. It is not generally perf
    1.77 +// sensitive.
    1.78 +TypedObjectModuleObject&
    1.79 +js::GlobalObject::getTypedObjectModule() const {
    1.80 +    Value v = getConstructor(JSProto_TypedObject);
    1.81 +    // only gets called from contexts where TypedObject must be initialized
    1.82 +    JS_ASSERT(v.isObject());
    1.83 +    return v.toObject().as<TypedObjectModuleObject>();
    1.84 +}
    1.85 +
    1.86 +JSObject *
    1.87 +js_InitObjectClass(JSContext *cx, HandleObject obj)
    1.88 +{
    1.89 +    JS_ASSERT(obj->isNative());
    1.90 +
    1.91 +    return obj->as<GlobalObject>().getOrCreateObjectPrototype(cx);
    1.92 +}
    1.93 +
    1.94 +JSObject *
    1.95 +js_InitFunctionClass(JSContext *cx, HandleObject obj)
    1.96 +{
    1.97 +    JS_ASSERT(obj->isNative());
    1.98 +
    1.99 +    return obj->as<GlobalObject>().getOrCreateFunctionPrototype(cx);
   1.100 +}
   1.101 +
   1.102 +static bool
   1.103 +ThrowTypeError(JSContext *cx, unsigned argc, Value *vp)
   1.104 +{
   1.105 +    JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, nullptr,
   1.106 +                                 JSMSG_THROW_TYPE_ERROR);
   1.107 +    return false;
   1.108 +}
   1.109 +
   1.110 +static bool
   1.111 +TestProtoThis(HandleValue v)
   1.112 +{
   1.113 +    return !v.isNullOrUndefined();
   1.114 +}
   1.115 +
   1.116 +static bool
   1.117 +ProtoGetterImpl(JSContext *cx, CallArgs args)
   1.118 +{
   1.119 +    JS_ASSERT(TestProtoThis(args.thisv()));
   1.120 +
   1.121 +    HandleValue thisv = args.thisv();
   1.122 +    if (thisv.isPrimitive() && !BoxNonStrictThis(cx, args))
   1.123 +        return false;
   1.124 +
   1.125 +    RootedObject obj(cx, &args.thisv().toObject());
   1.126 +    RootedObject proto(cx);
   1.127 +    if (!JSObject::getProto(cx, obj, &proto))
   1.128 +        return false;
   1.129 +    args.rval().setObjectOrNull(proto);
   1.130 +    return true;
   1.131 +}
   1.132 +
   1.133 +static bool
   1.134 +ProtoGetter(JSContext *cx, unsigned argc, Value *vp)
   1.135 +{
   1.136 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.137 +    return CallNonGenericMethod(cx, TestProtoThis, ProtoGetterImpl, args);
   1.138 +}
   1.139 +
   1.140 +namespace js {
   1.141 +size_t sSetProtoCalled = 0;
   1.142 +} // namespace js
   1.143 +
   1.144 +static bool
   1.145 +ProtoSetterImpl(JSContext *cx, CallArgs args)
   1.146 +{
   1.147 +    JS_ASSERT(TestProtoThis(args.thisv()));
   1.148 +
   1.149 +    HandleValue thisv = args.thisv();
   1.150 +    if (thisv.isPrimitive()) {
   1.151 +        JS_ASSERT(!thisv.isNullOrUndefined());
   1.152 +
   1.153 +        // Mutating a boxed primitive's [[Prototype]] has no side effects.
   1.154 +        args.rval().setUndefined();
   1.155 +        return true;
   1.156 +    }
   1.157 +
   1.158 +    if (!cx->runningWithTrustedPrincipals())
   1.159 +        ++sSetProtoCalled;
   1.160 +
   1.161 +    Rooted<JSObject*> obj(cx, &args.thisv().toObject());
   1.162 +
   1.163 +    /* Do nothing if __proto__ isn't being set to an object or null. */
   1.164 +    if (args.length() == 0 || !args[0].isObjectOrNull()) {
   1.165 +        args.rval().setUndefined();
   1.166 +        return true;
   1.167 +    }
   1.168 +
   1.169 +    Rooted<JSObject*> newProto(cx, args[0].toObjectOrNull());
   1.170 +
   1.171 +    bool success;
   1.172 +    if (!JSObject::setProto(cx, obj, newProto, &success))
   1.173 +        return false;
   1.174 +
   1.175 +    if (!success) {
   1.176 +        js_ReportValueError(cx, JSMSG_SETPROTOTYPEOF_FAIL, JSDVG_IGNORE_STACK, thisv, js::NullPtr());
   1.177 +        return false;
   1.178 +    }
   1.179 +
   1.180 +    args.rval().setUndefined();
   1.181 +    return true;
   1.182 +}
   1.183 +
   1.184 +static bool
   1.185 +ProtoSetter(JSContext *cx, unsigned argc, Value *vp)
   1.186 +{
   1.187 +    CallArgs args = CallArgsFromVp(argc, vp);
   1.188 +
   1.189 +    // Do this here, rather than in |ProtoSetterImpl|, so even likely-buggy
   1.190 +    // use of the __proto__ setter on unacceptable values, where no subsequent
   1.191 +    // use occurs on an acceptable value, will trigger a warning.
   1.192 +    RootedObject callee(cx, &args.callee());
   1.193 +    if (!GlobalObject::warnOnceAboutPrototypeMutation(cx, callee))
   1.194 +        return false;
   1.195 +
   1.196 +    return CallNonGenericMethod(cx, TestProtoThis, ProtoSetterImpl, args);
   1.197 +}
   1.198 +
   1.199 +JSObject *
   1.200 +GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
   1.201 +{
   1.202 +    Rooted<GlobalObject*> self(cx, this);
   1.203 +
   1.204 +    JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
   1.205 +    JS_ASSERT(isNative());
   1.206 +
   1.207 +    cx->setDefaultCompartmentObjectIfUnset(self);
   1.208 +
   1.209 +    RootedObject objectProto(cx);
   1.210 +
   1.211 +    /*
   1.212 +     * Create |Object.prototype| first, mirroring CreateBlankProto but for the
   1.213 +     * prototype of the created object.
   1.214 +     */
   1.215 +    objectProto = NewObjectWithGivenProto(cx, &JSObject::class_, nullptr, self, SingletonObject);
   1.216 +    if (!objectProto)
   1.217 +        return nullptr;
   1.218 +
   1.219 +    /*
   1.220 +     * The default 'new' type of Object.prototype is required by type inference
   1.221 +     * to have unknown properties, to simplify handling of e.g. heterogenous
   1.222 +     * objects in JSON and script literals.
   1.223 +     */
   1.224 +    if (!setNewTypeUnknown(cx, &JSObject::class_, objectProto))
   1.225 +        return nullptr;
   1.226 +
   1.227 +    /* Create |Function.prototype| next so we can create other functions. */
   1.228 +    RootedFunction functionProto(cx);
   1.229 +    {
   1.230 +        JSObject *functionProto_ = NewObjectWithGivenProto(cx, &JSFunction::class_,
   1.231 +                                                           objectProto, self, SingletonObject);
   1.232 +        if (!functionProto_)
   1.233 +            return nullptr;
   1.234 +        functionProto = &functionProto_->as<JSFunction>();
   1.235 +
   1.236 +        /*
   1.237 +         * Bizarrely, |Function.prototype| must be an interpreted function, so
   1.238 +         * give it the guts to be one.
   1.239 +         */
   1.240 +        {
   1.241 +            JSObject *proto = NewFunction(cx, functionProto, nullptr, 0, JSFunction::INTERPRETED,
   1.242 +                                          self, NullPtr());
   1.243 +            if (!proto)
   1.244 +                return nullptr;
   1.245 +            JS_ASSERT(proto == functionProto);
   1.246 +            functionProto->setIsFunctionPrototype();
   1.247 +        }
   1.248 +
   1.249 +        const char *rawSource = "() {\n}";
   1.250 +        size_t sourceLen = strlen(rawSource);
   1.251 +        jschar *source = InflateString(cx, rawSource, &sourceLen);
   1.252 +        if (!source)
   1.253 +            return nullptr;
   1.254 +        ScriptSource *ss =
   1.255 +            cx->new_<ScriptSource>();
   1.256 +        if (!ss) {
   1.257 +            js_free(source);
   1.258 +            return nullptr;
   1.259 +        }
   1.260 +        ScriptSourceHolder ssHolder(ss);
   1.261 +        ss->setSource(source, sourceLen);
   1.262 +        CompileOptions options(cx);
   1.263 +        options.setNoScriptRval(true)
   1.264 +               .setVersion(JSVERSION_DEFAULT);
   1.265 +        RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss, options));
   1.266 +        if (!sourceObject)
   1.267 +            return nullptr;
   1.268 +
   1.269 +        RootedScript script(cx, JSScript::Create(cx,
   1.270 +                                                 /* enclosingScope = */ NullPtr(),
   1.271 +                                                 /* savedCallerFun = */ false,
   1.272 +                                                 options,
   1.273 +                                                 /* staticLevel = */ 0,
   1.274 +                                                 sourceObject,
   1.275 +                                                 0,
   1.276 +                                                 ss->length()));
   1.277 +        if (!script || !JSScript::fullyInitTrivial(cx, script))
   1.278 +            return nullptr;
   1.279 +
   1.280 +        functionProto->initScript(script);
   1.281 +        types::TypeObject* protoType = functionProto->getType(cx);
   1.282 +        if (!protoType)
   1.283 +            return nullptr;
   1.284 +        protoType->interpretedFunction = functionProto;
   1.285 +        script->setFunction(functionProto);
   1.286 +
   1.287 +        /*
   1.288 +         * The default 'new' type of Function.prototype is required by type
   1.289 +         * inference to have unknown properties, to simplify handling of e.g.
   1.290 +         * CloneFunctionObject.
   1.291 +         */
   1.292 +        if (!setNewTypeUnknown(cx, &JSFunction::class_, functionProto))
   1.293 +            return nullptr;
   1.294 +    }
   1.295 +
   1.296 +    /* Create the Object function now that we have a [[Prototype]] for it. */
   1.297 +    RootedFunction objectCtor(cx);
   1.298 +    {
   1.299 +        RootedObject ctor(cx, NewObjectWithGivenProto(cx, &JSFunction::class_, functionProto,
   1.300 +                                                      self, SingletonObject));
   1.301 +        if (!ctor)
   1.302 +            return nullptr;
   1.303 +        RootedAtom objectAtom(cx, cx->names().Object);
   1.304 +        objectCtor = NewFunction(cx, ctor, obj_construct, 1, JSFunction::NATIVE_CTOR, self,
   1.305 +                                 objectAtom);
   1.306 +        if (!objectCtor)
   1.307 +            return nullptr;
   1.308 +    }
   1.309 +
   1.310 +    /*
   1.311 +     * Install |Object| and |Object.prototype| for the benefit of subsequent
   1.312 +     * code that looks for them.
   1.313 +     */
   1.314 +    self->setObjectClassDetails(objectCtor, objectProto);
   1.315 +
   1.316 +    /* Create |Function| so it and |Function.prototype| can be installed. */
   1.317 +    RootedFunction functionCtor(cx);
   1.318 +    {
   1.319 +        // Note that ctor is rooted purely for the JS_ASSERT at the end
   1.320 +        RootedObject ctor(cx, NewObjectWithGivenProto(cx, &JSFunction::class_, functionProto,
   1.321 +                                                      self, SingletonObject));
   1.322 +        if (!ctor)
   1.323 +            return nullptr;
   1.324 +        RootedAtom functionAtom(cx, cx->names().Function);
   1.325 +        functionCtor = NewFunction(cx, ctor, Function, 1, JSFunction::NATIVE_CTOR, self,
   1.326 +                                   functionAtom);
   1.327 +        if (!functionCtor)
   1.328 +            return nullptr;
   1.329 +        JS_ASSERT(ctor == functionCtor);
   1.330 +    }
   1.331 +
   1.332 +    /*
   1.333 +     * Install |Function| and |Function.prototype| so that we can freely create
   1.334 +     * functions and objects without special effort.
   1.335 +     */
   1.336 +    self->setFunctionClassDetails(functionCtor, functionProto);
   1.337 +
   1.338 +    /*
   1.339 +     * The hard part's done: now go back and add all the properties these
   1.340 +     * primordial values have.
   1.341 +     */
   1.342 +    if (!LinkConstructorAndPrototype(cx, objectCtor, objectProto) ||
   1.343 +        !DefinePropertiesAndBrand(cx, objectProto, nullptr, object_methods))
   1.344 +    {
   1.345 +        return nullptr;
   1.346 +    }
   1.347 +
   1.348 +    /*
   1.349 +     * Add an Object.prototype.__proto__ accessor property to implement that
   1.350 +     * extension (if it's actually enabled).  Cache the getter for this
   1.351 +     * function so that cross-compartment [[Prototype]]-getting is implemented
   1.352 +     * in one place.
   1.353 +     */
   1.354 +    RootedFunction getter(cx, NewFunction(cx, NullPtr(), ProtoGetter, 0, JSFunction::NATIVE_FUN,
   1.355 +                                          self, NullPtr()));
   1.356 +    if (!getter)
   1.357 +        return nullptr;
   1.358 +#if JS_HAS_OBJ_PROTO_PROP
   1.359 +    RootedFunction setter(cx, NewFunction(cx, NullPtr(), ProtoSetter, 0, JSFunction::NATIVE_FUN,
   1.360 +                                          self, NullPtr()));
   1.361 +    if (!setter)
   1.362 +        return nullptr;
   1.363 +    if (!JSObject::defineProperty(cx, objectProto,
   1.364 +                                  cx->names().proto, UndefinedHandleValue,
   1.365 +                                  JS_DATA_TO_FUNC_PTR(PropertyOp, getter.get()),
   1.366 +                                  JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setter.get()),
   1.367 +                                  JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED))
   1.368 +    {
   1.369 +        return nullptr;
   1.370 +    }
   1.371 +#endif /* JS_HAS_OBJ_PROTO_PROP */
   1.372 +    self->setProtoGetter(getter);
   1.373 +
   1.374 +
   1.375 +    if (!DefinePropertiesAndBrand(cx, objectCtor, nullptr, object_static_methods) ||
   1.376 +        !LinkConstructorAndPrototype(cx, functionCtor, functionProto) ||
   1.377 +        !DefinePropertiesAndBrand(cx, functionProto, nullptr, function_methods) ||
   1.378 +        !DefinePropertiesAndBrand(cx, functionCtor, nullptr, nullptr))
   1.379 +    {
   1.380 +        return nullptr;
   1.381 +    }
   1.382 +
   1.383 +    /* Add the global Function and Object properties now. */
   1.384 +    if (!self->addDataProperty(cx, cx->names().Object, constructorPropertySlot(JSProto_Object), 0))
   1.385 +        return nullptr;
   1.386 +    if (!self->addDataProperty(cx, cx->names().Function, constructorPropertySlot(JSProto_Function), 0))
   1.387 +        return nullptr;
   1.388 +
   1.389 +    /* Heavy lifting done, but lingering tasks remain. */
   1.390 +
   1.391 +    /* ES5 15.1.2.1. */
   1.392 +    RootedId evalId(cx, NameToId(cx->names().eval));
   1.393 +    JSObject *evalobj = DefineFunction(cx, self, evalId, IndirectEval, 1, JSFUN_STUB_GSOPS);
   1.394 +    if (!evalobj)
   1.395 +        return nullptr;
   1.396 +    self->setOriginalEval(evalobj);
   1.397 +
   1.398 +    /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
   1.399 +    RootedFunction throwTypeError(cx, NewFunction(cx, NullPtr(), ThrowTypeError, 0,
   1.400 +                                                  JSFunction::NATIVE_FUN, self, NullPtr()));
   1.401 +    if (!throwTypeError)
   1.402 +        return nullptr;
   1.403 +    if (!JSObject::preventExtensions(cx, throwTypeError))
   1.404 +        return nullptr;
   1.405 +    self->setThrowTypeError(throwTypeError);
   1.406 +
   1.407 +    RootedObject intrinsicsHolder(cx);
   1.408 +    if (cx->runtime()->isSelfHostingGlobal(self)) {
   1.409 +        intrinsicsHolder = self;
   1.410 +    } else {
   1.411 +        RootedObject proto(cx, self->getOrCreateObjectPrototype(cx));
   1.412 +        if (!proto)
   1.413 +            return nullptr;
   1.414 +        intrinsicsHolder = NewObjectWithGivenProto(cx, &JSObject::class_, proto, self,
   1.415 +                                                   TenuredObject);
   1.416 +        if (!intrinsicsHolder)
   1.417 +            return nullptr;
   1.418 +    }
   1.419 +    self->setIntrinsicsHolder(intrinsicsHolder);
   1.420 +    /* Define a property 'global' with the current global as its value. */
   1.421 +    RootedValue global(cx, ObjectValue(*self));
   1.422 +    if (!JSObject::defineProperty(cx, intrinsicsHolder, cx->names().global,
   1.423 +                                  global, JS_PropertyStub, JS_StrictPropertyStub,
   1.424 +                                  JSPROP_PERMANENT | JSPROP_READONLY))
   1.425 +    {
   1.426 +        return nullptr;
   1.427 +    }
   1.428 +
   1.429 +    /*
   1.430 +     * The global object should have |Object.prototype| as its [[Prototype]].
   1.431 +     * Eventually we'd like to have standard classes be there from the start,
   1.432 +     * and thus we would know we were always setting what had previously been a
   1.433 +     * null [[Prototype]], but right now some code assumes it can set the
   1.434 +     * [[Prototype]] before standard classes have been initialized.  For now,
   1.435 +     * only set the [[Prototype]] if it hasn't already been set.
   1.436 +     */
   1.437 +    Rooted<TaggedProto> tagged(cx, TaggedProto(objectProto));
   1.438 +    if (self->shouldSplicePrototype(cx) && !self->splicePrototype(cx, self->getClass(), tagged))
   1.439 +        return nullptr;
   1.440 +
   1.441 +    /*
   1.442 +     * Notify any debuggers about the creation of the script for
   1.443 +     * |Function.prototype| -- after all initialization, for simplicity.
   1.444 +     */
   1.445 +    RootedScript functionProtoScript(cx, functionProto->nonLazyScript());
   1.446 +    CallNewScriptHook(cx, functionProtoScript, functionProto);
   1.447 +    return functionProto;
   1.448 +}
   1.449 +
   1.450 +/* static */ bool
   1.451 +GlobalObject::ensureConstructor(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey key)
   1.452 +{
   1.453 +    if (global->isStandardClassResolved(key))
   1.454 +        return true;
   1.455 +    return resolveConstructor(cx, global, key);
   1.456 +}
   1.457 +
   1.458 +/* static*/ bool
   1.459 +GlobalObject::resolveConstructor(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey key)
   1.460 +{
   1.461 +    MOZ_ASSERT(!global->isStandardClassResolved(key));
   1.462 +
   1.463 +    // There are two different kinds of initialization hooks. One of them is
   1.464 +    // the class js_InitFoo hook, defined in a JSProtoKey-keyed table at the
   1.465 +    // top of this file. The other lives in the ClassSpec for classes that
   1.466 +    // define it. Classes may use one or the other, but not both.
   1.467 +    ClassInitializerOp init = protoTable[key].init;
   1.468 +    if (init == js_InitViaClassSpec)
   1.469 +        init = nullptr;
   1.470 +
   1.471 +    const Class *clasp = ProtoKeyToClass(key);
   1.472 +
   1.473 +    // Some classes have no init routine, which means that they're disabled at
   1.474 +    // compile-time. We could try to enforce that callers never pass such keys
   1.475 +    // to resolveConstructor, but that would cramp the style of consumers like
   1.476 +    // GlobalObject::initStandardClasses that want to just carpet-bomb-call
   1.477 +    // ensureConstructor with every JSProtoKey. So it's easier to just handle
   1.478 +    // it here.
   1.479 +    bool haveSpec = clasp && clasp->spec.defined();
   1.480 +    if (!init && !haveSpec)
   1.481 +        return true;
   1.482 +
   1.483 +    // See if there's an old-style initialization hook.
   1.484 +    if (init) {
   1.485 +        MOZ_ASSERT(!haveSpec);
   1.486 +        return init(cx, global);
   1.487 +    }
   1.488 +
   1.489 +    //
   1.490 +    // Ok, we're doing it with a class spec.
   1.491 +    //
   1.492 +
   1.493 +    // Create the constructor.
   1.494 +    RootedObject ctor(cx, clasp->spec.createConstructor(cx, key));
   1.495 +    if (!ctor)
   1.496 +        return false;
   1.497 +
   1.498 +    // Define any specified functions.
   1.499 +    if (const JSFunctionSpec *funs = clasp->spec.constructorFunctions) {
   1.500 +        if (!JS_DefineFunctions(cx, ctor, funs))
   1.501 +            return false;
   1.502 +    }
   1.503 +
   1.504 +    // We don't always have a prototype (i.e. Math and JSON). If we don't,
   1.505 +    // |createPrototype| and |prototypeFunctions| should both be null.
   1.506 +    RootedObject proto(cx);
   1.507 +    if (clasp->spec.createPrototype) {
   1.508 +        proto = clasp->spec.createPrototype(cx, key);
   1.509 +        if (!proto)
   1.510 +            return false;
   1.511 +    }
   1.512 +    if (const JSFunctionSpec *funs = clasp->spec.prototypeFunctions) {
   1.513 +        if (!JS_DefineFunctions(cx, proto, funs))
   1.514 +            return false;
   1.515 +    }
   1.516 +
   1.517 +    // If the prototype exists, link it with the constructor.
   1.518 +    if (proto && !LinkConstructorAndPrototype(cx, ctor, proto))
   1.519 +        return false;
   1.520 +
   1.521 +    // Call the post-initialization hook, if provided.
   1.522 +    if (clasp->spec.finishInit && !clasp->spec.finishInit(cx, ctor, proto))
   1.523 +        return false;
   1.524 +
   1.525 +    // Stash things in the right slots and define the constructor on the global.
   1.526 +    return initBuiltinConstructor(cx, global, key, ctor, proto);
   1.527 +}
   1.528 +
   1.529 +/* static */ bool
   1.530 +GlobalObject::initBuiltinConstructor(JSContext *cx, Handle<GlobalObject*> global,
   1.531 +                                     JSProtoKey key, HandleObject ctor, HandleObject proto)
   1.532 +{
   1.533 +    JS_ASSERT(!global->nativeEmpty()); // reserved slots already allocated
   1.534 +    JS_ASSERT(key != JSProto_Null);
   1.535 +    JS_ASSERT(ctor);
   1.536 +    JS_ASSERT(proto);
   1.537 +
   1.538 +    RootedId id(cx, NameToId(ClassName(key, cx)));
   1.539 +    JS_ASSERT(!global->nativeLookup(cx, id));
   1.540 +
   1.541 +    if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
   1.542 +        return false;
   1.543 +
   1.544 +    global->setConstructor(key, ObjectValue(*ctor));
   1.545 +    global->setPrototype(key, ObjectValue(*proto));
   1.546 +    global->setConstructorPropertySlot(key, ObjectValue(*ctor));
   1.547 +
   1.548 +    types::AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
   1.549 +    return true;
   1.550 +}
   1.551 +
   1.552 +GlobalObject *
   1.553 +GlobalObject::create(JSContext *cx, const Class *clasp)
   1.554 +{
   1.555 +    JS_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
   1.556 +    JS_ASSERT(clasp->trace == JS_GlobalObjectTraceHook);
   1.557 +
   1.558 +    JSObject *obj = NewObjectWithGivenProto(cx, clasp, nullptr, nullptr, SingletonObject);
   1.559 +    if (!obj)
   1.560 +        return nullptr;
   1.561 +
   1.562 +    Rooted<GlobalObject *> global(cx, &obj->as<GlobalObject>());
   1.563 +
   1.564 +    cx->compartment()->initGlobal(*global);
   1.565 +
   1.566 +    if (!global->setVarObj(cx))
   1.567 +        return nullptr;
   1.568 +    if (!global->setDelegate(cx))
   1.569 +        return nullptr;
   1.570 +
   1.571 +    /* Construct a regexp statics object for this global object. */
   1.572 +    JSObject *res = RegExpStatics::create(cx, global);
   1.573 +    if (!res)
   1.574 +        return nullptr;
   1.575 +
   1.576 +    global->initSlot(REGEXP_STATICS, ObjectValue(*res));
   1.577 +    return global;
   1.578 +}
   1.579 +
   1.580 +/* static */ bool
   1.581 +GlobalObject::getOrCreateEval(JSContext *cx, Handle<GlobalObject*> global,
   1.582 +                              MutableHandleObject eval)
   1.583 +{
   1.584 +    if (!global->getOrCreateObjectPrototype(cx))
   1.585 +        return false;
   1.586 +    eval.set(&global->getSlot(EVAL).toObject());
   1.587 +    return true;
   1.588 +}
   1.589 +
   1.590 +bool
   1.591 +GlobalObject::valueIsEval(Value val)
   1.592 +{
   1.593 +    Value eval = getSlot(EVAL);
   1.594 +    return eval.isObject() && eval == val;
   1.595 +}
   1.596 +
   1.597 +/* static */ bool
   1.598 +GlobalObject::initStandardClasses(JSContext *cx, Handle<GlobalObject*> global)
   1.599 +{
   1.600 +    /* Define a top-level property 'undefined' with the undefined value. */
   1.601 +    if (!JSObject::defineProperty(cx, global, cx->names().undefined, UndefinedHandleValue,
   1.602 +                                  JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY))
   1.603 +    {
   1.604 +        return false;
   1.605 +    }
   1.606 +
   1.607 +    for (size_t k = 0; k < JSProto_LIMIT; ++k) {
   1.608 +        if (!ensureConstructor(cx, global, static_cast<JSProtoKey>(k)))
   1.609 +            return false;
   1.610 +    }
   1.611 +    return true;
   1.612 +}
   1.613 +
   1.614 +/* static */ bool
   1.615 +GlobalObject::isRuntimeCodeGenEnabled(JSContext *cx, Handle<GlobalObject*> global)
   1.616 +{
   1.617 +    HeapSlot &v = global->getSlotRef(RUNTIME_CODEGEN_ENABLED);
   1.618 +    if (v.isUndefined()) {
   1.619 +        /*
   1.620 +         * If there are callbacks, make sure that the CSP callback is installed
   1.621 +         * and that it permits runtime code generation, then cache the result.
   1.622 +         */
   1.623 +        JSCSPEvalChecker allows = cx->runtime()->securityCallbacks->contentSecurityPolicyAllows;
   1.624 +        Value boolValue = BooleanValue(!allows || allows(cx));
   1.625 +        v.set(global, HeapSlot::Slot, RUNTIME_CODEGEN_ENABLED, boolValue);
   1.626 +    }
   1.627 +    return !v.isFalse();
   1.628 +}
   1.629 +
   1.630 +/* static */ bool
   1.631 +GlobalObject::warnOnceAbout(JSContext *cx, HandleObject obj, uint32_t slot, unsigned errorNumber)
   1.632 +{
   1.633 +    Rooted<GlobalObject*> global(cx, &obj->global());
   1.634 +    HeapSlot &v = global->getSlotRef(slot);
   1.635 +    if (v.isUndefined()) {
   1.636 +        if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr,
   1.637 +                                          errorNumber))
   1.638 +        {
   1.639 +            return false;
   1.640 +        }
   1.641 +        v.init(global, HeapSlot::Slot, slot, BooleanValue(true));
   1.642 +    }
   1.643 +    return true;
   1.644 +}
   1.645 +
   1.646 +JSFunction *
   1.647 +GlobalObject::createConstructor(JSContext *cx, Native ctor, JSAtom *nameArg, unsigned length,
   1.648 +                                gc::AllocKind kind)
   1.649 +{
   1.650 +    RootedAtom name(cx, nameArg);
   1.651 +    RootedObject self(cx, this);
   1.652 +    return NewFunction(cx, NullPtr(), ctor, length, JSFunction::NATIVE_CTOR, self, name, kind);
   1.653 +}
   1.654 +
   1.655 +static JSObject *
   1.656 +CreateBlankProto(JSContext *cx, const Class *clasp, JSObject &proto, GlobalObject &global)
   1.657 +{
   1.658 +    JS_ASSERT(clasp != &JSObject::class_);
   1.659 +    JS_ASSERT(clasp != &JSFunction::class_);
   1.660 +
   1.661 +    RootedObject blankProto(cx, NewObjectWithGivenProto(cx, clasp, &proto, &global, SingletonObject));
   1.662 +    if (!blankProto || !blankProto->setDelegate(cx))
   1.663 +        return nullptr;
   1.664 +
   1.665 +    return blankProto;
   1.666 +}
   1.667 +
   1.668 +JSObject *
   1.669 +GlobalObject::createBlankPrototype(JSContext *cx, const Class *clasp)
   1.670 +{
   1.671 +    Rooted<GlobalObject*> self(cx, this);
   1.672 +    JSObject *objectProto = getOrCreateObjectPrototype(cx);
   1.673 +    if (!objectProto)
   1.674 +        return nullptr;
   1.675 +
   1.676 +    return CreateBlankProto(cx, clasp, *objectProto, *self.get());
   1.677 +}
   1.678 +
   1.679 +JSObject *
   1.680 +GlobalObject::createBlankPrototypeInheriting(JSContext *cx, const Class *clasp, JSObject &proto)
   1.681 +{
   1.682 +    return CreateBlankProto(cx, clasp, proto, *this);
   1.683 +}
   1.684 +
   1.685 +bool
   1.686 +js::LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor_, JSObject *proto_)
   1.687 +{
   1.688 +    RootedObject ctor(cx, ctor_), proto(cx, proto_);
   1.689 +
   1.690 +    RootedValue protoVal(cx, ObjectValue(*proto));
   1.691 +    RootedValue ctorVal(cx, ObjectValue(*ctor));
   1.692 +
   1.693 +    return JSObject::defineProperty(cx, ctor, cx->names().prototype,
   1.694 +                                    protoVal, JS_PropertyStub, JS_StrictPropertyStub,
   1.695 +                                    JSPROP_PERMANENT | JSPROP_READONLY) &&
   1.696 +           JSObject::defineProperty(cx, proto, cx->names().constructor,
   1.697 +                                    ctorVal, JS_PropertyStub, JS_StrictPropertyStub, 0);
   1.698 +}
   1.699 +
   1.700 +bool
   1.701 +js::DefinePropertiesAndBrand(JSContext *cx, JSObject *obj_,
   1.702 +                             const JSPropertySpec *ps, const JSFunctionSpec *fs)
   1.703 +{
   1.704 +    RootedObject obj(cx, obj_);
   1.705 +
   1.706 +    if (ps && !JS_DefineProperties(cx, obj, ps))
   1.707 +        return false;
   1.708 +    if (fs && !JS_DefineFunctions(cx, obj, fs))
   1.709 +        return false;
   1.710 +    return true;
   1.711 +}
   1.712 +
   1.713 +static void
   1.714 +GlobalDebuggees_finalize(FreeOp *fop, JSObject *obj)
   1.715 +{
   1.716 +    fop->delete_((GlobalObject::DebuggerVector *) obj->getPrivate());
   1.717 +}
   1.718 +
   1.719 +static const Class
   1.720 +GlobalDebuggees_class = {
   1.721 +    "GlobalDebuggee", JSCLASS_HAS_PRIVATE,
   1.722 +    JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.723 +    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, GlobalDebuggees_finalize
   1.724 +};
   1.725 +
   1.726 +GlobalObject::DebuggerVector *
   1.727 +GlobalObject::getDebuggers()
   1.728 +{
   1.729 +    Value debuggers = getReservedSlot(DEBUGGERS);
   1.730 +    if (debuggers.isUndefined())
   1.731 +        return nullptr;
   1.732 +    JS_ASSERT(debuggers.toObject().getClass() == &GlobalDebuggees_class);
   1.733 +    return (DebuggerVector *) debuggers.toObject().getPrivate();
   1.734 +}
   1.735 +
   1.736 +/* static */ GlobalObject::DebuggerVector *
   1.737 +GlobalObject::getOrCreateDebuggers(JSContext *cx, Handle<GlobalObject*> global)
   1.738 +{
   1.739 +    assertSameCompartment(cx, global);
   1.740 +    DebuggerVector *debuggers = global->getDebuggers();
   1.741 +    if (debuggers)
   1.742 +        return debuggers;
   1.743 +
   1.744 +    JSObject *obj = NewObjectWithGivenProto(cx, &GlobalDebuggees_class, nullptr, global);
   1.745 +    if (!obj)
   1.746 +        return nullptr;
   1.747 +    debuggers = cx->new_<DebuggerVector>();
   1.748 +    if (!debuggers)
   1.749 +        return nullptr;
   1.750 +    obj->setPrivate(debuggers);
   1.751 +    global->setReservedSlot(DEBUGGERS, ObjectValue(*obj));
   1.752 +    return debuggers;
   1.753 +}
   1.754 +
   1.755 +/* static */ bool
   1.756 +GlobalObject::addDebugger(JSContext *cx, Handle<GlobalObject*> global, Debugger *dbg)
   1.757 +{
   1.758 +    DebuggerVector *debuggers = getOrCreateDebuggers(cx, global);
   1.759 +    if (!debuggers)
   1.760 +        return false;
   1.761 +#ifdef DEBUG
   1.762 +    for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++)
   1.763 +        JS_ASSERT(*p != dbg);
   1.764 +#endif
   1.765 +    if (debuggers->empty() && !global->compartment()->addDebuggee(cx, global))
   1.766 +        return false;
   1.767 +    if (!debuggers->append(dbg)) {
   1.768 +        (void) global->compartment()->removeDebuggee(cx, global);
   1.769 +        return false;
   1.770 +    }
   1.771 +    return true;
   1.772 +}
   1.773 +
   1.774 +/* static */ JSObject *
   1.775 +GlobalObject::getOrCreateForOfPICObject(JSContext *cx, Handle<GlobalObject *> global)
   1.776 +{
   1.777 +    assertSameCompartment(cx, global);
   1.778 +    JSObject *forOfPIC = global->getForOfPICObject();
   1.779 +    if (forOfPIC)
   1.780 +        return forOfPIC;
   1.781 +
   1.782 +    forOfPIC = ForOfPIC::createForOfPICObject(cx, global);
   1.783 +    if (!forOfPIC)
   1.784 +        return nullptr;
   1.785 +    global->setReservedSlot(FOR_OF_PIC_CHAIN, ObjectValue(*forOfPIC));
   1.786 +    return forOfPIC;
   1.787 +}
   1.788 +
   1.789 +bool
   1.790 +GlobalObject::getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, HandleAtom name,
   1.791 +                                    unsigned nargs, MutableHandleValue funVal)
   1.792 +{
   1.793 +    RootedId shId(cx, AtomToId(selfHostedName));
   1.794 +    RootedObject holder(cx, cx->global()->intrinsicsHolder());
   1.795 +
   1.796 +    if (cx->global()->maybeGetIntrinsicValue(shId, funVal.address()))
   1.797 +        return true;
   1.798 +
   1.799 +    JSFunction *fun = NewFunction(cx, NullPtr(), nullptr, nargs, JSFunction::INTERPRETED_LAZY,
   1.800 +                                  holder, name, JSFunction::ExtendedFinalizeKind, SingletonObject);
   1.801 +    if (!fun)
   1.802 +        return false;
   1.803 +    fun->setIsSelfHostedBuiltin();
   1.804 +    fun->setExtendedSlot(0, StringValue(selfHostedName));
   1.805 +    funVal.setObject(*fun);
   1.806 +
   1.807 +    return cx->global()->addIntrinsicValue(cx, shId, funVal);
   1.808 +}
   1.809 +
   1.810 +bool
   1.811 +GlobalObject::addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value)
   1.812 +{
   1.813 +    RootedObject holder(cx, intrinsicsHolder());
   1.814 +
   1.815 +    uint32_t slot = holder->slotSpan();
   1.816 +    RootedShape last(cx, holder->lastProperty());
   1.817 +    Rooted<UnownedBaseShape*> base(cx, last->base()->unowned());
   1.818 +
   1.819 +    StackShape child(base, id, slot, 0, 0);
   1.820 +    RootedShape shape(cx, cx->compartment()->propertyTree.getChild(cx, last, child));
   1.821 +    if (!shape)
   1.822 +        return false;
   1.823 +
   1.824 +    if (!JSObject::setLastProperty(cx, holder, shape))
   1.825 +        return false;
   1.826 +
   1.827 +    holder->setSlot(shape->slot(), value);
   1.828 +    return true;
   1.829 +}

mercurial