Wed, 31 Dec 2014 06:09:35 +0100
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 | } |