Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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);
1003 }
1005 JSString *
1006 RegExpReplace(JSContext *cx, HandleString string, HandleObject regexp, HandleString repl)
1007 {
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();
1016 }
1018 JSString *
1019 StringReplace(JSContext *cx, HandleString string, HandleString pattern, HandleString repl)
1020 {
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();
1030 }
1032 bool
1033 Recompile(JSContext *cx)
1034 {
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;
1054 }
1056 bool
1057 SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue value,
1058 bool strict)
1059 {
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);
1082 }
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);
1093 }
1095 #ifdef DEBUG
1096 void
1097 AssertValidObjectPtr(JSContext *cx, JSObject *obj)
1098 {
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());
1112 }
1113 }
1115 void
1116 AssertValidStringPtr(JSContext *cx, JSString *str)
1117 {
1118 // We can't closely inspect strings from another runtime.
1119 if (str->runtimeFromAnyThread() != cx->runtime()) {
1120 JS_ASSERT(str->isPermanentAtom());
1121 return;
1122 }
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);
1142 }
1144 void
1145 AssertValidValue(JSContext *cx, Value *v)
1146 {
1147 if (v->isObject()) {
1148 AssertValidObjectPtr(cx, &v->toObject());
1149 return;
1150 }
1151 if (v->isString()) {
1152 AssertValidStringPtr(cx, v->toString());
1153 return;
1154 }
1155 }
1156 #endif
1158 } // namespace jit
1159 } // namespace js