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 +}