1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=4 sw=4 et tw=99:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
20 * The Initial Developer of the Original Code is
21 * Brendan Eich <brendan@mozilla.org>
24 * David Anderson <danderson@mozilla.com>
25 * David Mandelin <dmandelin@mozilla.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
44 #include "jslibmath.h"
48 #include "jsstaticcheck.h"
50 #include "assembler/assembler/MacroAssemblerCodeRef.h"
53 #include "methodjit/Compiler.h"
54 #include "methodjit/StubCalls.h"
57 #include "jsinterpinlines.h"
58 #include "jspropertycache.h"
59 #include "jspropertycacheinlines.h"
60 #include "jsscopeinlines.h"
61 #include "jsscriptinlines.h"
62 #include "jsstrinlines.h"
63 #include "jsobjinlines.h"
64 #include "jscntxtinlines.h"
65 #include "jsatominlines.h"
66 #include "StubCalls-inl.h"
67 #include "jsfuninlines.h"
68 #include "jstypedarray.h"
74 #include "jsautooplen.h"
77 using namespace js::mjit
;
81 stubs::BindName(VMFrame
&f
)
83 PropertyCacheEntry
*entry
;
85 /* Fast-path should have caught this. See comment in interpreter. */
86 JS_ASSERT(f
.fp()->scopeChain().getParent());
91 JSObject
*obj
= &f
.fp()->scopeChain();
92 JS_PROPERTY_CACHE(cx
).test(cx
, f
.regs
.pc
, obj
, obj2
, entry
, atom
);
94 jsid id
= ATOM_TO_JSID(atom
);
95 obj
= js_FindIdentifierBase(cx
, &f
.fp()->scopeChain(), id
);
100 f
.regs
.sp
[-1].setObject(*obj
);
104 stubs::BindNameNoCache(VMFrame
&f
, JSAtom
*atom
)
106 JSObject
*obj
= js_FindIdentifierBase(f
.cx
, &f
.fp()->scopeChain(), ATOM_TO_JSID(atom
));
109 f
.regs
.sp
[0].setObject(*obj
);
112 JSObject
* JS_FASTCALL
113 stubs::BindGlobalName(VMFrame
&f
)
115 return f
.fp()->scopeChain().getGlobal();
118 template<JSBool strict
>
120 stubs::SetName(VMFrame
&f
, JSAtom
*origAtom
)
122 JSContext
*cx
= f
.cx
;
124 Value rval
= f
.regs
.sp
[-1];
125 Value
&lref
= f
.regs
.sp
[-2];
126 JSObject
*obj
= ValueToObject(cx
, &lref
);
131 PropertyCache
*cache
= &JS_PROPERTY_CACHE(cx
);
134 * Probe the property cache, specializing for two important
135 * set-property cases. First:
137 * function f(a, b, c) {
138 * var o = {p:a, q:b, r:c};
142 * or similar real-world cases, which evolve a newborn native
143 * object predicatably through some bounded number of property
144 * additions. And second:
148 * in a frequently executed method or loop body, where p will
149 * (possibly after the first iteration) always exist in native
152 PropertyCacheEntry
*entry
;
155 if (cache
->testForSet(cx
, f
.regs
.pc
, obj
, &entry
, &obj2
, &atom
)) {
157 * Property cache hit, only partially confirmed by testForSet. We
158 * know that the entry applies to regs.pc and that obj's shape
161 * The entry predicts either a new property to be added directly to
162 * obj by this set, or on an existing "own" property, or on a
163 * prototype property that has a setter.
165 const Shape
*shape
= entry
->vword
.toShape();
166 JS_ASSERT_IF(shape
->isDataDescriptor(), shape
->writable());
167 JS_ASSERT_IF(shape
->hasSlot(), entry
->vcapTag() == 0);
170 * Fastest path: check whether obj already has the cached shape and
171 * call NATIVE_SET and break to get out of the do-while(0). But we
172 * can call NATIVE_SET only for a direct or proto-setter hit.
174 if (!entry
->adding()) {
175 if (entry
->vcapTag() == 0 ||
176 ((obj2
= obj
->getProto()) && obj2
->shape() == entry
->vshape()))
179 if (entry
->directHit()) {
180 JS_ASSERT(obj
->nativeContains(*shape
));
182 JS_ASSERT(obj2
->nativeContains(*shape
));
183 JS_ASSERT(entry
->vcapTag() == 1);
184 JS_ASSERT(entry
->kshape
!= entry
->vshape());
185 JS_ASSERT(!shape
->hasSlot());
189 PCMETER(cache
->pchits
++);
190 PCMETER(cache
->setpchits
++);
191 NATIVE_SET(cx
, obj
, shape
, entry
, strict
, &rval
);
195 JS_ASSERT(obj
->isExtensible());
197 if (obj
->nativeEmpty()) {
198 if (!obj
->ensureClassReservedSlotsForEmptyObject(cx
))
203 if (shape
->previous() == obj
->lastProperty() &&
204 entry
->vshape() == cx
->runtime
->protoHazardShape
&&
205 shape
->hasDefaultSetter()) {
207 JS_ASSERT(slot
== obj
->slotSpan());
210 * Fast path: adding a plain old property that was once at
211 * the frontier of the property tree, whose slot is next to
212 * claim among the already-allocated slots in obj, where
213 * shape->table has not been created yet.
215 PCMETER(cache
->pchits
++);
216 PCMETER(cache
->addpchits
++);
218 if (slot
< obj
->numSlots()) {
219 JS_ASSERT(obj
->getSlot(slot
).isUndefined());
221 if (!obj
->allocSlot(cx
, &slot
))
223 JS_ASSERT(slot
== shape
->slot
);
226 /* Simply extend obj's property tree path with shape! */
227 obj
->extend(cx
, shape
);
230 * No method change check here because here we are adding a
231 * new property, not updating an existing slot's value that
232 * might contain a method of a branded shape.
234 obj
->setSlot(slot
, rval
);
237 * Purge the property cache of the id we may have just
238 * shadowed in obj's scope and proto chains.
240 js_PurgeScopeChain(cx
, obj
, shape
->id
);
244 PCMETER(cache
->setpcmisses
++);
251 jsid id
= ATOM_TO_JSID(atom
);
252 if (entry
&& JS_LIKELY(!obj
->getOps()->setProperty
)) {
254 JSOp op
= JSOp(*f
.regs
.pc
);
255 if (op
== JSOP_SETMETHOD
)
256 defineHow
= JSDNP_CACHE_RESULT
| JSDNP_SET_METHOD
;
257 else if (op
== JSOP_SETNAME
)
258 defineHow
= JSDNP_CACHE_RESULT
| JSDNP_UNQUALIFIED
;
260 defineHow
= JSDNP_CACHE_RESULT
;
261 if (!js_SetPropertyHelper(cx
, obj
, id
, defineHow
, &rval
, strict
))
264 if (!obj
->setProperty(cx
, id
, &rval
, strict
))
269 f
.regs
.sp
[-2] = f
.regs
.sp
[-1];
272 template void JS_FASTCALL
stubs::SetName
<true>(VMFrame
&f
, JSAtom
*origAtom
);
273 template void JS_FASTCALL
stubs::SetName
<false>(VMFrame
&f
, JSAtom
*origAtom
);
275 template<JSBool strict
>
277 stubs::SetPropNoCache(VMFrame
&f
, JSAtom
*atom
)
279 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-2]);
282 Value rval
= f
.regs
.sp
[-1];
283 if (!obj
->setProperty(f
.cx
, ATOM_TO_JSID(atom
), &f
.regs
.sp
[-1], strict
))
285 f
.regs
.sp
[-2] = rval
;
288 template void JS_FASTCALL
stubs::SetPropNoCache
<true>(VMFrame
&f
, JSAtom
*origAtom
);
289 template void JS_FASTCALL
stubs::SetPropNoCache
<false>(VMFrame
&f
, JSAtom
*origAtom
);
291 template<JSBool strict
>
293 stubs::SetGlobalNameNoCache(VMFrame
&f
, JSAtom
*atom
)
295 JSContext
*cx
= f
.cx
;
297 Value rval
= f
.regs
.sp
[-1];
298 Value
&lref
= f
.regs
.sp
[-2];
299 JSObject
*obj
= ValueToObject(cx
, &lref
);
302 jsid id
= ATOM_TO_JSID(atom
);
303 if (!obj
->setProperty(cx
, id
, &rval
, strict
))
306 f
.regs
.sp
[-2] = f
.regs
.sp
[-1];
309 template void JS_FASTCALL
stubs::SetGlobalNameNoCache
<true>(VMFrame
&f
, JSAtom
*atom
);
310 template void JS_FASTCALL
stubs::SetGlobalNameNoCache
<false>(VMFrame
&f
, JSAtom
*atom
);
312 template<JSBool strict
>
314 stubs::SetGlobalName(VMFrame
&f
, JSAtom
*atom
)
316 SetName
<strict
>(f
, atom
);
319 template void JS_FASTCALL
stubs::SetGlobalName
<true>(VMFrame
&f
, JSAtom
*atom
);
320 template void JS_FASTCALL
stubs::SetGlobalName
<false>(VMFrame
&f
, JSAtom
*atom
);
323 NameOp(VMFrame
&f
, JSObject
*obj
, bool callname
= false)
325 JSContext
*cx
= f
.cx
;
330 PropertyCacheEntry
*entry
;
333 JS_PROPERTY_CACHE(cx
).test(cx
, f
.regs
.pc
, obj
, obj2
, entry
, atom
);
335 if (entry
->vword
.isFunObj()) {
337 f
.regs
.sp
[-1].setObject(entry
->vword
.toFunObj());
338 } else if (entry
->vword
.isSlot()) {
339 uintN slot
= entry
->vword
.toSlot();
341 f
.regs
.sp
[-1] = obj2
->nativeGetSlot(slot
);
343 JS_ASSERT(entry
->vword
.isShape());
344 shape
= entry
->vword
.toShape();
345 NATIVE_GET(cx
, obj
, obj2
, shape
, JSGET_METHOD_BARRIER
, &rval
, return NULL
);
347 f
.regs
.sp
[-1] = rval
;
351 * Push results, the same as below, but with a prop$ hit there
352 * is no need to test for the unusual and uncacheable case where
353 * the caller determines |this|.
357 JS_ASSERT(!obj
->getParent() ||
358 (clasp
= obj
->getClass()) == &js_CallClass
||
359 clasp
== &js_BlockClass
||
360 clasp
== &js_DeclEnvClass
);
364 f
.regs
.sp
[-1].setUndefined();
370 id
= ATOM_TO_JSID(atom
);
372 if (!js_FindPropertyHelper(cx
, id
, true, &obj
, &obj2
, &prop
))
375 /* Kludge to allow (typeof foo == "undefined") tests. */
376 JSOp op2
= js_GetOpcode(cx
, f
.fp()->script(), f
.regs
.pc
+ JSOP_NAME_LENGTH
);
377 if (op2
== JSOP_TYPEOF
) {
379 f
.regs
.sp
[-1].setUndefined();
382 ReportAtomNotDefined(cx
, atom
);
386 /* Take the slow path if prop was not found in a native object. */
387 if (!obj
->isNative() || !obj2
->isNative()) {
388 if (!obj
->getProperty(cx
, id
, &rval
))
391 shape
= (Shape
*)prop
;
392 JSObject
*normalized
= obj
;
393 if (normalized
->getClass() == &js_WithClass
&& !shape
->hasDefaultGetter())
394 normalized
= js_UnwrapWithObject(cx
, normalized
);
395 NATIVE_GET(cx
, normalized
, obj2
, shape
, JSGET_METHOD_BARRIER
, &rval
, return NULL
);
399 f
.regs
.sp
[-1] = rval
;
402 JSObject
*thisp
= obj
;
403 if (!thisp
->getParent() ||
404 (clasp
= thisp
->getClass()) == &js_CallClass
||
405 clasp
== &js_BlockClass
||
406 clasp
== &js_DeclEnvClass
) {
408 f
.regs
.sp
[-1].setUndefined();
410 thisp
= thisp
->thisObject(cx
);
414 f
.regs
.sp
[-1].setObject(*thisp
);
421 stubs::Name(VMFrame
&f
)
423 if (!NameOp(f
, &f
.fp()->scopeChain()))
428 stubs::GetGlobalName(VMFrame
&f
)
430 JSObject
*globalObj
= f
.fp()->scopeChain().getGlobal();
431 if (!NameOp(f
, globalObj
))
436 stubs::GetElem(VMFrame
&f
)
438 JSContext
*cx
= f
.cx
;
439 JSFrameRegs
®s
= f
.regs
;
441 Value
&lref
= regs
.sp
[-2];
442 Value
&rref
= regs
.sp
[-1];
443 if (lref
.isString() && rref
.isInt32()) {
444 JSString
*str
= lref
.toString();
445 int32_t i
= rref
.toInt32();
446 if ((size_t)i
< str
->length()) {
447 str
= JSString::getUnitString(cx
, str
, (size_t)i
);
450 f
.regs
.sp
[-2].setString(str
);
455 JSObject
*obj
= ValueToObject(cx
, &lref
);
459 const Value
*copyFrom
;
462 if (rref
.isInt32()) {
463 int32_t i
= rref
.toInt32();
464 if (obj
->isDenseArray()) {
465 jsuint idx
= jsuint(i
);
467 if (idx
< obj
->getArrayLength() &&
468 idx
< obj
->getDenseArrayCapacity()) {
469 copyFrom
= obj
->addressOfDenseArrayElement(idx
);
470 if (!copyFrom
->isMagic())
473 } else if (obj
->isArguments()) {
474 uint32 arg
= uint32(i
);
476 if (arg
< obj
->getArgsInitialLength()) {
477 copyFrom
= obj
->addressOfArgsElement(arg
);
478 if (!copyFrom
->isMagic()) {
479 if (JSStackFrame
*afp
= (JSStackFrame
*) obj
->getPrivate())
480 copyFrom
= &afp
->canonicalActualArg(arg
);
485 if (JS_LIKELY(INT_FITS_IN_JSID(i
)))
492 if (ValueFitsInInt32(rref
, &i
) && INT_FITS_IN_JSID(i
)) {
496 if (!js_InternNonIntElementId(cx
, obj
, rref
, &id
))
501 if (!obj
->getProperty(cx
, id
, &rval
))
506 f
.regs
.sp
[-2] = *copyFrom
;
510 FetchElementId(VMFrame
&f
, JSObject
*obj
, const Value
&idval
, jsid
&id
, Value
*vp
)
513 if (ValueFitsInInt32(idval
, &i_
) && INT_FITS_IN_JSID(i_
)) {
514 id
= INT_TO_JSID(i_
);
517 return !!js_InternNonIntElementId(f
.cx
, obj
, idval
, &id
, vp
);
521 stubs::CallElem(VMFrame
&f
)
523 JSContext
*cx
= f
.cx
;
524 JSFrameRegs
®s
= f
.regs
;
526 /* Find the object on which to look for |this|'s properties. */
527 Value thisv
= regs
.sp
[-2];
528 JSObject
*thisObj
= ValuePropertyBearer(cx
, thisv
, -2);
532 /* Fetch index and convert it to id suitable for use with thisObj. */
534 if (!FetchElementId(f
, thisObj
, regs
.sp
[-1], id
, ®s
.sp
[-2]))
537 /* Get or set the element. */
538 if (!js_GetMethod(cx
, thisObj
, id
, JSGET_NO_METHOD_BARRIER
, ®s
.sp
[-2]))
541 #if JS_HAS_NO_SUCH_METHOD
542 if (JS_UNLIKELY(regs
.sp
[-2].isUndefined()) && thisv
.isObject()) {
543 regs
.sp
[-2] = regs
.sp
[-1];
544 regs
.sp
[-1].setObject(*thisObj
);
545 if (!js_OnUnknownMethod(cx
, regs
.sp
- 2))
554 template<JSBool strict
>
556 stubs::SetElem(VMFrame
&f
)
558 JSContext
*cx
= f
.cx
;
559 JSFrameRegs
®s
= f
.regs
;
561 Value
&objval
= regs
.sp
[-3];
562 Value
&idval
= regs
.sp
[-2];
563 Value rval
= regs
.sp
[-1];
568 obj
= ValueToObject(cx
, &objval
);
572 if (!FetchElementId(f
, obj
, idval
, id
, ®s
.sp
[-2]))
576 if (obj
->isDenseArray() && JSID_IS_INT(id
)) {
577 jsuint length
= obj
->getDenseArrayCapacity();
578 jsint i
= JSID_TO_INT(id
);
579 if ((jsuint
)i
< length
) {
580 if (obj
->getDenseArrayElement(i
).isMagic(JS_ARRAY_HOLE
)) {
581 if (js_PrototypeHasIndexedProperties(cx
, obj
))
583 if ((jsuint
)i
>= obj
->getArrayLength())
584 obj
->setArrayLength(i
+ 1);
586 obj
->setDenseArrayElement(i
, rval
);
591 if (!obj
->setProperty(cx
, id
, &rval
, strict
))
594 /* :FIXME: Moving the assigned object into the lowest stack slot
595 * is a temporary hack. What we actually want is an implementation
596 * of popAfterSet() that allows popping more than one value;
597 * this logic can then be handled in Compiler.cpp. */
598 regs
.sp
[-3] = regs
.sp
[-1];
601 template void JS_FASTCALL
stubs::SetElem
<true>(VMFrame
&f
);
602 template void JS_FASTCALL
stubs::SetElem
<false>(VMFrame
&f
);
605 stubs::CallName(VMFrame
&f
)
607 JSObject
*obj
= NameOp(f
, &f
.fp()->scopeChain(), true);
613 stubs::BitOr(VMFrame
&f
)
617 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-2], &i
) ||
618 !ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &j
)) {
622 f
.regs
.sp
[-2].setInt32(i
);
626 stubs::BitXor(VMFrame
&f
)
630 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-2], &i
) ||
631 !ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &j
)) {
635 f
.regs
.sp
[-2].setInt32(i
);
639 stubs::BitAnd(VMFrame
&f
)
643 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-2], &i
) ||
644 !ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &j
)) {
648 f
.regs
.sp
[-2].setInt32(i
);
652 stubs::BitNot(VMFrame
&f
)
656 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &i
))
659 f
.regs
.sp
[-1].setInt32(i
);
663 stubs::Lsh(VMFrame
&f
)
666 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-2], &i
))
668 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &j
))
671 f
.regs
.sp
[-2].setInt32(i
);
675 stubs::Rsh(VMFrame
&f
)
678 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-2], &i
))
680 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &j
))
683 f
.regs
.sp
[-2].setInt32(i
);
687 stubs::Ursh(VMFrame
&f
)
690 if (!ValueToECMAUint32(f
.cx
, f
.regs
.sp
[-2], &u
))
693 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &j
))
698 f
.regs
.sp
[-2].setNumber(uint32(u
));
701 template<JSBool strict
>
703 stubs::DefFun(VMFrame
&f
, JSFunction
*fun
)
707 JSContext
*cx
= f
.cx
;
708 JSStackFrame
*fp
= f
.fp();
711 * A top-level function defined in Global or Eval code (see ECMA-262
712 * Ed. 3), or else a SpiderMonkey extension: a named function statement in
713 * a compound statement (not at the top statement level of global code, or
714 * at the top level of a function body).
716 JSObject
*obj
= FUN_OBJECT(fun
);
718 if (FUN_NULL_CLOSURE(fun
)) {
720 * Even a null closure needs a parent for principals finding.
721 * FIXME: bug 476950, although debugger users may also demand some kind
722 * of scope link for debugger-assisted eval-in-frame.
724 obj2
= &fp
->scopeChain();
726 JS_ASSERT(!fun
->isFlatClosure());
728 obj2
= GetScopeChainFast(cx
, fp
, JSOP_DEFFUN
, JSOP_DEFFUN_LENGTH
);
734 * If static link is not current scope, clone fun's object to link to the
735 * current scope via parent. We do this to enable sharing of compiled
736 * functions among multiple equivalent scopes, amortizing the cost of
737 * compilation over a number of executions. Examples include XUL scripts
738 * and event handlers shared among Firefox or other Mozilla app chrome
739 * windows, and user-defined JS functions precompiled and then shared among
740 * requests in server-side JS.
742 if (obj
->getParent() != obj2
) {
743 obj
= CloneFunctionObject(cx
, fun
, obj2
);
749 * ECMA requires functions defined when entering Eval code to be
752 uintN attrs
= fp
->isEvalFrame()
754 : JSPROP_ENUMERATE
| JSPROP_PERMANENT
;
757 * We define the function as a property of the variable object and not the
758 * current scope chain even for the case of function expression statements
759 * and functions defined by eval inside let or with blocks.
761 JSObject
*parent
= &fp
->varobj(cx
);
763 /* ES5 10.5 (NB: with subsequent errata). */
764 jsid id
= ATOM_TO_JSID(fun
->atom
);
765 JSProperty
*prop
= NULL
;
767 if (!parent
->lookupProperty(cx
, id
, &pobj
, &prop
))
770 Value rval
= ObjectValue(*obj
);
774 if (!prop
|| pobj
!= parent
) {
775 if (!parent
->defineProperty(cx
, id
, rval
, PropertyStub
, StrictPropertyStub
, attrs
))
781 JS_ASSERT(parent
->isNative());
782 Shape
*shape
= reinterpret_cast<Shape
*>(prop
);
783 if (parent
->isGlobal()) {
784 if (shape
->configurable()) {
785 if (!parent
->defineProperty(cx
, id
, rval
, PropertyStub
, StrictPropertyStub
, attrs
))
790 if (shape
->isAccessorDescriptor() || !shape
->writable() || !shape
->enumerable()) {
791 JSAutoByteString bytes
;
792 if (const char *name
= js_ValueToPrintable(cx
, IdToValue(id
), &bytes
)) {
793 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
794 JSMSG_CANT_REDEFINE_PROP
, name
);
801 * Non-global properties, and global properties which we aren't simply
802 * redefining, must be set. First, this preserves their attributes.
803 * Second, this will produce warnings and/or errors as necessary if the
804 * specified Call object property is not writable (const).
808 if (!parent
->setProperty(cx
, id
, &rval
, strict
))
813 template void JS_FASTCALL
stubs::DefFun
<true>(VMFrame
&f
, JSFunction
*fun
);
814 template void JS_FASTCALL
stubs::DefFun
<false>(VMFrame
&f
, JSFunction
*fun
);
816 #define DEFAULT_VALUE(cx, n, hint, v) \
818 JS_ASSERT(v.isObject()); \
819 JS_ASSERT(v == regs.sp[n]); \
820 if (!DefaultValue(cx, &v.toObject(), hint, ®s.sp[n])) \
825 #define RELATIONAL(OP) \
827 JSContext *cx = f.cx; \
828 JSFrameRegs ®s = f.regs; \
829 Value rval = regs.sp[-1]; \
830 Value lval = regs.sp[-2]; \
832 if (lval.isObject()) \
833 DEFAULT_VALUE(cx, -2, JSTYPE_NUMBER, lval); \
834 if (rval.isObject()) \
835 DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \
836 if (lval.isString() && rval.isString()) { \
837 JSString *l = lval.toString(), *r = rval.toString(); \
839 if (!CompareStrings(cx, l, r, &cmp)) \
844 if (!ValueToNumber(cx, lval, &l) || \
845 !ValueToNumber(cx, rval, &r)) { \
848 cond = JSDOUBLE_COMPARE(l, OP, r, false); \
850 regs.sp[-2].setBoolean(cond); \
855 stubs::LessThan(VMFrame
&f
)
861 stubs::LessEqual(VMFrame
&f
)
867 stubs::GreaterThan(VMFrame
&f
)
873 stubs::GreaterEqual(VMFrame
&f
)
879 stubs::ValueToBoolean(VMFrame
&f
)
881 return js_ValueToBoolean(f
.regs
.sp
[-1]);
885 stubs::Not(VMFrame
&f
)
887 JSBool b
= !js_ValueToBoolean(f
.regs
.sp
[-1]);
888 f
.regs
.sp
[-1].setBoolean(b
);
891 template <JSBool EQ
, bool IFNAN
>
893 StubEqualityOp(VMFrame
&f
)
895 JSContext
*cx
= f
.cx
;
896 JSFrameRegs
®s
= f
.regs
;
898 Value rval
= regs
.sp
[-1];
899 Value lval
= regs
.sp
[-2];
903 /* The string==string case is easily the hottest; try it first. */
904 if (lval
.isString() && rval
.isString()) {
905 JSString
*l
= lval
.toString();
906 JSString
*r
= rval
.toString();
908 if (!EqualStrings(cx
, l
, r
, &equal
))
912 #if JS_HAS_XML_SUPPORT
913 if ((lval
.isObject() && lval
.toObject().isXML()) ||
914 (rval
.isObject() && rval
.toObject().isXML())) {
915 if (!js_TestXMLEquality(cx
, lval
, rval
, &cond
))
921 if (SameType(lval
, rval
)) {
922 JS_ASSERT(!lval
.isString()); /* this case is handled above */
923 if (lval
.isDouble()) {
924 double l
= lval
.toDouble();
925 double r
= rval
.toDouble();
927 cond
= JSDOUBLE_COMPARE(l
, ==, r
, IFNAN
);
929 cond
= JSDOUBLE_COMPARE(l
, !=, r
, IFNAN
);
930 } else if (lval
.isObject()) {
931 JSObject
*l
= &lval
.toObject(), *r
= &rval
.toObject();
932 l
->assertSpecialEqualitySynced();
933 if (EqualityOp eq
= l
->getClass()->ext
.equality
) {
934 if (!eq(cx
, l
, &rval
, &cond
))
938 cond
= (l
== r
) == EQ
;
940 } else if (lval
.isNullOrUndefined()) {
943 cond
= (lval
.payloadAsRawUint32() == rval
.payloadAsRawUint32()) == EQ
;
946 if (lval
.isNullOrUndefined()) {
947 cond
= rval
.isNullOrUndefined() == EQ
;
948 } else if (rval
.isNullOrUndefined()) {
951 if (lval
.isObject()) {
952 if (!DefaultValue(cx
, &lval
.toObject(), JSTYPE_VOID
, ®s
.sp
[-2]))
957 if (rval
.isObject()) {
958 if (!DefaultValue(cx
, &rval
.toObject(), JSTYPE_VOID
, ®s
.sp
[-1]))
964 * The string==string case is repeated because DefaultValue() can
965 * convert lval/rval to strings.
967 if (lval
.isString() && rval
.isString()) {
968 JSString
*l
= lval
.toString();
969 JSString
*r
= rval
.toString();
971 if (!EqualStrings(cx
, l
, r
, &equal
))
976 if (!ValueToNumber(cx
, lval
, &l
) ||
977 !ValueToNumber(cx
, rval
, &r
)) {
982 cond
= JSDOUBLE_COMPARE(l
, ==, r
, false);
984 cond
= JSDOUBLE_COMPARE(l
, !=, r
, true);
989 regs
.sp
[-2].setBoolean(cond
);
994 stubs::Equal(VMFrame
&f
)
996 if (!StubEqualityOp
<JS_TRUE
, false>(f
))
998 return f
.regs
.sp
[-2].toBoolean();
1002 stubs::NotEqual(VMFrame
&f
)
1004 if (!StubEqualityOp
<JS_FALSE
, true>(f
))
1006 return f
.regs
.sp
[-2].toBoolean();
1010 DefaultValue(VMFrame
&f
, JSType hint
, Value
&v
, int n
)
1012 JS_ASSERT(v
.isObject());
1013 if (!DefaultValue(f
.cx
, &v
.toObject(), hint
, &f
.regs
.sp
[n
]))
1020 stubs::Add(VMFrame
&f
)
1022 JSContext
*cx
= f
.cx
;
1023 JSFrameRegs
®s
= f
.regs
;
1024 Value rval
= regs
.sp
[-1];
1025 Value lval
= regs
.sp
[-2];
1027 /* The string + string case is easily the hottest; try it first. */
1028 bool lIsString
= lval
.isString();
1029 bool rIsString
= rval
.isString();
1030 JSString
*lstr
, *rstr
;
1031 if (lIsString
&& rIsString
) {
1032 lstr
= lval
.toString();
1033 rstr
= rval
.toString();
1037 #if JS_HAS_XML_SUPPORT
1038 if (lval
.isObject() && lval
.toObject().isXML() &&
1039 rval
.isObject() && rval
.toObject().isXML()) {
1040 if (!js_ConcatenateXML(cx
, &lval
.toObject(), &rval
.toObject(), &rval
))
1047 /* These can convert lval/rval to strings. */
1048 if (lval
.isObject() && !DefaultValue(f
, JSTYPE_VOID
, lval
, -2))
1050 if (rval
.isObject() && !DefaultValue(f
, JSTYPE_VOID
, rval
, -1))
1052 if ((lIsString
= lval
.isString()) || (rIsString
= rval
.isString())) {
1054 lstr
= lval
.toString();
1056 lstr
= js_ValueToString(cx
, lval
);
1059 regs
.sp
[-2].setString(lstr
);
1062 rstr
= rval
.toString();
1064 rstr
= js_ValueToString(cx
, rval
);
1067 regs
.sp
[-1].setString(rstr
);
1073 if (!ValueToNumber(cx
, lval
, &l
) || !ValueToNumber(cx
, rval
, &r
))
1077 regs
.sp
[-1].setNumber(l
);
1083 JSString
*str
= js_ConcatStrings(cx
, lstr
, rstr
);
1087 regs
.sp
[-1].setString(str
);
1092 stubs::Sub(VMFrame
&f
)
1094 JSContext
*cx
= f
.cx
;
1095 JSFrameRegs
®s
= f
.regs
;
1097 if (!ValueToNumber(cx
, regs
.sp
[-2], &d1
) ||
1098 !ValueToNumber(cx
, regs
.sp
[-1], &d2
)) {
1102 regs
.sp
[-2].setNumber(d
);
1106 stubs::Mul(VMFrame
&f
)
1108 JSContext
*cx
= f
.cx
;
1109 JSFrameRegs
®s
= f
.regs
;
1111 if (!ValueToNumber(cx
, regs
.sp
[-2], &d1
) ||
1112 !ValueToNumber(cx
, regs
.sp
[-1], &d2
)) {
1116 regs
.sp
[-2].setNumber(d
);
1120 stubs::Div(VMFrame
&f
)
1122 JSContext
*cx
= f
.cx
;
1123 JSRuntime
*rt
= cx
->runtime
;
1124 JSFrameRegs
®s
= f
.regs
;
1127 if (!ValueToNumber(cx
, regs
.sp
[-2], &d1
) ||
1128 !ValueToNumber(cx
, regs
.sp
[-1], &d2
)) {
1134 /* XXX MSVC miscompiles such that (NaN == 0) */
1135 if (JSDOUBLE_IS_NaN(d2
))
1139 if (d1
== 0 || JSDOUBLE_IS_NaN(d1
))
1141 else if (JSDOUBLE_IS_NEG(d1
) != JSDOUBLE_IS_NEG(d2
))
1142 vp
= &rt
->negativeInfinityValue
;
1144 vp
= &rt
->positiveInfinityValue
;
1148 regs
.sp
[-2].setNumber(d1
);
1153 stubs::Mod(VMFrame
&f
)
1155 JSContext
*cx
= f
.cx
;
1156 JSFrameRegs
®s
= f
.regs
;
1158 Value
&lref
= regs
.sp
[-2];
1159 Value
&rref
= regs
.sp
[-1];
1161 if (lref
.isInt32() && rref
.isInt32() &&
1162 (l
= lref
.toInt32()) >= 0 && (r
= rref
.toInt32()) > 0) {
1163 int32_t mod
= l
% r
;
1164 regs
.sp
[-2].setInt32(mod
);
1167 if (!ValueToNumber(cx
, regs
.sp
[-2], &d1
) ||
1168 !ValueToNumber(cx
, regs
.sp
[-1], &d2
)) {
1172 regs
.sp
[-2].setDouble(js_NaN
);
1174 d1
= js_fmod(d1
, d2
);
1175 regs
.sp
[-2].setDouble(d1
);
1181 stubs::Debugger(VMFrame
&f
, jsbytecode
*pc
)
1183 JSDebuggerHandler handler
= f
.cx
->debugHooks
->debuggerHandler
;
1186 switch (handler(f
.cx
, f
.cx
->fp()->script(), pc
, Jsvalify(&rval
),
1187 f
.cx
->debugHooks
->debuggerHandlerData
)) {
1189 f
.cx
->setPendingException(rval
);
1193 f
.cx
->clearPendingException();
1194 f
.cx
->fp()->setReturnValue(rval
);
1195 #if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
1196 *f
.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
1197 f
.cx
->jaegerCompartment()->forceReturnFastTrampoline());
1199 *f
.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
1200 f
.cx
->jaegerCompartment()->forceReturnTrampoline());
1205 f
.cx
->clearPendingException();
1215 stubs::Interrupt(VMFrame
&f
, jsbytecode
*pc
)
1217 if (!js_HandleExecutionInterrupt(f
.cx
))
1222 stubs::Trap(VMFrame
&f
, uint32 trapTypes
)
1225 jsbytecode
*pc
= f
.cx
->regs
->pc
;
1228 * Trap may be called for a single-step interrupt trap and/or a
1229 * regular trap. Try the single-step first, and if it lets control
1230 * flow through or does not exist, do the regular trap.
1232 JSTrapStatus result
= JSTRAP_CONTINUE
;
1233 if (trapTypes
& JSTRAP_SINGLESTEP
) {
1235 * single step mode may be paused without recompiling by
1236 * setting the interruptHook to NULL.
1238 JSInterruptHook hook
= f
.cx
->debugHooks
->interruptHook
;
1240 result
= hook(f
.cx
, f
.cx
->fp()->script(), pc
, Jsvalify(&rval
),
1241 f
.cx
->debugHooks
->interruptHookData
);
1244 if (result
== JSTRAP_CONTINUE
&& (trapTypes
& JSTRAP_TRAP
))
1245 result
= JS_HandleTrap(f
.cx
, f
.cx
->fp()->script(), pc
, Jsvalify(&rval
));
1249 f
.cx
->setPendingException(rval
);
1253 f
.cx
->clearPendingException();
1254 f
.cx
->fp()->setReturnValue(rval
);
1255 #if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
1256 *f
.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
1257 f
.cx
->jaegerCompartment()->forceReturnFastTrampoline());
1259 *f
.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
1260 f
.cx
->jaegerCompartment()->forceReturnTrampoline());
1265 f
.cx
->clearPendingException();
1274 stubs::This(VMFrame
&f
)
1276 if (!f
.fp()->computeThis(f
.cx
))
1278 f
.regs
.sp
[-1] = f
.fp()->thisValue();
1282 stubs::Neg(VMFrame
&f
)
1285 if (!ValueToNumber(f
.cx
, f
.regs
.sp
[-1], &d
))
1288 f
.regs
.sp
[-1].setNumber(d
);
1291 JSObject
* JS_FASTCALL
1292 stubs::NewInitArray(VMFrame
&f
, uint32 count
)
1294 JSObject
*obj
= NewDenseAllocatedArray(f
.cx
, count
);
1301 JSObject
* JS_FASTCALL
1302 stubs::NewInitObject(VMFrame
&f
, JSObject
*baseobj
)
1304 JSContext
*cx
= f
.cx
;
1307 gc::FinalizeKind kind
= GuessObjectGCKind(0, false);
1308 JSObject
*obj
= NewBuiltinClassInstance(cx
, &js_ObjectClass
, kind
);
1314 JSObject
*obj
= CopyInitializerObject(cx
, baseobj
);
1322 stubs::InitElem(VMFrame
&f
, uint32 last
)
1324 JSContext
*cx
= f
.cx
;
1325 JSFrameRegs
®s
= f
.regs
;
1327 /* Pop the element's value into rval. */
1328 JS_ASSERT(regs
.sp
- f
.fp()->base() >= 3);
1329 const Value
&rref
= regs
.sp
[-1];
1331 /* Find the object being initialized at top of stack. */
1332 const Value
&lref
= regs
.sp
[-3];
1333 JS_ASSERT(lref
.isObject());
1334 JSObject
*obj
= &lref
.toObject();
1336 /* Fetch id now that we have obj. */
1338 const Value
&idval
= regs
.sp
[-2];
1339 if (!FetchElementId(f
, obj
, idval
, id
, ®s
.sp
[-2]))
1343 * If rref is a hole, do not call JSObject::defineProperty. In this case,
1344 * obj must be an array, so if the current op is the last element
1345 * initialiser, set the array length to one greater than id.
1347 if (rref
.isMagic(JS_ARRAY_HOLE
)) {
1348 JS_ASSERT(obj
->isArray());
1349 JS_ASSERT(JSID_IS_INT(id
));
1350 JS_ASSERT(jsuint(JSID_TO_INT(id
)) < JS_ARGS_LENGTH_MAX
);
1351 if (last
&& !js_SetLengthProperty(cx
, obj
, (jsuint
) (JSID_TO_INT(id
) + 1)))
1354 if (!obj
->defineProperty(cx
, id
, rref
, NULL
, NULL
, JSPROP_ENUMERATE
))
1360 stubs::GetUpvar(VMFrame
&f
, uint32 ck
)
1362 /* :FIXME: We can do better, this stub isn't needed. */
1363 uint32 staticLevel
= f
.fp()->script()->staticLevel
;
1365 cookie
.fromInteger(ck
);
1366 f
.regs
.sp
[0] = GetUpvar(f
.cx
, staticLevel
, cookie
);
1369 JSObject
* JS_FASTCALL
1370 stubs::DefLocalFun(VMFrame
&f
, JSFunction
*fun
)
1373 * Define a local function (i.e., one nested at the top level of another
1374 * function), parented by the current scope chain, stored in a local
1375 * variable slot that the compiler allocated. This is an optimization over
1376 * JSOP_DEFFUN that avoids requiring a call object for the outer function's
1379 JS_ASSERT(fun
->isInterpreted());
1380 JS_ASSERT(!FUN_FLAT_CLOSURE(fun
));
1381 JSObject
*obj
= FUN_OBJECT(fun
);
1383 if (FUN_NULL_CLOSURE(fun
)) {
1384 obj
= CloneFunctionObject(f
.cx
, fun
, &f
.fp()->scopeChain());
1388 JSObject
*parent
= GetScopeChainFast(f
.cx
, f
.fp(), JSOP_DEFLOCALFUN
,
1389 JSOP_DEFLOCALFUN_LENGTH
);
1393 if (obj
->getParent() != parent
) {
1394 obj
= CloneFunctionObject(f
.cx
, fun
, parent
);
1403 JSObject
* JS_FASTCALL
1404 stubs::DefLocalFun_FC(VMFrame
&f
, JSFunction
*fun
)
1406 JSObject
*obj
= js_NewFlatClosure(f
.cx
, fun
, JSOP_DEFLOCALFUN_FC
, JSOP_DEFLOCALFUN_FC_LENGTH
);
1412 JSObject
* JS_FASTCALL
1413 stubs::RegExp(VMFrame
&f
, JSObject
*regex
)
1416 * Push a regexp object cloned from the regexp literal object mapped by the
1417 * bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was
1418 * flouted by many browser-based implementations.
1420 * We avoid the GetScopeChain call here and pass fp->scopeChain() as
1421 * js_GetClassPrototype uses the latter only to locate the global.
1424 if (!js_GetClassPrototype(f
.cx
, &f
.fp()->scopeChain(), JSProto_RegExp
, &proto
))
1427 JSObject
*obj
= js_CloneRegExpObject(f
.cx
, regex
, proto
);
1433 JSObject
* JS_FASTCALL
1434 stubs::LambdaForInit(VMFrame
&f
, JSFunction
*fun
)
1436 JSObject
*obj
= FUN_OBJECT(fun
);
1437 if (FUN_NULL_CLOSURE(fun
) && obj
->getParent() == &f
.fp()->scopeChain()) {
1438 fun
->setMethodAtom(f
.fp()->script()->getAtom(GET_SLOTNO(f
.regs
.pc
)));
1441 return Lambda(f
, fun
);
1444 JSObject
* JS_FASTCALL
1445 stubs::LambdaForSet(VMFrame
&f
, JSFunction
*fun
)
1447 JSObject
*obj
= FUN_OBJECT(fun
);
1448 if (FUN_NULL_CLOSURE(fun
) && obj
->getParent() == &f
.fp()->scopeChain()) {
1449 const Value
&lref
= f
.regs
.sp
[-1];
1450 if (lref
.isObject() && lref
.toObject().canHaveMethodBarrier()) {
1451 fun
->setMethodAtom(f
.fp()->script()->getAtom(GET_SLOTNO(f
.regs
.pc
)));
1455 return Lambda(f
, fun
);
1458 JSObject
* JS_FASTCALL
1459 stubs::LambdaJoinableForCall(VMFrame
&f
, JSFunction
*fun
)
1461 JSObject
*obj
= FUN_OBJECT(fun
);
1462 if (FUN_NULL_CLOSURE(fun
) && obj
->getParent() == &f
.fp()->scopeChain()) {
1464 * Array.prototype.sort and String.prototype.replace are
1465 * optimized as if they are special form. We know that they
1466 * won't leak the joined function object in obj, therefore
1467 * we don't need to clone that compiler- created function
1468 * object for identity/mutation reasons.
1470 int iargc
= GET_ARGC(f
.regs
.pc
);
1473 * Note that we have not yet pushed obj as the final argument,
1474 * so regs.sp[1 - (iargc + 2)], and not regs.sp[-(iargc + 2)],
1475 * is the callee for this JSOP_CALL.
1477 const Value
&cref
= f
.regs
.sp
[1 - (iargc
+ 2)];
1480 if (IsFunctionObject(cref
, &callee
)) {
1481 JSFunction
*calleeFun
= callee
->getFunctionPrivate();
1482 Native native
= calleeFun
->maybeNative();
1485 if (iargc
== 1 && native
== array_sort
)
1487 if (iargc
== 2 && native
== str_replace
)
1492 return Lambda(f
, fun
);
1495 JSObject
* JS_FASTCALL
1496 stubs::LambdaJoinableForNull(VMFrame
&f
, JSFunction
*fun
)
1498 JSObject
*obj
= FUN_OBJECT(fun
);
1499 if (FUN_NULL_CLOSURE(fun
) && obj
->getParent() == &f
.fp()->scopeChain()) {
1500 jsbytecode
*pc2
= f
.regs
.pc
+ JSOP_NULL_LENGTH
;
1501 JSOp op2
= JSOp(*pc2
);
1503 if (op2
== JSOP_CALL
&& GET_ARGC(pc2
) == 0)
1506 return Lambda(f
, fun
);
1509 JSObject
* JS_FASTCALL
1510 stubs::Lambda(VMFrame
&f
, JSFunction
*fun
)
1512 JSObject
*obj
= FUN_OBJECT(fun
);
1515 if (FUN_NULL_CLOSURE(fun
)) {
1516 parent
= &f
.fp()->scopeChain();
1518 parent
= GetScopeChainFast(f
.cx
, f
.fp(), JSOP_LAMBDA
, JSOP_LAMBDA_LENGTH
);
1523 obj
= CloneFunctionObject(f
.cx
, fun
, parent
);
1530 /* Test whether v is an int in the range [-2^31 + 1, 2^31 - 2] */
1531 static JS_ALWAYS_INLINE
bool
1532 CanIncDecWithoutOverflow(int32_t i
)
1534 return (i
> JSVAL_INT_MIN
) && (i
< JSVAL_INT_MAX
);
1537 template <int32 N
, bool POST
, JSBool strict
>
1539 ObjIncOp(VMFrame
&f
, JSObject
*obj
, jsid id
)
1541 JSContext
*cx
= f
.cx
;
1542 JSStackFrame
*fp
= f
.fp();
1544 f
.regs
.sp
[0].setNull();
1546 if (!obj
->getProperty(cx
, id
, &f
.regs
.sp
[-1]))
1549 Value
&ref
= f
.regs
.sp
[-1];
1551 if (JS_LIKELY(ref
.isInt32() && CanIncDecWithoutOverflow(tmp
= ref
.toInt32()))) {
1553 ref
.getInt32Ref() = tmp
+ N
;
1555 ref
.getInt32Ref() = tmp
+= N
;
1557 JSBool ok
= obj
->setProperty(cx
, id
, &ref
, strict
);
1558 fp
->clearAssigning();
1563 * We must set regs.sp[-1] to tmp for both post and pre increments
1564 * as the setter overwrites regs.sp[-1].
1570 if (!ValueToNumber(cx
, ref
, &d
))
1581 JSBool ok
= obj
->setProperty(cx
, id
, &v
, strict
);
1582 fp
->clearAssigning();
1590 template <int32 N
, bool POST
, JSBool strict
>
1592 NameIncDec(VMFrame
&f
, JSObject
*obj
, JSAtom
*origAtom
)
1594 JSContext
*cx
= f
.cx
;
1599 PropertyCacheEntry
*entry
;
1600 JS_PROPERTY_CACHE(cx
).test(cx
, f
.regs
.pc
, obj
, obj2
, entry
, atom
);
1602 if (obj
== obj2
&& entry
->vword
.isSlot()) {
1603 uint32 slot
= entry
->vword
.toSlot();
1604 Value
&rref
= obj
->nativeGetSlotRef(slot
);
1606 if (JS_LIKELY(rref
.isInt32() && CanIncDecWithoutOverflow(tmp
= rref
.toInt32()))) {
1607 int32_t inc
= tmp
+ N
;
1610 rref
.getInt32Ref() = inc
;
1611 f
.regs
.sp
[0].setInt32(tmp
);
1618 jsid id
= ATOM_TO_JSID(atom
);
1619 if (!js_FindPropertyHelper(cx
, id
, true, &obj
, &obj2
, &prop
))
1622 ReportAtomNotDefined(cx
, atom
);
1625 return ObjIncOp
<N
, POST
, strict
>(f
, obj
, id
);
1628 template<JSBool strict
>
1630 stubs::PropInc(VMFrame
&f
, JSAtom
*atom
)
1632 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-1]);
1635 if (!ObjIncOp
<1, true, strict
>(f
, obj
, ATOM_TO_JSID(atom
)))
1637 f
.regs
.sp
[-2] = f
.regs
.sp
[-1];
1640 template void JS_FASTCALL
stubs::PropInc
<true>(VMFrame
&f
, JSAtom
*atom
);
1641 template void JS_FASTCALL
stubs::PropInc
<false>(VMFrame
&f
, JSAtom
*atom
);
1643 template<JSBool strict
>
1645 stubs::PropDec(VMFrame
&f
, JSAtom
*atom
)
1647 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-1]);
1650 if (!ObjIncOp
<-1, true, strict
>(f
, obj
, ATOM_TO_JSID(atom
)))
1652 f
.regs
.sp
[-2] = f
.regs
.sp
[-1];
1655 template void JS_FASTCALL
stubs::PropDec
<true>(VMFrame
&f
, JSAtom
*atom
);
1656 template void JS_FASTCALL
stubs::PropDec
<false>(VMFrame
&f
, JSAtom
*atom
);
1658 template<JSBool strict
>
1660 stubs::IncProp(VMFrame
&f
, JSAtom
*atom
)
1662 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-1]);
1665 if (!ObjIncOp
<1, false, strict
>(f
, obj
, ATOM_TO_JSID(atom
)))
1667 f
.regs
.sp
[-2] = f
.regs
.sp
[-1];
1670 template void JS_FASTCALL
stubs::IncProp
<true>(VMFrame
&f
, JSAtom
*atom
);
1671 template void JS_FASTCALL
stubs::IncProp
<false>(VMFrame
&f
, JSAtom
*atom
);
1673 template<JSBool strict
>
1675 stubs::DecProp(VMFrame
&f
, JSAtom
*atom
)
1677 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-1]);
1680 if (!ObjIncOp
<-1, false, strict
>(f
, obj
, ATOM_TO_JSID(atom
)))
1682 f
.regs
.sp
[-2] = f
.regs
.sp
[-1];
1685 template void JS_FASTCALL
stubs::DecProp
<true>(VMFrame
&f
, JSAtom
*atom
);
1686 template void JS_FASTCALL
stubs::DecProp
<false>(VMFrame
&f
, JSAtom
*atom
);
1688 template<JSBool strict
>
1690 stubs::ElemInc(VMFrame
&f
)
1692 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-2]);
1696 if (!FetchElementId(f
, obj
, f
.regs
.sp
[-1], id
, &f
.regs
.sp
[-1]))
1698 if (!ObjIncOp
<1, true, strict
>(f
, obj
, id
))
1700 f
.regs
.sp
[-3] = f
.regs
.sp
[-1];
1703 template void JS_FASTCALL
stubs::ElemInc
<true>(VMFrame
&f
);
1704 template void JS_FASTCALL
stubs::ElemInc
<false>(VMFrame
&f
);
1706 template<JSBool strict
>
1708 stubs::ElemDec(VMFrame
&f
)
1710 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-2]);
1714 if (!FetchElementId(f
, obj
, f
.regs
.sp
[-1], id
, &f
.regs
.sp
[-1]))
1716 if (!ObjIncOp
<-1, true, strict
>(f
, obj
, id
))
1718 f
.regs
.sp
[-3] = f
.regs
.sp
[-1];
1721 template void JS_FASTCALL
stubs::ElemDec
<true>(VMFrame
&f
);
1722 template void JS_FASTCALL
stubs::ElemDec
<false>(VMFrame
&f
);
1724 template<JSBool strict
>
1726 stubs::IncElem(VMFrame
&f
)
1728 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-2]);
1732 if (!FetchElementId(f
, obj
, f
.regs
.sp
[-1], id
, &f
.regs
.sp
[-1]))
1734 if (!ObjIncOp
<1, false, strict
>(f
, obj
, id
))
1736 f
.regs
.sp
[-3] = f
.regs
.sp
[-1];
1739 template void JS_FASTCALL
stubs::IncElem
<true>(VMFrame
&f
);
1740 template void JS_FASTCALL
stubs::IncElem
<false>(VMFrame
&f
);
1742 template<JSBool strict
>
1744 stubs::DecElem(VMFrame
&f
)
1746 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-2]);
1750 if (!FetchElementId(f
, obj
, f
.regs
.sp
[-1], id
, &f
.regs
.sp
[-1]))
1752 if (!ObjIncOp
<-1, false, strict
>(f
, obj
, id
))
1754 f
.regs
.sp
[-3] = f
.regs
.sp
[-1];
1757 template void JS_FASTCALL
stubs::DecElem
<true>(VMFrame
&f
);
1758 template void JS_FASTCALL
stubs::DecElem
<false>(VMFrame
&f
);
1760 template<JSBool strict
>
1762 stubs::NameInc(VMFrame
&f
, JSAtom
*atom
)
1764 JSObject
*obj
= &f
.fp()->scopeChain();
1765 if (!NameIncDec
<1, true, strict
>(f
, obj
, atom
))
1769 template void JS_FASTCALL
stubs::NameInc
<true>(VMFrame
&f
, JSAtom
*atom
);
1770 template void JS_FASTCALL
stubs::NameInc
<false>(VMFrame
&f
, JSAtom
*atom
);
1772 template<JSBool strict
>
1774 stubs::NameDec(VMFrame
&f
, JSAtom
*atom
)
1776 JSObject
*obj
= &f
.fp()->scopeChain();
1777 if (!NameIncDec
<-1, true, strict
>(f
, obj
, atom
))
1781 template void JS_FASTCALL
stubs::NameDec
<true>(VMFrame
&f
, JSAtom
*atom
);
1782 template void JS_FASTCALL
stubs::NameDec
<false>(VMFrame
&f
, JSAtom
*atom
);
1784 template<JSBool strict
>
1786 stubs::IncName(VMFrame
&f
, JSAtom
*atom
)
1788 JSObject
*obj
= &f
.fp()->scopeChain();
1789 if (!NameIncDec
<1, false, strict
>(f
, obj
, atom
))
1793 template void JS_FASTCALL
stubs::IncName
<true>(VMFrame
&f
, JSAtom
*atom
);
1794 template void JS_FASTCALL
stubs::IncName
<false>(VMFrame
&f
, JSAtom
*atom
);
1796 template<JSBool strict
>
1798 stubs::DecName(VMFrame
&f
, JSAtom
*atom
)
1800 JSObject
*obj
= &f
.fp()->scopeChain();
1801 if (!NameIncDec
<-1, false, strict
>(f
, obj
, atom
))
1805 template void JS_FASTCALL
stubs::DecName
<true>(VMFrame
&f
, JSAtom
*atom
);
1806 template void JS_FASTCALL
stubs::DecName
<false>(VMFrame
&f
, JSAtom
*atom
);
1808 template<JSBool strict
>
1810 stubs::GlobalNameInc(VMFrame
&f
, JSAtom
*atom
)
1812 JSObject
*obj
= f
.fp()->scopeChain().getGlobal();
1813 if (!NameIncDec
<1, true, strict
>(f
, obj
, atom
))
1817 template void JS_FASTCALL
stubs::GlobalNameInc
<true>(VMFrame
&f
, JSAtom
*atom
);
1818 template void JS_FASTCALL
stubs::GlobalNameInc
<false>(VMFrame
&f
, JSAtom
*atom
);
1820 template<JSBool strict
>
1822 stubs::GlobalNameDec(VMFrame
&f
, JSAtom
*atom
)
1824 JSObject
*obj
= f
.fp()->scopeChain().getGlobal();
1825 if (!NameIncDec
<-1, true, strict
>(f
, obj
, atom
))
1829 template void JS_FASTCALL
stubs::GlobalNameDec
<true>(VMFrame
&f
, JSAtom
*atom
);
1830 template void JS_FASTCALL
stubs::GlobalNameDec
<false>(VMFrame
&f
, JSAtom
*atom
);
1832 template<JSBool strict
>
1834 stubs::IncGlobalName(VMFrame
&f
, JSAtom
*atom
)
1836 JSObject
*obj
= f
.fp()->scopeChain().getGlobal();
1837 if (!NameIncDec
<1, false, strict
>(f
, obj
, atom
))
1841 template void JS_FASTCALL
stubs::IncGlobalName
<true>(VMFrame
&f
, JSAtom
*atom
);
1842 template void JS_FASTCALL
stubs::IncGlobalName
<false>(VMFrame
&f
, JSAtom
*atom
);
1844 template<JSBool strict
>
1846 stubs::DecGlobalName(VMFrame
&f
, JSAtom
*atom
)
1848 JSObject
*obj
= f
.fp()->scopeChain().getGlobal();
1849 if (!NameIncDec
<-1, false, strict
>(f
, obj
, atom
))
1853 template void JS_FASTCALL
stubs::DecGlobalName
<true>(VMFrame
&f
, JSAtom
*atom
);
1854 template void JS_FASTCALL
stubs::DecGlobalName
<false>(VMFrame
&f
, JSAtom
*atom
);
1856 static bool JS_FASTCALL
1857 InlineGetProp(VMFrame
&f
)
1859 JSContext
*cx
= f
.cx
;
1860 JSFrameRegs
®s
= f
.regs
;
1862 Value
*vp
= &f
.regs
.sp
[-1];
1863 JSObject
*obj
= ValueToObject(f
.cx
, vp
);
1870 * We do not impose the method read barrier if in an imacro,
1871 * assuming any property gets it does (e.g., for 'toString'
1872 * from JSOP_NEW) will not be leaked to the calling script.
1874 JSObject
*aobj
= js_GetProtoIfDenseArray(obj
);
1876 PropertyCacheEntry
*entry
;
1879 JS_PROPERTY_CACHE(cx
).test(cx
, regs
.pc
, aobj
, obj2
, entry
, atom
);
1881 if (entry
->vword
.isFunObj()) {
1882 rval
.setObject(entry
->vword
.toFunObj());
1883 } else if (entry
->vword
.isSlot()) {
1884 uint32 slot
= entry
->vword
.toSlot();
1885 rval
= obj2
->nativeGetSlot(slot
);
1887 JS_ASSERT(entry
->vword
.isShape());
1888 const Shape
*shape
= entry
->vword
.toShape();
1889 NATIVE_GET(cx
, obj
, obj2
, shape
,
1890 f
.fp()->hasImacropc() ? JSGET_NO_METHOD_BARRIER
: JSGET_METHOD_BARRIER
,
1891 &rval
, return false);
1896 jsid id
= ATOM_TO_JSID(atom
);
1897 if (JS_LIKELY(!aobj
->getOps()->getProperty
)
1898 ? !js_GetPropertyHelper(cx
, obj
, id
,
1899 f
.fp()->hasImacropc()
1900 ? JSGET_CACHE_RESULT
| JSGET_NO_METHOD_BARRIER
1901 : JSGET_CACHE_RESULT
| JSGET_METHOD_BARRIER
,
1903 : !obj
->getProperty(cx
, id
, &rval
)) {
1913 stubs::GetProp(VMFrame
&f
)
1915 if (!InlineGetProp(f
))
1920 stubs::GetPropNoCache(VMFrame
&f
, JSAtom
*atom
)
1922 JSContext
*cx
= f
.cx
;
1924 Value
*vp
= &f
.regs
.sp
[-1];
1925 JSObject
*obj
= ValueToObject(cx
, vp
);
1929 if (!obj
->getProperty(cx
, ATOM_TO_JSID(atom
), vp
))
1934 stubs::CallProp(VMFrame
&f
, JSAtom
*origAtom
)
1936 JSContext
*cx
= f
.cx
;
1937 JSFrameRegs
®s
= f
.regs
;
1943 if (lval
.isObject()) {
1946 JSProtoKey protoKey
;
1947 if (lval
.isString()) {
1948 protoKey
= JSProto_String
;
1949 } else if (lval
.isNumber()) {
1950 protoKey
= JSProto_Number
;
1951 } else if (lval
.isBoolean()) {
1952 protoKey
= JSProto_Boolean
;
1954 JS_ASSERT(lval
.isNull() || lval
.isUndefined());
1955 js_ReportIsNullOrUndefined(cx
, -1, lval
, NULL
);
1959 if (!js_GetClassPrototype(cx
, NULL
, protoKey
, &pobj
))
1961 objv
.setObject(*pobj
);
1964 JSObject
*aobj
= js_GetProtoIfDenseArray(&objv
.toObject());
1967 PropertyCacheEntry
*entry
;
1970 JS_PROPERTY_CACHE(cx
).test(cx
, regs
.pc
, aobj
, obj2
, entry
, atom
);
1972 if (entry
->vword
.isFunObj()) {
1973 rval
.setObject(entry
->vword
.toFunObj());
1974 } else if (entry
->vword
.isSlot()) {
1975 uint32 slot
= entry
->vword
.toSlot();
1976 rval
= obj2
->nativeGetSlot(slot
);
1978 JS_ASSERT(entry
->vword
.isShape());
1979 const Shape
*shape
= entry
->vword
.toShape();
1980 NATIVE_GET(cx
, &objv
.toObject(), obj2
, shape
, JSGET_NO_METHOD_BARRIER
, &rval
,
1988 * Cache miss: use the immediate atom that was loaded for us under
1989 * PropertyCache::test.
1992 id
= ATOM_TO_JSID(origAtom
);
1995 regs
.sp
[-1].setNull();
1996 if (lval
.isObject()) {
1997 if (!js_GetMethod(cx
, &objv
.toObject(), id
,
1998 JS_LIKELY(!aobj
->getOps()->getProperty
)
1999 ? JSGET_CACHE_RESULT
| JSGET_NO_METHOD_BARRIER
2000 : JSGET_NO_METHOD_BARRIER
,
2007 JS_ASSERT(!objv
.toObject().getOps()->getProperty
);
2008 if (!js_GetPropertyHelper(cx
, &objv
.toObject(), id
,
2009 JSGET_CACHE_RESULT
| JSGET_NO_METHOD_BARRIER
,
2017 #if JS_HAS_NO_SUCH_METHOD
2018 if (JS_UNLIKELY(rval
.isUndefined()) && regs
.sp
[-1].isObject()) {
2019 regs
.sp
[-2].setString(ATOM_TO_STRING(origAtom
));
2020 if (!js_OnUnknownMethod(cx
, regs
.sp
- 2))
2027 stubs::Length(VMFrame
&f
)
2029 JSFrameRegs
®s
= f
.regs
;
2030 Value
*vp
= ®s
.sp
[-1];
2032 if (vp
->isString()) {
2033 vp
->setInt32(vp
->toString()->length());
2035 } else if (vp
->isObject()) {
2036 JSObject
*obj
= &vp
->toObject();
2037 if (obj
->isArray()) {
2038 jsuint length
= obj
->getArrayLength();
2039 regs
.sp
[-1].setNumber(length
);
2041 } else if (obj
->isArguments() && !obj
->isArgsLengthOverridden()) {
2042 uint32 length
= obj
->getArgsInitialLength();
2043 JS_ASSERT(length
< INT32_MAX
);
2044 regs
.sp
[-1].setInt32(int32_t(length
));
2049 if (!InlineGetProp(f
))
2054 stubs::Iter(VMFrame
&f
, uint32 flags
)
2056 if (!js_ValueToIterator(f
.cx
, flags
, &f
.regs
.sp
[-1]))
2058 JS_ASSERT(!f
.regs
.sp
[-1].isPrimitive());
2062 InitPropOrMethod(VMFrame
&f
, JSAtom
*atom
, JSOp op
)
2064 JSContext
*cx
= f
.cx
;
2065 JSRuntime
*rt
= cx
->runtime
;
2066 JSFrameRegs
®s
= f
.regs
;
2068 /* Load the property's initial value into rval. */
2069 JS_ASSERT(regs
.sp
- f
.fp()->base() >= 2);
2073 /* Load the object being initialized into lval/obj. */
2074 JSObject
*obj
= ®s
.sp
[-2].toObject();
2075 JS_ASSERT(obj
->isNative());
2078 * Probe the property cache.
2080 * We can not assume that the object created by JSOP_NEWINIT is still
2081 * single-threaded as the debugger can access it from other threads.
2084 * On a hit, if the cached shape has a non-default setter, it must be
2085 * __proto__. If shape->previous() != obj->lastProperty(), there must be a
2086 * repeated property name. The fast path does not handle these two cases.
2088 PropertyCacheEntry
*entry
;
2090 if (JS_PROPERTY_CACHE(cx
).testForInit(rt
, regs
.pc
, obj
, &shape
, &entry
) &&
2091 shape
->hasDefaultSetter() &&
2092 shape
->previous() == obj
->lastProperty())
2094 /* Fast path. Property cache hit. */
2095 uint32 slot
= shape
->slot
;
2097 JS_ASSERT(slot
== obj
->slotSpan());
2098 JS_ASSERT(slot
>= JSSLOT_FREE(obj
->getClass()));
2099 if (slot
< obj
->numSlots()) {
2100 JS_ASSERT(obj
->getSlot(slot
).isUndefined());
2102 if (!obj
->allocSlot(cx
, &slot
))
2104 JS_ASSERT(slot
== shape
->slot
);
2107 /* A new object, or one we just extended in a recent initprop op. */
2108 JS_ASSERT(!obj
->lastProperty() ||
2109 obj
->shape() == obj
->lastProperty()->shape
);
2110 obj
->extend(cx
, shape
);
2113 * No method change check here because here we are adding a new
2114 * property, not updating an existing slot's value that might
2115 * contain a method of a branded shape.
2117 obj
->nativeSetSlot(slot
, rval
);
2119 PCMETER(JS_PROPERTY_CACHE(cx
).inipcmisses
++);
2121 /* Get the immediate property name into id. */
2122 jsid id
= ATOM_TO_JSID(atom
);
2124 uintN defineHow
= (op
== JSOP_INITMETHOD
)
2125 ? JSDNP_CACHE_RESULT
| JSDNP_SET_METHOD
2126 : JSDNP_CACHE_RESULT
;
2127 if (!(JS_UNLIKELY(atom
== cx
->runtime
->atomState
.protoAtom
)
2128 ? js_SetPropertyHelper(cx
, obj
, id
, defineHow
, &rval
, false)
2129 : js_DefineNativeProperty(cx
, obj
, id
, rval
, NULL
, NULL
,
2130 JSPROP_ENUMERATE
, 0, 0, NULL
,
2138 stubs::InitProp(VMFrame
&f
, JSAtom
*atom
)
2140 InitPropOrMethod(f
, atom
, JSOP_INITPROP
);
2144 stubs::InitMethod(VMFrame
&f
, JSAtom
*atom
)
2146 InitPropOrMethod(f
, atom
, JSOP_INITMETHOD
);
2150 stubs::IterNext(VMFrame
&f
)
2152 JS_ASSERT(f
.regs
.sp
- 1 >= f
.fp()->base());
2153 JS_ASSERT(f
.regs
.sp
[-1].isObject());
2155 JSObject
*iterobj
= &f
.regs
.sp
[-1].toObject();
2156 f
.regs
.sp
[0].setNull();
2158 if (!js_IteratorNext(f
.cx
, iterobj
, &f
.regs
.sp
[-1]))
2163 stubs::IterMore(VMFrame
&f
)
2165 JS_ASSERT(f
.regs
.sp
- 1 >= f
.fp()->base());
2166 JS_ASSERT(f
.regs
.sp
[-1].isObject());
2169 JSObject
*iterobj
= &f
.regs
.sp
[-1].toObject();
2170 if (!js_IteratorMore(f
.cx
, iterobj
, &v
))
2173 return v
.toBoolean();
2177 stubs::EndIter(VMFrame
&f
)
2179 JS_ASSERT(f
.regs
.sp
- 1 >= f
.fp()->base());
2180 if (!js_CloseIterator(f
.cx
, &f
.regs
.sp
[-1].toObject()))
2184 JSString
* JS_FASTCALL
2185 stubs::TypeOf(VMFrame
&f
)
2187 const Value
&ref
= f
.regs
.sp
[-1];
2188 JSType type
= JS_TypeOfValue(f
.cx
, Jsvalify(ref
));
2189 JSAtom
*atom
= f
.cx
->runtime
->atomState
.typeAtoms
[type
];
2190 return ATOM_TO_STRING(atom
);
2194 stubs::StrictEq(VMFrame
&f
)
2196 const Value
&rhs
= f
.regs
.sp
[-1];
2197 const Value
&lhs
= f
.regs
.sp
[-2];
2199 if (!StrictlyEqual(f
.cx
, lhs
, rhs
, &equal
))
2202 f
.regs
.sp
[-1].setBoolean(equal
== JS_TRUE
);
2206 stubs::StrictNe(VMFrame
&f
)
2208 const Value
&rhs
= f
.regs
.sp
[-1];
2209 const Value
&lhs
= f
.regs
.sp
[-2];
2211 if (!StrictlyEqual(f
.cx
, lhs
, rhs
, &equal
))
2214 f
.regs
.sp
[-1].setBoolean(equal
!= JS_TRUE
);
2218 stubs::Throw(VMFrame
&f
)
2220 JSContext
*cx
= f
.cx
;
2222 JS_ASSERT(!cx
->isExceptionPending());
2223 cx
->setPendingException(f
.regs
.sp
[-1]);
2227 JSObject
* JS_FASTCALL
2228 stubs::FlatLambda(VMFrame
&f
, JSFunction
*fun
)
2230 JSObject
*obj
= js_NewFlatClosure(f
.cx
, fun
, JSOP_LAMBDA_FC
, JSOP_LAMBDA_FC_LENGTH
);
2237 stubs::Arguments(VMFrame
&f
)
2240 if (!js_GetArgsValue(f
.cx
, f
.fp(), &f
.regs
.sp
[-1]))
2245 stubs::InstanceOf(VMFrame
&f
)
2247 JSContext
*cx
= f
.cx
;
2248 JSFrameRegs
®s
= f
.regs
;
2250 const Value
&rref
= regs
.sp
[-1];
2251 if (rref
.isPrimitive()) {
2252 js_ReportValueError(cx
, JSMSG_BAD_INSTANCEOF_RHS
,
2256 JSObject
*obj
= &rref
.toObject();
2257 const Value
&lref
= regs
.sp
[-2];
2258 JSBool cond
= JS_FALSE
;
2259 if (!HasInstance(cx
, obj
, &lref
, &cond
))
2261 f
.regs
.sp
[-2].setBoolean(cond
);
2266 stubs::FastInstanceOf(VMFrame
&f
)
2268 const Value
&lref
= f
.regs
.sp
[-1];
2270 if (lref
.isPrimitive()) {
2272 * Throw a runtime error if instanceof is called on a function that
2273 * has a non-object as its .prototype value.
2275 js_ReportValueError(f
.cx
, JSMSG_BAD_PROTOTYPE
, -1, f
.regs
.sp
[-2], NULL
);
2279 f
.regs
.sp
[-3].setBoolean(js_IsDelegate(f
.cx
, &lref
.toObject(), f
.regs
.sp
[-3]));
2283 stubs::ArgCnt(VMFrame
&f
)
2285 JSContext
*cx
= f
.cx
;
2286 JSRuntime
*rt
= cx
->runtime
;
2287 JSStackFrame
*fp
= f
.fp();
2289 jsid id
= ATOM_TO_JSID(rt
->atomState
.lengthAtom
);
2291 if (!js_GetArgsProperty(cx
, fp
, id
, &f
.regs
.sp
[-1]))
2296 stubs::EnterBlock(VMFrame
&f
, JSObject
*obj
)
2298 JSFrameRegs
®s
= f
.regs
;
2300 JSStackFrame
*fp
= f
.fp();
2303 JS_ASSERT(obj
->isStaticBlock());
2304 JS_ASSERT(fp
->base() + OBJ_BLOCK_DEPTH(cx
, obj
) == regs
.sp
);
2305 Value
*vp
= regs
.sp
+ OBJ_BLOCK_COUNT(cx
, obj
);
2306 JS_ASSERT(regs
.sp
< vp
);
2307 JS_ASSERT(vp
<= fp
->slots() + fp
->script()->nslots
);
2308 SetValueRangeToUndefined(regs
.sp
, vp
);
2312 JSContext
*cx
= f
.cx
;
2315 * The young end of fp->scopeChain() may omit blocks if we haven't closed
2316 * over them, but if there are any closure blocks on fp->scopeChain(), they'd
2317 * better be (clones of) ancestors of the block we're entering now;
2318 * anything else we should have popped off fp->scopeChain() when we left its
2321 JSObject
*obj2
= &fp
->scopeChain();
2323 while ((clasp
= obj2
->getClass()) == &js_WithClass
)
2324 obj2
= obj2
->getParent();
2325 if (clasp
== &js_BlockClass
&&
2326 obj2
->getPrivate() == js_FloatingFrameIfGenerator(cx
, fp
)) {
2327 JSObject
*youngestProto
= obj2
->getProto();
2328 JS_ASSERT(youngestProto
->isStaticBlock());
2329 JSObject
*parent
= obj
;
2330 while ((parent
= parent
->getParent()) != youngestProto
)
2337 stubs::LeaveBlock(VMFrame
&f
, JSObject
*blockChain
)
2339 JSContext
*cx
= f
.cx
;
2340 JSStackFrame
*fp
= f
.fp();
2343 JS_ASSERT(blockChain
->isStaticBlock());
2344 uintN blockDepth
= OBJ_BLOCK_DEPTH(cx
, blockChain
);
2346 JS_ASSERT(blockDepth
<= StackDepth(fp
->script()));
2349 * If we're about to leave the dynamic scope of a block that has been
2350 * cloned onto fp->scopeChain(), clear its private data, move its locals from
2351 * the stack into the clone, and pop it off the chain.
2353 JSObject
*obj
= &fp
->scopeChain();
2354 if (obj
->getProto() == blockChain
) {
2355 JS_ASSERT(obj
->getClass() == &js_BlockClass
);
2356 if (!js_PutBlockObject(cx
, JS_TRUE
))
2362 stubs::LookupSwitch(VMFrame
&f
, jsbytecode
*pc
)
2364 jsbytecode
*jpc
= pc
;
2365 JSScript
*script
= f
.fp()->script();
2366 bool ctor
= f
.fp()->isConstructing();
2368 /* This is correct because the compiler adjusts the stack beforehand. */
2369 Value lval
= f
.regs
.sp
[-1];
2371 if (!lval
.isPrimitive()) {
2372 void* native
= script
->nativeCodeForPC(ctor
, pc
+ GET_JUMP_OFFSET(pc
));
2377 JS_ASSERT(pc
[0] == JSOP_LOOKUPSWITCH
);
2379 pc
+= JUMP_OFFSET_LEN
;
2380 uint32 npairs
= GET_UINT16(pc
);
2385 if (lval
.isString()) {
2386 JSLinearString
*str
= lval
.toString()->ensureLinear(f
.cx
);
2389 for (uint32 i
= 1; i
<= npairs
; i
++) {
2390 Value rval
= script
->getConst(GET_INDEX(pc
));
2392 if (rval
.isString()) {
2393 JSLinearString
*rhs
= rval
.toString()->assertIsLinear();
2394 if (rhs
== str
|| EqualStrings(str
, rhs
)) {
2395 void* native
= script
->nativeCodeForPC(ctor
,
2396 jpc
+ GET_JUMP_OFFSET(pc
));
2401 pc
+= JUMP_OFFSET_LEN
;
2403 } else if (lval
.isNumber()) {
2404 double d
= lval
.toNumber();
2405 for (uint32 i
= 1; i
<= npairs
; i
++) {
2406 Value rval
= script
->getConst(GET_INDEX(pc
));
2408 if (rval
.isNumber() && d
== rval
.toNumber()) {
2409 void* native
= script
->nativeCodeForPC(ctor
,
2410 jpc
+ GET_JUMP_OFFSET(pc
));
2414 pc
+= JUMP_OFFSET_LEN
;
2417 for (uint32 i
= 1; i
<= npairs
; i
++) {
2418 Value rval
= script
->getConst(GET_INDEX(pc
));
2421 void* native
= script
->nativeCodeForPC(ctor
,
2422 jpc
+ GET_JUMP_OFFSET(pc
));
2426 pc
+= JUMP_OFFSET_LEN
;
2430 void* native
= script
->nativeCodeForPC(ctor
, jpc
+ GET_JUMP_OFFSET(jpc
));
2436 stubs::TableSwitch(VMFrame
&f
, jsbytecode
*origPc
)
2438 jsbytecode
* const originalPC
= origPc
;
2439 jsbytecode
*pc
= originalPC
;
2440 uint32 jumpOffset
= GET_JUMP_OFFSET(pc
);
2441 pc
+= JUMP_OFFSET_LEN
;
2443 /* Note: compiler adjusts the stack beforehand. */
2444 Value rval
= f
.regs
.sp
[-1];
2447 if (rval
.isInt32()) {
2448 tableIdx
= rval
.toInt32();
2449 } else if (rval
.isDouble()) {
2450 double d
= rval
.toDouble();
2452 /* Treat -0 (double) as 0. */
2454 } else if (!JSDOUBLE_IS_INT32(d
, (int32_t *)&tableIdx
)) {
2462 jsint low
= GET_JUMP_OFFSET(pc
);
2463 pc
+= JUMP_OFFSET_LEN
;
2464 jsint high
= GET_JUMP_OFFSET(pc
);
2465 pc
+= JUMP_OFFSET_LEN
;
2468 if ((jsuint
) tableIdx
< (jsuint
)(high
- low
+ 1)) {
2469 pc
+= JUMP_OFFSET_LEN
* tableIdx
;
2470 uint32 candidateOffset
= GET_JUMP_OFFSET(pc
);
2471 if (candidateOffset
)
2472 jumpOffset
= candidateOffset
;
2477 /* Provide the native address. */
2478 JSScript
* script
= f
.fp()->script();
2479 void* native
= script
->nativeCodeForPC(f
.fp()->isConstructing(),
2480 originalPC
+ jumpOffset
);
2486 stubs::Unbrand(VMFrame
&f
)
2488 const Value
&thisv
= f
.regs
.sp
[-1];
2489 if (!thisv
.isObject())
2491 JSObject
*obj
= &thisv
.toObject();
2492 if (obj
->isNative())
2497 stubs::Pos(VMFrame
&f
)
2499 if (!ValueToNumber(f
.cx
, &f
.regs
.sp
[-1]))
2504 stubs::ArgSub(VMFrame
&f
, uint32 n
)
2506 jsid id
= INT_TO_JSID(n
);
2508 if (!js_GetArgsProperty(f
.cx
, f
.fp(), id
, &rval
))
2510 f
.regs
.sp
[0] = rval
;
2514 stubs::DelName(VMFrame
&f
, JSAtom
*atom
)
2516 jsid id
= ATOM_TO_JSID(atom
);
2517 JSObject
*obj
, *obj2
;
2519 if (!js_FindProperty(f
.cx
, id
, &obj
, &obj2
, &prop
))
2522 /* Strict mode code should never contain JSOP_DELNAME opcodes. */
2523 JS_ASSERT(!f
.fp()->script()->strictModeCode
);
2525 /* ECMA says to return true if name is undefined or inherited. */
2527 f
.regs
.sp
[-1] = BooleanValue(true);
2529 if (!obj
->deleteProperty(f
.cx
, id
, &f
.regs
.sp
[-1], false))
2534 template<JSBool strict
>
2536 stubs::DelProp(VMFrame
&f
, JSAtom
*atom
)
2538 JSContext
*cx
= f
.cx
;
2540 JSObject
*obj
= ValueToObject(cx
, &f
.regs
.sp
[-1]);
2545 if (!obj
->deleteProperty(cx
, ATOM_TO_JSID(atom
), &rval
, strict
))
2548 f
.regs
.sp
[-1] = rval
;
2551 template void JS_FASTCALL
stubs::DelProp
<true>(VMFrame
&f
, JSAtom
*atom
);
2552 template void JS_FASTCALL
stubs::DelProp
<false>(VMFrame
&f
, JSAtom
*atom
);
2554 template<JSBool strict
>
2556 stubs::DelElem(VMFrame
&f
)
2558 JSContext
*cx
= f
.cx
;
2560 JSObject
*obj
= ValueToObject(cx
, &f
.regs
.sp
[-2]);
2565 if (!FetchElementId(f
, obj
, f
.regs
.sp
[-1], id
, &f
.regs
.sp
[-1]))
2568 if (!obj
->deleteProperty(cx
, id
, &f
.regs
.sp
[-2], strict
))
2573 stubs::DefVarOrConst(VMFrame
&f
, JSAtom
*atom
)
2575 JSContext
*cx
= f
.cx
;
2576 JSStackFrame
*fp
= f
.fp();
2578 JSObject
*obj
= &fp
->varobj(cx
);
2579 JS_ASSERT(!obj
->getOps()->defineProperty
);
2580 uintN attrs
= JSPROP_ENUMERATE
;
2581 if (!fp
->isEvalFrame())
2582 attrs
|= JSPROP_PERMANENT
;
2584 /* Lookup id in order to check for redeclaration problems. */
2585 jsid id
= ATOM_TO_JSID(atom
);
2587 if (JSOp(*f
.regs
.pc
) == JSOP_DEFVAR
) {
2589 * Redundant declaration of a |var|, even one for a non-writable
2590 * property like |undefined| in ES5, does nothing.
2594 if (!obj
->lookupProperty(cx
, id
, &obj2
, &prop
))
2596 shouldDefine
= (!prop
|| obj2
!= obj
);
2598 JS_ASSERT(JSOp(*f
.regs
.pc
) == JSOP_DEFCONST
);
2599 attrs
|= JSPROP_READONLY
;
2600 if (!CheckRedeclaration(cx
, obj
, id
, attrs
))
2604 * As attrs includes readonly, CheckRedeclaration can succeed only
2605 * if prop does not exist.
2607 shouldDefine
= true;
2610 /* Bind a variable only if it's not yet defined. */
2612 !js_DefineNativeProperty(cx
, obj
, id
, UndefinedValue(), PropertyStub
, StrictPropertyStub
,
2613 attrs
, 0, 0, NULL
)) {
2619 stubs::SetConst(VMFrame
&f
, JSAtom
*atom
)
2621 JSContext
*cx
= f
.cx
;
2622 JSStackFrame
*fp
= f
.fp();
2624 JSObject
*obj
= &fp
->varobj(cx
);
2625 const Value
&ref
= f
.regs
.sp
[-1];
2626 if (!obj
->defineProperty(cx
, ATOM_TO_JSID(atom
), ref
,
2627 PropertyStub
, StrictPropertyStub
,
2628 JSPROP_ENUMERATE
| JSPROP_PERMANENT
| JSPROP_READONLY
)) {
2634 stubs::In(VMFrame
&f
)
2636 JSContext
*cx
= f
.cx
;
2638 const Value
&rref
= f
.regs
.sp
[-1];
2639 if (!rref
.isObject()) {
2640 js_ReportValueError(cx
, JSMSG_IN_NOT_OBJECT
, -1, rref
, NULL
);
2644 JSObject
*obj
= &rref
.toObject();
2646 if (!FetchElementId(f
, obj
, f
.regs
.sp
[-2], id
, &f
.regs
.sp
[-2]))
2651 if (!obj
->lookupProperty(cx
, id
, &obj2
, &prop
))
2657 template void JS_FASTCALL
stubs::DelElem
<true>(VMFrame
&f
);
2658 template void JS_FASTCALL
stubs::DelElem
<false>(VMFrame
&f
);
2661 stubs::Exception(VMFrame
&f
)
2663 f
.regs
.sp
[0] = f
.cx
->getPendingException();
2664 f
.cx
->clearPendingException();
2666 template <bool Clamped
>
2668 stubs::ConvertToTypedInt(JSContext
*cx
, Value
*vp
)
2670 JS_ASSERT(!vp
->isInt32());
2672 if (vp
->isDouble()) {
2674 return js_TypedArray_uint8_clamp_double(vp
->toDouble());
2675 return js_DoubleToECMAInt32(vp
->toDouble());
2678 if (vp
->isNull() || vp
->isObject() || vp
->isUndefined())
2681 if (vp
->isBoolean())
2682 return vp
->toBoolean() ? 1 : 0;
2684 JS_ASSERT(vp
->isString());
2690 StringToNumberType
<jsint
>(cx
, vp
->toString(), &i32
);
2696 template int32 JS_FASTCALL
stubs::ConvertToTypedInt
<true>(JSContext
*, Value
*);
2697 template int32 JS_FASTCALL
stubs::ConvertToTypedInt
<false>(JSContext
*, Value
*);
2700 stubs::ConvertToTypedFloat(JSContext
*cx
, Value
*vp
)
2702 JS_ASSERT(!vp
->isDouble() && !vp
->isInt32());
2706 } else if (vp
->isObject() || vp
->isUndefined()) {
2707 vp
->setDouble(js_NaN
);
2708 } else if (vp
->isBoolean()) {
2709 vp
->setDouble(vp
->toBoolean() ? 1 : 0);
2711 JS_ASSERT(vp
->isString());
2716 StringToNumberType
<double>(cx
, vp
->toString(), &d
);