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.

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

mercurial