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"
73 #include "jsautooplen.h"
76 using namespace js::mjit
;
80 stubs::BindName(VMFrame
&f
)
82 PropertyCacheEntry
*entry
;
84 /* Fast-path should have caught this. See comment in interpreter. */
85 JS_ASSERT(f
.fp()->scopeChain().getParent());
90 JSObject
*obj
= &f
.fp()->scopeChain();
91 JS_PROPERTY_CACHE(cx
).test(cx
, f
.regs
.pc
, obj
, obj2
, entry
, atom
);
93 jsid id
= ATOM_TO_JSID(atom
);
94 obj
= js_FindIdentifierBase(cx
, &f
.fp()->scopeChain(), id
);
99 f
.regs
.sp
[-1].setObject(*obj
);
103 stubs::BindNameNoCache(VMFrame
&f
, JSAtom
*atom
)
105 JSObject
*obj
= js_FindIdentifierBase(f
.cx
, &f
.fp()->scopeChain(), ATOM_TO_JSID(atom
));
108 f
.regs
.sp
[0].setObject(*obj
);
111 JSObject
* JS_FASTCALL
112 stubs::BindGlobalName(VMFrame
&f
)
114 return f
.fp()->scopeChain().getGlobal();
117 template<JSBool strict
>
119 stubs::SetName(VMFrame
&f
, JSAtom
*origAtom
)
121 JSContext
*cx
= f
.cx
;
123 Value rval
= f
.regs
.sp
[-1];
124 Value
&lref
= f
.regs
.sp
[-2];
125 JSObject
*obj
= ValueToObject(cx
, &lref
);
130 PropertyCache
*cache
= &JS_PROPERTY_CACHE(cx
);
133 * Probe the property cache, specializing for two important
134 * set-property cases. First:
136 * function f(a, b, c) {
137 * var o = {p:a, q:b, r:c};
141 * or similar real-world cases, which evolve a newborn native
142 * object predicatably through some bounded number of property
143 * additions. And second:
147 * in a frequently executed method or loop body, where p will
148 * (possibly after the first iteration) always exist in native
151 PropertyCacheEntry
*entry
;
154 if (cache
->testForSet(cx
, f
.regs
.pc
, obj
, &entry
, &obj2
, &atom
)) {
156 * Fast property cache hit, only partially confirmed by
157 * testForSet. We know that the entry applies to regs.pc and
158 * that obj's shape matches.
160 * The entry predicts either a new property to be added
161 * directly to obj by this set, or on an existing "own"
162 * property, or on a prototype property that has a setter.
164 const Shape
*shape
= entry
->vword
.toShape();
165 JS_ASSERT_IF(shape
->isDataDescriptor(), shape
->writable());
166 JS_ASSERT_IF(shape
->hasSlot(), entry
->vcapTag() == 0);
169 * Fastest path: check whether obj already has the cached shape and
170 * call NATIVE_SET and break to get out of the do-while(0). But we
171 * can call NATIVE_SET only for a direct or proto-setter hit.
173 if (!entry
->adding()) {
174 if (entry
->vcapTag() == 0 ||
175 ((obj2
= obj
->getProto()) && obj2
->shape() == entry
->vshape()))
178 if (entry
->directHit()) {
179 JS_ASSERT(obj
->nativeContains(*shape
));
181 JS_ASSERT(obj2
->nativeContains(*shape
));
182 JS_ASSERT(entry
->vcapTag() == 1);
183 JS_ASSERT(entry
->kshape
!= entry
->vshape());
184 JS_ASSERT(!shape
->hasSlot());
188 PCMETER(cache
->pchits
++);
189 PCMETER(cache
->setpchits
++);
190 NATIVE_SET(cx
, obj
, shape
, entry
, &rval
);
194 JS_ASSERT(obj
->isExtensible());
196 if (obj
->nativeEmpty()) {
197 if (!obj
->ensureClassReservedSlotsForEmptyObject(cx
))
202 if (shape
->previous() == obj
->lastProperty() &&
203 entry
->vshape() == cx
->runtime
->protoHazardShape
&&
204 shape
->hasDefaultSetter()) {
206 JS_ASSERT(slot
== obj
->slotSpan());
209 * Fast path: adding a plain old property that was once at
210 * the frontier of the property tree, whose slot is next to
211 * claim among the already-allocated slots in obj, where
212 * shape->table has not been created yet.
214 PCMETER(cache
->pchits
++);
215 PCMETER(cache
->addpchits
++);
217 if (slot
< obj
->numSlots()) {
218 JS_ASSERT(obj
->getSlot(slot
).isUndefined());
220 if (!obj
->allocSlot(cx
, &slot
))
222 JS_ASSERT(slot
== shape
->slot
);
225 /* Simply extend obj's property tree path with shape! */
226 obj
->extend(cx
, shape
);
229 * No method change check here because here we are adding a
230 * new property, not updating an existing slot's value that
231 * might contain a method of a branded shape.
233 obj
->setSlot(slot
, rval
);
236 * Purge the property cache of the id we may have just
237 * shadowed in obj's scope and proto chains.
239 js_PurgeScopeChain(cx
, obj
, shape
->id
);
243 PCMETER(cache
->setpcmisses
++);
247 * Slower property cache hit, fully confirmed by testForSet (in the
248 * slow path, via fullTest).
250 const Shape
*shape
= NULL
;
252 shape
= entry
->vword
.toShape();
253 JS_ASSERT(shape
->writable());
254 JS_ASSERT(obj2
->isExtensible());
255 NATIVE_SET(cx
, obj
, shape
, entry
, &rval
);
263 jsid id
= ATOM_TO_JSID(atom
);
264 if (entry
&& JS_LIKELY(!obj
->getOps()->setProperty
)) {
266 JSOp op
= JSOp(*f
.regs
.pc
);
267 if (op
== JSOP_SETMETHOD
)
268 defineHow
= JSDNP_CACHE_RESULT
| JSDNP_SET_METHOD
;
269 else if (op
== JSOP_SETNAME
)
270 defineHow
= JSDNP_CACHE_RESULT
| JSDNP_UNQUALIFIED
;
272 defineHow
= JSDNP_CACHE_RESULT
;
273 if (!js_SetPropertyHelper(cx
, obj
, id
, defineHow
, &rval
, strict
))
276 if (!obj
->setProperty(cx
, id
, &rval
, strict
))
281 f
.regs
.sp
[-2] = f
.regs
.sp
[-1];
284 template void JS_FASTCALL
stubs::SetName
<true>(VMFrame
&f
, JSAtom
*origAtom
);
285 template void JS_FASTCALL
stubs::SetName
<false>(VMFrame
&f
, JSAtom
*origAtom
);
287 template<JSBool strict
>
289 stubs::SetPropNoCache(VMFrame
&f
, JSAtom
*atom
)
291 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-2]);
294 Value rval
= f
.regs
.sp
[-1];
295 if (!obj
->setProperty(f
.cx
, ATOM_TO_JSID(atom
), &f
.regs
.sp
[-1], strict
))
297 f
.regs
.sp
[-2] = rval
;
300 template void JS_FASTCALL
stubs::SetPropNoCache
<true>(VMFrame
&f
, JSAtom
*origAtom
);
301 template void JS_FASTCALL
stubs::SetPropNoCache
<false>(VMFrame
&f
, JSAtom
*origAtom
);
303 template<JSBool strict
>
305 stubs::SetGlobalNameDumb(VMFrame
&f
, JSAtom
*atom
)
307 JSContext
*cx
= f
.cx
;
309 Value rval
= f
.regs
.sp
[-1];
310 Value
&lref
= f
.regs
.sp
[-2];
311 JSObject
*obj
= ValueToObject(cx
, &lref
);
314 jsid id
= ATOM_TO_JSID(atom
);
315 if (!obj
->setProperty(cx
, id
, &rval
, strict
))
318 f
.regs
.sp
[-2] = f
.regs
.sp
[-1];
321 template void JS_FASTCALL
stubs::SetGlobalNameDumb
<true>(VMFrame
&f
, JSAtom
*atom
);
322 template void JS_FASTCALL
stubs::SetGlobalNameDumb
<false>(VMFrame
&f
, JSAtom
*atom
);
324 template<JSBool strict
>
326 stubs::SetGlobalName(VMFrame
&f
, JSAtom
*atom
)
328 SetName
<strict
>(f
, atom
);
331 template void JS_FASTCALL
stubs::SetGlobalName
<true>(VMFrame
&f
, JSAtom
*atom
);
332 template void JS_FASTCALL
stubs::SetGlobalName
<false>(VMFrame
&f
, JSAtom
*atom
);
335 NameOp(VMFrame
&f
, JSObject
*obj
, bool callname
= false)
337 JSContext
*cx
= f
.cx
;
342 PropertyCacheEntry
*entry
;
345 JS_PROPERTY_CACHE(cx
).test(cx
, f
.regs
.pc
, obj
, obj2
, entry
, atom
);
347 if (entry
->vword
.isFunObj()) {
349 f
.regs
.sp
[-1].setObject(entry
->vword
.toFunObj());
350 } else if (entry
->vword
.isSlot()) {
351 uintN slot
= entry
->vword
.toSlot();
353 f
.regs
.sp
[-1] = obj2
->nativeGetSlot(slot
);
355 JS_ASSERT(entry
->vword
.isShape());
356 shape
= entry
->vword
.toShape();
357 NATIVE_GET(cx
, obj
, obj2
, shape
, JSGET_METHOD_BARRIER
, &rval
, return NULL
);
359 f
.regs
.sp
[-1] = rval
;
363 * Push results, the same as below, but with a prop$ hit there
364 * is no need to test for the unusual and uncacheable case where
365 * the caller determines |this|.
369 JS_ASSERT(!obj
->getParent() ||
370 (clasp
= obj
->getClass()) == &js_CallClass
||
371 clasp
== &js_BlockClass
||
372 clasp
== &js_DeclEnvClass
);
376 f
.regs
.sp
[-1].setUndefined();
382 id
= ATOM_TO_JSID(atom
);
384 if (!js_FindPropertyHelper(cx
, id
, true, &obj
, &obj2
, &prop
))
387 /* Kludge to allow (typeof foo == "undefined") tests. */
388 JSOp op2
= js_GetOpcode(cx
, f
.fp()->script(), f
.regs
.pc
+ JSOP_NAME_LENGTH
);
389 if (op2
== JSOP_TYPEOF
) {
391 f
.regs
.sp
[-1].setUndefined();
394 ReportAtomNotDefined(cx
, atom
);
398 /* Take the slow path if prop was not found in a native object. */
399 if (!obj
->isNative() || !obj2
->isNative()) {
400 if (!obj
->getProperty(cx
, id
, &rval
))
403 shape
= (Shape
*)prop
;
404 JSObject
*normalized
= obj
;
405 if (normalized
->getClass() == &js_WithClass
&& !shape
->hasDefaultGetter())
406 normalized
= js_UnwrapWithObject(cx
, normalized
);
407 NATIVE_GET(cx
, normalized
, obj2
, shape
, JSGET_METHOD_BARRIER
, &rval
, return NULL
);
411 f
.regs
.sp
[-1] = rval
;
414 JSObject
*thisp
= obj
;
415 if (!thisp
->getParent() ||
416 (clasp
= thisp
->getClass()) == &js_CallClass
||
417 clasp
== &js_BlockClass
||
418 clasp
== &js_DeclEnvClass
) {
420 f
.regs
.sp
[-1].setUndefined();
422 thisp
= thisp
->thisObject(cx
);
426 f
.regs
.sp
[-1].setObject(*thisp
);
433 stubs::Name(VMFrame
&f
)
435 if (!NameOp(f
, &f
.fp()->scopeChain()))
440 stubs::GetGlobalName(VMFrame
&f
)
442 JSObject
*globalObj
= f
.fp()->scopeChain().getGlobal();
443 if (!NameOp(f
, globalObj
))
448 stubs::GetElem(VMFrame
&f
)
450 JSContext
*cx
= f
.cx
;
451 JSFrameRegs
®s
= f
.regs
;
453 Value
&lref
= regs
.sp
[-2];
454 Value
&rref
= regs
.sp
[-1];
455 if (lref
.isString() && rref
.isInt32()) {
456 JSString
*str
= lref
.toString();
457 int32_t i
= rref
.toInt32();
458 if ((size_t)i
< str
->length()) {
459 str
= JSString::getUnitString(cx
, str
, (size_t)i
);
462 f
.regs
.sp
[-2].setString(str
);
467 JSObject
*obj
= ValueToObject(cx
, &lref
);
471 const Value
*copyFrom
;
474 if (rref
.isInt32()) {
475 int32_t i
= rref
.toInt32();
476 if (obj
->isDenseArray()) {
477 jsuint idx
= jsuint(i
);
479 if (idx
< obj
->getArrayLength() &&
480 idx
< obj
->getDenseArrayCapacity()) {
481 copyFrom
= obj
->addressOfDenseArrayElement(idx
);
482 if (!copyFrom
->isMagic())
485 } else if (obj
->isArguments()) {
486 uint32 arg
= uint32(i
);
488 if (arg
< obj
->getArgsInitialLength()) {
489 copyFrom
= obj
->addressOfArgsElement(arg
);
490 if (!copyFrom
->isMagic()) {
491 if (JSStackFrame
*afp
= (JSStackFrame
*) obj
->getPrivate())
492 copyFrom
= &afp
->canonicalActualArg(arg
);
497 if (JS_LIKELY(INT_FITS_IN_JSID(i
)))
504 if (!js_InternNonIntElementId(cx
, obj
, rref
, &id
))
508 if (!obj
->getProperty(cx
, id
, &rval
))
513 f
.regs
.sp
[-2] = *copyFrom
;
517 FetchElementId(VMFrame
&f
, JSObject
*obj
, const Value
&idval
, jsid
&id
, Value
*vp
)
520 if (ValueFitsInInt32(idval
, &i_
) && INT_FITS_IN_JSID(i_
)) {
521 id
= INT_TO_JSID(i_
);
524 return !!js_InternNonIntElementId(f
.cx
, obj
, idval
, &id
, vp
);
528 stubs::CallElem(VMFrame
&f
)
530 JSContext
*cx
= f
.cx
;
531 JSFrameRegs
®s
= f
.regs
;
533 /* Find the object on which to look for |this|'s properties. */
534 Value thisv
= regs
.sp
[-2];
535 JSObject
*thisObj
= ValuePropertyBearer(cx
, thisv
, -2);
539 /* Fetch index and convert it to id suitable for use with thisObj. */
541 if (!FetchElementId(f
, thisObj
, regs
.sp
[-1], id
, ®s
.sp
[-2]))
544 /* Get or set the element. */
545 if (!js_GetMethod(cx
, thisObj
, id
, JSGET_NO_METHOD_BARRIER
, ®s
.sp
[-2]))
548 #if JS_HAS_NO_SUCH_METHOD
549 if (JS_UNLIKELY(regs
.sp
[-2].isUndefined()) && thisv
.isObject()) {
550 regs
.sp
[-2] = regs
.sp
[-1];
551 regs
.sp
[-1].setObject(*thisObj
);
552 if (!js_OnUnknownMethod(cx
, regs
.sp
- 2))
561 template<JSBool strict
>
563 stubs::SetElem(VMFrame
&f
)
565 JSContext
*cx
= f
.cx
;
566 JSFrameRegs
®s
= f
.regs
;
568 Value
&objval
= regs
.sp
[-3];
569 Value
&idval
= regs
.sp
[-2];
570 Value retval
= regs
.sp
[-1];
575 obj
= ValueToObject(cx
, &objval
);
579 if (!FetchElementId(f
, obj
, idval
, id
, ®s
.sp
[-2]))
583 if (obj
->isDenseArray() && JSID_IS_INT(id
)) {
584 jsuint length
= obj
->getDenseArrayCapacity();
585 jsint i
= JSID_TO_INT(id
);
586 if ((jsuint
)i
< length
) {
587 if (obj
->getDenseArrayElement(i
).isMagic(JS_ARRAY_HOLE
)) {
588 if (js_PrototypeHasIndexedProperties(cx
, obj
))
590 if ((jsuint
)i
>= obj
->getArrayLength())
591 obj
->setArrayLength(i
+ 1);
593 obj
->setDenseArrayElement(i
, regs
.sp
[-1]);
598 if (!obj
->setProperty(cx
, id
, &retval
, strict
))
601 /* :FIXME: Moving the assigned object into the lowest stack slot
602 * is a temporary hack. What we actually want is an implementation
603 * of popAfterSet() that allows popping more than one value;
604 * this logic can then be handled in Compiler.cpp. */
605 regs
.sp
[-3] = retval
;
608 template void JS_FASTCALL
stubs::SetElem
<true>(VMFrame
&f
);
609 template void JS_FASTCALL
stubs::SetElem
<false>(VMFrame
&f
);
612 stubs::CallName(VMFrame
&f
)
614 JSObject
*obj
= NameOp(f
, &f
.fp()->scopeChain(), true);
620 stubs::BitOr(VMFrame
&f
)
624 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-2], &i
) ||
625 !ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &j
)) {
629 f
.regs
.sp
[-2].setInt32(i
);
633 stubs::BitXor(VMFrame
&f
)
637 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-2], &i
) ||
638 !ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &j
)) {
642 f
.regs
.sp
[-2].setInt32(i
);
646 stubs::BitAnd(VMFrame
&f
)
650 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-2], &i
) ||
651 !ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &j
)) {
655 f
.regs
.sp
[-2].setInt32(i
);
659 stubs::BitNot(VMFrame
&f
)
663 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &i
))
666 f
.regs
.sp
[-1].setInt32(i
);
670 stubs::Lsh(VMFrame
&f
)
673 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-2], &i
))
675 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &j
))
678 f
.regs
.sp
[-2].setInt32(i
);
682 stubs::Rsh(VMFrame
&f
)
685 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-2], &i
))
687 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &j
))
690 f
.regs
.sp
[-2].setInt32(i
);
694 stubs::Ursh(VMFrame
&f
)
697 if (!ValueToECMAUint32(f
.cx
, f
.regs
.sp
[-2], &u
))
700 if (!ValueToECMAInt32(f
.cx
, f
.regs
.sp
[-1], &j
))
705 f
.regs
.sp
[-2].setNumber(uint32(u
));
710 PostInc(VMFrame
&f
, Value
*vp
)
713 if (!ValueToNumber(f
.cx
, *vp
, &d
))
716 f
.regs
.sp
[-1].setDouble(d
);
724 PreInc(VMFrame
&f
, Value
*vp
)
727 if (!ValueToNumber(f
.cx
, *vp
, &d
))
732 f
.regs
.sp
[-1].setDouble(d
);
737 stubs::VpInc(VMFrame
&f
, Value
*vp
)
739 if (!PostInc
<1>(f
, vp
))
744 stubs::VpDec(VMFrame
&f
, Value
*vp
)
746 if (!PostInc
<-1>(f
, vp
))
751 stubs::DecVp(VMFrame
&f
, Value
*vp
)
753 if (!PreInc
<-1>(f
, vp
))
758 stubs::IncVp(VMFrame
&f
, Value
*vp
)
760 if (!PreInc
<1>(f
, vp
))
765 stubs::LocalInc(VMFrame
&f
, uint32 slot
)
768 if (!ValueToNumber(f
.cx
, f
.regs
.sp
[-2], &d
))
770 f
.regs
.sp
[-2].setNumber(d
);
771 f
.regs
.sp
[-1].setNumber(d
+ 1);
772 f
.fp()->slots()[slot
] = f
.regs
.sp
[-1];
776 stubs::LocalDec(VMFrame
&f
, uint32 slot
)
779 if (!ValueToNumber(f
.cx
, f
.regs
.sp
[-2], &d
))
781 f
.regs
.sp
[-2].setNumber(d
);
782 f
.regs
.sp
[-1].setNumber(d
- 1);
783 f
.fp()->slots()[slot
] = f
.regs
.sp
[-1];
787 stubs::IncLocal(VMFrame
&f
, uint32 slot
)
790 if (!ValueToNumber(f
.cx
, f
.regs
.sp
[-1], &d
))
792 f
.regs
.sp
[-1].setNumber(d
+ 1);
793 f
.fp()->slots()[slot
] = f
.regs
.sp
[-1];
797 stubs::DecLocal(VMFrame
&f
, uint32 slot
)
800 if (!ValueToNumber(f
.cx
, f
.regs
.sp
[-1], &d
))
802 f
.regs
.sp
[-1].setNumber(d
- 1);
803 f
.fp()->slots()[slot
] = f
.regs
.sp
[-1];
806 template<JSBool strict
>
808 stubs::DefFun(VMFrame
&f
, JSFunction
*fun
)
812 JSContext
*cx
= f
.cx
;
813 JSStackFrame
*fp
= f
.fp();
816 * A top-level function defined in Global or Eval code (see ECMA-262
817 * Ed. 3), or else a SpiderMonkey extension: a named function statement in
818 * a compound statement (not at the top statement level of global code, or
819 * at the top level of a function body).
821 JSObject
*obj
= FUN_OBJECT(fun
);
823 if (FUN_NULL_CLOSURE(fun
)) {
825 * Even a null closure needs a parent for principals finding.
826 * FIXME: bug 476950, although debugger users may also demand some kind
827 * of scope link for debugger-assisted eval-in-frame.
829 obj2
= &fp
->scopeChain();
831 JS_ASSERT(!FUN_FLAT_CLOSURE(fun
));
833 obj2
= js_GetScopeChainFast(cx
, fp
, JSOP_DEFFUN
, JSOP_DEFFUN_LENGTH
);
839 * If static link is not current scope, clone fun's object to link to the
840 * current scope via parent. We do this to enable sharing of compiled
841 * functions among multiple equivalent scopes, amortizing the cost of
842 * compilation over a number of executions. Examples include XUL scripts
843 * and event handlers shared among Firefox or other Mozilla app chrome
844 * windows, and user-defined JS functions precompiled and then shared among
845 * requests in server-side JS.
847 if (obj
->getParent() != obj2
) {
848 obj
= CloneFunctionObject(cx
, fun
, obj2
);
854 * ECMA requires functions defined when entering Eval code to be
857 uintN attrs
= fp
->isEvalFrame()
859 : JSPROP_ENUMERATE
| JSPROP_PERMANENT
;
862 * We define the function as a property of the variable object and not the
863 * current scope chain even for the case of function expression statements
864 * and functions defined by eval inside let or with blocks.
866 JSObject
*parent
= &fp
->varobj(cx
);
869 * Check for a const property of the same name -- or any kind of property
870 * if executing with the strict option. We check here at runtime as well
871 * as at compile-time, to handle eval as well as multiple HTML script tags.
873 jsid id
= ATOM_TO_JSID(fun
->atom
);
874 JSProperty
*prop
= NULL
;
876 JSBool ok
= CheckRedeclaration(cx
, parent
, id
, attrs
, &pobj
, &prop
);
881 * We deviate from ES3 10.1.3, ES5 10.5, by using JSObject::setProperty not
882 * JSObject::defineProperty for a function declaration in eval code whose
883 * id is already bound to a JSPROP_PERMANENT property, to ensure that such
884 * properties can't be deleted.
886 * We also use JSObject::setProperty for the existing properties of Call
887 * objects with matching attributes to preserve the internal (JSPropertyOp)
888 * getters and setters that update the value of the property in the stack
889 * frame. See bug 467495.
893 JS_ASSERT(!(attrs
& ~(JSPROP_ENUMERATE
| JSPROP_PERMANENT
)));
894 JS_ASSERT((attrs
== JSPROP_ENUMERATE
) == fp
->isEvalFrame());
896 if (attrs
== JSPROP_ENUMERATE
) {
897 /* In eval code: assign rather than (re-)define, always. */
899 } else if (parent
->isCall()) {
900 JS_ASSERT(parent
== pobj
);
902 uintN oldAttrs
= ((Shape
*) prop
)->attributes();
903 JS_ASSERT(!(oldAttrs
& (JSPROP_READONLY
| JSPROP_GETTER
| JSPROP_SETTER
)));
906 * We may be processing a function sub-statement or declaration in
907 * function code: we assign rather than redefine if the essential
908 * JSPROP_PERMANENT (not [[Configurable]] in ES5 terms) attribute
909 * is not changing (note that JSPROP_ENUMERATE is set for all Call
910 * object properties).
912 JS_ASSERT(oldAttrs
& attrs
& JSPROP_ENUMERATE
);
913 if (oldAttrs
& JSPROP_PERMANENT
)
918 Value rval
= ObjectValue(*obj
);
920 ? parent
->setProperty(cx
, id
, &rval
, strict
)
921 : parent
->defineProperty(cx
, id
, rval
, PropertyStub
, PropertyStub
, attrs
);
926 template void JS_FASTCALL
stubs::DefFun
<true>(VMFrame
&f
, JSFunction
*fun
);
927 template void JS_FASTCALL
stubs::DefFun
<false>(VMFrame
&f
, JSFunction
*fun
);
929 #define DEFAULT_VALUE(cx, n, hint, v) \
931 JS_ASSERT(v.isObject()); \
932 JS_ASSERT(v == regs.sp[n]); \
933 if (!DefaultValue(cx, &v.toObject(), hint, ®s.sp[n])) \
938 #define RELATIONAL(OP) \
940 JSContext *cx = f.cx; \
941 JSFrameRegs ®s = f.regs; \
942 Value rval = regs.sp[-1]; \
943 Value lval = regs.sp[-2]; \
945 if (lval.isObject()) \
946 DEFAULT_VALUE(cx, -2, JSTYPE_NUMBER, lval); \
947 if (rval.isObject()) \
948 DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \
949 if (lval.isString() && rval.isString()) { \
950 JSString *l = lval.toString(), *r = rval.toString(); \
951 cond = js_CompareStrings(l, r) OP 0; \
954 if (!ValueToNumber(cx, lval, &l) || \
955 !ValueToNumber(cx, rval, &r)) { \
958 cond = JSDOUBLE_COMPARE(l, OP, r, false); \
960 regs.sp[-2].setBoolean(cond); \
965 stubs::LessThan(VMFrame
&f
)
971 stubs::LessEqual(VMFrame
&f
)
977 stubs::GreaterThan(VMFrame
&f
)
983 stubs::GreaterEqual(VMFrame
&f
)
989 stubs::ValueToBoolean(VMFrame
&f
)
991 return js_ValueToBoolean(f
.regs
.sp
[-1]);
995 stubs::Not(VMFrame
&f
)
997 JSBool b
= !js_ValueToBoolean(f
.regs
.sp
[-1]);
998 f
.regs
.sp
[-1].setBoolean(b
);
1001 template <JSBool EQ
, bool IFNAN
>
1003 StubEqualityOp(VMFrame
&f
)
1005 JSContext
*cx
= f
.cx
;
1006 JSFrameRegs
®s
= f
.regs
;
1008 Value rval
= regs
.sp
[-1];
1009 Value lval
= regs
.sp
[-2];
1013 /* The string==string case is easily the hottest; try it first. */
1014 if (lval
.isString() && rval
.isString()) {
1015 JSString
*l
= lval
.toString();
1016 JSString
*r
= rval
.toString();
1017 cond
= js_EqualStrings(l
, r
) == EQ
;
1019 #if JS_HAS_XML_SUPPORT
1020 if ((lval
.isObject() && lval
.toObject().isXML()) ||
1021 (rval
.isObject() && rval
.toObject().isXML())) {
1022 if (!js_TestXMLEquality(cx
, lval
, rval
, &cond
))
1028 if (SameType(lval
, rval
)) {
1029 JS_ASSERT(!lval
.isString()); /* this case is handled above */
1030 if (lval
.isDouble()) {
1031 double l
= lval
.toDouble();
1032 double r
= rval
.toDouble();
1034 cond
= JSDOUBLE_COMPARE(l
, ==, r
, IFNAN
);
1036 cond
= JSDOUBLE_COMPARE(l
, !=, r
, IFNAN
);
1037 } else if (lval
.isObject()) {
1038 JSObject
*l
= &lval
.toObject(), *r
= &rval
.toObject();
1039 if (EqualityOp eq
= l
->getClass()->ext
.equality
) {
1040 if (!eq(cx
, l
, &rval
, &cond
))
1044 cond
= (l
== r
) == EQ
;
1046 } else if (lval
.isNullOrUndefined()) {
1049 cond
= (lval
.payloadAsRawUint32() == rval
.payloadAsRawUint32()) == EQ
;
1052 if (lval
.isNullOrUndefined()) {
1053 cond
= rval
.isNullOrUndefined() == EQ
;
1054 } else if (rval
.isNullOrUndefined()) {
1057 if (lval
.isObject()) {
1058 if (!DefaultValue(cx
, &lval
.toObject(), JSTYPE_VOID
, ®s
.sp
[-2]))
1063 if (rval
.isObject()) {
1064 if (!DefaultValue(cx
, &rval
.toObject(), JSTYPE_VOID
, ®s
.sp
[-1]))
1070 * The string==string case is repeated because DefaultValue() can
1071 * convert lval/rval to strings.
1073 if (lval
.isString() && rval
.isString()) {
1074 JSString
*l
= lval
.toString();
1075 JSString
*r
= rval
.toString();
1076 cond
= js_EqualStrings(l
, r
) == EQ
;
1079 if (!ValueToNumber(cx
, lval
, &l
) ||
1080 !ValueToNumber(cx
, rval
, &r
)) {
1085 cond
= JSDOUBLE_COMPARE(l
, ==, r
, false);
1087 cond
= JSDOUBLE_COMPARE(l
, !=, r
, true);
1092 regs
.sp
[-2].setBoolean(cond
);
1097 stubs::Equal(VMFrame
&f
)
1099 if (!StubEqualityOp
<JS_TRUE
, false>(f
))
1101 return f
.regs
.sp
[-2].toBoolean();
1105 stubs::NotEqual(VMFrame
&f
)
1107 if (!StubEqualityOp
<JS_FALSE
, true>(f
))
1109 return f
.regs
.sp
[-2].toBoolean();
1113 DefaultValue(VMFrame
&f
, JSType hint
, Value
&v
, int n
)
1115 JS_ASSERT(v
.isObject());
1116 if (!DefaultValue(f
.cx
, &v
.toObject(), hint
, &f
.regs
.sp
[n
]))
1123 stubs::Add(VMFrame
&f
)
1125 JSContext
*cx
= f
.cx
;
1126 JSFrameRegs
®s
= f
.regs
;
1127 Value rval
= regs
.sp
[-1];
1128 Value lval
= regs
.sp
[-2];
1130 /* The string + string case is easily the hottest; try it first. */
1131 bool lIsString
= lval
.isString();
1132 bool rIsString
= rval
.isString();
1133 JSString
*lstr
, *rstr
;
1134 if (lIsString
&& rIsString
) {
1135 lstr
= lval
.toString();
1136 rstr
= rval
.toString();
1140 #if JS_HAS_XML_SUPPORT
1141 if (lval
.isObject() && lval
.toObject().isXML() &&
1142 rval
.isObject() && rval
.toObject().isXML()) {
1143 if (!js_ConcatenateXML(cx
, &lval
.toObject(), &rval
.toObject(), &rval
))
1150 /* These can convert lval/rval to strings. */
1151 if (lval
.isObject() && !DefaultValue(f
, JSTYPE_VOID
, lval
, -2))
1153 if (rval
.isObject() && !DefaultValue(f
, JSTYPE_VOID
, rval
, -1))
1155 if ((lIsString
= lval
.isString()) || (rIsString
= rval
.isString())) {
1157 lstr
= lval
.toString();
1159 lstr
= js_ValueToString(cx
, lval
);
1162 regs
.sp
[-2].setString(lstr
);
1165 rstr
= rval
.toString();
1167 rstr
= js_ValueToString(cx
, rval
);
1170 regs
.sp
[-1].setString(rstr
);
1176 if (!ValueToNumber(cx
, lval
, &l
) || !ValueToNumber(cx
, rval
, &r
))
1180 regs
.sp
[-1].setNumber(l
);
1186 JSString
*str
= js_ConcatStrings(cx
, lstr
, rstr
);
1190 regs
.sp
[-1].setString(str
);
1195 stubs::Sub(VMFrame
&f
)
1197 JSContext
*cx
= f
.cx
;
1198 JSFrameRegs
®s
= f
.regs
;
1200 if (!ValueToNumber(cx
, regs
.sp
[-2], &d1
) ||
1201 !ValueToNumber(cx
, regs
.sp
[-1], &d2
)) {
1205 regs
.sp
[-2].setNumber(d
);
1209 stubs::Mul(VMFrame
&f
)
1211 JSContext
*cx
= f
.cx
;
1212 JSFrameRegs
®s
= f
.regs
;
1214 if (!ValueToNumber(cx
, regs
.sp
[-2], &d1
) ||
1215 !ValueToNumber(cx
, regs
.sp
[-1], &d2
)) {
1219 regs
.sp
[-2].setNumber(d
);
1223 stubs::Div(VMFrame
&f
)
1225 JSContext
*cx
= f
.cx
;
1226 JSRuntime
*rt
= cx
->runtime
;
1227 JSFrameRegs
®s
= f
.regs
;
1230 if (!ValueToNumber(cx
, regs
.sp
[-2], &d1
) ||
1231 !ValueToNumber(cx
, regs
.sp
[-1], &d2
)) {
1237 /* XXX MSVC miscompiles such that (NaN == 0) */
1238 if (JSDOUBLE_IS_NaN(d2
))
1242 if (d1
== 0 || JSDOUBLE_IS_NaN(d1
))
1244 else if (JSDOUBLE_IS_NEG(d1
) != JSDOUBLE_IS_NEG(d2
))
1245 vp
= &rt
->negativeInfinityValue
;
1247 vp
= &rt
->positiveInfinityValue
;
1251 regs
.sp
[-2].setNumber(d1
);
1256 stubs::Mod(VMFrame
&f
)
1258 JSContext
*cx
= f
.cx
;
1259 JSFrameRegs
®s
= f
.regs
;
1261 Value
&lref
= regs
.sp
[-2];
1262 Value
&rref
= regs
.sp
[-1];
1264 if (lref
.isInt32() && rref
.isInt32() &&
1265 (l
= lref
.toInt32()) >= 0 && (r
= rref
.toInt32()) > 0) {
1266 int32_t mod
= l
% r
;
1267 regs
.sp
[-2].setInt32(mod
);
1270 if (!ValueToNumber(cx
, regs
.sp
[-2], &d1
) ||
1271 !ValueToNumber(cx
, regs
.sp
[-1], &d2
)) {
1275 regs
.sp
[-2].setDouble(js_NaN
);
1277 d1
= js_fmod(d1
, d2
);
1278 regs
.sp
[-2].setDouble(d1
);
1283 JSObject
*JS_FASTCALL
1284 stubs::NewArray(VMFrame
&f
, uint32 len
)
1286 JSObject
*obj
= js_NewArrayObject(f
.cx
, len
, f
.regs
.sp
- len
);
1293 stubs::Debugger(VMFrame
&f
, jsbytecode
*pc
)
1295 JSDebuggerHandler handler
= f
.cx
->debugHooks
->debuggerHandler
;
1298 switch (handler(f
.cx
, f
.cx
->fp()->script(), pc
, Jsvalify(&rval
),
1299 f
.cx
->debugHooks
->debuggerHandlerData
)) {
1301 f
.cx
->throwing
= JS_TRUE
;
1302 f
.cx
->exception
= rval
;
1306 f
.cx
->throwing
= JS_FALSE
;
1307 f
.cx
->fp()->setReturnValue(rval
);
1308 #if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
1309 *f
.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
1310 JS_METHODJIT_DATA(f
.cx
).trampolines
.forceReturnFast
);
1312 *f
.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
1313 JS_METHODJIT_DATA(f
.cx
).trampolines
.forceReturn
);
1318 f
.cx
->throwing
= JS_FALSE
;
1328 stubs::Interrupt(VMFrame
&f
, jsbytecode
*pc
)
1330 if (!js_HandleExecutionInterrupt(f
.cx
))
1335 stubs::Trap(VMFrame
&f
, jsbytecode
*pc
)
1339 switch (JS_HandleTrap(f
.cx
, f
.cx
->fp()->script(), pc
, Jsvalify(&rval
))) {
1341 f
.cx
->throwing
= JS_TRUE
;
1342 f
.cx
->exception
= rval
;
1346 f
.cx
->throwing
= JS_FALSE
;
1347 f
.cx
->fp()->setReturnValue(rval
);
1348 #if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
1349 *f
.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
1350 JS_METHODJIT_DATA(f
.cx
).trampolines
.forceReturnFast
);
1352 *f
.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
1353 JS_METHODJIT_DATA(f
.cx
).trampolines
.forceReturn
);
1358 f
.cx
->throwing
= JS_FALSE
;
1367 stubs::This(VMFrame
&f
)
1369 if (!f
.fp()->computeThis(f
.cx
))
1371 f
.regs
.sp
[-1] = f
.fp()->thisValue();
1375 stubs::Neg(VMFrame
&f
)
1378 if (!ValueToNumber(f
.cx
, f
.regs
.sp
[-1], &d
))
1381 f
.regs
.sp
[-1].setNumber(d
);
1384 JSObject
* JS_FASTCALL
1385 stubs::NewInitArray(VMFrame
&f
, uint32 count
)
1387 JSContext
*cx
= f
.cx
;
1388 gc::FinalizeKind kind
= GuessObjectGCKind(count
, true);
1390 JSObject
*obj
= NewArrayWithKind(cx
, kind
);
1391 if (!obj
|| !obj
->ensureSlots(cx
, count
))
1396 JSObject
* JS_FASTCALL
1397 stubs::NewInitObject(VMFrame
&f
, uint32 count
)
1399 JSContext
*cx
= f
.cx
;
1400 gc::FinalizeKind kind
= GuessObjectGCKind(count
, false);
1402 JSObject
*obj
= NewBuiltinClassInstance(cx
, &js_ObjectClass
, kind
);
1403 if (!obj
|| !obj
->ensureSlots(cx
, count
))
1410 stubs::InitElem(VMFrame
&f
, uint32 last
)
1412 JSContext
*cx
= f
.cx
;
1413 JSFrameRegs
®s
= f
.regs
;
1415 /* Pop the element's value into rval. */
1416 JS_ASSERT(regs
.sp
- f
.fp()->base() >= 3);
1417 const Value
&rref
= regs
.sp
[-1];
1419 /* Find the object being initialized at top of stack. */
1420 const Value
&lref
= regs
.sp
[-3];
1421 JS_ASSERT(lref
.isObject());
1422 JSObject
*obj
= &lref
.toObject();
1424 /* Fetch id now that we have obj. */
1426 const Value
&idval
= regs
.sp
[-2];
1427 if (!FetchElementId(f
, obj
, idval
, id
, ®s
.sp
[-2]))
1431 * Check for property redeclaration strict warning (we may be in an object
1432 * initialiser, not an array initialiser).
1434 if (!CheckRedeclaration(cx
, obj
, id
, JSPROP_INITIALIZER
, NULL
, NULL
))
1438 * If rref is a hole, do not call JSObject::defineProperty. In this case,
1439 * obj must be an array, so if the current op is the last element
1440 * initialiser, set the array length to one greater than id.
1442 if (rref
.isMagic(JS_ARRAY_HOLE
)) {
1443 JS_ASSERT(obj
->isArray());
1444 JS_ASSERT(JSID_IS_INT(id
));
1445 JS_ASSERT(jsuint(JSID_TO_INT(id
)) < JS_ARGS_LENGTH_MAX
);
1446 if (last
&& !js_SetLengthProperty(cx
, obj
, (jsuint
) (JSID_TO_INT(id
) + 1)))
1449 if (!obj
->defineProperty(cx
, id
, rref
, NULL
, NULL
, JSPROP_ENUMERATE
))
1455 stubs::GetUpvar(VMFrame
&f
, uint32 ck
)
1457 /* :FIXME: We can do better, this stub isn't needed. */
1458 uint32 staticLevel
= f
.fp()->script()->staticLevel
;
1460 cookie
.fromInteger(ck
);
1461 f
.regs
.sp
[0] = GetUpvar(f
.cx
, staticLevel
, cookie
);
1464 JSObject
* JS_FASTCALL
1465 stubs::DefLocalFun(VMFrame
&f
, JSFunction
*fun
)
1468 * Define a local function (i.e., one nested at the top level of another
1469 * function), parented by the current scope chain, stored in a local
1470 * variable slot that the compiler allocated. This is an optimization over
1471 * JSOP_DEFFUN that avoids requiring a call object for the outer function's
1474 JS_ASSERT(fun
->isInterpreted());
1475 JS_ASSERT(!FUN_FLAT_CLOSURE(fun
));
1476 JSObject
*obj
= FUN_OBJECT(fun
);
1478 if (FUN_NULL_CLOSURE(fun
)) {
1479 obj
= CloneFunctionObject(f
.cx
, fun
, &f
.fp()->scopeChain());
1483 JSObject
*parent
= js_GetScopeChainFast(f
.cx
, f
.fp(), JSOP_DEFLOCALFUN
,
1484 JSOP_DEFLOCALFUN_LENGTH
);
1488 if (obj
->getParent() != parent
) {
1489 obj
= CloneFunctionObject(f
.cx
, fun
, parent
);
1498 JSObject
* JS_FASTCALL
1499 stubs::DefLocalFun_FC(VMFrame
&f
, JSFunction
*fun
)
1501 JSObject
*obj
= js_NewFlatClosure(f
.cx
, fun
, JSOP_DEFLOCALFUN_FC
, JSOP_DEFLOCALFUN_FC_LENGTH
);
1507 JSObject
* JS_FASTCALL
1508 stubs::RegExp(VMFrame
&f
, JSObject
*regex
)
1511 * Push a regexp object cloned from the regexp literal object mapped by the
1512 * bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was
1513 * flouted by many browser-based implementations.
1515 * We avoid the js_GetScopeChain call here and pass fp->scopeChain() as
1516 * js_GetClassPrototype uses the latter only to locate the global.
1519 if (!js_GetClassPrototype(f
.cx
, &f
.fp()->scopeChain(), JSProto_RegExp
, &proto
))
1522 JSObject
*obj
= js_CloneRegExpObject(f
.cx
, regex
, proto
);
1528 JSObject
* JS_FASTCALL
1529 stubs::LambdaForInit(VMFrame
&f
, JSFunction
*fun
)
1531 JSObject
*obj
= FUN_OBJECT(fun
);
1532 if (FUN_NULL_CLOSURE(fun
) && obj
->getParent() == &f
.fp()->scopeChain()) {
1533 fun
->setMethodAtom(f
.fp()->script()->getAtom(GET_SLOTNO(f
.regs
.pc
)));
1536 return Lambda(f
, fun
);
1539 JSObject
* JS_FASTCALL
1540 stubs::LambdaForSet(VMFrame
&f
, JSFunction
*fun
)
1542 JSObject
*obj
= FUN_OBJECT(fun
);
1543 if (FUN_NULL_CLOSURE(fun
) && obj
->getParent() == &f
.fp()->scopeChain()) {
1544 const Value
&lref
= f
.regs
.sp
[-1];
1545 if (lref
.isObject() && lref
.toObject().canHaveMethodBarrier()) {
1546 fun
->setMethodAtom(f
.fp()->script()->getAtom(GET_SLOTNO(f
.regs
.pc
)));
1550 return Lambda(f
, fun
);
1553 JSObject
* JS_FASTCALL
1554 stubs::LambdaJoinableForCall(VMFrame
&f
, JSFunction
*fun
)
1556 JSObject
*obj
= FUN_OBJECT(fun
);
1557 if (FUN_NULL_CLOSURE(fun
) && obj
->getParent() == &f
.fp()->scopeChain()) {
1559 * Array.prototype.sort and String.prototype.replace are
1560 * optimized as if they are special form. We know that they
1561 * won't leak the joined function object in obj, therefore
1562 * we don't need to clone that compiler- created function
1563 * object for identity/mutation reasons.
1565 int iargc
= GET_ARGC(f
.regs
.pc
);
1568 * Note that we have not yet pushed obj as the final argument,
1569 * so regs.sp[1 - (iargc + 2)], and not regs.sp[-(iargc + 2)],
1570 * is the callee for this JSOP_CALL.
1572 const Value
&cref
= f
.regs
.sp
[1 - (iargc
+ 2)];
1575 if (IsFunctionObject(cref
, &callee
)) {
1576 JSFunction
*calleeFun
= callee
->getFunctionPrivate();
1577 Native native
= calleeFun
->maybeNative();
1580 if (iargc
== 1 && native
== array_sort
)
1582 if (iargc
== 2 && native
== str_replace
)
1587 return Lambda(f
, fun
);
1590 JSObject
* JS_FASTCALL
1591 stubs::LambdaJoinableForNull(VMFrame
&f
, JSFunction
*fun
)
1593 JSObject
*obj
= FUN_OBJECT(fun
);
1594 if (FUN_NULL_CLOSURE(fun
) && obj
->getParent() == &f
.fp()->scopeChain()) {
1595 jsbytecode
*pc2
= f
.regs
.pc
+ JSOP_NULL_LENGTH
;
1596 JSOp op2
= JSOp(*pc2
);
1598 if (op2
== JSOP_CALL
&& GET_ARGC(pc2
) == 0)
1601 return Lambda(f
, fun
);
1604 JSObject
* JS_FASTCALL
1605 stubs::Lambda(VMFrame
&f
, JSFunction
*fun
)
1607 JSObject
*obj
= FUN_OBJECT(fun
);
1610 if (FUN_NULL_CLOSURE(fun
)) {
1611 parent
= &f
.fp()->scopeChain();
1613 parent
= js_GetScopeChainFast(f
.cx
, f
.fp(), JSOP_LAMBDA
, JSOP_LAMBDA_LENGTH
);
1618 obj
= CloneFunctionObject(f
.cx
, fun
, parent
);
1625 /* Test whether v is an int in the range [-2^31 + 1, 2^31 - 2] */
1626 static JS_ALWAYS_INLINE
bool
1627 CanIncDecWithoutOverflow(int32_t i
)
1629 return (i
> JSVAL_INT_MIN
) && (i
< JSVAL_INT_MAX
);
1632 template <int32 N
, bool POST
, JSBool strict
>
1634 ObjIncOp(VMFrame
&f
, JSObject
*obj
, jsid id
)
1636 JSContext
*cx
= f
.cx
;
1637 JSStackFrame
*fp
= f
.fp();
1639 f
.regs
.sp
[0].setNull();
1641 if (!obj
->getProperty(cx
, id
, &f
.regs
.sp
[-1]))
1644 Value
&ref
= f
.regs
.sp
[-1];
1646 if (JS_LIKELY(ref
.isInt32() && CanIncDecWithoutOverflow(tmp
= ref
.toInt32()))) {
1648 ref
.getInt32Ref() = tmp
+ N
;
1650 ref
.getInt32Ref() = tmp
+= N
;
1652 JSBool ok
= obj
->setProperty(cx
, id
, &ref
, strict
);
1653 fp
->clearAssigning();
1658 * We must set regs.sp[-1] to tmp for both post and pre increments
1659 * as the setter overwrites regs.sp[-1].
1665 if (!ValueToNumber(cx
, ref
, &d
))
1676 JSBool ok
= obj
->setProperty(cx
, id
, &v
, strict
);
1677 fp
->clearAssigning();
1685 template <int32 N
, bool POST
, JSBool strict
>
1687 NameIncDec(VMFrame
&f
, JSObject
*obj
, JSAtom
*origAtom
)
1689 JSContext
*cx
= f
.cx
;
1694 PropertyCacheEntry
*entry
;
1695 JS_PROPERTY_CACHE(cx
).test(cx
, f
.regs
.pc
, obj
, obj2
, entry
, atom
);
1697 if (obj
== obj2
&& entry
->vword
.isSlot()) {
1698 uint32 slot
= entry
->vword
.toSlot();
1699 Value
&rref
= obj
->nativeGetSlotRef(slot
);
1701 if (JS_LIKELY(rref
.isInt32() && CanIncDecWithoutOverflow(tmp
= rref
.toInt32()))) {
1702 int32_t inc
= tmp
+ N
;
1705 rref
.getInt32Ref() = inc
;
1706 f
.regs
.sp
[0].setInt32(tmp
);
1713 jsid id
= ATOM_TO_JSID(atom
);
1714 if (!js_FindPropertyHelper(cx
, id
, true, &obj
, &obj2
, &prop
))
1717 ReportAtomNotDefined(cx
, atom
);
1720 return ObjIncOp
<N
, POST
, strict
>(f
, obj
, id
);
1723 template<JSBool strict
>
1725 stubs::PropInc(VMFrame
&f
, JSAtom
*atom
)
1727 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-1]);
1730 if (!ObjIncOp
<1, true, strict
>(f
, obj
, ATOM_TO_JSID(atom
)))
1732 f
.regs
.sp
[-2] = f
.regs
.sp
[-1];
1735 template void JS_FASTCALL
stubs::PropInc
<true>(VMFrame
&f
, JSAtom
*atom
);
1736 template void JS_FASTCALL
stubs::PropInc
<false>(VMFrame
&f
, JSAtom
*atom
);
1738 template<JSBool strict
>
1740 stubs::PropDec(VMFrame
&f
, JSAtom
*atom
)
1742 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-1]);
1745 if (!ObjIncOp
<-1, true, strict
>(f
, obj
, ATOM_TO_JSID(atom
)))
1747 f
.regs
.sp
[-2] = f
.regs
.sp
[-1];
1750 template void JS_FASTCALL
stubs::PropDec
<true>(VMFrame
&f
, JSAtom
*atom
);
1751 template void JS_FASTCALL
stubs::PropDec
<false>(VMFrame
&f
, JSAtom
*atom
);
1753 template<JSBool strict
>
1755 stubs::IncProp(VMFrame
&f
, JSAtom
*atom
)
1757 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-1]);
1760 if (!ObjIncOp
<1, false, strict
>(f
, obj
, ATOM_TO_JSID(atom
)))
1762 f
.regs
.sp
[-2] = f
.regs
.sp
[-1];
1765 template void JS_FASTCALL
stubs::IncProp
<true>(VMFrame
&f
, JSAtom
*atom
);
1766 template void JS_FASTCALL
stubs::IncProp
<false>(VMFrame
&f
, JSAtom
*atom
);
1768 template<JSBool strict
>
1770 stubs::DecProp(VMFrame
&f
, JSAtom
*atom
)
1772 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-1]);
1775 if (!ObjIncOp
<-1, false, strict
>(f
, obj
, ATOM_TO_JSID(atom
)))
1777 f
.regs
.sp
[-2] = f
.regs
.sp
[-1];
1780 template void JS_FASTCALL
stubs::DecProp
<true>(VMFrame
&f
, JSAtom
*atom
);
1781 template void JS_FASTCALL
stubs::DecProp
<false>(VMFrame
&f
, JSAtom
*atom
);
1783 template<JSBool strict
>
1785 stubs::ElemInc(VMFrame
&f
)
1787 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-2]);
1791 if (!FetchElementId(f
, obj
, f
.regs
.sp
[-1], id
, &f
.regs
.sp
[-1]))
1793 if (!ObjIncOp
<1, true, strict
>(f
, obj
, id
))
1795 f
.regs
.sp
[-3] = f
.regs
.sp
[-1];
1798 template void JS_FASTCALL
stubs::ElemInc
<true>(VMFrame
&f
);
1799 template void JS_FASTCALL
stubs::ElemInc
<false>(VMFrame
&f
);
1801 template<JSBool strict
>
1803 stubs::ElemDec(VMFrame
&f
)
1805 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-2]);
1809 if (!FetchElementId(f
, obj
, f
.regs
.sp
[-1], id
, &f
.regs
.sp
[-1]))
1811 if (!ObjIncOp
<-1, true, strict
>(f
, obj
, id
))
1813 f
.regs
.sp
[-3] = f
.regs
.sp
[-1];
1816 template void JS_FASTCALL
stubs::ElemDec
<true>(VMFrame
&f
);
1817 template void JS_FASTCALL
stubs::ElemDec
<false>(VMFrame
&f
);
1819 template<JSBool strict
>
1821 stubs::IncElem(VMFrame
&f
)
1823 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-2]);
1827 if (!FetchElementId(f
, obj
, f
.regs
.sp
[-1], id
, &f
.regs
.sp
[-1]))
1829 if (!ObjIncOp
<1, false, strict
>(f
, obj
, id
))
1831 f
.regs
.sp
[-3] = f
.regs
.sp
[-1];
1834 template void JS_FASTCALL
stubs::IncElem
<true>(VMFrame
&f
);
1835 template void JS_FASTCALL
stubs::IncElem
<false>(VMFrame
&f
);
1837 template<JSBool strict
>
1839 stubs::DecElem(VMFrame
&f
)
1841 JSObject
*obj
= ValueToObject(f
.cx
, &f
.regs
.sp
[-2]);
1845 if (!FetchElementId(f
, obj
, f
.regs
.sp
[-1], id
, &f
.regs
.sp
[-1]))
1847 if (!ObjIncOp
<-1, false, strict
>(f
, obj
, id
))
1849 f
.regs
.sp
[-3] = f
.regs
.sp
[-1];
1852 template void JS_FASTCALL
stubs::DecElem
<true>(VMFrame
&f
);
1853 template void JS_FASTCALL
stubs::DecElem
<false>(VMFrame
&f
);
1855 template<JSBool strict
>
1857 stubs::NameInc(VMFrame
&f
, JSAtom
*atom
)
1859 JSObject
*obj
= &f
.fp()->scopeChain();
1860 if (!NameIncDec
<1, true, strict
>(f
, obj
, atom
))
1864 template void JS_FASTCALL
stubs::NameInc
<true>(VMFrame
&f
, JSAtom
*atom
);
1865 template void JS_FASTCALL
stubs::NameInc
<false>(VMFrame
&f
, JSAtom
*atom
);
1867 template<JSBool strict
>
1869 stubs::NameDec(VMFrame
&f
, JSAtom
*atom
)
1871 JSObject
*obj
= &f
.fp()->scopeChain();
1872 if (!NameIncDec
<-1, true, strict
>(f
, obj
, atom
))
1876 template void JS_FASTCALL
stubs::NameDec
<true>(VMFrame
&f
, JSAtom
*atom
);
1877 template void JS_FASTCALL
stubs::NameDec
<false>(VMFrame
&f
, JSAtom
*atom
);
1879 template<JSBool strict
>
1881 stubs::IncName(VMFrame
&f
, JSAtom
*atom
)
1883 JSObject
*obj
= &f
.fp()->scopeChain();
1884 if (!NameIncDec
<1, false, strict
>(f
, obj
, atom
))
1888 template void JS_FASTCALL
stubs::IncName
<true>(VMFrame
&f
, JSAtom
*atom
);
1889 template void JS_FASTCALL
stubs::IncName
<false>(VMFrame
&f
, JSAtom
*atom
);
1891 template<JSBool strict
>
1893 stubs::DecName(VMFrame
&f
, JSAtom
*atom
)
1895 JSObject
*obj
= &f
.fp()->scopeChain();
1896 if (!NameIncDec
<-1, false, strict
>(f
, obj
, atom
))
1900 template void JS_FASTCALL
stubs::DecName
<true>(VMFrame
&f
, JSAtom
*atom
);
1901 template void JS_FASTCALL
stubs::DecName
<false>(VMFrame
&f
, JSAtom
*atom
);
1903 template<JSBool strict
>
1905 stubs::GlobalNameInc(VMFrame
&f
, JSAtom
*atom
)
1907 JSObject
*obj
= f
.fp()->scopeChain().getGlobal();
1908 if (!NameIncDec
<1, true, strict
>(f
, obj
, atom
))
1912 template void JS_FASTCALL
stubs::GlobalNameInc
<true>(VMFrame
&f
, JSAtom
*atom
);
1913 template void JS_FASTCALL
stubs::GlobalNameInc
<false>(VMFrame
&f
, JSAtom
*atom
);
1915 template<JSBool strict
>
1917 stubs::GlobalNameDec(VMFrame
&f
, JSAtom
*atom
)
1919 JSObject
*obj
= f
.fp()->scopeChain().getGlobal();
1920 if (!NameIncDec
<-1, true, strict
>(f
, obj
, atom
))
1924 template void JS_FASTCALL
stubs::GlobalNameDec
<true>(VMFrame
&f
, JSAtom
*atom
);
1925 template void JS_FASTCALL
stubs::GlobalNameDec
<false>(VMFrame
&f
, JSAtom
*atom
);
1927 template<JSBool strict
>
1929 stubs::IncGlobalName(VMFrame
&f
, JSAtom
*atom
)
1931 JSObject
*obj
= f
.fp()->scopeChain().getGlobal();
1932 if (!NameIncDec
<1, false, strict
>(f
, obj
, atom
))
1936 template void JS_FASTCALL
stubs::IncGlobalName
<true>(VMFrame
&f
, JSAtom
*atom
);
1937 template void JS_FASTCALL
stubs::IncGlobalName
<false>(VMFrame
&f
, JSAtom
*atom
);
1939 template<JSBool strict
>
1941 stubs::DecGlobalName(VMFrame
&f
, JSAtom
*atom
)
1943 JSObject
*obj
= f
.fp()->scopeChain().getGlobal();
1944 if (!NameIncDec
<-1, false, strict
>(f
, obj
, atom
))
1948 template void JS_FASTCALL
stubs::DecGlobalName
<true>(VMFrame
&f
, JSAtom
*atom
);
1949 template void JS_FASTCALL
stubs::DecGlobalName
<false>(VMFrame
&f
, JSAtom
*atom
);
1951 static bool JS_FASTCALL
1952 InlineGetProp(VMFrame
&f
)
1954 JSContext
*cx
= f
.cx
;
1955 JSFrameRegs
®s
= f
.regs
;
1957 Value
*vp
= &f
.regs
.sp
[-1];
1958 JSObject
*obj
= ValueToObject(f
.cx
, vp
);
1965 * We do not impose the method read barrier if in an imacro,
1966 * assuming any property gets it does (e.g., for 'toString'
1967 * from JSOP_NEW) will not be leaked to the calling script.
1969 JSObject
*aobj
= js_GetProtoIfDenseArray(obj
);
1971 PropertyCacheEntry
*entry
;
1974 JS_PROPERTY_CACHE(cx
).test(cx
, regs
.pc
, aobj
, obj2
, entry
, atom
);
1976 if (entry
->vword
.isFunObj()) {
1977 rval
.setObject(entry
->vword
.toFunObj());
1978 } else if (entry
->vword
.isSlot()) {
1979 uint32 slot
= entry
->vword
.toSlot();
1980 rval
= obj2
->nativeGetSlot(slot
);
1982 JS_ASSERT(entry
->vword
.isShape());
1983 const Shape
*shape
= entry
->vword
.toShape();
1984 NATIVE_GET(cx
, obj
, obj2
, shape
,
1985 f
.fp()->hasImacropc() ? JSGET_NO_METHOD_BARRIER
: JSGET_METHOD_BARRIER
,
1986 &rval
, return false);
1991 jsid id
= ATOM_TO_JSID(atom
);
1992 if (JS_LIKELY(!aobj
->getOps()->getProperty
)
1993 ? !js_GetPropertyHelper(cx
, obj
, id
,
1994 f
.fp()->hasImacropc()
1995 ? JSGET_CACHE_RESULT
| JSGET_NO_METHOD_BARRIER
1996 : JSGET_CACHE_RESULT
| JSGET_METHOD_BARRIER
,
1998 : !obj
->getProperty(cx
, id
, &rval
)) {
2008 stubs::GetProp(VMFrame
&f
)
2010 if (!InlineGetProp(f
))
2015 stubs::GetPropNoCache(VMFrame
&f
, JSAtom
*atom
)
2017 JSContext
*cx
= f
.cx
;
2019 Value
*vp
= &f
.regs
.sp
[-1];
2020 JSObject
*obj
= ValueToObject(cx
, vp
);
2024 if (!obj
->getProperty(cx
, ATOM_TO_JSID(atom
), vp
))
2029 stubs::CallProp(VMFrame
&f
, JSAtom
*origAtom
)
2031 JSContext
*cx
= f
.cx
;
2032 JSFrameRegs
®s
= f
.regs
;
2038 if (lval
.isObject()) {
2041 JSProtoKey protoKey
;
2042 if (lval
.isString()) {
2043 protoKey
= JSProto_String
;
2044 } else if (lval
.isNumber()) {
2045 protoKey
= JSProto_Number
;
2046 } else if (lval
.isBoolean()) {
2047 protoKey
= JSProto_Boolean
;
2049 JS_ASSERT(lval
.isNull() || lval
.isUndefined());
2050 js_ReportIsNullOrUndefined(cx
, -1, lval
, NULL
);
2054 if (!js_GetClassPrototype(cx
, NULL
, protoKey
, &pobj
))
2056 objv
.setObject(*pobj
);
2059 JSObject
*aobj
= js_GetProtoIfDenseArray(&objv
.toObject());
2062 PropertyCacheEntry
*entry
;
2065 JS_PROPERTY_CACHE(cx
).test(cx
, regs
.pc
, aobj
, obj2
, entry
, atom
);
2067 if (entry
->vword
.isFunObj()) {
2068 rval
.setObject(entry
->vword
.toFunObj());
2069 } else if (entry
->vword
.isSlot()) {
2070 uint32 slot
= entry
->vword
.toSlot();
2071 rval
= obj2
->nativeGetSlot(slot
);
2073 JS_ASSERT(entry
->vword
.isShape());
2074 const Shape
*shape
= entry
->vword
.toShape();
2075 NATIVE_GET(cx
, &objv
.toObject(), obj2
, shape
, JSGET_NO_METHOD_BARRIER
, &rval
,
2083 * Cache miss: use the immediate atom that was loaded for us under
2084 * PropertyCache::test.
2087 id
= ATOM_TO_JSID(origAtom
);
2090 regs
.sp
[-1].setNull();
2091 if (lval
.isObject()) {
2092 if (!js_GetMethod(cx
, &objv
.toObject(), id
,
2093 JS_LIKELY(!aobj
->getOps()->getProperty
)
2094 ? JSGET_CACHE_RESULT
| JSGET_NO_METHOD_BARRIER
2095 : JSGET_NO_METHOD_BARRIER
,
2102 JS_ASSERT(!objv
.toObject().getOps()->getProperty
);
2103 if (!js_GetPropertyHelper(cx
, &objv
.toObject(), id
,
2104 JSGET_CACHE_RESULT
| JSGET_NO_METHOD_BARRIER
,
2112 #if JS_HAS_NO_SUCH_METHOD
2113 if (JS_UNLIKELY(rval
.isUndefined()) && regs
.sp
[-1].isObject()) {
2114 regs
.sp
[-2].setString(ATOM_TO_STRING(origAtom
));
2115 if (!js_OnUnknownMethod(cx
, regs
.sp
- 2))
2122 stubs::Length(VMFrame
&f
)
2124 JSFrameRegs
®s
= f
.regs
;
2125 Value
*vp
= ®s
.sp
[-1];
2127 if (vp
->isString()) {
2128 vp
->setInt32(vp
->toString()->length());
2130 } else if (vp
->isObject()) {
2131 JSObject
*obj
= &vp
->toObject();
2132 if (obj
->isArray()) {
2133 jsuint length
= obj
->getArrayLength();
2134 regs
.sp
[-1].setNumber(length
);
2136 } else if (obj
->isArguments() && !obj
->isArgsLengthOverridden()) {
2137 uint32 length
= obj
->getArgsInitialLength();
2138 JS_ASSERT(length
< INT32_MAX
);
2139 regs
.sp
[-1].setInt32(int32_t(length
));
2144 if (!InlineGetProp(f
))
2149 stubs::Iter(VMFrame
&f
, uint32 flags
)
2151 if (!js_ValueToIterator(f
.cx
, flags
, &f
.regs
.sp
[-1]))
2153 JS_ASSERT(!f
.regs
.sp
[-1].isPrimitive());
2157 InitPropOrMethod(VMFrame
&f
, JSAtom
*atom
, JSOp op
)
2159 JSContext
*cx
= f
.cx
;
2160 JSRuntime
*rt
= cx
->runtime
;
2161 JSFrameRegs
®s
= f
.regs
;
2163 /* Load the property's initial value into rval. */
2164 JS_ASSERT(regs
.sp
- f
.fp()->base() >= 2);
2168 /* Load the object being initialized into lval/obj. */
2169 JSObject
*obj
= ®s
.sp
[-2].toObject();
2170 JS_ASSERT(obj
->isNative());
2173 * Probe the property cache.
2175 * We can not assume that the object created by JSOP_NEWINIT is still
2176 * single-threaded as the debugger can access it from other threads.
2179 * On a hit, if the cached shape has a non-default setter, it must be
2180 * __proto__. If shape->previous() != obj->lastProperty(), there must be a
2181 * repeated property name. The fast path does not handle these two cases.
2183 PropertyCacheEntry
*entry
;
2185 if (JS_PROPERTY_CACHE(cx
).testForInit(rt
, regs
.pc
, obj
, &shape
, &entry
) &&
2186 shape
->hasDefaultSetter() &&
2187 shape
->previous() == obj
->lastProperty())
2189 /* Fast path. Property cache hit. */
2190 uint32 slot
= shape
->slot
;
2192 JS_ASSERT(slot
== obj
->slotSpan());
2193 JS_ASSERT(slot
>= JSSLOT_FREE(obj
->getClass()));
2194 if (slot
< obj
->numSlots()) {
2195 JS_ASSERT(obj
->getSlot(slot
).isUndefined());
2197 if (!obj
->allocSlot(cx
, &slot
))
2199 JS_ASSERT(slot
== shape
->slot
);
2202 /* A new object, or one we just extended in a recent initprop op. */
2203 JS_ASSERT(!obj
->lastProperty() ||
2204 obj
->shape() == obj
->lastProperty()->shape
);
2205 obj
->extend(cx
, shape
);
2208 * No method change check here because here we are adding a new
2209 * property, not updating an existing slot's value that might
2210 * contain a method of a branded shape.
2212 obj
->nativeSetSlot(slot
, rval
);
2214 PCMETER(JS_PROPERTY_CACHE(cx
).inipcmisses
++);
2216 /* Get the immediate property name into id. */
2217 jsid id
= ATOM_TO_JSID(atom
);
2219 /* No need to check for duplicate property; the compiler already did. */
2221 uintN defineHow
= (op
== JSOP_INITMETHOD
)
2222 ? JSDNP_CACHE_RESULT
| JSDNP_SET_METHOD
2223 : JSDNP_CACHE_RESULT
;
2224 if (!(JS_UNLIKELY(atom
== cx
->runtime
->atomState
.protoAtom
)
2225 ? js_SetPropertyHelper(cx
, obj
, id
, defineHow
, &rval
, false)
2226 : js_DefineNativeProperty(cx
, obj
, id
, rval
, NULL
, NULL
,
2227 JSPROP_ENUMERATE
, 0, 0, NULL
,
2235 stubs::InitProp(VMFrame
&f
, JSAtom
*atom
)
2237 InitPropOrMethod(f
, atom
, JSOP_INITPROP
);
2241 stubs::InitMethod(VMFrame
&f
, JSAtom
*atom
)
2243 InitPropOrMethod(f
, atom
, JSOP_INITMETHOD
);
2247 stubs::IterNext(VMFrame
&f
)
2249 JS_ASSERT(f
.regs
.sp
- 1 >= f
.fp()->base());
2250 JS_ASSERT(f
.regs
.sp
[-1].isObject());
2252 JSObject
*iterobj
= &f
.regs
.sp
[-1].toObject();
2253 f
.regs
.sp
[0].setNull();
2255 if (!js_IteratorNext(f
.cx
, iterobj
, &f
.regs
.sp
[-1]))
2260 stubs::IterMore(VMFrame
&f
)
2262 JS_ASSERT(f
.regs
.sp
- 1 >= f
.fp()->base());
2263 JS_ASSERT(f
.regs
.sp
[-1].isObject());
2266 JSObject
*iterobj
= &f
.regs
.sp
[-1].toObject();
2267 if (!js_IteratorMore(f
.cx
, iterobj
, &v
))
2270 return v
.toBoolean();
2274 stubs::EndIter(VMFrame
&f
)
2276 JS_ASSERT(f
.regs
.sp
- 1 >= f
.fp()->base());
2277 if (!js_CloseIterator(f
.cx
, &f
.regs
.sp
[-1].toObject()))
2281 JSString
* JS_FASTCALL
2282 stubs::TypeOf(VMFrame
&f
)
2284 const Value
&ref
= f
.regs
.sp
[-1];
2285 JSType type
= JS_TypeOfValue(f
.cx
, Jsvalify(ref
));
2286 JSAtom
*atom
= f
.cx
->runtime
->atomState
.typeAtoms
[type
];
2287 return ATOM_TO_STRING(atom
);
2291 stubs::StrictEq(VMFrame
&f
)
2293 const Value
&rhs
= f
.regs
.sp
[-1];
2294 const Value
&lhs
= f
.regs
.sp
[-2];
2295 const bool b
= StrictlyEqual(f
.cx
, lhs
, rhs
) == true;
2297 f
.regs
.sp
[-1].setBoolean(b
);
2301 stubs::StrictNe(VMFrame
&f
)
2303 const Value
&rhs
= f
.regs
.sp
[-1];
2304 const Value
&lhs
= f
.regs
.sp
[-2];
2305 const bool b
= StrictlyEqual(f
.cx
, lhs
, rhs
) != true;
2307 f
.regs
.sp
[-1].setBoolean(b
);
2311 stubs::Throw(VMFrame
&f
)
2313 JSContext
*cx
= f
.cx
;
2315 JS_ASSERT(!cx
->throwing
);
2316 cx
->throwing
= JS_TRUE
;
2317 cx
->exception
= f
.regs
.sp
[-1];
2321 JSObject
* JS_FASTCALL
2322 stubs::FlatLambda(VMFrame
&f
, JSFunction
*fun
)
2324 JSObject
*obj
= js_NewFlatClosure(f
.cx
, fun
, JSOP_LAMBDA_FC
, JSOP_LAMBDA_FC_LENGTH
);
2331 stubs::Arguments(VMFrame
&f
)
2334 if (!js_GetArgsValue(f
.cx
, f
.fp(), &f
.regs
.sp
[-1]))
2339 stubs::InstanceOf(VMFrame
&f
)
2341 JSContext
*cx
= f
.cx
;
2342 JSFrameRegs
®s
= f
.regs
;
2344 const Value
&rref
= regs
.sp
[-1];
2345 if (rref
.isPrimitive()) {
2346 js_ReportValueError(cx
, JSMSG_BAD_INSTANCEOF_RHS
,
2350 JSObject
*obj
= &rref
.toObject();
2351 const Value
&lref
= regs
.sp
[-2];
2352 JSBool cond
= JS_FALSE
;
2353 if (!HasInstance(cx
, obj
, &lref
, &cond
))
2355 f
.regs
.sp
[-2].setBoolean(cond
);
2360 stubs::FastInstanceOf(VMFrame
&f
)
2362 const Value
&lref
= f
.regs
.sp
[-1];
2364 if (lref
.isPrimitive()) {
2366 * Throw a runtime error if instanceof is called on a function that
2367 * has a non-object as its .prototype value.
2369 js_ReportValueError(f
.cx
, JSMSG_BAD_PROTOTYPE
, -1, f
.regs
.sp
[-2], NULL
);
2373 f
.regs
.sp
[-3].setBoolean(js_IsDelegate(f
.cx
, &lref
.toObject(), f
.regs
.sp
[-3]));
2377 stubs::ArgCnt(VMFrame
&f
)
2379 JSContext
*cx
= f
.cx
;
2380 JSRuntime
*rt
= cx
->runtime
;
2381 JSStackFrame
*fp
= f
.fp();
2383 jsid id
= ATOM_TO_JSID(rt
->atomState
.lengthAtom
);
2385 if (!js_GetArgsProperty(cx
, fp
, id
, &f
.regs
.sp
[-1]))
2390 stubs::EnterBlock(VMFrame
&f
, JSObject
*obj
)
2392 JSFrameRegs
®s
= f
.regs
;
2394 JSStackFrame
*fp
= f
.fp();
2397 JS_ASSERT(obj
->isStaticBlock());
2398 JS_ASSERT(fp
->base() + OBJ_BLOCK_DEPTH(cx
, obj
) == regs
.sp
);
2399 Value
*vp
= regs
.sp
+ OBJ_BLOCK_COUNT(cx
, obj
);
2400 JS_ASSERT(regs
.sp
< vp
);
2401 JS_ASSERT(vp
<= fp
->slots() + fp
->script()->nslots
);
2402 SetValueRangeToUndefined(regs
.sp
, vp
);
2406 JSContext
*cx
= f
.cx
;
2409 * The young end of fp->scopeChain() may omit blocks if we haven't closed
2410 * over them, but if there are any closure blocks on fp->scopeChain(), they'd
2411 * better be (clones of) ancestors of the block we're entering now;
2412 * anything else we should have popped off fp->scopeChain() when we left its
2415 JSObject
*obj2
= &fp
->scopeChain();
2417 while ((clasp
= obj2
->getClass()) == &js_WithClass
)
2418 obj2
= obj2
->getParent();
2419 if (clasp
== &js_BlockClass
&&
2420 obj2
->getPrivate() == js_FloatingFrameIfGenerator(cx
, fp
)) {
2421 JSObject
*youngestProto
= obj2
->getProto();
2422 JS_ASSERT(youngestProto
->isStaticBlock());
2423 JSObject
*parent
= obj
;
2424 while ((parent
= parent
->getParent()) != youngestProto
)
2431 stubs::LeaveBlock(VMFrame
&f
, JSObject
*blockChain
)
2433 JSContext
*cx
= f
.cx
;
2434 JSStackFrame
*fp
= f
.fp();
2437 JS_ASSERT(blockChain
->isStaticBlock());
2438 uintN blockDepth
= OBJ_BLOCK_DEPTH(cx
, blockChain
);
2440 JS_ASSERT(blockDepth
<= StackDepth(fp
->script()));
2443 * If we're about to leave the dynamic scope of a block that has been
2444 * cloned onto fp->scopeChain(), clear its private data, move its locals from
2445 * the stack into the clone, and pop it off the chain.
2447 JSObject
*obj
= &fp
->scopeChain();
2448 if (obj
->getProto() == blockChain
) {
2449 JS_ASSERT(obj
->getClass() == &js_BlockClass
);
2450 if (!js_PutBlockObject(cx
, JS_TRUE
))
2456 stubs::LookupSwitch(VMFrame
&f
, jsbytecode
*pc
)
2458 jsbytecode
*jpc
= pc
;
2459 JSScript
*script
= f
.fp()->script();
2460 void **nmap
= script
->nativeMap(f
.fp()->isConstructing());
2462 /* This is correct because the compiler adjusts the stack beforehand. */
2463 Value lval
= f
.regs
.sp
[-1];
2465 if (!lval
.isPrimitive()) {
2466 ptrdiff_t offs
= (pc
+ GET_JUMP_OFFSET(pc
)) - script
->code
;
2467 JS_ASSERT(nmap
[offs
]);
2471 JS_ASSERT(pc
[0] == JSOP_LOOKUPSWITCH
);
2473 pc
+= JUMP_OFFSET_LEN
;
2474 uint32 npairs
= GET_UINT16(pc
);
2479 if (lval
.isString()) {
2480 JSString
*str
= lval
.toString();
2481 for (uint32 i
= 1; i
<= npairs
; i
++) {
2482 Value rval
= script
->getConst(GET_INDEX(pc
));
2484 if (rval
.isString()) {
2485 JSString
*rhs
= rval
.toString();
2486 if (rhs
== str
|| js_EqualStrings(str
, rhs
)) {
2487 ptrdiff_t offs
= (jpc
+ GET_JUMP_OFFSET(pc
)) - script
->code
;
2488 JS_ASSERT(nmap
[offs
]);
2492 pc
+= JUMP_OFFSET_LEN
;
2494 } else if (lval
.isNumber()) {
2495 double d
= lval
.toNumber();
2496 for (uint32 i
= 1; i
<= npairs
; i
++) {
2497 Value rval
= script
->getConst(GET_INDEX(pc
));
2499 if (rval
.isNumber() && d
== rval
.toNumber()) {
2500 ptrdiff_t offs
= (jpc
+ GET_JUMP_OFFSET(pc
)) - script
->code
;
2501 JS_ASSERT(nmap
[offs
]);
2504 pc
+= JUMP_OFFSET_LEN
;
2507 for (uint32 i
= 1; i
<= npairs
; i
++) {
2508 Value rval
= script
->getConst(GET_INDEX(pc
));
2511 ptrdiff_t offs
= (jpc
+ GET_JUMP_OFFSET(pc
)) - script
->code
;
2512 JS_ASSERT(nmap
[offs
]);
2515 pc
+= JUMP_OFFSET_LEN
;
2519 ptrdiff_t offs
= (jpc
+ GET_JUMP_OFFSET(jpc
)) - script
->code
;
2520 JS_ASSERT(nmap
[offs
]);
2525 stubs::TableSwitch(VMFrame
&f
, jsbytecode
*origPc
)
2527 jsbytecode
* const originalPC
= origPc
;
2528 jsbytecode
*pc
= originalPC
;
2529 uint32 jumpOffset
= GET_JUMP_OFFSET(pc
);
2530 pc
+= JUMP_OFFSET_LEN
;
2532 /* Note: compiler adjusts the stack beforehand. */
2533 Value rval
= f
.regs
.sp
[-1];
2536 if (rval
.isInt32()) {
2537 tableIdx
= rval
.toInt32();
2538 } else if (rval
.isDouble()) {
2539 double d
= rval
.toDouble();
2541 /* Treat -0 (double) as 0. */
2543 } else if (!JSDOUBLE_IS_INT32(d
, (int32_t *)&tableIdx
)) {
2551 uint32 low
= GET_JUMP_OFFSET(pc
);
2552 pc
+= JUMP_OFFSET_LEN
;
2553 uint32 high
= GET_JUMP_OFFSET(pc
);
2554 pc
+= JUMP_OFFSET_LEN
;
2557 if ((jsuint
) tableIdx
< (jsuint
)(high
- low
+ 1)) {
2558 pc
+= JUMP_OFFSET_LEN
* tableIdx
;
2559 uint32 candidateOffset
= GET_JUMP_OFFSET(pc
);
2560 if (candidateOffset
)
2561 jumpOffset
= candidateOffset
;
2566 JSScript
*script
= f
.fp()->script();
2567 void **nmap
= script
->nativeMap(f
.fp()->isConstructing());
2569 /* Provide the native address. */
2570 ptrdiff_t offset
= (originalPC
+ jumpOffset
) - script
->code
;
2571 JS_ASSERT(nmap
[offset
]);
2572 return nmap
[offset
];
2576 stubs::Unbrand(VMFrame
&f
)
2578 const Value
&thisv
= f
.regs
.sp
[-1];
2579 if (!thisv
.isObject())
2581 JSObject
*obj
= &thisv
.toObject();
2582 if (obj
->isNative() && !obj
->unbrand(f
.cx
))
2587 stubs::Pos(VMFrame
&f
)
2589 if (!ValueToNumber(f
.cx
, &f
.regs
.sp
[-1]))
2594 stubs::ArgSub(VMFrame
&f
, uint32 n
)
2596 jsid id
= INT_TO_JSID(n
);
2598 if (!js_GetArgsProperty(f
.cx
, f
.fp(), id
, &rval
))
2600 f
.regs
.sp
[0] = rval
;
2604 stubs::DelName(VMFrame
&f
, JSAtom
*atom
)
2606 jsid id
= ATOM_TO_JSID(atom
);
2607 JSObject
*obj
, *obj2
;
2609 if (!js_FindProperty(f
.cx
, id
, &obj
, &obj2
, &prop
))
2612 /* Strict mode code should never contain JSOP_DELNAME opcodes. */
2613 JS_ASSERT(!f
.fp()->script()->strictModeCode
);
2615 /* ECMA says to return true if name is undefined or inherited. */
2617 f
.regs
.sp
[-1] = BooleanValue(true);
2619 if (!obj
->deleteProperty(f
.cx
, id
, &f
.regs
.sp
[-1], false))
2624 template<JSBool strict
>
2626 stubs::DelProp(VMFrame
&f
, JSAtom
*atom
)
2628 JSContext
*cx
= f
.cx
;
2630 JSObject
*obj
= ValueToObject(cx
, &f
.regs
.sp
[-1]);
2635 if (!obj
->deleteProperty(cx
, ATOM_TO_JSID(atom
), &rval
, strict
))
2638 f
.regs
.sp
[-1] = rval
;
2641 template void JS_FASTCALL
stubs::DelProp
<true>(VMFrame
&f
, JSAtom
*atom
);
2642 template void JS_FASTCALL
stubs::DelProp
<false>(VMFrame
&f
, JSAtom
*atom
);
2644 template<JSBool strict
>
2646 stubs::DelElem(VMFrame
&f
)
2648 JSContext
*cx
= f
.cx
;
2650 JSObject
*obj
= ValueToObject(cx
, &f
.regs
.sp
[-2]);
2655 if (!FetchElementId(f
, obj
, f
.regs
.sp
[-1], id
, &f
.regs
.sp
[-1]))
2658 if (!obj
->deleteProperty(cx
, id
, &f
.regs
.sp
[-2], strict
))
2663 stubs::DefVar(VMFrame
&f
, JSAtom
*atom
)
2665 JSContext
*cx
= f
.cx
;
2666 JSStackFrame
*fp
= f
.fp();
2668 JSObject
*obj
= &fp
->varobj(cx
);
2669 JS_ASSERT(!obj
->getOps()->defineProperty
);
2670 uintN attrs
= JSPROP_ENUMERATE
;
2671 if (!fp
->isEvalFrame())
2672 attrs
|= JSPROP_PERMANENT
;
2674 /* Lookup id in order to check for redeclaration problems. */
2675 jsid id
= ATOM_TO_JSID(atom
);
2676 JSProperty
*prop
= NULL
;
2680 * Redundant declaration of a |var|, even one for a non-writable
2681 * property like |undefined| in ES5, does nothing.
2683 if (!obj
->lookupProperty(cx
, id
, &obj2
, &prop
))
2686 /* Bind a variable only if it's not yet defined. */
2688 if (!js_DefineNativeProperty(cx
, obj
, id
, UndefinedValue(), PropertyStub
, PropertyStub
,
2689 attrs
, 0, 0, &prop
)) {
2698 stubs::In(VMFrame
&f
)
2700 JSContext
*cx
= f
.cx
;
2702 const Value
&rref
= f
.regs
.sp
[-1];
2703 if (!rref
.isObject()) {
2704 js_ReportValueError(cx
, JSMSG_IN_NOT_OBJECT
, -1, rref
, NULL
);
2708 JSObject
*obj
= &rref
.toObject();
2710 if (!FetchElementId(f
, obj
, f
.regs
.sp
[-2], id
, &f
.regs
.sp
[-2]))
2715 if (!obj
->lookupProperty(cx
, id
, &obj2
, &prop
))
2721 template void JS_FASTCALL
stubs::DelElem
<true>(VMFrame
&f
);
2722 template void JS_FASTCALL
stubs::DelElem
<false>(VMFrame
&f
);