js/src/jit/VMFunctions.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 "jit/VMFunctions.h"
michael@0 8
michael@0 9 #include "builtin/TypedObject.h"
michael@0 10 #include "frontend/BytecodeCompiler.h"
michael@0 11 #include "jit/arm/Simulator-arm.h"
michael@0 12 #include "jit/BaselineIC.h"
michael@0 13 #include "jit/IonFrames.h"
michael@0 14 #include "jit/JitCompartment.h"
michael@0 15 #include "vm/ArrayObject.h"
michael@0 16 #include "vm/Debugger.h"
michael@0 17 #include "vm/Interpreter.h"
michael@0 18
michael@0 19 #include "jsinferinlines.h"
michael@0 20
michael@0 21 #include "jit/BaselineFrame-inl.h"
michael@0 22 #include "jit/IonFrames-inl.h"
michael@0 23 #include "vm/Interpreter-inl.h"
michael@0 24 #include "vm/StringObject-inl.h"
michael@0 25
michael@0 26 using namespace js;
michael@0 27 using namespace js::jit;
michael@0 28
michael@0 29 namespace js {
michael@0 30 namespace jit {
michael@0 31
michael@0 32 // Don't explicitly initialize, it's not guaranteed that this initializer will
michael@0 33 // run before the constructors for static VMFunctions.
michael@0 34 /* static */ VMFunction *VMFunction::functions;
michael@0 35
michael@0 36 AutoDetectInvalidation::AutoDetectInvalidation(JSContext *cx, Value *rval, IonScript *ionScript)
michael@0 37 : cx_(cx),
michael@0 38 ionScript_(ionScript ? ionScript : GetTopIonJSScript(cx)->ionScript()),
michael@0 39 rval_(rval),
michael@0 40 disabled_(false)
michael@0 41 { }
michael@0 42
michael@0 43 void
michael@0 44 VMFunction::addToFunctions()
michael@0 45 {
michael@0 46 static bool initialized = false;
michael@0 47 if (!initialized) {
michael@0 48 initialized = true;
michael@0 49 functions = nullptr;
michael@0 50 }
michael@0 51 this->next = functions;
michael@0 52 functions = this;
michael@0 53 }
michael@0 54
michael@0 55 bool
michael@0 56 InvokeFunction(JSContext *cx, HandleObject obj0, uint32_t argc, Value *argv, Value *rval)
michael@0 57 {
michael@0 58 RootedObject obj(cx, obj0);
michael@0 59 if (obj->is<JSFunction>()) {
michael@0 60 RootedFunction fun(cx, &obj->as<JSFunction>());
michael@0 61 if (fun->isInterpreted()) {
michael@0 62 if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
michael@0 63 return false;
michael@0 64
michael@0 65 // Clone function at call site if needed.
michael@0 66 if (fun->nonLazyScript()->shouldCloneAtCallsite()) {
michael@0 67 jsbytecode *pc;
michael@0 68 RootedScript script(cx, cx->currentScript(&pc));
michael@0 69 fun = CloneFunctionAtCallsite(cx, fun, script, pc);
michael@0 70 if (!fun)
michael@0 71 return false;
michael@0 72 }
michael@0 73 }
michael@0 74 }
michael@0 75
michael@0 76 // Data in the argument vector is arranged for a JIT -> JIT call.
michael@0 77 Value thisv = argv[0];
michael@0 78 Value *argvWithoutThis = argv + 1;
michael@0 79
michael@0 80 // For constructing functions, |this| is constructed at caller side and we can just call Invoke.
michael@0 81 // When creating this failed / is impossible at caller site, i.e. MagicValue(JS_IS_CONSTRUCTING),
michael@0 82 // we use InvokeConstructor that creates it at the callee side.
michael@0 83 RootedValue rv(cx);
michael@0 84 if (thisv.isMagic(JS_IS_CONSTRUCTING)) {
michael@0 85 if (!InvokeConstructor(cx, ObjectValue(*obj), argc, argvWithoutThis, rv.address()))
michael@0 86 return false;
michael@0 87 } else {
michael@0 88 if (!Invoke(cx, thisv, ObjectValue(*obj), argc, argvWithoutThis, &rv))
michael@0 89 return false;
michael@0 90 }
michael@0 91
michael@0 92 if (obj->is<JSFunction>()) {
michael@0 93 jsbytecode *pc;
michael@0 94 RootedScript script(cx, cx->currentScript(&pc));
michael@0 95 types::TypeScript::Monitor(cx, script, pc, rv.get());
michael@0 96 }
michael@0 97
michael@0 98 *rval = rv;
michael@0 99 return true;
michael@0 100 }
michael@0 101
michael@0 102 JSObject *
michael@0 103 NewGCObject(JSContext *cx, gc::AllocKind allocKind, gc::InitialHeap initialHeap)
michael@0 104 {
michael@0 105 return js::NewGCObject<CanGC>(cx, allocKind, 0, initialHeap);
michael@0 106 }
michael@0 107
michael@0 108 bool
michael@0 109 CheckOverRecursed(JSContext *cx)
michael@0 110 {
michael@0 111 // IonMonkey's stackLimit is equal to nativeStackLimit by default. When we
michael@0 112 // request an interrupt, we set the jitStackLimit to nullptr, which causes
michael@0 113 // the stack limit check to fail.
michael@0 114 //
michael@0 115 // There are two states we're concerned about here:
michael@0 116 // (1) The interrupt bit is set, and we need to fire the interrupt callback.
michael@0 117 // (2) The stack limit has been exceeded, and we need to throw an error.
michael@0 118 //
michael@0 119 // Note that we can reach here if jitStackLimit is MAXADDR, but interrupt
michael@0 120 // has not yet been set to 1. That's okay; it will be set to 1 very shortly,
michael@0 121 // and in the interim we might just fire a few useless calls to
michael@0 122 // CheckOverRecursed.
michael@0 123 #ifdef JS_ARM_SIMULATOR
michael@0 124 JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, 0, return false);
michael@0 125 #else
michael@0 126 JS_CHECK_RECURSION(cx, return false);
michael@0 127 #endif
michael@0 128
michael@0 129 if (cx->runtime()->interrupt)
michael@0 130 return InterruptCheck(cx);
michael@0 131
michael@0 132 return true;
michael@0 133 }
michael@0 134
michael@0 135 // This function can get called in two contexts. In the usual context, it's
michael@0 136 // called with ealyCheck=false, after the scope chain has been initialized on
michael@0 137 // a baseline frame. In this case, it's ok to throw an exception, so a failed
michael@0 138 // stack check returns false, and a successful stack check promps a check for
michael@0 139 // an interrupt from the runtime, which may also cause a false return.
michael@0 140 //
michael@0 141 // In the second case, it's called with earlyCheck=true, prior to frame
michael@0 142 // initialization. An exception cannot be thrown in this instance, so instead
michael@0 143 // an error flag is set on the frame and true returned.
michael@0 144 bool
michael@0 145 CheckOverRecursedWithExtra(JSContext *cx, BaselineFrame *frame,
michael@0 146 uint32_t extra, uint32_t earlyCheck)
michael@0 147 {
michael@0 148 JS_ASSERT_IF(earlyCheck, !frame->overRecursed());
michael@0 149
michael@0 150 // See |CheckOverRecursed| above. This is a variant of that function which
michael@0 151 // accepts an argument holding the extra stack space needed for the Baseline
michael@0 152 // frame that's about to be pushed.
michael@0 153 uint8_t spDummy;
michael@0 154 uint8_t *checkSp = (&spDummy) - extra;
michael@0 155 if (earlyCheck) {
michael@0 156 #ifdef JS_ARM_SIMULATOR
michael@0 157 (void)checkSp;
michael@0 158 JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, frame->setOverRecursed());
michael@0 159 #else
michael@0 160 JS_CHECK_RECURSION_WITH_SP(cx, checkSp, frame->setOverRecursed());
michael@0 161 #endif
michael@0 162 return true;
michael@0 163 }
michael@0 164
michael@0 165 // The OVERRECURSED flag may have already been set on the frame by an
michael@0 166 // early over-recursed check. If so, throw immediately.
michael@0 167 if (frame->overRecursed())
michael@0 168 return false;
michael@0 169
michael@0 170 #ifdef JS_ARM_SIMULATOR
michael@0 171 JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, return false);
michael@0 172 #else
michael@0 173 JS_CHECK_RECURSION_WITH_SP(cx, checkSp, return false);
michael@0 174 #endif
michael@0 175
michael@0 176 if (cx->runtime()->interrupt)
michael@0 177 return InterruptCheck(cx);
michael@0 178
michael@0 179 return true;
michael@0 180 }
michael@0 181
michael@0 182 bool
michael@0 183 DefVarOrConst(JSContext *cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain)
michael@0 184 {
michael@0 185 // Given the ScopeChain, extract the VarObj.
michael@0 186 RootedObject obj(cx, scopeChain);
michael@0 187 while (!obj->isVarObj())
michael@0 188 obj = obj->enclosingScope();
michael@0 189
michael@0 190 return DefVarOrConstOperation(cx, obj, dn, attrs);
michael@0 191 }
michael@0 192
michael@0 193 bool
michael@0 194 SetConst(JSContext *cx, HandlePropertyName name, HandleObject scopeChain, HandleValue rval)
michael@0 195 {
michael@0 196 // Given the ScopeChain, extract the VarObj.
michael@0 197 RootedObject obj(cx, scopeChain);
michael@0 198 while (!obj->isVarObj())
michael@0 199 obj = obj->enclosingScope();
michael@0 200
michael@0 201 return SetConstOperation(cx, obj, name, rval);
michael@0 202 }
michael@0 203
michael@0 204 bool
michael@0 205 MutatePrototype(JSContext *cx, HandleObject obj, HandleValue value)
michael@0 206 {
michael@0 207 MOZ_ASSERT(obj->is<JSObject>(), "must only be used with object literals");
michael@0 208 if (!value.isObjectOrNull())
michael@0 209 return true;
michael@0 210
michael@0 211 RootedObject newProto(cx, value.toObjectOrNull());
michael@0 212
michael@0 213 bool succeeded;
michael@0 214 if (!JSObject::setProto(cx, obj, newProto, &succeeded))
michael@0 215 return false;
michael@0 216 MOZ_ASSERT(succeeded);
michael@0 217 return true;
michael@0 218 }
michael@0 219
michael@0 220 bool
michael@0 221 InitProp(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value)
michael@0 222 {
michael@0 223 // Copy the incoming value. This may be overwritten; the return value is discarded.
michael@0 224 RootedValue rval(cx, value);
michael@0 225 RootedId id(cx, NameToId(name));
michael@0 226
michael@0 227 MOZ_ASSERT(name != cx->names().proto,
michael@0 228 "__proto__ should have been handled by JSOP_MUTATEPROTO");
michael@0 229 return DefineNativeProperty(cx, obj, id, rval, nullptr, nullptr, JSPROP_ENUMERATE);
michael@0 230 }
michael@0 231
michael@0 232 template<bool Equal>
michael@0 233 bool
michael@0 234 LooselyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
michael@0 235 {
michael@0 236 if (!js::LooselyEqual(cx, lhs, rhs, res))
michael@0 237 return false;
michael@0 238 if (!Equal)
michael@0 239 *res = !*res;
michael@0 240 return true;
michael@0 241 }
michael@0 242
michael@0 243 template bool LooselyEqual<true>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
michael@0 244 template bool LooselyEqual<false>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
michael@0 245
michael@0 246 template<bool Equal>
michael@0 247 bool
michael@0 248 StrictlyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
michael@0 249 {
michael@0 250 if (!js::StrictlyEqual(cx, lhs, rhs, res))
michael@0 251 return false;
michael@0 252 if (!Equal)
michael@0 253 *res = !*res;
michael@0 254 return true;
michael@0 255 }
michael@0 256
michael@0 257 template bool StrictlyEqual<true>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
michael@0 258 template bool StrictlyEqual<false>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
michael@0 259
michael@0 260 bool
michael@0 261 LessThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
michael@0 262 {
michael@0 263 return LessThanOperation(cx, lhs, rhs, res);
michael@0 264 }
michael@0 265
michael@0 266 bool
michael@0 267 LessThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
michael@0 268 {
michael@0 269 return LessThanOrEqualOperation(cx, lhs, rhs, res);
michael@0 270 }
michael@0 271
michael@0 272 bool
michael@0 273 GreaterThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
michael@0 274 {
michael@0 275 return GreaterThanOperation(cx, lhs, rhs, res);
michael@0 276 }
michael@0 277
michael@0 278 bool
michael@0 279 GreaterThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
michael@0 280 {
michael@0 281 return GreaterThanOrEqualOperation(cx, lhs, rhs, res);
michael@0 282 }
michael@0 283
michael@0 284 template<bool Equal>
michael@0 285 bool
michael@0 286 StringsEqual(JSContext *cx, HandleString lhs, HandleString rhs, bool *res)
michael@0 287 {
michael@0 288 if (!js::EqualStrings(cx, lhs, rhs, res))
michael@0 289 return false;
michael@0 290 if (!Equal)
michael@0 291 *res = !*res;
michael@0 292 return true;
michael@0 293 }
michael@0 294
michael@0 295 template bool StringsEqual<true>(JSContext *cx, HandleString lhs, HandleString rhs, bool *res);
michael@0 296 template bool StringsEqual<false>(JSContext *cx, HandleString lhs, HandleString rhs, bool *res);
michael@0 297
michael@0 298 bool
michael@0 299 IteratorMore(JSContext *cx, HandleObject obj, bool *res)
michael@0 300 {
michael@0 301 RootedValue tmp(cx);
michael@0 302 if (!js_IteratorMore(cx, obj, &tmp))
michael@0 303 return false;
michael@0 304
michael@0 305 *res = tmp.toBoolean();
michael@0 306 return true;
michael@0 307 }
michael@0 308
michael@0 309 JSObject*
michael@0 310 NewInitArray(JSContext *cx, uint32_t count, types::TypeObject *typeArg)
michael@0 311 {
michael@0 312 RootedTypeObject type(cx, typeArg);
michael@0 313 NewObjectKind newKind = !type ? SingletonObject : GenericObject;
michael@0 314 if (type && type->shouldPreTenure())
michael@0 315 newKind = TenuredObject;
michael@0 316 RootedObject obj(cx, NewDenseAllocatedArray(cx, count, nullptr, newKind));
michael@0 317 if (!obj)
michael@0 318 return nullptr;
michael@0 319
michael@0 320 if (type)
michael@0 321 obj->setType(type);
michael@0 322
michael@0 323 return obj;
michael@0 324 }
michael@0 325
michael@0 326 JSObject*
michael@0 327 NewInitObject(JSContext *cx, HandleObject templateObject)
michael@0 328 {
michael@0 329 NewObjectKind newKind = templateObject->hasSingletonType() ? SingletonObject : GenericObject;
michael@0 330 if (!templateObject->hasLazyType() && templateObject->type()->shouldPreTenure())
michael@0 331 newKind = TenuredObject;
michael@0 332 RootedObject obj(cx, CopyInitializerObject(cx, templateObject, newKind));
michael@0 333
michael@0 334 if (!obj)
michael@0 335 return nullptr;
michael@0 336
michael@0 337 if (!templateObject->hasSingletonType())
michael@0 338 obj->setType(templateObject->type());
michael@0 339
michael@0 340 return obj;
michael@0 341 }
michael@0 342
michael@0 343 JSObject *
michael@0 344 NewInitObjectWithClassPrototype(JSContext *cx, HandleObject templateObject)
michael@0 345 {
michael@0 346 JS_ASSERT(!templateObject->hasSingletonType());
michael@0 347 JS_ASSERT(!templateObject->hasLazyType());
michael@0 348
michael@0 349 NewObjectKind newKind = templateObject->type()->shouldPreTenure()
michael@0 350 ? TenuredObject
michael@0 351 : GenericObject;
michael@0 352 JSObject *obj = NewObjectWithGivenProto(cx,
michael@0 353 templateObject->getClass(),
michael@0 354 templateObject->getProto(),
michael@0 355 cx->global(),
michael@0 356 newKind);
michael@0 357 if (!obj)
michael@0 358 return nullptr;
michael@0 359
michael@0 360 obj->setType(templateObject->type());
michael@0 361
michael@0 362 return obj;
michael@0 363 }
michael@0 364
michael@0 365 bool
michael@0 366 ArraySpliceDense(JSContext *cx, HandleObject obj, uint32_t start, uint32_t deleteCount)
michael@0 367 {
michael@0 368 JS::AutoValueArray<4> argv(cx);
michael@0 369 argv[0].setUndefined();
michael@0 370 argv[1].setObject(*obj);
michael@0 371 argv[2].set(Int32Value(start));
michael@0 372 argv[3].set(Int32Value(deleteCount));
michael@0 373
michael@0 374 return js::array_splice_impl(cx, 2, argv.begin(), false);
michael@0 375 }
michael@0 376
michael@0 377 bool
michael@0 378 ArrayPopDense(JSContext *cx, HandleObject obj, MutableHandleValue rval)
michael@0 379 {
michael@0 380 JS_ASSERT(obj->is<ArrayObject>());
michael@0 381
michael@0 382 AutoDetectInvalidation adi(cx, rval.address());
michael@0 383
michael@0 384 JS::AutoValueArray<2> argv(cx);
michael@0 385 argv[0].setUndefined();
michael@0 386 argv[1].setObject(*obj);
michael@0 387 if (!js::array_pop(cx, 0, argv.begin()))
michael@0 388 return false;
michael@0 389
michael@0 390 // If the result is |undefined|, the array was probably empty and we
michael@0 391 // have to monitor the return value.
michael@0 392 rval.set(argv[0]);
michael@0 393 if (rval.isUndefined())
michael@0 394 types::TypeScript::Monitor(cx, rval);
michael@0 395 return true;
michael@0 396 }
michael@0 397
michael@0 398 bool
michael@0 399 ArrayPushDense(JSContext *cx, HandleObject obj, HandleValue v, uint32_t *length)
michael@0 400 {
michael@0 401 JS_ASSERT(obj->is<ArrayObject>());
michael@0 402
michael@0 403 JS::AutoValueArray<3> argv(cx);
michael@0 404 argv[0].setUndefined();
michael@0 405 argv[1].setObject(*obj);
michael@0 406 argv[2].set(v);
michael@0 407 if (!js::array_push(cx, 1, argv.begin()))
michael@0 408 return false;
michael@0 409
michael@0 410 *length = argv[0].toInt32();
michael@0 411 return true;
michael@0 412 }
michael@0 413
michael@0 414 bool
michael@0 415 ArrayShiftDense(JSContext *cx, HandleObject obj, MutableHandleValue rval)
michael@0 416 {
michael@0 417 JS_ASSERT(obj->is<ArrayObject>());
michael@0 418
michael@0 419 AutoDetectInvalidation adi(cx, rval.address());
michael@0 420
michael@0 421 JS::AutoValueArray<2> argv(cx);
michael@0 422 argv[0].setUndefined();
michael@0 423 argv[1].setObject(*obj);
michael@0 424 if (!js::array_shift(cx, 0, argv.begin()))
michael@0 425 return false;
michael@0 426
michael@0 427 // If the result is |undefined|, the array was probably empty and we
michael@0 428 // have to monitor the return value.
michael@0 429 rval.set(argv[0]);
michael@0 430 if (rval.isUndefined())
michael@0 431 types::TypeScript::Monitor(cx, rval);
michael@0 432 return true;
michael@0 433 }
michael@0 434
michael@0 435 JSObject *
michael@0 436 ArrayConcatDense(JSContext *cx, HandleObject obj1, HandleObject obj2, HandleObject objRes)
michael@0 437 {
michael@0 438 Rooted<ArrayObject*> arr1(cx, &obj1->as<ArrayObject>());
michael@0 439 Rooted<ArrayObject*> arr2(cx, &obj2->as<ArrayObject>());
michael@0 440 Rooted<ArrayObject*> arrRes(cx, objRes ? &objRes->as<ArrayObject>() : nullptr);
michael@0 441
michael@0 442 if (arrRes) {
michael@0 443 // Fast path if we managed to allocate an object inline.
michael@0 444 if (!js::array_concat_dense(cx, arr1, arr2, arrRes))
michael@0 445 return nullptr;
michael@0 446 return arrRes;
michael@0 447 }
michael@0 448
michael@0 449 JS::AutoValueArray<3> argv(cx);
michael@0 450 argv[0].setUndefined();
michael@0 451 argv[1].setObject(*arr1);
michael@0 452 argv[2].setObject(*arr2);
michael@0 453 if (!js::array_concat(cx, 1, argv.begin()))
michael@0 454 return nullptr;
michael@0 455 return &argv[0].toObject();
michael@0 456 }
michael@0 457
michael@0 458 bool
michael@0 459 CharCodeAt(JSContext *cx, HandleString str, int32_t index, uint32_t *code)
michael@0 460 {
michael@0 461 jschar c;
michael@0 462 if (!str->getChar(cx, index, &c))
michael@0 463 return false;
michael@0 464 *code = c;
michael@0 465 return true;
michael@0 466 }
michael@0 467
michael@0 468 JSFlatString *
michael@0 469 StringFromCharCode(JSContext *cx, int32_t code)
michael@0 470 {
michael@0 471 jschar c = jschar(code);
michael@0 472
michael@0 473 if (StaticStrings::hasUnit(c))
michael@0 474 return cx->staticStrings().getUnit(c);
michael@0 475
michael@0 476 return js_NewStringCopyN<CanGC>(cx, &c, 1);
michael@0 477 }
michael@0 478
michael@0 479 bool
michael@0 480 SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
michael@0 481 bool strict, jsbytecode *pc)
michael@0 482 {
michael@0 483 RootedValue v(cx, value);
michael@0 484 RootedId id(cx, NameToId(name));
michael@0 485
michael@0 486 JSOp op = JSOp(*pc);
michael@0 487
michael@0 488 if (op == JSOP_SETALIASEDVAR) {
michael@0 489 // Aliased var assigns ignore readonly attributes on the property, as
michael@0 490 // required for initializing 'const' closure variables.
michael@0 491 Shape *shape = obj->nativeLookup(cx, name);
michael@0 492 JS_ASSERT(shape && shape->hasSlot());
michael@0 493 obj->nativeSetSlotWithType(cx, shape, value);
michael@0 494 return true;
michael@0 495 }
michael@0 496
michael@0 497 if (MOZ_LIKELY(!obj->getOps()->setProperty)) {
michael@0 498 return baseops::SetPropertyHelper<SequentialExecution>(
michael@0 499 cx, obj, obj, id,
michael@0 500 (op == JSOP_SETNAME || op == JSOP_SETGNAME)
michael@0 501 ? baseops::Unqualified
michael@0 502 : baseops::Qualified,
michael@0 503 &v,
michael@0 504 strict);
michael@0 505 }
michael@0 506
michael@0 507 return JSObject::setGeneric(cx, obj, obj, id, &v, strict);
michael@0 508 }
michael@0 509
michael@0 510 bool
michael@0 511 InterruptCheck(JSContext *cx)
michael@0 512 {
michael@0 513 gc::MaybeVerifyBarriers(cx);
michael@0 514
michael@0 515 // Fix loop backedges so that they do not invoke the interrupt again.
michael@0 516 // No lock is held here and it's possible we could segv in the middle here
michael@0 517 // and end up with a state where some fraction of the backedges point to
michael@0 518 // the interrupt handler and some don't. This is ok since the interrupt
michael@0 519 // is definitely about to be handled; if there are still backedges
michael@0 520 // afterwards which point to the interrupt handler, the next time they are
michael@0 521 // taken the backedges will just be reset again.
michael@0 522 cx->runtime()->jitRuntime()->patchIonBackedges(cx->runtime(),
michael@0 523 JitRuntime::BackedgeLoopHeader);
michael@0 524
michael@0 525 return CheckForInterrupt(cx);
michael@0 526 }
michael@0 527
michael@0 528 HeapSlot *
michael@0 529 NewSlots(JSRuntime *rt, unsigned nslots)
michael@0 530 {
michael@0 531 JS_STATIC_ASSERT(sizeof(Value) == sizeof(HeapSlot));
michael@0 532
michael@0 533 Value *slots = reinterpret_cast<Value *>(rt->malloc_(nslots * sizeof(Value)));
michael@0 534 if (!slots)
michael@0 535 return nullptr;
michael@0 536
michael@0 537 for (unsigned i = 0; i < nslots; i++)
michael@0 538 slots[i] = UndefinedValue();
michael@0 539
michael@0 540 return reinterpret_cast<HeapSlot *>(slots);
michael@0 541 }
michael@0 542
michael@0 543 JSObject *
michael@0 544 NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots)
michael@0 545 {
michael@0 546 JSObject *obj = CallObject::create(cx, shape, type, slots);
michael@0 547 if (!obj)
michael@0 548 return nullptr;
michael@0 549
michael@0 550 #ifdef JSGC_GENERATIONAL
michael@0 551 // The JIT creates call objects in the nursery, so elides barriers for
michael@0 552 // the initializing writes. The interpreter, however, may have allocated
michael@0 553 // the call object tenured, so barrier as needed before re-entering.
michael@0 554 if (!IsInsideNursery(cx->runtime(), obj))
michael@0 555 cx->runtime()->gcStoreBuffer.putWholeCell(obj);
michael@0 556 #endif
michael@0 557
michael@0 558 return obj;
michael@0 559 }
michael@0 560
michael@0 561 JSObject *
michael@0 562 NewSingletonCallObject(JSContext *cx, HandleShape shape, HeapSlot *slots)
michael@0 563 {
michael@0 564 JSObject *obj = CallObject::createSingleton(cx, shape, slots);
michael@0 565 if (!obj)
michael@0 566 return nullptr;
michael@0 567
michael@0 568 #ifdef JSGC_GENERATIONAL
michael@0 569 // The JIT creates call objects in the nursery, so elides barriers for
michael@0 570 // the initializing writes. The interpreter, however, may have allocated
michael@0 571 // the call object tenured, so barrier as needed before re-entering.
michael@0 572 MOZ_ASSERT(!IsInsideNursery(cx->runtime(), obj),
michael@0 573 "singletons are created in the tenured heap");
michael@0 574 cx->runtime()->gcStoreBuffer.putWholeCell(obj);
michael@0 575 #endif
michael@0 576
michael@0 577 return obj;
michael@0 578 }
michael@0 579
michael@0 580 JSObject *
michael@0 581 NewStringObject(JSContext *cx, HandleString str)
michael@0 582 {
michael@0 583 return StringObject::create(cx, str);
michael@0 584 }
michael@0 585
michael@0 586 bool
michael@0 587 SPSEnter(JSContext *cx, HandleScript script)
michael@0 588 {
michael@0 589 return cx->runtime()->spsProfiler.enter(script, script->functionNonDelazifying());
michael@0 590 }
michael@0 591
michael@0 592 bool
michael@0 593 SPSExit(JSContext *cx, HandleScript script)
michael@0 594 {
michael@0 595 cx->runtime()->spsProfiler.exit(script, script->functionNonDelazifying());
michael@0 596 return true;
michael@0 597 }
michael@0 598
michael@0 599 bool
michael@0 600 OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, bool *out)
michael@0 601 {
michael@0 602 RootedId id(cx);
michael@0 603 if (!ValueToId<CanGC>(cx, key, &id))
michael@0 604 return false;
michael@0 605
michael@0 606 RootedObject obj2(cx);
michael@0 607 RootedShape prop(cx);
michael@0 608 if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &prop))
michael@0 609 return false;
michael@0 610
michael@0 611 *out = !!prop;
michael@0 612 return true;
michael@0 613 }
michael@0 614
michael@0 615 bool
michael@0 616 OperatorInI(JSContext *cx, uint32_t index, HandleObject obj, bool *out)
michael@0 617 {
michael@0 618 RootedValue key(cx, Int32Value(index));
michael@0 619 return OperatorIn(cx, key, obj, out);
michael@0 620 }
michael@0 621
michael@0 622 bool
michael@0 623 GetIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue rval)
michael@0 624 {
michael@0 625 if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, rval))
michael@0 626 return false;
michael@0 627
michael@0 628 // This function is called when we try to compile a cold getintrinsic
michael@0 629 // op. MCallGetIntrinsicValue has an AliasSet of None for optimization
michael@0 630 // purposes, as its side effect is not observable from JS. We are
michael@0 631 // guaranteed to bail out after this function, but because of its AliasSet,
michael@0 632 // type info will not be reflowed. Manually monitor here.
michael@0 633 types::TypeScript::Monitor(cx, rval);
michael@0 634
michael@0 635 return true;
michael@0 636 }
michael@0 637
michael@0 638 bool
michael@0 639 CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval)
michael@0 640 {
michael@0 641 rval.set(MagicValue(JS_IS_CONSTRUCTING));
michael@0 642
michael@0 643 if (callee->is<JSFunction>()) {
michael@0 644 JSFunction *fun = &callee->as<JSFunction>();
michael@0 645 if (fun->isInterpretedConstructor()) {
michael@0 646 JSScript *script = fun->getOrCreateScript(cx);
michael@0 647 if (!script || !script->ensureHasTypes(cx))
michael@0 648 return false;
michael@0 649 JSObject *thisObj = CreateThisForFunction(cx, callee, GenericObject);
michael@0 650 if (!thisObj)
michael@0 651 return false;
michael@0 652 rval.set(ObjectValue(*thisObj));
michael@0 653 }
michael@0 654 }
michael@0 655
michael@0 656 return true;
michael@0 657 }
michael@0 658
michael@0 659 void
michael@0 660 GetDynamicName(JSContext *cx, JSObject *scopeChain, JSString *str, Value *vp)
michael@0 661 {
michael@0 662 // Lookup a string on the scope chain, returning either the value found or
michael@0 663 // undefined through rval. This function is infallible, and cannot GC or
michael@0 664 // invalidate.
michael@0 665
michael@0 666 JSAtom *atom;
michael@0 667 if (str->isAtom()) {
michael@0 668 atom = &str->asAtom();
michael@0 669 } else {
michael@0 670 atom = AtomizeString(cx, str);
michael@0 671 if (!atom) {
michael@0 672 vp->setUndefined();
michael@0 673 return;
michael@0 674 }
michael@0 675 }
michael@0 676
michael@0 677 if (!frontend::IsIdentifier(atom) || frontend::IsKeyword(atom)) {
michael@0 678 vp->setUndefined();
michael@0 679 return;
michael@0 680 }
michael@0 681
michael@0 682 Shape *shape = nullptr;
michael@0 683 JSObject *scope = nullptr, *pobj = nullptr;
michael@0 684 if (LookupNameNoGC(cx, atom->asPropertyName(), scopeChain, &scope, &pobj, &shape)) {
michael@0 685 if (FetchNameNoGC(pobj, shape, MutableHandleValue::fromMarkedLocation(vp)))
michael@0 686 return;
michael@0 687 }
michael@0 688
michael@0 689 vp->setUndefined();
michael@0 690 }
michael@0 691
michael@0 692 bool
michael@0 693 FilterArgumentsOrEval(JSContext *cx, JSString *str)
michael@0 694 {
michael@0 695 // getChars() is fallible, but cannot GC: it can only allocate a character
michael@0 696 // for the flattened string. If this call fails then the calling Ion code
michael@0 697 // will bailout, resume in the interpreter and likely fail again when
michael@0 698 // trying to flatten the string and unwind the stack.
michael@0 699 const jschar *chars = str->getChars(cx);
michael@0 700 if (!chars)
michael@0 701 return false;
michael@0 702
michael@0 703 static const jschar arguments[] = {'a', 'r', 'g', 'u', 'm', 'e', 'n', 't', 's'};
michael@0 704 static const jschar eval[] = {'e', 'v', 'a', 'l'};
michael@0 705
michael@0 706 return !StringHasPattern(chars, str->length(), arguments, mozilla::ArrayLength(arguments)) &&
michael@0 707 !StringHasPattern(chars, str->length(), eval, mozilla::ArrayLength(eval));
michael@0 708 }
michael@0 709
michael@0 710 #ifdef JSGC_GENERATIONAL
michael@0 711 void
michael@0 712 PostWriteBarrier(JSRuntime *rt, JSObject *obj)
michael@0 713 {
michael@0 714 JS_ASSERT(!IsInsideNursery(rt, obj));
michael@0 715 rt->gcStoreBuffer.putWholeCell(obj);
michael@0 716 }
michael@0 717
michael@0 718 void
michael@0 719 PostGlobalWriteBarrier(JSRuntime *rt, JSObject *obj)
michael@0 720 {
michael@0 721 JS_ASSERT(obj->is<GlobalObject>());
michael@0 722 if (!obj->compartment()->globalWriteBarriered) {
michael@0 723 PostWriteBarrier(rt, obj);
michael@0 724 obj->compartment()->globalWriteBarriered = true;
michael@0 725 }
michael@0 726 }
michael@0 727 #endif
michael@0 728
michael@0 729 uint32_t
michael@0 730 GetIndexFromString(JSString *str)
michael@0 731 {
michael@0 732 // Masks the return value UINT32_MAX as failure to get the index.
michael@0 733 // I.e. it is impossible to distinguish between failing to get the index
michael@0 734 // or the actual index UINT32_MAX.
michael@0 735
michael@0 736 if (!str->isAtom())
michael@0 737 return UINT32_MAX;
michael@0 738
michael@0 739 uint32_t index;
michael@0 740 JSAtom *atom = &str->asAtom();
michael@0 741 if (!atom->isIndex(&index))
michael@0 742 return UINT32_MAX;
michael@0 743
michael@0 744 return index;
michael@0 745 }
michael@0 746
michael@0 747 bool
michael@0 748 DebugPrologue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn)
michael@0 749 {
michael@0 750 *mustReturn = false;
michael@0 751
michael@0 752 JSTrapStatus status = ScriptDebugPrologue(cx, frame, pc);
michael@0 753 switch (status) {
michael@0 754 case JSTRAP_CONTINUE:
michael@0 755 return true;
michael@0 756
michael@0 757 case JSTRAP_RETURN:
michael@0 758 // The script is going to return immediately, so we have to call the
michael@0 759 // debug epilogue handler as well.
michael@0 760 JS_ASSERT(frame->hasReturnValue());
michael@0 761 *mustReturn = true;
michael@0 762 return jit::DebugEpilogue(cx, frame, pc, true);
michael@0 763
michael@0 764 case JSTRAP_THROW:
michael@0 765 case JSTRAP_ERROR:
michael@0 766 return false;
michael@0 767
michael@0 768 default:
michael@0 769 MOZ_ASSUME_UNREACHABLE("Invalid trap status");
michael@0 770 }
michael@0 771 }
michael@0 772
michael@0 773 bool
michael@0 774 DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok)
michael@0 775 {
michael@0 776 // Unwind scope chain to stack depth 0.
michael@0 777 ScopeIter si(frame, pc, cx);
michael@0 778 UnwindScope(cx, si, frame->script()->main());
michael@0 779
michael@0 780 // If ScriptDebugEpilogue returns |true| we have to return the frame's
michael@0 781 // return value. If it returns |false|, the debugger threw an exception.
michael@0 782 // In both cases we have to pop debug scopes.
michael@0 783 ok = ScriptDebugEpilogue(cx, frame, pc, ok);
michael@0 784
michael@0 785 if (frame->isNonEvalFunctionFrame()) {
michael@0 786 JS_ASSERT_IF(ok, frame->hasReturnValue());
michael@0 787 DebugScopes::onPopCall(frame, cx);
michael@0 788 } else if (frame->isStrictEvalFrame()) {
michael@0 789 JS_ASSERT_IF(frame->hasCallObj(), frame->scopeChain()->as<CallObject>().isForEval());
michael@0 790 DebugScopes::onPopStrictEvalScope(frame);
michael@0 791 }
michael@0 792
michael@0 793 // If the frame has a pushed SPS frame, make sure to pop it.
michael@0 794 if (frame->hasPushedSPSFrame()) {
michael@0 795 cx->runtime()->spsProfiler.exit(frame->script(), frame->maybeFun());
michael@0 796 // Unset the pushedSPSFrame flag because DebugEpilogue may get called before
michael@0 797 // probes::ExitScript in baseline during exception handling, and we don't
michael@0 798 // want to double-pop SPS frames.
michael@0 799 frame->unsetPushedSPSFrame();
michael@0 800 }
michael@0 801
michael@0 802 if (!ok) {
michael@0 803 // Pop this frame by updating ionTop, so that the exception handling
michael@0 804 // code will start at the previous frame.
michael@0 805
michael@0 806 IonJSFrameLayout *prefix = frame->framePrefix();
michael@0 807 EnsureExitFrame(prefix);
michael@0 808 cx->mainThread().ionTop = (uint8_t *)prefix;
michael@0 809 }
michael@0 810
michael@0 811 return ok;
michael@0 812 }
michael@0 813
michael@0 814 bool
michael@0 815 StrictEvalPrologue(JSContext *cx, BaselineFrame *frame)
michael@0 816 {
michael@0 817 return frame->strictEvalPrologue(cx);
michael@0 818 }
michael@0 819
michael@0 820 bool
michael@0 821 HeavyweightFunPrologue(JSContext *cx, BaselineFrame *frame)
michael@0 822 {
michael@0 823 return frame->heavyweightFunPrologue(cx);
michael@0 824 }
michael@0 825
michael@0 826 bool
michael@0 827 NewArgumentsObject(JSContext *cx, BaselineFrame *frame, MutableHandleValue res)
michael@0 828 {
michael@0 829 ArgumentsObject *obj = ArgumentsObject::createExpected(cx, frame);
michael@0 830 if (!obj)
michael@0 831 return false;
michael@0 832 res.setObject(*obj);
michael@0 833 return true;
michael@0 834 }
michael@0 835
michael@0 836 JSObject *
michael@0 837 InitRestParameter(JSContext *cx, uint32_t length, Value *rest, HandleObject templateObj,
michael@0 838 HandleObject objRes)
michael@0 839 {
michael@0 840 if (objRes) {
michael@0 841 Rooted<ArrayObject*> arrRes(cx, &objRes->as<ArrayObject>());
michael@0 842
michael@0 843 JS_ASSERT(!arrRes->getDenseInitializedLength());
michael@0 844 JS_ASSERT(arrRes->type() == templateObj->type());
michael@0 845
michael@0 846 // Fast path: we managed to allocate the array inline; initialize the
michael@0 847 // slots.
michael@0 848 if (length > 0) {
michael@0 849 if (!arrRes->ensureElements(cx, length))
michael@0 850 return nullptr;
michael@0 851 arrRes->setDenseInitializedLength(length);
michael@0 852 arrRes->initDenseElements(0, rest, length);
michael@0 853 arrRes->setLengthInt32(length);
michael@0 854 }
michael@0 855 return arrRes;
michael@0 856 }
michael@0 857
michael@0 858 NewObjectKind newKind = templateObj->type()->shouldPreTenure()
michael@0 859 ? TenuredObject
michael@0 860 : GenericObject;
michael@0 861 ArrayObject *arrRes = NewDenseCopiedArray(cx, length, rest, nullptr, newKind);
michael@0 862 if (arrRes)
michael@0 863 arrRes->setType(templateObj->type());
michael@0 864 return arrRes;
michael@0 865 }
michael@0 866
michael@0 867 bool
michael@0 868 HandleDebugTrap(JSContext *cx, BaselineFrame *frame, uint8_t *retAddr, bool *mustReturn)
michael@0 869 {
michael@0 870 *mustReturn = false;
michael@0 871
michael@0 872 RootedScript script(cx, frame->script());
michael@0 873 jsbytecode *pc = script->baselineScript()->icEntryFromReturnAddress(retAddr).pc(script);
michael@0 874
michael@0 875 JS_ASSERT(cx->compartment()->debugMode());
michael@0 876 JS_ASSERT(script->stepModeEnabled() || script->hasBreakpointsAt(pc));
michael@0 877
michael@0 878 RootedValue rval(cx);
michael@0 879 JSTrapStatus status = JSTRAP_CONTINUE;
michael@0 880 JSInterruptHook hook = cx->runtime()->debugHooks.interruptHook;
michael@0 881
michael@0 882 if (hook || script->stepModeEnabled()) {
michael@0 883 if (hook)
michael@0 884 status = hook(cx, script, pc, rval.address(), cx->runtime()->debugHooks.interruptHookData);
michael@0 885 if (status == JSTRAP_CONTINUE && script->stepModeEnabled())
michael@0 886 status = Debugger::onSingleStep(cx, &rval);
michael@0 887 }
michael@0 888
michael@0 889 if (status == JSTRAP_CONTINUE && script->hasBreakpointsAt(pc))
michael@0 890 status = Debugger::onTrap(cx, &rval);
michael@0 891
michael@0 892 switch (status) {
michael@0 893 case JSTRAP_CONTINUE:
michael@0 894 break;
michael@0 895
michael@0 896 case JSTRAP_ERROR:
michael@0 897 return false;
michael@0 898
michael@0 899 case JSTRAP_RETURN:
michael@0 900 *mustReturn = true;
michael@0 901 frame->setReturnValue(rval);
michael@0 902 return jit::DebugEpilogue(cx, frame, pc, true);
michael@0 903
michael@0 904 case JSTRAP_THROW:
michael@0 905 cx->setPendingException(rval);
michael@0 906 return false;
michael@0 907
michael@0 908 default:
michael@0 909 MOZ_ASSUME_UNREACHABLE("Invalid trap status");
michael@0 910 }
michael@0 911
michael@0 912 return true;
michael@0 913 }
michael@0 914
michael@0 915 bool
michael@0 916 OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn)
michael@0 917 {
michael@0 918 *mustReturn = false;
michael@0 919
michael@0 920 RootedScript script(cx, frame->script());
michael@0 921 JSTrapStatus status = JSTRAP_CONTINUE;
michael@0 922 RootedValue rval(cx);
michael@0 923
michael@0 924 if (JSDebuggerHandler handler = cx->runtime()->debugHooks.debuggerHandler)
michael@0 925 status = handler(cx, script, pc, rval.address(), cx->runtime()->debugHooks.debuggerHandlerData);
michael@0 926
michael@0 927 if (status == JSTRAP_CONTINUE)
michael@0 928 status = Debugger::onDebuggerStatement(cx, &rval);
michael@0 929
michael@0 930 switch (status) {
michael@0 931 case JSTRAP_ERROR:
michael@0 932 return false;
michael@0 933
michael@0 934 case JSTRAP_CONTINUE:
michael@0 935 return true;
michael@0 936
michael@0 937 case JSTRAP_RETURN:
michael@0 938 frame->setReturnValue(rval);
michael@0 939 *mustReturn = true;
michael@0 940 return jit::DebugEpilogue(cx, frame, pc, true);
michael@0 941
michael@0 942 case JSTRAP_THROW:
michael@0 943 cx->setPendingException(rval);
michael@0 944 return false;
michael@0 945
michael@0 946 default:
michael@0 947 MOZ_ASSUME_UNREACHABLE("Invalid trap status");
michael@0 948 }
michael@0 949 }
michael@0 950
michael@0 951 bool
michael@0 952 PushBlockScope(JSContext *cx, BaselineFrame *frame, Handle<StaticBlockObject *> block)
michael@0 953 {
michael@0 954 return frame->pushBlock(cx, block);
michael@0 955 }
michael@0 956
michael@0 957 bool
michael@0 958 PopBlockScope(JSContext *cx, BaselineFrame *frame)
michael@0 959 {
michael@0 960 frame->popBlock(cx);
michael@0 961 return true;
michael@0 962 }
michael@0 963
michael@0 964 bool
michael@0 965 DebugLeaveBlock(JSContext *cx, BaselineFrame *frame, jsbytecode *pc)
michael@0 966 {
michael@0 967 JS_ASSERT(frame->script()->baselineScript()->debugMode());
michael@0 968
michael@0 969 DebugScopes::onPopBlock(cx, frame, pc);
michael@0 970
michael@0 971 return true;
michael@0 972 }
michael@0 973
michael@0 974 bool
michael@0 975 EnterWith(JSContext *cx, BaselineFrame *frame, HandleValue val, Handle<StaticWithObject *> templ)
michael@0 976 {
michael@0 977 return EnterWithOperation(cx, frame, val, templ);
michael@0 978 }
michael@0 979
michael@0 980 bool
michael@0 981 LeaveWith(JSContext *cx, BaselineFrame *frame)
michael@0 982 {
michael@0 983 frame->popWith(cx);
michael@0 984 return true;
michael@0 985 }
michael@0 986
michael@0 987 bool
michael@0 988 InitBaselineFrameForOsr(BaselineFrame *frame, InterpreterFrame *interpFrame,
michael@0 989 uint32_t numStackValues)
michael@0 990 {
michael@0 991 return frame->initForOsr(interpFrame, numStackValues);
michael@0 992 }
michael@0 993
michael@0 994 JSObject *
michael@0 995 CreateDerivedTypedObj(JSContext *cx, HandleObject descr,
michael@0 996 HandleObject owner, int32_t offset)
michael@0 997 {
michael@0 998 JS_ASSERT(descr->is<SizedTypeDescr>());
michael@0 999 JS_ASSERT(owner->is<TypedObject>());
michael@0 1000 Rooted<SizedTypeDescr*> descr1(cx, &descr->as<SizedTypeDescr>());
michael@0 1001 Rooted<TypedObject*> owner1(cx, &owner->as<TypedObject>());
michael@0 1002 return TypedObject::createDerived(cx, descr1, owner1, offset);
michael@0 1003 }
michael@0 1004
michael@0 1005 JSString *
michael@0 1006 RegExpReplace(JSContext *cx, HandleString string, HandleObject regexp, HandleString repl)
michael@0 1007 {
michael@0 1008 JS_ASSERT(string);
michael@0 1009 JS_ASSERT(repl);
michael@0 1010
michael@0 1011 RootedValue rval(cx);
michael@0 1012 if (!str_replace_regexp_raw(cx, string, regexp, repl, &rval))
michael@0 1013 return nullptr;
michael@0 1014
michael@0 1015 return rval.toString();
michael@0 1016 }
michael@0 1017
michael@0 1018 JSString *
michael@0 1019 StringReplace(JSContext *cx, HandleString string, HandleString pattern, HandleString repl)
michael@0 1020 {
michael@0 1021 JS_ASSERT(string);
michael@0 1022 JS_ASSERT(pattern);
michael@0 1023 JS_ASSERT(repl);
michael@0 1024
michael@0 1025 RootedValue rval(cx);
michael@0 1026 if (!str_replace_string_raw(cx, string, pattern, repl, &rval))
michael@0 1027 return nullptr;
michael@0 1028
michael@0 1029 return rval.toString();
michael@0 1030 }
michael@0 1031
michael@0 1032 bool
michael@0 1033 Recompile(JSContext *cx)
michael@0 1034 {
michael@0 1035 JS_ASSERT(cx->currentlyRunningInJit());
michael@0 1036 JitActivationIterator activations(cx->runtime());
michael@0 1037 JitFrameIterator iter(activations);
michael@0 1038
michael@0 1039 JS_ASSERT(iter.type() == JitFrame_Exit);
michael@0 1040 ++iter;
michael@0 1041
michael@0 1042 bool isConstructing = iter.isConstructing();
michael@0 1043 RootedScript script(cx, iter.script());
michael@0 1044 JS_ASSERT(script->hasIonScript());
michael@0 1045
michael@0 1046 if (!IsIonEnabled(cx))
michael@0 1047 return true;
michael@0 1048
michael@0 1049 MethodStatus status = Recompile(cx, script, nullptr, nullptr, isConstructing);
michael@0 1050 if (status == Method_Error)
michael@0 1051 return false;
michael@0 1052
michael@0 1053 return true;
michael@0 1054 }
michael@0 1055
michael@0 1056 bool
michael@0 1057 SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue value,
michael@0 1058 bool strict)
michael@0 1059 {
michael@0 1060 // This function is called from Ion code for StoreElementHole's OOL path.
michael@0 1061 // In this case we know the object is native, has no indexed properties
michael@0 1062 // and we can use setDenseElement instead of setDenseElementWithType.
michael@0 1063
michael@0 1064 MOZ_ASSERT(obj->isNative());
michael@0 1065 MOZ_ASSERT(!obj->isIndexed());
michael@0 1066
michael@0 1067 JSObject::EnsureDenseResult result = JSObject::ED_SPARSE;
michael@0 1068 do {
michael@0 1069 if (index < 0)
michael@0 1070 break;
michael@0 1071 bool isArray = obj->is<ArrayObject>();
michael@0 1072 if (isArray && !obj->as<ArrayObject>().lengthIsWritable())
michael@0 1073 break;
michael@0 1074 uint32_t idx = uint32_t(index);
michael@0 1075 result = obj->ensureDenseElements(cx, idx, 1);
michael@0 1076 if (result != JSObject::ED_OK)
michael@0 1077 break;
michael@0 1078 if (isArray) {
michael@0 1079 ArrayObject &arr = obj->as<ArrayObject>();
michael@0 1080 if (idx >= arr.length())
michael@0 1081 arr.setLengthInt32(idx + 1);
michael@0 1082 }
michael@0 1083 obj->setDenseElement(idx, value);
michael@0 1084 return true;
michael@0 1085 } while (false);
michael@0 1086
michael@0 1087 if (result == JSObject::ED_FAILED)
michael@0 1088 return false;
michael@0 1089 MOZ_ASSERT(result == JSObject::ED_SPARSE);
michael@0 1090
michael@0 1091 RootedValue indexVal(cx, Int32Value(index));
michael@0 1092 return SetObjectElement(cx, obj, indexVal, value, strict);
michael@0 1093 }
michael@0 1094
michael@0 1095 #ifdef DEBUG
michael@0 1096 void
michael@0 1097 AssertValidObjectPtr(JSContext *cx, JSObject *obj)
michael@0 1098 {
michael@0 1099 // Check what we can, so that we'll hopefully assert/crash if we get a
michael@0 1100 // bogus object (pointer).
michael@0 1101 JS_ASSERT(obj->compartment() == cx->compartment());
michael@0 1102 JS_ASSERT(obj->runtimeFromMainThread() == cx->runtime());
michael@0 1103
michael@0 1104 JS_ASSERT_IF(!obj->hasLazyType(),
michael@0 1105 obj->type()->clasp() == obj->lastProperty()->getObjectClass());
michael@0 1106
michael@0 1107 if (obj->isTenured()) {
michael@0 1108 JS_ASSERT(obj->isAligned());
michael@0 1109 gc::AllocKind kind = obj->tenuredGetAllocKind();
michael@0 1110 JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
michael@0 1111 JS_ASSERT(obj->tenuredZone() == cx->zone());
michael@0 1112 }
michael@0 1113 }
michael@0 1114
michael@0 1115 void
michael@0 1116 AssertValidStringPtr(JSContext *cx, JSString *str)
michael@0 1117 {
michael@0 1118 // We can't closely inspect strings from another runtime.
michael@0 1119 if (str->runtimeFromAnyThread() != cx->runtime()) {
michael@0 1120 JS_ASSERT(str->isPermanentAtom());
michael@0 1121 return;
michael@0 1122 }
michael@0 1123
michael@0 1124 if (str->isAtom())
michael@0 1125 JS_ASSERT(cx->runtime()->isAtomsZone(str->tenuredZone()));
michael@0 1126 else
michael@0 1127 JS_ASSERT(str->tenuredZone() == cx->zone());
michael@0 1128
michael@0 1129 JS_ASSERT(str->runtimeFromMainThread() == cx->runtime());
michael@0 1130 JS_ASSERT(str->isAligned());
michael@0 1131 JS_ASSERT(str->length() <= JSString::MAX_LENGTH);
michael@0 1132
michael@0 1133 gc::AllocKind kind = str->tenuredGetAllocKind();
michael@0 1134 if (str->isFatInline())
michael@0 1135 JS_ASSERT(kind == gc::FINALIZE_FAT_INLINE_STRING);
michael@0 1136 else if (str->isExternal())
michael@0 1137 JS_ASSERT(kind == gc::FINALIZE_EXTERNAL_STRING);
michael@0 1138 else if (str->isAtom() || str->isFlat())
michael@0 1139 JS_ASSERT(kind == gc::FINALIZE_STRING || kind == gc::FINALIZE_FAT_INLINE_STRING);
michael@0 1140 else
michael@0 1141 JS_ASSERT(kind == gc::FINALIZE_STRING);
michael@0 1142 }
michael@0 1143
michael@0 1144 void
michael@0 1145 AssertValidValue(JSContext *cx, Value *v)
michael@0 1146 {
michael@0 1147 if (v->isObject()) {
michael@0 1148 AssertValidObjectPtr(cx, &v->toObject());
michael@0 1149 return;
michael@0 1150 }
michael@0 1151 if (v->isString()) {
michael@0 1152 AssertValidStringPtr(cx, v->toString());
michael@0 1153 return;
michael@0 1154 }
michael@0 1155 }
michael@0 1156 #endif
michael@0 1157
michael@0 1158 } // namespace jit
michael@0 1159 } // namespace js

mercurial