js/src/vm/GlobalObject.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial