js/src/jit/VMFunctions.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/VMFunctions.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1159 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "jit/VMFunctions.h"
    1.11 +
    1.12 +#include "builtin/TypedObject.h"
    1.13 +#include "frontend/BytecodeCompiler.h"
    1.14 +#include "jit/arm/Simulator-arm.h"
    1.15 +#include "jit/BaselineIC.h"
    1.16 +#include "jit/IonFrames.h"
    1.17 +#include "jit/JitCompartment.h"
    1.18 +#include "vm/ArrayObject.h"
    1.19 +#include "vm/Debugger.h"
    1.20 +#include "vm/Interpreter.h"
    1.21 +
    1.22 +#include "jsinferinlines.h"
    1.23 +
    1.24 +#include "jit/BaselineFrame-inl.h"
    1.25 +#include "jit/IonFrames-inl.h"
    1.26 +#include "vm/Interpreter-inl.h"
    1.27 +#include "vm/StringObject-inl.h"
    1.28 +
    1.29 +using namespace js;
    1.30 +using namespace js::jit;
    1.31 +
    1.32 +namespace js {
    1.33 +namespace jit {
    1.34 +
    1.35 +// Don't explicitly initialize, it's not guaranteed that this initializer will
    1.36 +// run before the constructors for static VMFunctions.
    1.37 +/* static */ VMFunction *VMFunction::functions;
    1.38 +
    1.39 +AutoDetectInvalidation::AutoDetectInvalidation(JSContext *cx, Value *rval, IonScript *ionScript)
    1.40 +  : cx_(cx),
    1.41 +    ionScript_(ionScript ? ionScript : GetTopIonJSScript(cx)->ionScript()),
    1.42 +    rval_(rval),
    1.43 +    disabled_(false)
    1.44 +{ }
    1.45 +
    1.46 +void
    1.47 +VMFunction::addToFunctions()
    1.48 +{
    1.49 +    static bool initialized = false;
    1.50 +    if (!initialized) {
    1.51 +        initialized = true;
    1.52 +        functions = nullptr;
    1.53 +    }
    1.54 +    this->next = functions;
    1.55 +    functions = this;
    1.56 +}
    1.57 +
    1.58 +bool
    1.59 +InvokeFunction(JSContext *cx, HandleObject obj0, uint32_t argc, Value *argv, Value *rval)
    1.60 +{
    1.61 +    RootedObject obj(cx, obj0);
    1.62 +    if (obj->is<JSFunction>()) {
    1.63 +        RootedFunction fun(cx, &obj->as<JSFunction>());
    1.64 +        if (fun->isInterpreted()) {
    1.65 +            if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
    1.66 +                return false;
    1.67 +
    1.68 +            // Clone function at call site if needed.
    1.69 +            if (fun->nonLazyScript()->shouldCloneAtCallsite()) {
    1.70 +                jsbytecode *pc;
    1.71 +                RootedScript script(cx, cx->currentScript(&pc));
    1.72 +                fun = CloneFunctionAtCallsite(cx, fun, script, pc);
    1.73 +                if (!fun)
    1.74 +                    return false;
    1.75 +            }
    1.76 +        }
    1.77 +    }
    1.78 +
    1.79 +    // Data in the argument vector is arranged for a JIT -> JIT call.
    1.80 +    Value thisv = argv[0];
    1.81 +    Value *argvWithoutThis = argv + 1;
    1.82 +
    1.83 +    // For constructing functions, |this| is constructed at caller side and we can just call Invoke.
    1.84 +    // When creating this failed / is impossible at caller site, i.e. MagicValue(JS_IS_CONSTRUCTING),
    1.85 +    // we use InvokeConstructor that creates it at the callee side.
    1.86 +    RootedValue rv(cx);
    1.87 +    if (thisv.isMagic(JS_IS_CONSTRUCTING)) {
    1.88 +        if (!InvokeConstructor(cx, ObjectValue(*obj), argc, argvWithoutThis, rv.address()))
    1.89 +            return false;
    1.90 +    } else {
    1.91 +        if (!Invoke(cx, thisv, ObjectValue(*obj), argc, argvWithoutThis, &rv))
    1.92 +            return false;
    1.93 +    }
    1.94 +
    1.95 +    if (obj->is<JSFunction>()) {
    1.96 +        jsbytecode *pc;
    1.97 +        RootedScript script(cx, cx->currentScript(&pc));
    1.98 +        types::TypeScript::Monitor(cx, script, pc, rv.get());
    1.99 +    }
   1.100 +
   1.101 +    *rval = rv;
   1.102 +    return true;
   1.103 +}
   1.104 +
   1.105 +JSObject *
   1.106 +NewGCObject(JSContext *cx, gc::AllocKind allocKind, gc::InitialHeap initialHeap)
   1.107 +{
   1.108 +    return js::NewGCObject<CanGC>(cx, allocKind, 0, initialHeap);
   1.109 +}
   1.110 +
   1.111 +bool
   1.112 +CheckOverRecursed(JSContext *cx)
   1.113 +{
   1.114 +    // IonMonkey's stackLimit is equal to nativeStackLimit by default. When we
   1.115 +    // request an interrupt, we set the jitStackLimit to nullptr, which causes
   1.116 +    // the stack limit check to fail.
   1.117 +    //
   1.118 +    // There are two states we're concerned about here:
   1.119 +    //   (1) The interrupt bit is set, and we need to fire the interrupt callback.
   1.120 +    //   (2) The stack limit has been exceeded, and we need to throw an error.
   1.121 +    //
   1.122 +    // Note that we can reach here if jitStackLimit is MAXADDR, but interrupt
   1.123 +    // has not yet been set to 1. That's okay; it will be set to 1 very shortly,
   1.124 +    // and in the interim we might just fire a few useless calls to
   1.125 +    // CheckOverRecursed.
   1.126 +#ifdef JS_ARM_SIMULATOR
   1.127 +    JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, 0, return false);
   1.128 +#else
   1.129 +    JS_CHECK_RECURSION(cx, return false);
   1.130 +#endif
   1.131 +
   1.132 +    if (cx->runtime()->interrupt)
   1.133 +        return InterruptCheck(cx);
   1.134 +
   1.135 +    return true;
   1.136 +}
   1.137 +
   1.138 +// This function can get called in two contexts.  In the usual context, it's
   1.139 +// called with ealyCheck=false, after the scope chain has been initialized on
   1.140 +// a baseline frame.  In this case, it's ok to throw an exception, so a failed
   1.141 +// stack check returns false, and a successful stack check promps a check for
   1.142 +// an interrupt from the runtime, which may also cause a false return.
   1.143 +//
   1.144 +// In the second case, it's called with earlyCheck=true, prior to frame
   1.145 +// initialization.  An exception cannot be thrown in this instance, so instead
   1.146 +// an error flag is set on the frame and true returned.
   1.147 +bool
   1.148 +CheckOverRecursedWithExtra(JSContext *cx, BaselineFrame *frame,
   1.149 +                           uint32_t extra, uint32_t earlyCheck)
   1.150 +{
   1.151 +    JS_ASSERT_IF(earlyCheck, !frame->overRecursed());
   1.152 +
   1.153 +    // See |CheckOverRecursed| above.  This is a variant of that function which
   1.154 +    // accepts an argument holding the extra stack space needed for the Baseline
   1.155 +    // frame that's about to be pushed.
   1.156 +    uint8_t spDummy;
   1.157 +    uint8_t *checkSp = (&spDummy) - extra;
   1.158 +    if (earlyCheck) {
   1.159 +#ifdef JS_ARM_SIMULATOR
   1.160 +        (void)checkSp;
   1.161 +        JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, frame->setOverRecursed());
   1.162 +#else
   1.163 +        JS_CHECK_RECURSION_WITH_SP(cx, checkSp, frame->setOverRecursed());
   1.164 +#endif
   1.165 +        return true;
   1.166 +    }
   1.167 +
   1.168 +    // The OVERRECURSED flag may have already been set on the frame by an
   1.169 +    // early over-recursed check.  If so, throw immediately.
   1.170 +    if (frame->overRecursed())
   1.171 +        return false;
   1.172 +
   1.173 +#ifdef JS_ARM_SIMULATOR
   1.174 +    JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, return false);
   1.175 +#else
   1.176 +    JS_CHECK_RECURSION_WITH_SP(cx, checkSp, return false);
   1.177 +#endif
   1.178 +
   1.179 +    if (cx->runtime()->interrupt)
   1.180 +        return InterruptCheck(cx);
   1.181 +
   1.182 +    return true;
   1.183 +}
   1.184 +
   1.185 +bool
   1.186 +DefVarOrConst(JSContext *cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain)
   1.187 +{
   1.188 +    // Given the ScopeChain, extract the VarObj.
   1.189 +    RootedObject obj(cx, scopeChain);
   1.190 +    while (!obj->isVarObj())
   1.191 +        obj = obj->enclosingScope();
   1.192 +
   1.193 +    return DefVarOrConstOperation(cx, obj, dn, attrs);
   1.194 +}
   1.195 +
   1.196 +bool
   1.197 +SetConst(JSContext *cx, HandlePropertyName name, HandleObject scopeChain, HandleValue rval)
   1.198 +{
   1.199 +    // Given the ScopeChain, extract the VarObj.
   1.200 +    RootedObject obj(cx, scopeChain);
   1.201 +    while (!obj->isVarObj())
   1.202 +        obj = obj->enclosingScope();
   1.203 +
   1.204 +    return SetConstOperation(cx, obj, name, rval);
   1.205 +}
   1.206 +
   1.207 +bool
   1.208 +MutatePrototype(JSContext *cx, HandleObject obj, HandleValue value)
   1.209 +{
   1.210 +    MOZ_ASSERT(obj->is<JSObject>(), "must only be used with object literals");
   1.211 +    if (!value.isObjectOrNull())
   1.212 +        return true;
   1.213 +
   1.214 +    RootedObject newProto(cx, value.toObjectOrNull());
   1.215 +
   1.216 +    bool succeeded;
   1.217 +    if (!JSObject::setProto(cx, obj, newProto, &succeeded))
   1.218 +        return false;
   1.219 +    MOZ_ASSERT(succeeded);
   1.220 +    return true;
   1.221 +}
   1.222 +
   1.223 +bool
   1.224 +InitProp(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value)
   1.225 +{
   1.226 +    // Copy the incoming value. This may be overwritten; the return value is discarded.
   1.227 +    RootedValue rval(cx, value);
   1.228 +    RootedId id(cx, NameToId(name));
   1.229 +
   1.230 +    MOZ_ASSERT(name != cx->names().proto,
   1.231 +               "__proto__ should have been handled by JSOP_MUTATEPROTO");
   1.232 +    return DefineNativeProperty(cx, obj, id, rval, nullptr, nullptr, JSPROP_ENUMERATE);
   1.233 +}
   1.234 +
   1.235 +template<bool Equal>
   1.236 +bool
   1.237 +LooselyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
   1.238 +{
   1.239 +    if (!js::LooselyEqual(cx, lhs, rhs, res))
   1.240 +        return false;
   1.241 +    if (!Equal)
   1.242 +        *res = !*res;
   1.243 +    return true;
   1.244 +}
   1.245 +
   1.246 +template bool LooselyEqual<true>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
   1.247 +template bool LooselyEqual<false>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
   1.248 +
   1.249 +template<bool Equal>
   1.250 +bool
   1.251 +StrictlyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
   1.252 +{
   1.253 +    if (!js::StrictlyEqual(cx, lhs, rhs, res))
   1.254 +        return false;
   1.255 +    if (!Equal)
   1.256 +        *res = !*res;
   1.257 +    return true;
   1.258 +}
   1.259 +
   1.260 +template bool StrictlyEqual<true>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
   1.261 +template bool StrictlyEqual<false>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
   1.262 +
   1.263 +bool
   1.264 +LessThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
   1.265 +{
   1.266 +    return LessThanOperation(cx, lhs, rhs, res);
   1.267 +}
   1.268 +
   1.269 +bool
   1.270 +LessThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
   1.271 +{
   1.272 +    return LessThanOrEqualOperation(cx, lhs, rhs, res);
   1.273 +}
   1.274 +
   1.275 +bool
   1.276 +GreaterThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
   1.277 +{
   1.278 +    return GreaterThanOperation(cx, lhs, rhs, res);
   1.279 +}
   1.280 +
   1.281 +bool
   1.282 +GreaterThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
   1.283 +{
   1.284 +    return GreaterThanOrEqualOperation(cx, lhs, rhs, res);
   1.285 +}
   1.286 +
   1.287 +template<bool Equal>
   1.288 +bool
   1.289 +StringsEqual(JSContext *cx, HandleString lhs, HandleString rhs, bool *res)
   1.290 +{
   1.291 +    if (!js::EqualStrings(cx, lhs, rhs, res))
   1.292 +        return false;
   1.293 +    if (!Equal)
   1.294 +        *res = !*res;
   1.295 +    return true;
   1.296 +}
   1.297 +
   1.298 +template bool StringsEqual<true>(JSContext *cx, HandleString lhs, HandleString rhs, bool *res);
   1.299 +template bool StringsEqual<false>(JSContext *cx, HandleString lhs, HandleString rhs, bool *res);
   1.300 +
   1.301 +bool
   1.302 +IteratorMore(JSContext *cx, HandleObject obj, bool *res)
   1.303 +{
   1.304 +    RootedValue tmp(cx);
   1.305 +    if (!js_IteratorMore(cx, obj, &tmp))
   1.306 +        return false;
   1.307 +
   1.308 +    *res = tmp.toBoolean();
   1.309 +    return true;
   1.310 +}
   1.311 +
   1.312 +JSObject*
   1.313 +NewInitArray(JSContext *cx, uint32_t count, types::TypeObject *typeArg)
   1.314 +{
   1.315 +    RootedTypeObject type(cx, typeArg);
   1.316 +    NewObjectKind newKind = !type ? SingletonObject : GenericObject;
   1.317 +    if (type && type->shouldPreTenure())
   1.318 +        newKind = TenuredObject;
   1.319 +    RootedObject obj(cx, NewDenseAllocatedArray(cx, count, nullptr, newKind));
   1.320 +    if (!obj)
   1.321 +        return nullptr;
   1.322 +
   1.323 +    if (type)
   1.324 +        obj->setType(type);
   1.325 +
   1.326 +    return obj;
   1.327 +}
   1.328 +
   1.329 +JSObject*
   1.330 +NewInitObject(JSContext *cx, HandleObject templateObject)
   1.331 +{
   1.332 +    NewObjectKind newKind = templateObject->hasSingletonType() ? SingletonObject : GenericObject;
   1.333 +    if (!templateObject->hasLazyType() && templateObject->type()->shouldPreTenure())
   1.334 +        newKind = TenuredObject;
   1.335 +    RootedObject obj(cx, CopyInitializerObject(cx, templateObject, newKind));
   1.336 +
   1.337 +    if (!obj)
   1.338 +        return nullptr;
   1.339 +
   1.340 +    if (!templateObject->hasSingletonType())
   1.341 +        obj->setType(templateObject->type());
   1.342 +
   1.343 +    return obj;
   1.344 +}
   1.345 +
   1.346 +JSObject *
   1.347 +NewInitObjectWithClassPrototype(JSContext *cx, HandleObject templateObject)
   1.348 +{
   1.349 +    JS_ASSERT(!templateObject->hasSingletonType());
   1.350 +    JS_ASSERT(!templateObject->hasLazyType());
   1.351 +
   1.352 +    NewObjectKind newKind = templateObject->type()->shouldPreTenure()
   1.353 +                            ? TenuredObject
   1.354 +                            : GenericObject;
   1.355 +    JSObject *obj = NewObjectWithGivenProto(cx,
   1.356 +                                            templateObject->getClass(),
   1.357 +                                            templateObject->getProto(),
   1.358 +                                            cx->global(),
   1.359 +                                            newKind);
   1.360 +    if (!obj)
   1.361 +        return nullptr;
   1.362 +
   1.363 +    obj->setType(templateObject->type());
   1.364 +
   1.365 +    return obj;
   1.366 +}
   1.367 +
   1.368 +bool
   1.369 +ArraySpliceDense(JSContext *cx, HandleObject obj, uint32_t start, uint32_t deleteCount)
   1.370 +{
   1.371 +    JS::AutoValueArray<4> argv(cx);
   1.372 +    argv[0].setUndefined();
   1.373 +    argv[1].setObject(*obj);
   1.374 +    argv[2].set(Int32Value(start));
   1.375 +    argv[3].set(Int32Value(deleteCount));
   1.376 +
   1.377 +    return js::array_splice_impl(cx, 2, argv.begin(), false);
   1.378 +}
   1.379 +
   1.380 +bool
   1.381 +ArrayPopDense(JSContext *cx, HandleObject obj, MutableHandleValue rval)
   1.382 +{
   1.383 +    JS_ASSERT(obj->is<ArrayObject>());
   1.384 +
   1.385 +    AutoDetectInvalidation adi(cx, rval.address());
   1.386 +
   1.387 +    JS::AutoValueArray<2> argv(cx);
   1.388 +    argv[0].setUndefined();
   1.389 +    argv[1].setObject(*obj);
   1.390 +    if (!js::array_pop(cx, 0, argv.begin()))
   1.391 +        return false;
   1.392 +
   1.393 +    // If the result is |undefined|, the array was probably empty and we
   1.394 +    // have to monitor the return value.
   1.395 +    rval.set(argv[0]);
   1.396 +    if (rval.isUndefined())
   1.397 +        types::TypeScript::Monitor(cx, rval);
   1.398 +    return true;
   1.399 +}
   1.400 +
   1.401 +bool
   1.402 +ArrayPushDense(JSContext *cx, HandleObject obj, HandleValue v, uint32_t *length)
   1.403 +{
   1.404 +    JS_ASSERT(obj->is<ArrayObject>());
   1.405 +
   1.406 +    JS::AutoValueArray<3> argv(cx);
   1.407 +    argv[0].setUndefined();
   1.408 +    argv[1].setObject(*obj);
   1.409 +    argv[2].set(v);
   1.410 +    if (!js::array_push(cx, 1, argv.begin()))
   1.411 +        return false;
   1.412 +
   1.413 +    *length = argv[0].toInt32();
   1.414 +    return true;
   1.415 +}
   1.416 +
   1.417 +bool
   1.418 +ArrayShiftDense(JSContext *cx, HandleObject obj, MutableHandleValue rval)
   1.419 +{
   1.420 +    JS_ASSERT(obj->is<ArrayObject>());
   1.421 +
   1.422 +    AutoDetectInvalidation adi(cx, rval.address());
   1.423 +
   1.424 +    JS::AutoValueArray<2> argv(cx);
   1.425 +    argv[0].setUndefined();
   1.426 +    argv[1].setObject(*obj);
   1.427 +    if (!js::array_shift(cx, 0, argv.begin()))
   1.428 +        return false;
   1.429 +
   1.430 +    // If the result is |undefined|, the array was probably empty and we
   1.431 +    // have to monitor the return value.
   1.432 +    rval.set(argv[0]);
   1.433 +    if (rval.isUndefined())
   1.434 +        types::TypeScript::Monitor(cx, rval);
   1.435 +    return true;
   1.436 +}
   1.437 +
   1.438 +JSObject *
   1.439 +ArrayConcatDense(JSContext *cx, HandleObject obj1, HandleObject obj2, HandleObject objRes)
   1.440 +{
   1.441 +    Rooted<ArrayObject*> arr1(cx, &obj1->as<ArrayObject>());
   1.442 +    Rooted<ArrayObject*> arr2(cx, &obj2->as<ArrayObject>());
   1.443 +    Rooted<ArrayObject*> arrRes(cx, objRes ? &objRes->as<ArrayObject>() : nullptr);
   1.444 +
   1.445 +    if (arrRes) {
   1.446 +        // Fast path if we managed to allocate an object inline.
   1.447 +        if (!js::array_concat_dense(cx, arr1, arr2, arrRes))
   1.448 +            return nullptr;
   1.449 +        return arrRes;
   1.450 +    }
   1.451 +
   1.452 +    JS::AutoValueArray<3> argv(cx);
   1.453 +    argv[0].setUndefined();
   1.454 +    argv[1].setObject(*arr1);
   1.455 +    argv[2].setObject(*arr2);
   1.456 +    if (!js::array_concat(cx, 1, argv.begin()))
   1.457 +        return nullptr;
   1.458 +    return &argv[0].toObject();
   1.459 +}
   1.460 +
   1.461 +bool
   1.462 +CharCodeAt(JSContext *cx, HandleString str, int32_t index, uint32_t *code)
   1.463 +{
   1.464 +    jschar c;
   1.465 +    if (!str->getChar(cx, index, &c))
   1.466 +        return false;
   1.467 +    *code = c;
   1.468 +    return true;
   1.469 +}
   1.470 +
   1.471 +JSFlatString *
   1.472 +StringFromCharCode(JSContext *cx, int32_t code)
   1.473 +{
   1.474 +    jschar c = jschar(code);
   1.475 +
   1.476 +    if (StaticStrings::hasUnit(c))
   1.477 +        return cx->staticStrings().getUnit(c);
   1.478 +
   1.479 +    return js_NewStringCopyN<CanGC>(cx, &c, 1);
   1.480 +}
   1.481 +
   1.482 +bool
   1.483 +SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
   1.484 +            bool strict, jsbytecode *pc)
   1.485 +{
   1.486 +    RootedValue v(cx, value);
   1.487 +    RootedId id(cx, NameToId(name));
   1.488 +
   1.489 +    JSOp op = JSOp(*pc);
   1.490 +
   1.491 +    if (op == JSOP_SETALIASEDVAR) {
   1.492 +        // Aliased var assigns ignore readonly attributes on the property, as
   1.493 +        // required for initializing 'const' closure variables.
   1.494 +        Shape *shape = obj->nativeLookup(cx, name);
   1.495 +        JS_ASSERT(shape && shape->hasSlot());
   1.496 +        obj->nativeSetSlotWithType(cx, shape, value);
   1.497 +        return true;
   1.498 +    }
   1.499 +
   1.500 +    if (MOZ_LIKELY(!obj->getOps()->setProperty)) {
   1.501 +        return baseops::SetPropertyHelper<SequentialExecution>(
   1.502 +            cx, obj, obj, id,
   1.503 +            (op == JSOP_SETNAME || op == JSOP_SETGNAME)
   1.504 +            ? baseops::Unqualified
   1.505 +            : baseops::Qualified,
   1.506 +            &v,
   1.507 +            strict);
   1.508 +    }
   1.509 +
   1.510 +    return JSObject::setGeneric(cx, obj, obj, id, &v, strict);
   1.511 +}
   1.512 +
   1.513 +bool
   1.514 +InterruptCheck(JSContext *cx)
   1.515 +{
   1.516 +    gc::MaybeVerifyBarriers(cx);
   1.517 +
   1.518 +    // Fix loop backedges so that they do not invoke the interrupt again.
   1.519 +    // No lock is held here and it's possible we could segv in the middle here
   1.520 +    // and end up with a state where some fraction of the backedges point to
   1.521 +    // the interrupt handler and some don't. This is ok since the interrupt
   1.522 +    // is definitely about to be handled; if there are still backedges
   1.523 +    // afterwards which point to the interrupt handler, the next time they are
   1.524 +    // taken the backedges will just be reset again.
   1.525 +    cx->runtime()->jitRuntime()->patchIonBackedges(cx->runtime(),
   1.526 +                                                   JitRuntime::BackedgeLoopHeader);
   1.527 +
   1.528 +    return CheckForInterrupt(cx);
   1.529 +}
   1.530 +
   1.531 +HeapSlot *
   1.532 +NewSlots(JSRuntime *rt, unsigned nslots)
   1.533 +{
   1.534 +    JS_STATIC_ASSERT(sizeof(Value) == sizeof(HeapSlot));
   1.535 +
   1.536 +    Value *slots = reinterpret_cast<Value *>(rt->malloc_(nslots * sizeof(Value)));
   1.537 +    if (!slots)
   1.538 +        return nullptr;
   1.539 +
   1.540 +    for (unsigned i = 0; i < nslots; i++)
   1.541 +        slots[i] = UndefinedValue();
   1.542 +
   1.543 +    return reinterpret_cast<HeapSlot *>(slots);
   1.544 +}
   1.545 +
   1.546 +JSObject *
   1.547 +NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots)
   1.548 +{
   1.549 +    JSObject *obj = CallObject::create(cx, shape, type, slots);
   1.550 +    if (!obj)
   1.551 +        return nullptr;
   1.552 +
   1.553 +#ifdef JSGC_GENERATIONAL
   1.554 +    // The JIT creates call objects in the nursery, so elides barriers for
   1.555 +    // the initializing writes. The interpreter, however, may have allocated
   1.556 +    // the call object tenured, so barrier as needed before re-entering.
   1.557 +    if (!IsInsideNursery(cx->runtime(), obj))
   1.558 +        cx->runtime()->gcStoreBuffer.putWholeCell(obj);
   1.559 +#endif
   1.560 +
   1.561 +    return obj;
   1.562 +}
   1.563 +
   1.564 +JSObject *
   1.565 +NewSingletonCallObject(JSContext *cx, HandleShape shape, HeapSlot *slots)
   1.566 +{
   1.567 +    JSObject *obj = CallObject::createSingleton(cx, shape, slots);
   1.568 +    if (!obj)
   1.569 +        return nullptr;
   1.570 +
   1.571 +#ifdef JSGC_GENERATIONAL
   1.572 +    // The JIT creates call objects in the nursery, so elides barriers for
   1.573 +    // the initializing writes. The interpreter, however, may have allocated
   1.574 +    // the call object tenured, so barrier as needed before re-entering.
   1.575 +    MOZ_ASSERT(!IsInsideNursery(cx->runtime(), obj),
   1.576 +               "singletons are created in the tenured heap");
   1.577 +    cx->runtime()->gcStoreBuffer.putWholeCell(obj);
   1.578 +#endif
   1.579 +
   1.580 +    return obj;
   1.581 +}
   1.582 +
   1.583 +JSObject *
   1.584 +NewStringObject(JSContext *cx, HandleString str)
   1.585 +{
   1.586 +    return StringObject::create(cx, str);
   1.587 +}
   1.588 +
   1.589 +bool
   1.590 +SPSEnter(JSContext *cx, HandleScript script)
   1.591 +{
   1.592 +    return cx->runtime()->spsProfiler.enter(script, script->functionNonDelazifying());
   1.593 +}
   1.594 +
   1.595 +bool
   1.596 +SPSExit(JSContext *cx, HandleScript script)
   1.597 +{
   1.598 +    cx->runtime()->spsProfiler.exit(script, script->functionNonDelazifying());
   1.599 +    return true;
   1.600 +}
   1.601 +
   1.602 +bool
   1.603 +OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, bool *out)
   1.604 +{
   1.605 +    RootedId id(cx);
   1.606 +    if (!ValueToId<CanGC>(cx, key, &id))
   1.607 +        return false;
   1.608 +
   1.609 +    RootedObject obj2(cx);
   1.610 +    RootedShape prop(cx);
   1.611 +    if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &prop))
   1.612 +        return false;
   1.613 +
   1.614 +    *out = !!prop;
   1.615 +    return true;
   1.616 +}
   1.617 +
   1.618 +bool
   1.619 +OperatorInI(JSContext *cx, uint32_t index, HandleObject obj, bool *out)
   1.620 +{
   1.621 +    RootedValue key(cx, Int32Value(index));
   1.622 +    return OperatorIn(cx, key, obj, out);
   1.623 +}
   1.624 +
   1.625 +bool
   1.626 +GetIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue rval)
   1.627 +{
   1.628 +    if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, rval))
   1.629 +        return false;
   1.630 +
   1.631 +    // This function is called when we try to compile a cold getintrinsic
   1.632 +    // op. MCallGetIntrinsicValue has an AliasSet of None for optimization
   1.633 +    // purposes, as its side effect is not observable from JS. We are
   1.634 +    // guaranteed to bail out after this function, but because of its AliasSet,
   1.635 +    // type info will not be reflowed. Manually monitor here.
   1.636 +    types::TypeScript::Monitor(cx, rval);
   1.637 +
   1.638 +    return true;
   1.639 +}
   1.640 +
   1.641 +bool
   1.642 +CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval)
   1.643 +{
   1.644 +    rval.set(MagicValue(JS_IS_CONSTRUCTING));
   1.645 +
   1.646 +    if (callee->is<JSFunction>()) {
   1.647 +        JSFunction *fun = &callee->as<JSFunction>();
   1.648 +        if (fun->isInterpretedConstructor()) {
   1.649 +            JSScript *script = fun->getOrCreateScript(cx);
   1.650 +            if (!script || !script->ensureHasTypes(cx))
   1.651 +                return false;
   1.652 +            JSObject *thisObj = CreateThisForFunction(cx, callee, GenericObject);
   1.653 +            if (!thisObj)
   1.654 +                return false;
   1.655 +            rval.set(ObjectValue(*thisObj));
   1.656 +        }
   1.657 +    }
   1.658 +
   1.659 +    return true;
   1.660 +}
   1.661 +
   1.662 +void
   1.663 +GetDynamicName(JSContext *cx, JSObject *scopeChain, JSString *str, Value *vp)
   1.664 +{
   1.665 +    // Lookup a string on the scope chain, returning either the value found or
   1.666 +    // undefined through rval. This function is infallible, and cannot GC or
   1.667 +    // invalidate.
   1.668 +
   1.669 +    JSAtom *atom;
   1.670 +    if (str->isAtom()) {
   1.671 +        atom = &str->asAtom();
   1.672 +    } else {
   1.673 +        atom = AtomizeString(cx, str);
   1.674 +        if (!atom) {
   1.675 +            vp->setUndefined();
   1.676 +            return;
   1.677 +        }
   1.678 +    }
   1.679 +
   1.680 +    if (!frontend::IsIdentifier(atom) || frontend::IsKeyword(atom)) {
   1.681 +        vp->setUndefined();
   1.682 +        return;
   1.683 +    }
   1.684 +
   1.685 +    Shape *shape = nullptr;
   1.686 +    JSObject *scope = nullptr, *pobj = nullptr;
   1.687 +    if (LookupNameNoGC(cx, atom->asPropertyName(), scopeChain, &scope, &pobj, &shape)) {
   1.688 +        if (FetchNameNoGC(pobj, shape, MutableHandleValue::fromMarkedLocation(vp)))
   1.689 +            return;
   1.690 +    }
   1.691 +
   1.692 +    vp->setUndefined();
   1.693 +}
   1.694 +
   1.695 +bool
   1.696 +FilterArgumentsOrEval(JSContext *cx, JSString *str)
   1.697 +{
   1.698 +    // getChars() is fallible, but cannot GC: it can only allocate a character
   1.699 +    // for the flattened string. If this call fails then the calling Ion code
   1.700 +    // will bailout, resume in the interpreter and likely fail again when
   1.701 +    // trying to flatten the string and unwind the stack.
   1.702 +    const jschar *chars = str->getChars(cx);
   1.703 +    if (!chars)
   1.704 +        return false;
   1.705 +
   1.706 +    static const jschar arguments[] = {'a', 'r', 'g', 'u', 'm', 'e', 'n', 't', 's'};
   1.707 +    static const jschar eval[] = {'e', 'v', 'a', 'l'};
   1.708 +
   1.709 +    return !StringHasPattern(chars, str->length(), arguments, mozilla::ArrayLength(arguments)) &&
   1.710 +        !StringHasPattern(chars, str->length(), eval, mozilla::ArrayLength(eval));
   1.711 +}
   1.712 +
   1.713 +#ifdef JSGC_GENERATIONAL
   1.714 +void
   1.715 +PostWriteBarrier(JSRuntime *rt, JSObject *obj)
   1.716 +{
   1.717 +    JS_ASSERT(!IsInsideNursery(rt, obj));
   1.718 +    rt->gcStoreBuffer.putWholeCell(obj);
   1.719 +}
   1.720 +
   1.721 +void
   1.722 +PostGlobalWriteBarrier(JSRuntime *rt, JSObject *obj)
   1.723 +{
   1.724 +    JS_ASSERT(obj->is<GlobalObject>());
   1.725 +    if (!obj->compartment()->globalWriteBarriered) {
   1.726 +        PostWriteBarrier(rt, obj);
   1.727 +        obj->compartment()->globalWriteBarriered = true;
   1.728 +    }
   1.729 +}
   1.730 +#endif
   1.731 +
   1.732 +uint32_t
   1.733 +GetIndexFromString(JSString *str)
   1.734 +{
   1.735 +    // Masks the return value UINT32_MAX as failure to get the index.
   1.736 +    // I.e. it is impossible to distinguish between failing to get the index
   1.737 +    // or the actual index UINT32_MAX.
   1.738 +
   1.739 +    if (!str->isAtom())
   1.740 +        return UINT32_MAX;
   1.741 +
   1.742 +    uint32_t index;
   1.743 +    JSAtom *atom = &str->asAtom();
   1.744 +    if (!atom->isIndex(&index))
   1.745 +        return UINT32_MAX;
   1.746 +
   1.747 +    return index;
   1.748 +}
   1.749 +
   1.750 +bool
   1.751 +DebugPrologue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn)
   1.752 +{
   1.753 +    *mustReturn = false;
   1.754 +
   1.755 +    JSTrapStatus status = ScriptDebugPrologue(cx, frame, pc);
   1.756 +    switch (status) {
   1.757 +      case JSTRAP_CONTINUE:
   1.758 +        return true;
   1.759 +
   1.760 +      case JSTRAP_RETURN:
   1.761 +        // The script is going to return immediately, so we have to call the
   1.762 +        // debug epilogue handler as well.
   1.763 +        JS_ASSERT(frame->hasReturnValue());
   1.764 +        *mustReturn = true;
   1.765 +        return jit::DebugEpilogue(cx, frame, pc, true);
   1.766 +
   1.767 +      case JSTRAP_THROW:
   1.768 +      case JSTRAP_ERROR:
   1.769 +        return false;
   1.770 +
   1.771 +      default:
   1.772 +        MOZ_ASSUME_UNREACHABLE("Invalid trap status");
   1.773 +    }
   1.774 +}
   1.775 +
   1.776 +bool
   1.777 +DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok)
   1.778 +{
   1.779 +    // Unwind scope chain to stack depth 0.
   1.780 +    ScopeIter si(frame, pc, cx);
   1.781 +    UnwindScope(cx, si, frame->script()->main());
   1.782 +
   1.783 +    // If ScriptDebugEpilogue returns |true| we have to return the frame's
   1.784 +    // return value. If it returns |false|, the debugger threw an exception.
   1.785 +    // In both cases we have to pop debug scopes.
   1.786 +    ok = ScriptDebugEpilogue(cx, frame, pc, ok);
   1.787 +
   1.788 +    if (frame->isNonEvalFunctionFrame()) {
   1.789 +        JS_ASSERT_IF(ok, frame->hasReturnValue());
   1.790 +        DebugScopes::onPopCall(frame, cx);
   1.791 +    } else if (frame->isStrictEvalFrame()) {
   1.792 +        JS_ASSERT_IF(frame->hasCallObj(), frame->scopeChain()->as<CallObject>().isForEval());
   1.793 +        DebugScopes::onPopStrictEvalScope(frame);
   1.794 +    }
   1.795 +
   1.796 +    // If the frame has a pushed SPS frame, make sure to pop it.
   1.797 +    if (frame->hasPushedSPSFrame()) {
   1.798 +        cx->runtime()->spsProfiler.exit(frame->script(), frame->maybeFun());
   1.799 +        // Unset the pushedSPSFrame flag because DebugEpilogue may get called before
   1.800 +        // probes::ExitScript in baseline during exception handling, and we don't
   1.801 +        // want to double-pop SPS frames.
   1.802 +        frame->unsetPushedSPSFrame();
   1.803 +    }
   1.804 +
   1.805 +    if (!ok) {
   1.806 +        // Pop this frame by updating ionTop, so that the exception handling
   1.807 +        // code will start at the previous frame.
   1.808 +
   1.809 +        IonJSFrameLayout *prefix = frame->framePrefix();
   1.810 +        EnsureExitFrame(prefix);
   1.811 +        cx->mainThread().ionTop = (uint8_t *)prefix;
   1.812 +    }
   1.813 +
   1.814 +    return ok;
   1.815 +}
   1.816 +
   1.817 +bool
   1.818 +StrictEvalPrologue(JSContext *cx, BaselineFrame *frame)
   1.819 +{
   1.820 +    return frame->strictEvalPrologue(cx);
   1.821 +}
   1.822 +
   1.823 +bool
   1.824 +HeavyweightFunPrologue(JSContext *cx, BaselineFrame *frame)
   1.825 +{
   1.826 +    return frame->heavyweightFunPrologue(cx);
   1.827 +}
   1.828 +
   1.829 +bool
   1.830 +NewArgumentsObject(JSContext *cx, BaselineFrame *frame, MutableHandleValue res)
   1.831 +{
   1.832 +    ArgumentsObject *obj = ArgumentsObject::createExpected(cx, frame);
   1.833 +    if (!obj)
   1.834 +        return false;
   1.835 +    res.setObject(*obj);
   1.836 +    return true;
   1.837 +}
   1.838 +
   1.839 +JSObject *
   1.840 +InitRestParameter(JSContext *cx, uint32_t length, Value *rest, HandleObject templateObj,
   1.841 +                  HandleObject objRes)
   1.842 +{
   1.843 +    if (objRes) {
   1.844 +        Rooted<ArrayObject*> arrRes(cx, &objRes->as<ArrayObject>());
   1.845 +
   1.846 +        JS_ASSERT(!arrRes->getDenseInitializedLength());
   1.847 +        JS_ASSERT(arrRes->type() == templateObj->type());
   1.848 +
   1.849 +        // Fast path: we managed to allocate the array inline; initialize the
   1.850 +        // slots.
   1.851 +        if (length > 0) {
   1.852 +            if (!arrRes->ensureElements(cx, length))
   1.853 +                return nullptr;
   1.854 +            arrRes->setDenseInitializedLength(length);
   1.855 +            arrRes->initDenseElements(0, rest, length);
   1.856 +            arrRes->setLengthInt32(length);
   1.857 +        }
   1.858 +        return arrRes;
   1.859 +    }
   1.860 +
   1.861 +    NewObjectKind newKind = templateObj->type()->shouldPreTenure()
   1.862 +                            ? TenuredObject
   1.863 +                            : GenericObject;
   1.864 +    ArrayObject *arrRes = NewDenseCopiedArray(cx, length, rest, nullptr, newKind);
   1.865 +    if (arrRes)
   1.866 +        arrRes->setType(templateObj->type());
   1.867 +    return arrRes;
   1.868 +}
   1.869 +
   1.870 +bool
   1.871 +HandleDebugTrap(JSContext *cx, BaselineFrame *frame, uint8_t *retAddr, bool *mustReturn)
   1.872 +{
   1.873 +    *mustReturn = false;
   1.874 +
   1.875 +    RootedScript script(cx, frame->script());
   1.876 +    jsbytecode *pc = script->baselineScript()->icEntryFromReturnAddress(retAddr).pc(script);
   1.877 +
   1.878 +    JS_ASSERT(cx->compartment()->debugMode());
   1.879 +    JS_ASSERT(script->stepModeEnabled() || script->hasBreakpointsAt(pc));
   1.880 +
   1.881 +    RootedValue rval(cx);
   1.882 +    JSTrapStatus status = JSTRAP_CONTINUE;
   1.883 +    JSInterruptHook hook = cx->runtime()->debugHooks.interruptHook;
   1.884 +
   1.885 +    if (hook || script->stepModeEnabled()) {
   1.886 +        if (hook)
   1.887 +            status = hook(cx, script, pc, rval.address(), cx->runtime()->debugHooks.interruptHookData);
   1.888 +        if (status == JSTRAP_CONTINUE && script->stepModeEnabled())
   1.889 +            status = Debugger::onSingleStep(cx, &rval);
   1.890 +    }
   1.891 +
   1.892 +    if (status == JSTRAP_CONTINUE && script->hasBreakpointsAt(pc))
   1.893 +        status = Debugger::onTrap(cx, &rval);
   1.894 +
   1.895 +    switch (status) {
   1.896 +      case JSTRAP_CONTINUE:
   1.897 +        break;
   1.898 +
   1.899 +      case JSTRAP_ERROR:
   1.900 +        return false;
   1.901 +
   1.902 +      case JSTRAP_RETURN:
   1.903 +        *mustReturn = true;
   1.904 +        frame->setReturnValue(rval);
   1.905 +        return jit::DebugEpilogue(cx, frame, pc, true);
   1.906 +
   1.907 +      case JSTRAP_THROW:
   1.908 +        cx->setPendingException(rval);
   1.909 +        return false;
   1.910 +
   1.911 +      default:
   1.912 +        MOZ_ASSUME_UNREACHABLE("Invalid trap status");
   1.913 +    }
   1.914 +
   1.915 +    return true;
   1.916 +}
   1.917 +
   1.918 +bool
   1.919 +OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn)
   1.920 +{
   1.921 +    *mustReturn = false;
   1.922 +
   1.923 +    RootedScript script(cx, frame->script());
   1.924 +    JSTrapStatus status = JSTRAP_CONTINUE;
   1.925 +    RootedValue rval(cx);
   1.926 +
   1.927 +    if (JSDebuggerHandler handler = cx->runtime()->debugHooks.debuggerHandler)
   1.928 +        status = handler(cx, script, pc, rval.address(), cx->runtime()->debugHooks.debuggerHandlerData);
   1.929 +
   1.930 +    if (status == JSTRAP_CONTINUE)
   1.931 +        status = Debugger::onDebuggerStatement(cx, &rval);
   1.932 +
   1.933 +    switch (status) {
   1.934 +      case JSTRAP_ERROR:
   1.935 +        return false;
   1.936 +
   1.937 +      case JSTRAP_CONTINUE:
   1.938 +        return true;
   1.939 +
   1.940 +      case JSTRAP_RETURN:
   1.941 +        frame->setReturnValue(rval);
   1.942 +        *mustReturn = true;
   1.943 +        return jit::DebugEpilogue(cx, frame, pc, true);
   1.944 +
   1.945 +      case JSTRAP_THROW:
   1.946 +        cx->setPendingException(rval);
   1.947 +        return false;
   1.948 +
   1.949 +      default:
   1.950 +        MOZ_ASSUME_UNREACHABLE("Invalid trap status");
   1.951 +    }
   1.952 +}
   1.953 +
   1.954 +bool
   1.955 +PushBlockScope(JSContext *cx, BaselineFrame *frame, Handle<StaticBlockObject *> block)
   1.956 +{
   1.957 +    return frame->pushBlock(cx, block);
   1.958 +}
   1.959 +
   1.960 +bool
   1.961 +PopBlockScope(JSContext *cx, BaselineFrame *frame)
   1.962 +{
   1.963 +    frame->popBlock(cx);
   1.964 +    return true;
   1.965 +}
   1.966 +
   1.967 +bool
   1.968 +DebugLeaveBlock(JSContext *cx, BaselineFrame *frame, jsbytecode *pc)
   1.969 +{
   1.970 +    JS_ASSERT(frame->script()->baselineScript()->debugMode());
   1.971 +
   1.972 +    DebugScopes::onPopBlock(cx, frame, pc);
   1.973 +
   1.974 +    return true;
   1.975 +}
   1.976 +
   1.977 +bool
   1.978 +EnterWith(JSContext *cx, BaselineFrame *frame, HandleValue val, Handle<StaticWithObject *> templ)
   1.979 +{
   1.980 +    return EnterWithOperation(cx, frame, val, templ);
   1.981 +}
   1.982 +
   1.983 +bool
   1.984 +LeaveWith(JSContext *cx, BaselineFrame *frame)
   1.985 +{
   1.986 +    frame->popWith(cx);
   1.987 +    return true;
   1.988 +}
   1.989 +
   1.990 +bool
   1.991 +InitBaselineFrameForOsr(BaselineFrame *frame, InterpreterFrame *interpFrame,
   1.992 +                        uint32_t numStackValues)
   1.993 +{
   1.994 +    return frame->initForOsr(interpFrame, numStackValues);
   1.995 +}
   1.996 +
   1.997 +JSObject *
   1.998 +CreateDerivedTypedObj(JSContext *cx, HandleObject descr,
   1.999 +                      HandleObject owner, int32_t offset)
  1.1000 +{
  1.1001 +    JS_ASSERT(descr->is<SizedTypeDescr>());
  1.1002 +    JS_ASSERT(owner->is<TypedObject>());
  1.1003 +    Rooted<SizedTypeDescr*> descr1(cx, &descr->as<SizedTypeDescr>());
  1.1004 +    Rooted<TypedObject*> owner1(cx, &owner->as<TypedObject>());
  1.1005 +    return TypedObject::createDerived(cx, descr1, owner1, offset);
  1.1006 +}
  1.1007 +
  1.1008 +JSString *
  1.1009 +RegExpReplace(JSContext *cx, HandleString string, HandleObject regexp, HandleString repl)
  1.1010 +{
  1.1011 +    JS_ASSERT(string);
  1.1012 +    JS_ASSERT(repl);
  1.1013 +
  1.1014 +    RootedValue rval(cx);
  1.1015 +    if (!str_replace_regexp_raw(cx, string, regexp, repl, &rval))
  1.1016 +        return nullptr;
  1.1017 +
  1.1018 +    return rval.toString();
  1.1019 +}
  1.1020 +
  1.1021 +JSString *
  1.1022 +StringReplace(JSContext *cx, HandleString string, HandleString pattern, HandleString repl)
  1.1023 +{
  1.1024 +    JS_ASSERT(string);
  1.1025 +    JS_ASSERT(pattern);
  1.1026 +    JS_ASSERT(repl);
  1.1027 +
  1.1028 +    RootedValue rval(cx);
  1.1029 +    if (!str_replace_string_raw(cx, string, pattern, repl, &rval))
  1.1030 +        return nullptr;
  1.1031 +
  1.1032 +    return rval.toString();
  1.1033 +}
  1.1034 +
  1.1035 +bool
  1.1036 +Recompile(JSContext *cx)
  1.1037 +{
  1.1038 +    JS_ASSERT(cx->currentlyRunningInJit());
  1.1039 +    JitActivationIterator activations(cx->runtime());
  1.1040 +    JitFrameIterator iter(activations);
  1.1041 +
  1.1042 +    JS_ASSERT(iter.type() == JitFrame_Exit);
  1.1043 +    ++iter;
  1.1044 +
  1.1045 +    bool isConstructing = iter.isConstructing();
  1.1046 +    RootedScript script(cx, iter.script());
  1.1047 +    JS_ASSERT(script->hasIonScript());
  1.1048 +
  1.1049 +    if (!IsIonEnabled(cx))
  1.1050 +        return true;
  1.1051 +
  1.1052 +    MethodStatus status = Recompile(cx, script, nullptr, nullptr, isConstructing);
  1.1053 +    if (status == Method_Error)
  1.1054 +        return false;
  1.1055 +
  1.1056 +    return true;
  1.1057 +}
  1.1058 +
  1.1059 +bool
  1.1060 +SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue value,
  1.1061 +                bool strict)
  1.1062 +{
  1.1063 +    // This function is called from Ion code for StoreElementHole's OOL path.
  1.1064 +    // In this case we know the object is native, has no indexed properties
  1.1065 +    // and we can use setDenseElement instead of setDenseElementWithType.
  1.1066 +
  1.1067 +    MOZ_ASSERT(obj->isNative());
  1.1068 +    MOZ_ASSERT(!obj->isIndexed());
  1.1069 +
  1.1070 +    JSObject::EnsureDenseResult result = JSObject::ED_SPARSE;
  1.1071 +    do {
  1.1072 +        if (index < 0)
  1.1073 +            break;
  1.1074 +        bool isArray = obj->is<ArrayObject>();
  1.1075 +        if (isArray && !obj->as<ArrayObject>().lengthIsWritable())
  1.1076 +            break;
  1.1077 +        uint32_t idx = uint32_t(index);
  1.1078 +        result = obj->ensureDenseElements(cx, idx, 1);
  1.1079 +        if (result != JSObject::ED_OK)
  1.1080 +            break;
  1.1081 +        if (isArray) {
  1.1082 +            ArrayObject &arr = obj->as<ArrayObject>();
  1.1083 +            if (idx >= arr.length())
  1.1084 +                arr.setLengthInt32(idx + 1);
  1.1085 +        }
  1.1086 +        obj->setDenseElement(idx, value);
  1.1087 +        return true;
  1.1088 +    } while (false);
  1.1089 +
  1.1090 +    if (result == JSObject::ED_FAILED)
  1.1091 +        return false;
  1.1092 +    MOZ_ASSERT(result == JSObject::ED_SPARSE);
  1.1093 +
  1.1094 +    RootedValue indexVal(cx, Int32Value(index));
  1.1095 +    return SetObjectElement(cx, obj, indexVal, value, strict);
  1.1096 +}
  1.1097 +
  1.1098 +#ifdef DEBUG
  1.1099 +void
  1.1100 +AssertValidObjectPtr(JSContext *cx, JSObject *obj)
  1.1101 +{
  1.1102 +    // Check what we can, so that we'll hopefully assert/crash if we get a
  1.1103 +    // bogus object (pointer).
  1.1104 +    JS_ASSERT(obj->compartment() == cx->compartment());
  1.1105 +    JS_ASSERT(obj->runtimeFromMainThread() == cx->runtime());
  1.1106 +
  1.1107 +    JS_ASSERT_IF(!obj->hasLazyType(),
  1.1108 +                 obj->type()->clasp() == obj->lastProperty()->getObjectClass());
  1.1109 +
  1.1110 +    if (obj->isTenured()) {
  1.1111 +        JS_ASSERT(obj->isAligned());
  1.1112 +        gc::AllocKind kind = obj->tenuredGetAllocKind();
  1.1113 +        JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
  1.1114 +        JS_ASSERT(obj->tenuredZone() == cx->zone());
  1.1115 +    }
  1.1116 +}
  1.1117 +
  1.1118 +void
  1.1119 +AssertValidStringPtr(JSContext *cx, JSString *str)
  1.1120 +{
  1.1121 +    // We can't closely inspect strings from another runtime.
  1.1122 +    if (str->runtimeFromAnyThread() != cx->runtime()) {
  1.1123 +        JS_ASSERT(str->isPermanentAtom());
  1.1124 +        return;
  1.1125 +    }
  1.1126 +
  1.1127 +    if (str->isAtom())
  1.1128 +        JS_ASSERT(cx->runtime()->isAtomsZone(str->tenuredZone()));
  1.1129 +    else
  1.1130 +        JS_ASSERT(str->tenuredZone() == cx->zone());
  1.1131 +
  1.1132 +    JS_ASSERT(str->runtimeFromMainThread() == cx->runtime());
  1.1133 +    JS_ASSERT(str->isAligned());
  1.1134 +    JS_ASSERT(str->length() <= JSString::MAX_LENGTH);
  1.1135 +
  1.1136 +    gc::AllocKind kind = str->tenuredGetAllocKind();
  1.1137 +    if (str->isFatInline())
  1.1138 +        JS_ASSERT(kind == gc::FINALIZE_FAT_INLINE_STRING);
  1.1139 +    else if (str->isExternal())
  1.1140 +        JS_ASSERT(kind == gc::FINALIZE_EXTERNAL_STRING);
  1.1141 +    else if (str->isAtom() || str->isFlat())
  1.1142 +        JS_ASSERT(kind == gc::FINALIZE_STRING || kind == gc::FINALIZE_FAT_INLINE_STRING);
  1.1143 +    else
  1.1144 +        JS_ASSERT(kind == gc::FINALIZE_STRING);
  1.1145 +}
  1.1146 +
  1.1147 +void
  1.1148 +AssertValidValue(JSContext *cx, Value *v)
  1.1149 +{
  1.1150 +    if (v->isObject()) {
  1.1151 +        AssertValidObjectPtr(cx, &v->toObject());
  1.1152 +        return;
  1.1153 +    }
  1.1154 +    if (v->isString()) {
  1.1155 +        AssertValidStringPtr(cx, v->toString());
  1.1156 +        return;
  1.1157 +    }
  1.1158 +}
  1.1159 +#endif
  1.1160 +
  1.1161 +} // namespace jit
  1.1162 +} // namespace js

mercurial