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 PushImplicitThis(VMFrame &f, JSObject *obj, Value &rval)
327 if (!ComputeImplicitThis(f.cx, obj, rval, &thisv))
329 *f.regs.sp++ = thisv;
333 NameOp(VMFrame &f, JSObject *obj, bool callname = false)
335 JSContext *cx = f.cx;
340 PropertyCacheEntry *entry;
343 JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom);
345 if (entry->vword.isFunObj()) {
346 rval.setObject(entry->vword.toFunObj());
347 } else if (entry->vword.isSlot()) {
348 uintN slot = entry->vword.toSlot();
349 rval = obj2->nativeGetSlot(slot);
351 JS_ASSERT(entry->vword.isShape());
352 shape = entry->vword.toShape();
353 NATIVE_GET(cx, obj, obj2, shape, JSGET_METHOD_BARRIER, &rval, return NULL);
356 JS_ASSERT(obj->isGlobal() || IsCacheableNonGlobalScope(obj));
359 id = ATOM_TO_JSID(atom);
361 if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop))
364 /* Kludge to allow (typeof foo == "undefined") tests. */
365 JSOp op2 = js_GetOpcode(cx, f.fp()->script(), f.regs.pc + JSOP_NAME_LENGTH);
366 if (op2 == JSOP_TYPEOF) {
368 f.regs.sp[-1].setUndefined();
371 ReportAtomNotDefined(cx, atom);
375 /* Take the slow path if prop was not found in a native object. */
376 if (!obj->isNative() || !obj2->isNative()) {
377 if (!obj->getProperty(cx, id, &rval))
380 shape = (Shape *)prop;
381 JSObject *normalized = obj;
382 if (normalized->getClass() == &js_WithClass && !shape->hasDefaultGetter())
383 normalized = js_UnwrapWithObject(cx, normalized);
384 NATIVE_GET(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, &rval, return NULL);
391 PushImplicitThis(f, obj, rval);
397 stubs::Name(VMFrame &f)
399 if (!NameOp(f, &f.fp()->scopeChain()))
404 stubs::GetGlobalName(VMFrame &f)
406 JSObject *globalObj = f.fp()->scopeChain().getGlobal();
407 if (!NameOp(f, globalObj))
412 stubs::GetElem(VMFrame &f)
414 JSContext *cx = f.cx;
415 JSFrameRegs ®s = f.regs;
417 Value &lref = regs.sp[-2];
418 Value &rref = regs.sp[-1];
419 if (lref.isString() && rref.isInt32()) {
420 JSString *str = lref.toString();
421 int32_t i = rref.toInt32();
422 if ((size_t)i < str->length()) {
423 str = JSString::getUnitString(cx, str, (size_t)i);
426 f.regs.sp[-2].setString(str);
431 JSObject *obj = ValueToObject(cx, &lref);
435 const Value *copyFrom;
438 if (rref.isInt32()) {
439 int32_t i = rref.toInt32();
440 if (obj->isDenseArray()) {
441 jsuint idx = jsuint(i);
443 if (idx < obj->getArrayLength() &&
444 idx < obj->getDenseArrayCapacity()) {
445 copyFrom = obj->addressOfDenseArrayElement(idx);
446 if (!copyFrom->isMagic())
449 } else if (obj->isArguments()) {
450 uint32 arg = uint32(i);
452 if (arg < obj->getArgsInitialLength()) {
453 copyFrom = obj->addressOfArgsElement(arg);
454 if (!copyFrom->isMagic()) {
455 if (JSStackFrame *afp = (JSStackFrame *) obj->getPrivate())
456 copyFrom = &afp->canonicalActualArg(arg);
461 if (JS_LIKELY(INT_FITS_IN_JSID(i)))
468 if (ValueFitsInInt32(rref, &i) && INT_FITS_IN_JSID(i)) {
472 if (!js_InternNonIntElementId(cx, obj, rref, &id))
477 if (!obj->getProperty(cx, id, &rval))
482 f.regs.sp[-2] = *copyFrom;
486 FetchElementId(VMFrame &f, JSObject *obj, const Value &idval, jsid &id, Value *vp)
489 if (ValueFitsInInt32(idval, &i_) && INT_FITS_IN_JSID(i_)) {
490 id = INT_TO_JSID(i_);
493 return !!js_InternNonIntElementId(f.cx, obj, idval, &id, vp);
497 stubs::CallElem(VMFrame &f)
499 JSContext *cx = f.cx;
500 JSFrameRegs ®s = f.regs;
502 /* Find the object on which to look for |this|'s properties. */
503 Value thisv = regs.sp[-2];
504 JSObject *thisObj = ValuePropertyBearer(cx, thisv, -2);
508 /* Fetch index and convert it to id suitable for use with thisObj. */
510 if (!FetchElementId(f, thisObj, regs.sp[-1], id, ®s.sp[-2]))
513 /* Get or set the element. */
514 if (!js_GetMethod(cx, thisObj, id, JSGET_NO_METHOD_BARRIER, ®s.sp[-2]))
517 #if JS_HAS_NO_SUCH_METHOD
518 if (JS_UNLIKELY(regs.sp[-2].isUndefined()) && thisv.isObject()) {
519 regs.sp[-2] = regs.sp[-1];
520 regs.sp[-1].setObject(*thisObj);
521 if (!js_OnUnknownMethod(cx, regs.sp - 2))
530 template<JSBool strict>
532 stubs::SetElem(VMFrame &f)
534 JSContext *cx = f.cx;
535 JSFrameRegs ®s = f.regs;
537 Value &objval = regs.sp[-3];
538 Value &idval = regs.sp[-2];
539 Value rval = regs.sp[-1];
544 obj = ValueToObject(cx, &objval);
548 if (!FetchElementId(f, obj, idval, id, ®s.sp[-2]))
552 if (obj->isDenseArray() && JSID_IS_INT(id)) {
553 jsuint length = obj->getDenseArrayCapacity();
554 jsint i = JSID_TO_INT(id);
555 if ((jsuint)i < length) {
556 if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
557 if (js_PrototypeHasIndexedProperties(cx, obj))
559 if ((jsuint)i >= obj->getArrayLength())
560 obj->setArrayLength(i + 1);
562 obj->setDenseArrayElement(i, rval);
567 if (!obj->setProperty(cx, id, &rval, strict))
570 /* :FIXME: Moving the assigned object into the lowest stack slot
571 * is a temporary hack. What we actually want is an implementation
572 * of popAfterSet() that allows popping more than one value;
573 * this logic can then be handled in Compiler.cpp. */
574 regs.sp[-3] = regs.sp[-1];
577 template void JS_FASTCALL stubs::SetElem<true>(VMFrame &f);
578 template void JS_FASTCALL stubs::SetElem<false>(VMFrame &f);
581 stubs::CallName(VMFrame &f)
583 JSObject *obj = NameOp(f, &f.fp()->scopeChain(), true);
589 * Push the implicit this value, with the assumption that the callee
590 * (which is on top of the stack) was read as a property from the
594 stubs::PushImplicitThisForGlobal(VMFrame &f)
596 return PushImplicitThis(f, f.fp()->scopeChain().getGlobal(), f.regs.sp[-1]);
600 stubs::BitOr(VMFrame &f)
604 if (!ValueToECMAInt32(f.cx, f.regs.sp[-2], &i) ||
605 !ValueToECMAInt32(f.cx, f.regs.sp[-1], &j)) {
609 f.regs.sp[-2].setInt32(i);
613 stubs::BitXor(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::BitAnd(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::BitNot(VMFrame &f)
643 if (!ValueToECMAInt32(f.cx, f.regs.sp[-1], &i))
646 f.regs.sp[-1].setInt32(i);
650 stubs::Lsh(VMFrame &f)
653 if (!ValueToECMAInt32(f.cx, f.regs.sp[-2], &i))
655 if (!ValueToECMAInt32(f.cx, f.regs.sp[-1], &j))
658 f.regs.sp[-2].setInt32(i);
662 stubs::Rsh(VMFrame &f)
665 if (!ValueToECMAInt32(f.cx, f.regs.sp[-2], &i))
667 if (!ValueToECMAInt32(f.cx, f.regs.sp[-1], &j))
670 f.regs.sp[-2].setInt32(i);
674 stubs::Ursh(VMFrame &f)
677 if (!ValueToECMAUint32(f.cx, f.regs.sp[-2], &u))
680 if (!ValueToECMAInt32(f.cx, f.regs.sp[-1], &j))
685 f.regs.sp[-2].setNumber(uint32(u));
688 template<JSBool strict>
690 stubs::DefFun(VMFrame &f, JSFunction *fun)
694 JSContext *cx = f.cx;
695 JSStackFrame *fp = f.fp();
698 * A top-level function defined in Global or Eval code (see ECMA-262
699 * Ed. 3), or else a SpiderMonkey extension: a named function statement in
700 * a compound statement (not at the top statement level of global code, or
701 * at the top level of a function body).
703 JSObject *obj = FUN_OBJECT(fun);
705 if (FUN_NULL_CLOSURE(fun)) {
707 * Even a null closure needs a parent for principals finding.
708 * FIXME: bug 476950, although debugger users may also demand some kind
709 * of scope link for debugger-assisted eval-in-frame.
711 obj2 = &fp->scopeChain();
713 JS_ASSERT(!fun->isFlatClosure());
715 obj2 = GetScopeChainFast(cx, fp, JSOP_DEFFUN, JSOP_DEFFUN_LENGTH);
721 * If static link is not current scope, clone fun's object to link to the
722 * current scope via parent. We do this to enable sharing of compiled
723 * functions among multiple equivalent scopes, amortizing the cost of
724 * compilation over a number of executions. Examples include XUL scripts
725 * and event handlers shared among Firefox or other Mozilla app chrome
726 * windows, and user-defined JS functions precompiled and then shared among
727 * requests in server-side JS.
729 if (obj->getParent() != obj2) {
730 obj = CloneFunctionObject(cx, fun, obj2);
736 * ECMA requires functions defined when entering Eval code to be
739 uintN attrs = fp->isEvalFrame()
741 : JSPROP_ENUMERATE | JSPROP_PERMANENT;
744 * We define the function as a property of the variable object and not the
745 * current scope chain even for the case of function expression statements
746 * and functions defined by eval inside let or with blocks.
748 JSObject *parent = &fp->varobj(cx);
750 /* ES5 10.5 (NB: with subsequent errata). */
751 jsid id = ATOM_TO_JSID(fun->atom);
752 JSProperty *prop = NULL;
754 if (!parent->lookupProperty(cx, id, &pobj, &prop))
757 Value rval = ObjectValue(*obj);
761 if (!prop || pobj != parent) {
762 if (!parent->defineProperty(cx, id, rval, PropertyStub, StrictPropertyStub, attrs))
768 JS_ASSERT(parent->isNative());
769 Shape *shape = reinterpret_cast<Shape *>(prop);
770 if (parent->isGlobal()) {
771 if (shape->configurable()) {
772 if (!parent->defineProperty(cx, id, rval, PropertyStub, StrictPropertyStub, attrs))
777 if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
778 JSAutoByteString bytes;
779 if (const char *name = js_ValueToPrintable(cx, IdToValue(id), &bytes)) {
780 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
781 JSMSG_CANT_REDEFINE_PROP, name);
788 * Non-global properties, and global properties which we aren't simply
789 * redefining, must be set. First, this preserves their attributes.
790 * Second, this will produce warnings and/or errors as necessary if the
791 * specified Call object property is not writable (const).
795 if (!parent->setProperty(cx, id, &rval, strict))
800 template void JS_FASTCALL stubs::DefFun<true>(VMFrame &f, JSFunction *fun);
801 template void JS_FASTCALL stubs::DefFun<false>(VMFrame &f, JSFunction *fun);
803 #define DEFAULT_VALUE(cx, n, hint, v) \
805 JS_ASSERT(v.isObject()); \
806 JS_ASSERT(v == regs.sp[n]); \
807 if (!DefaultValue(cx, &v.toObject(), hint, ®s.sp[n])) \
812 #define RELATIONAL(OP) \
814 JSContext *cx = f.cx; \
815 JSFrameRegs ®s = f.regs; \
816 Value rval = regs.sp[-1]; \
817 Value lval = regs.sp[-2]; \
819 if (lval.isObject()) \
820 DEFAULT_VALUE(cx, -2, JSTYPE_NUMBER, lval); \
821 if (rval.isObject()) \
822 DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \
823 if (lval.isString() && rval.isString()) { \
824 JSString *l = lval.toString(), *r = rval.toString(); \
826 if (!CompareStrings(cx, l, r, &cmp)) \
831 if (!ValueToNumber(cx, lval, &l) || \
832 !ValueToNumber(cx, rval, &r)) { \
835 cond = JSDOUBLE_COMPARE(l, OP, r, false); \
837 regs.sp[-2].setBoolean(cond); \
842 stubs::LessThan(VMFrame &f)
848 stubs::LessEqual(VMFrame &f)
854 stubs::GreaterThan(VMFrame &f)
860 stubs::GreaterEqual(VMFrame &f)
866 stubs::ValueToBoolean(VMFrame &f)
868 return js_ValueToBoolean(f.regs.sp[-1]);
872 stubs::Not(VMFrame &f)
874 JSBool b = !js_ValueToBoolean(f.regs.sp[-1]);
875 f.regs.sp[-1].setBoolean(b);
878 template <JSBool EQ, bool IFNAN>
880 StubEqualityOp(VMFrame &f)
882 JSContext *cx = f.cx;
883 JSFrameRegs ®s = f.regs;
885 Value rval = regs.sp[-1];
886 Value lval = regs.sp[-2];
890 /* The string==string case is easily the hottest; try it first. */
891 if (lval.isString() && rval.isString()) {
892 JSString *l = lval.toString();
893 JSString *r = rval.toString();
895 if (!EqualStrings(cx, l, r, &equal))
899 #if JS_HAS_XML_SUPPORT
900 if ((lval.isObject() && lval.toObject().isXML()) ||
901 (rval.isObject() && rval.toObject().isXML())) {
902 if (!js_TestXMLEquality(cx, lval, rval, &cond))
908 if (SameType(lval, rval)) {
909 JS_ASSERT(!lval.isString()); /* this case is handled above */
910 if (lval.isDouble()) {
911 double l = lval.toDouble();
912 double r = rval.toDouble();
914 cond = JSDOUBLE_COMPARE(l, ==, r, IFNAN);
916 cond = JSDOUBLE_COMPARE(l, !=, r, IFNAN);
917 } else if (lval.isObject()) {
918 JSObject *l = &lval.toObject(), *r = &rval.toObject();
919 l->assertSpecialEqualitySynced();
920 if (EqualityOp eq = l->getClass()->ext.equality) {
921 if (!eq(cx, l, &rval, &cond))
925 cond = (l == r) == EQ;
927 } else if (lval.isNullOrUndefined()) {
930 cond = (lval.payloadAsRawUint32() == rval.payloadAsRawUint32()) == EQ;
933 if (lval.isNullOrUndefined()) {
934 cond = rval.isNullOrUndefined() == EQ;
935 } else if (rval.isNullOrUndefined()) {
938 if (lval.isObject()) {
939 if (!DefaultValue(cx, &lval.toObject(), JSTYPE_VOID, ®s.sp[-2]))
944 if (rval.isObject()) {
945 if (!DefaultValue(cx, &rval.toObject(), JSTYPE_VOID, ®s.sp[-1]))
951 * The string==string case is repeated because DefaultValue() can
952 * convert lval/rval to strings.
954 if (lval.isString() && rval.isString()) {
955 JSString *l = lval.toString();
956 JSString *r = rval.toString();
958 if (!EqualStrings(cx, l, r, &equal))
963 if (!ValueToNumber(cx, lval, &l) ||
964 !ValueToNumber(cx, rval, &r)) {
969 cond = JSDOUBLE_COMPARE(l, ==, r, false);
971 cond = JSDOUBLE_COMPARE(l, !=, r, true);
976 regs.sp[-2].setBoolean(cond);
981 stubs::Equal(VMFrame &f)
983 if (!StubEqualityOp<JS_TRUE, false>(f))
985 return f.regs.sp[-2].toBoolean();
989 stubs::NotEqual(VMFrame &f)
991 if (!StubEqualityOp<JS_FALSE, true>(f))
993 return f.regs.sp[-2].toBoolean();
997 DefaultValue(VMFrame &f, JSType hint, Value &v, int n)
999 JS_ASSERT(v.isObject());
1000 if (!DefaultValue(f.cx, &v.toObject(), hint, &f.regs.sp[n]))
1007 stubs::Add(VMFrame &f)
1009 JSContext *cx = f.cx;
1010 JSFrameRegs ®s = f.regs;
1011 Value rval = regs.sp[-1];
1012 Value lval = regs.sp[-2];
1014 /* The string + string case is easily the hottest; try it first. */
1015 bool lIsString = lval.isString();
1016 bool rIsString = rval.isString();
1017 JSString *lstr, *rstr;
1018 if (lIsString && rIsString) {
1019 lstr = lval.toString();
1020 rstr = rval.toString();
1024 #if JS_HAS_XML_SUPPORT
1025 if (lval.isObject() && lval.toObject().isXML() &&
1026 rval.isObject() && rval.toObject().isXML()) {
1027 if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), &rval))
1034 /* These can convert lval/rval to strings. */
1035 if (lval.isObject() && !DefaultValue(f, JSTYPE_VOID, lval, -2))
1037 if (rval.isObject() && !DefaultValue(f, JSTYPE_VOID, rval, -1))
1039 if ((lIsString = lval.isString()) || (rIsString = rval.isString())) {
1041 lstr = lval.toString();
1043 lstr = js_ValueToString(cx, lval);
1046 regs.sp[-2].setString(lstr);
1049 rstr = rval.toString();
1051 rstr = js_ValueToString(cx, rval);
1054 regs.sp[-1].setString(rstr);
1060 if (!ValueToNumber(cx, lval, &l) || !ValueToNumber(cx, rval, &r))
1064 regs.sp[-1].setNumber(l);
1070 JSString *str = js_ConcatStrings(cx, lstr, rstr);
1074 regs.sp[-1].setString(str);
1079 stubs::Sub(VMFrame &f)
1081 JSContext *cx = f.cx;
1082 JSFrameRegs ®s = f.regs;
1084 if (!ValueToNumber(cx, regs.sp[-2], &d1) ||
1085 !ValueToNumber(cx, regs.sp[-1], &d2)) {
1089 regs.sp[-2].setNumber(d);
1093 stubs::Mul(VMFrame &f)
1095 JSContext *cx = f.cx;
1096 JSFrameRegs ®s = f.regs;
1098 if (!ValueToNumber(cx, regs.sp[-2], &d1) ||
1099 !ValueToNumber(cx, regs.sp[-1], &d2)) {
1103 regs.sp[-2].setNumber(d);
1107 stubs::Div(VMFrame &f)
1109 JSContext *cx = f.cx;
1110 JSRuntime *rt = cx->runtime;
1111 JSFrameRegs ®s = f.regs;
1114 if (!ValueToNumber(cx, regs.sp[-2], &d1) ||
1115 !ValueToNumber(cx, regs.sp[-1], &d2)) {
1121 /* XXX MSVC miscompiles such that (NaN == 0) */
1122 if (JSDOUBLE_IS_NaN(d2))
1126 if (d1 == 0 || JSDOUBLE_IS_NaN(d1))
1128 else if (JSDOUBLE_IS_NEG(d1) != JSDOUBLE_IS_NEG(d2))
1129 vp = &rt->negativeInfinityValue;
1131 vp = &rt->positiveInfinityValue;
1135 regs.sp[-2].setNumber(d1);
1140 stubs::Mod(VMFrame &f)
1142 JSContext *cx = f.cx;
1143 JSFrameRegs ®s = f.regs;
1145 Value &lref = regs.sp[-2];
1146 Value &rref = regs.sp[-1];
1148 if (lref.isInt32() && rref.isInt32() &&
1149 (l = lref.toInt32()) >= 0 && (r = rref.toInt32()) > 0) {
1150 int32_t mod = l % r;
1151 regs.sp[-2].setInt32(mod);
1154 if (!ValueToNumber(cx, regs.sp[-2], &d1) ||
1155 !ValueToNumber(cx, regs.sp[-1], &d2)) {
1159 regs.sp[-2].setDouble(js_NaN);
1161 d1 = js_fmod(d1, d2);
1162 regs.sp[-2].setDouble(d1);
1168 stubs::Debugger(VMFrame &f, jsbytecode *pc)
1170 JSDebuggerHandler handler = f.cx->debugHooks->debuggerHandler;
1173 switch (handler(f.cx, f.cx->fp()->script(), pc, Jsvalify(&rval),
1174 f.cx->debugHooks->debuggerHandlerData)) {
1176 f.cx->setPendingException(rval);
1180 f.cx->clearPendingException();
1181 f.cx->fp()->setReturnValue(rval);
1182 #if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
1183 *f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
1184 f.cx->jaegerCompartment()->forceReturnFastTrampoline());
1186 *f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
1187 f.cx->jaegerCompartment()->forceReturnTrampoline());
1192 f.cx->clearPendingException();
1202 stubs::Interrupt(VMFrame &f, jsbytecode *pc)
1204 if (!js_HandleExecutionInterrupt(f.cx))
1209 stubs::Trap(VMFrame &f, uint32 trapTypes)
1212 jsbytecode *pc = f.cx->regs->pc;
1215 * Trap may be called for a single-step interrupt trap and/or a
1216 * regular trap. Try the single-step first, and if it lets control
1217 * flow through or does not exist, do the regular trap.
1219 JSTrapStatus result = JSTRAP_CONTINUE;
1220 if (trapTypes & JSTRAP_SINGLESTEP) {
1222 * single step mode may be paused without recompiling by
1223 * setting the interruptHook to NULL.
1225 JSInterruptHook hook = f.cx->debugHooks->interruptHook;
1227 result = hook(f.cx, f.cx->fp()->script(), pc, Jsvalify(&rval),
1228 f.cx->debugHooks->interruptHookData);
1231 if (result == JSTRAP_CONTINUE && (trapTypes & JSTRAP_TRAP))
1232 result = JS_HandleTrap(f.cx, f.cx->fp()->script(), pc, Jsvalify(&rval));
1236 f.cx->setPendingException(rval);
1240 f.cx->clearPendingException();
1241 f.cx->fp()->setReturnValue(rval);
1242 #if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
1243 *f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
1244 f.cx->jaegerCompartment()->forceReturnFastTrampoline());
1246 *f.returnAddressLocation() = JS_FUNC_TO_DATA_PTR(void *,
1247 f.cx->jaegerCompartment()->forceReturnTrampoline());
1252 f.cx->clearPendingException();
1261 stubs::This(VMFrame &f)
1263 if (!f.fp()->computeThis(f.cx))
1265 f.regs.sp[-1] = f.fp()->thisValue();
1269 stubs::Neg(VMFrame &f)
1272 if (!ValueToNumber(f.cx, f.regs.sp[-1], &d))
1275 f.regs.sp[-1].setNumber(d);
1278 JSObject * JS_FASTCALL
1279 stubs::NewInitArray(VMFrame &f, uint32 count)
1281 JSObject *obj = NewDenseAllocatedArray(f.cx, count);
1288 JSObject * JS_FASTCALL
1289 stubs::NewInitObject(VMFrame &f, JSObject *baseobj)
1291 JSContext *cx = f.cx;
1294 gc::FinalizeKind kind = GuessObjectGCKind(0, false);
1295 JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
1301 JSObject *obj = CopyInitializerObject(cx, baseobj);
1309 stubs::InitElem(VMFrame &f, uint32 last)
1311 JSContext *cx = f.cx;
1312 JSFrameRegs ®s = f.regs;
1314 /* Pop the element's value into rval. */
1315 JS_ASSERT(regs.sp - f.fp()->base() >= 3);
1316 const Value &rref = regs.sp[-1];
1318 /* Find the object being initialized at top of stack. */
1319 const Value &lref = regs.sp[-3];
1320 JS_ASSERT(lref.isObject());
1321 JSObject *obj = &lref.toObject();
1323 /* Fetch id now that we have obj. */
1325 const Value &idval = regs.sp[-2];
1326 if (!FetchElementId(f, obj, idval, id, ®s.sp[-2]))
1330 * If rref is a hole, do not call JSObject::defineProperty. In this case,
1331 * obj must be an array, so if the current op is the last element
1332 * initialiser, set the array length to one greater than id.
1334 if (rref.isMagic(JS_ARRAY_HOLE)) {
1335 JS_ASSERT(obj->isArray());
1336 JS_ASSERT(JSID_IS_INT(id));
1337 JS_ASSERT(jsuint(JSID_TO_INT(id)) < JS_ARGS_LENGTH_MAX);
1338 if (last && !js_SetLengthProperty(cx, obj, (jsuint) (JSID_TO_INT(id) + 1)))
1341 if (!obj->defineProperty(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
1347 stubs::GetUpvar(VMFrame &f, uint32 ck)
1349 /* :FIXME: We can do better, this stub isn't needed. */
1350 uint32 staticLevel = f.fp()->script()->staticLevel;
1352 cookie.fromInteger(ck);
1353 f.regs.sp[0] = GetUpvar(f.cx, staticLevel, cookie);
1356 JSObject * JS_FASTCALL
1357 stubs::DefLocalFun(VMFrame &f, JSFunction *fun)
1360 * Define a local function (i.e., one nested at the top level of another
1361 * function), parented by the current scope chain, stored in a local
1362 * variable slot that the compiler allocated. This is an optimization over
1363 * JSOP_DEFFUN that avoids requiring a call object for the outer function's
1366 JS_ASSERT(fun->isInterpreted());
1367 JS_ASSERT(!FUN_FLAT_CLOSURE(fun));
1368 JSObject *obj = FUN_OBJECT(fun);
1370 if (FUN_NULL_CLOSURE(fun)) {
1371 obj = CloneFunctionObject(f.cx, fun, &f.fp()->scopeChain());
1375 JSObject *parent = GetScopeChainFast(f.cx, f.fp(), JSOP_DEFLOCALFUN,
1376 JSOP_DEFLOCALFUN_LENGTH);
1380 if (obj->getParent() != parent) {
1381 obj = CloneFunctionObject(f.cx, fun, parent);
1390 JSObject * JS_FASTCALL
1391 stubs::DefLocalFun_FC(VMFrame &f, JSFunction *fun)
1393 JSObject *obj = js_NewFlatClosure(f.cx, fun, JSOP_DEFLOCALFUN_FC, JSOP_DEFLOCALFUN_FC_LENGTH);
1399 JSObject * JS_FASTCALL
1400 stubs::RegExp(VMFrame &f, JSObject *regex)
1403 * Push a regexp object cloned from the regexp literal object mapped by the
1404 * bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was
1405 * flouted by many browser-based implementations.
1407 * We avoid the GetScopeChain call here and pass fp->scopeChain() as
1408 * js_GetClassPrototype uses the latter only to locate the global.
1411 if (!js_GetClassPrototype(f.cx, &f.fp()->scopeChain(), JSProto_RegExp, &proto))
1414 JSObject *obj = js_CloneRegExpObject(f.cx, regex, proto);
1420 JSObject * JS_FASTCALL
1421 stubs::LambdaForInit(VMFrame &f, JSFunction *fun)
1423 JSObject *obj = FUN_OBJECT(fun);
1424 if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
1425 fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(f.regs.pc)));
1428 return Lambda(f, fun);
1431 JSObject * JS_FASTCALL
1432 stubs::LambdaForSet(VMFrame &f, JSFunction *fun)
1434 JSObject *obj = FUN_OBJECT(fun);
1435 if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
1436 const Value &lref = f.regs.sp[-1];
1437 if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) {
1438 fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(f.regs.pc)));
1442 return Lambda(f, fun);
1445 JSObject * JS_FASTCALL
1446 stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *fun)
1448 JSObject *obj = FUN_OBJECT(fun);
1449 if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
1451 * Array.prototype.sort and String.prototype.replace are
1452 * optimized as if they are special form. We know that they
1453 * won't leak the joined function object in obj, therefore
1454 * we don't need to clone that compiler- created function
1455 * object for identity/mutation reasons.
1457 int iargc = GET_ARGC(f.regs.pc);
1460 * Note that we have not yet pushed obj as the final argument,
1461 * so regs.sp[1 - (iargc + 2)], and not regs.sp[-(iargc + 2)],
1462 * is the callee for this JSOP_CALL.
1464 const Value &cref = f.regs.sp[1 - (iargc + 2)];
1467 if (IsFunctionObject(cref, &callee)) {
1468 JSFunction *calleeFun = callee->getFunctionPrivate();
1469 Native native = calleeFun->maybeNative();
1472 if (iargc == 1 && native == array_sort)
1474 if (iargc == 2 && native == str_replace)
1479 return Lambda(f, fun);
1482 JSObject * JS_FASTCALL
1483 stubs::LambdaJoinableForNull(VMFrame &f, JSFunction *fun)
1485 JSObject *obj = FUN_OBJECT(fun);
1486 if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
1487 jsbytecode *pc2 = f.regs.pc + JSOP_NULL_LENGTH;
1488 JSOp op2 = JSOp(*pc2);
1490 if (op2 == JSOP_CALL && GET_ARGC(pc2) == 0)
1493 return Lambda(f, fun);
1496 JSObject * JS_FASTCALL
1497 stubs::Lambda(VMFrame &f, JSFunction *fun)
1499 JSObject *obj = FUN_OBJECT(fun);
1502 if (FUN_NULL_CLOSURE(fun)) {
1503 parent = &f.fp()->scopeChain();
1505 parent = GetScopeChainFast(f.cx, f.fp(), JSOP_LAMBDA, JSOP_LAMBDA_LENGTH);
1510 obj = CloneFunctionObject(f.cx, fun, parent);
1517 /* Test whether v is an int in the range [-2^31 + 1, 2^31 - 2] */
1518 static JS_ALWAYS_INLINE bool
1519 CanIncDecWithoutOverflow(int32_t i)
1521 return (i > JSVAL_INT_MIN) && (i < JSVAL_INT_MAX);
1524 template <int32 N, bool POST, JSBool strict>
1526 ObjIncOp(VMFrame &f, JSObject *obj, jsid id)
1528 JSContext *cx = f.cx;
1529 JSStackFrame *fp = f.fp();
1531 f.regs.sp[0].setNull();
1533 if (!obj->getProperty(cx, id, &f.regs.sp[-1]))
1536 Value &ref = f.regs.sp[-1];
1538 if (JS_LIKELY(ref.isInt32() && CanIncDecWithoutOverflow(tmp = ref.toInt32()))) {
1540 ref.getInt32Ref() = tmp + N;
1542 ref.getInt32Ref() = tmp += N;
1544 JSBool ok = obj->setProperty(cx, id, &ref, strict);
1545 fp->clearAssigning();
1550 * We must set regs.sp[-1] to tmp for both post and pre increments
1551 * as the setter overwrites regs.sp[-1].
1557 if (!ValueToNumber(cx, ref, &d))
1568 JSBool ok = obj->setProperty(cx, id, &v, strict);
1569 fp->clearAssigning();
1577 template <int32 N, bool POST, JSBool strict>
1579 NameIncDec(VMFrame &f, JSObject *obj, JSAtom *origAtom)
1581 JSContext *cx = f.cx;
1586 PropertyCacheEntry *entry;
1587 JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom);
1589 if (obj == obj2 && entry->vword.isSlot()) {
1590 uint32 slot = entry->vword.toSlot();
1591 Value &rref = obj->nativeGetSlotRef(slot);
1593 if (JS_LIKELY(rref.isInt32() && CanIncDecWithoutOverflow(tmp = rref.toInt32()))) {
1594 int32_t inc = tmp + N;
1597 rref.getInt32Ref() = inc;
1598 f.regs.sp[0].setInt32(tmp);
1605 jsid id = ATOM_TO_JSID(atom);
1606 if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop))
1609 ReportAtomNotDefined(cx, atom);
1612 return ObjIncOp<N, POST, strict>(f, obj, id);
1615 template<JSBool strict>
1617 stubs::PropInc(VMFrame &f, JSAtom *atom)
1619 JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]);
1622 if (!ObjIncOp<1, true, strict>(f, obj, ATOM_TO_JSID(atom)))
1624 f.regs.sp[-2] = f.regs.sp[-1];
1627 template void JS_FASTCALL stubs::PropInc<true>(VMFrame &f, JSAtom *atom);
1628 template void JS_FASTCALL stubs::PropInc<false>(VMFrame &f, JSAtom *atom);
1630 template<JSBool strict>
1632 stubs::PropDec(VMFrame &f, JSAtom *atom)
1634 JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]);
1637 if (!ObjIncOp<-1, true, strict>(f, obj, ATOM_TO_JSID(atom)))
1639 f.regs.sp[-2] = f.regs.sp[-1];
1642 template void JS_FASTCALL stubs::PropDec<true>(VMFrame &f, JSAtom *atom);
1643 template void JS_FASTCALL stubs::PropDec<false>(VMFrame &f, JSAtom *atom);
1645 template<JSBool strict>
1647 stubs::IncProp(VMFrame &f, JSAtom *atom)
1649 JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]);
1652 if (!ObjIncOp<1, false, strict>(f, obj, ATOM_TO_JSID(atom)))
1654 f.regs.sp[-2] = f.regs.sp[-1];
1657 template void JS_FASTCALL stubs::IncProp<true>(VMFrame &f, JSAtom *atom);
1658 template void JS_FASTCALL stubs::IncProp<false>(VMFrame &f, JSAtom *atom);
1660 template<JSBool strict>
1662 stubs::DecProp(VMFrame &f, JSAtom *atom)
1664 JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]);
1667 if (!ObjIncOp<-1, false, strict>(f, obj, ATOM_TO_JSID(atom)))
1669 f.regs.sp[-2] = f.regs.sp[-1];
1672 template void JS_FASTCALL stubs::DecProp<true>(VMFrame &f, JSAtom *atom);
1673 template void JS_FASTCALL stubs::DecProp<false>(VMFrame &f, JSAtom *atom);
1675 template<JSBool strict>
1677 stubs::ElemInc(VMFrame &f)
1679 JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
1683 if (!FetchElementId(f, obj, f.regs.sp[-1], id, &f.regs.sp[-1]))
1685 if (!ObjIncOp<1, true, strict>(f, obj, id))
1687 f.regs.sp[-3] = f.regs.sp[-1];
1690 template void JS_FASTCALL stubs::ElemInc<true>(VMFrame &f);
1691 template void JS_FASTCALL stubs::ElemInc<false>(VMFrame &f);
1693 template<JSBool strict>
1695 stubs::ElemDec(VMFrame &f)
1697 JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
1701 if (!FetchElementId(f, obj, f.regs.sp[-1], id, &f.regs.sp[-1]))
1703 if (!ObjIncOp<-1, true, strict>(f, obj, id))
1705 f.regs.sp[-3] = f.regs.sp[-1];
1708 template void JS_FASTCALL stubs::ElemDec<true>(VMFrame &f);
1709 template void JS_FASTCALL stubs::ElemDec<false>(VMFrame &f);
1711 template<JSBool strict>
1713 stubs::IncElem(VMFrame &f)
1715 JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
1719 if (!FetchElementId(f, obj, f.regs.sp[-1], id, &f.regs.sp[-1]))
1721 if (!ObjIncOp<1, false, strict>(f, obj, id))
1723 f.regs.sp[-3] = f.regs.sp[-1];
1726 template void JS_FASTCALL stubs::IncElem<true>(VMFrame &f);
1727 template void JS_FASTCALL stubs::IncElem<false>(VMFrame &f);
1729 template<JSBool strict>
1731 stubs::DecElem(VMFrame &f)
1733 JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
1737 if (!FetchElementId(f, obj, f.regs.sp[-1], id, &f.regs.sp[-1]))
1739 if (!ObjIncOp<-1, false, strict>(f, obj, id))
1741 f.regs.sp[-3] = f.regs.sp[-1];
1744 template void JS_FASTCALL stubs::DecElem<true>(VMFrame &f);
1745 template void JS_FASTCALL stubs::DecElem<false>(VMFrame &f);
1747 template<JSBool strict>
1749 stubs::NameInc(VMFrame &f, JSAtom *atom)
1751 JSObject *obj = &f.fp()->scopeChain();
1752 if (!NameIncDec<1, true, strict>(f, obj, atom))
1756 template void JS_FASTCALL stubs::NameInc<true>(VMFrame &f, JSAtom *atom);
1757 template void JS_FASTCALL stubs::NameInc<false>(VMFrame &f, JSAtom *atom);
1759 template<JSBool strict>
1761 stubs::NameDec(VMFrame &f, JSAtom *atom)
1763 JSObject *obj = &f.fp()->scopeChain();
1764 if (!NameIncDec<-1, true, strict>(f, obj, atom))
1768 template void JS_FASTCALL stubs::NameDec<true>(VMFrame &f, JSAtom *atom);
1769 template void JS_FASTCALL stubs::NameDec<false>(VMFrame &f, JSAtom *atom);
1771 template<JSBool strict>
1773 stubs::IncName(VMFrame &f, JSAtom *atom)
1775 JSObject *obj = &f.fp()->scopeChain();
1776 if (!NameIncDec<1, false, strict>(f, obj, atom))
1780 template void JS_FASTCALL stubs::IncName<true>(VMFrame &f, JSAtom *atom);
1781 template void JS_FASTCALL stubs::IncName<false>(VMFrame &f, JSAtom *atom);
1783 template<JSBool strict>
1785 stubs::DecName(VMFrame &f, JSAtom *atom)
1787 JSObject *obj = &f.fp()->scopeChain();
1788 if (!NameIncDec<-1, false, strict>(f, obj, atom))
1792 template void JS_FASTCALL stubs::DecName<true>(VMFrame &f, JSAtom *atom);
1793 template void JS_FASTCALL stubs::DecName<false>(VMFrame &f, JSAtom *atom);
1795 template<JSBool strict>
1797 stubs::GlobalNameInc(VMFrame &f, JSAtom *atom)
1799 JSObject *obj = f.fp()->scopeChain().getGlobal();
1800 if (!NameIncDec<1, true, strict>(f, obj, atom))
1804 template void JS_FASTCALL stubs::GlobalNameInc<true>(VMFrame &f, JSAtom *atom);
1805 template void JS_FASTCALL stubs::GlobalNameInc<false>(VMFrame &f, JSAtom *atom);
1807 template<JSBool strict>
1809 stubs::GlobalNameDec(VMFrame &f, JSAtom *atom)
1811 JSObject *obj = f.fp()->scopeChain().getGlobal();
1812 if (!NameIncDec<-1, true, strict>(f, obj, atom))
1816 template void JS_FASTCALL stubs::GlobalNameDec<true>(VMFrame &f, JSAtom *atom);
1817 template void JS_FASTCALL stubs::GlobalNameDec<false>(VMFrame &f, JSAtom *atom);
1819 template<JSBool strict>
1821 stubs::IncGlobalName(VMFrame &f, JSAtom *atom)
1823 JSObject *obj = f.fp()->scopeChain().getGlobal();
1824 if (!NameIncDec<1, false, strict>(f, obj, atom))
1828 template void JS_FASTCALL stubs::IncGlobalName<true>(VMFrame &f, JSAtom *atom);
1829 template void JS_FASTCALL stubs::IncGlobalName<false>(VMFrame &f, JSAtom *atom);
1831 template<JSBool strict>
1833 stubs::DecGlobalName(VMFrame &f, JSAtom *atom)
1835 JSObject *obj = f.fp()->scopeChain().getGlobal();
1836 if (!NameIncDec<-1, false, strict>(f, obj, atom))
1840 template void JS_FASTCALL stubs::DecGlobalName<true>(VMFrame &f, JSAtom *atom);
1841 template void JS_FASTCALL stubs::DecGlobalName<false>(VMFrame &f, JSAtom *atom);
1843 static bool JS_FASTCALL
1844 InlineGetProp(VMFrame &f)
1846 JSContext *cx = f.cx;
1847 JSFrameRegs ®s = f.regs;
1849 Value *vp = &f.regs.sp[-1];
1850 JSObject *obj = ValueToObject(f.cx, vp);
1857 * We do not impose the method read barrier if in an imacro,
1858 * assuming any property gets it does (e.g., for 'toString'
1859 * from JSOP_NEW) will not be leaked to the calling script.
1861 JSObject *aobj = js_GetProtoIfDenseArray(obj);
1863 PropertyCacheEntry *entry;
1866 JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom);
1868 if (entry->vword.isFunObj()) {
1869 rval.setObject(entry->vword.toFunObj());
1870 } else if (entry->vword.isSlot()) {
1871 uint32 slot = entry->vword.toSlot();
1872 rval = obj2->nativeGetSlot(slot);
1874 JS_ASSERT(entry->vword.isShape());
1875 const Shape *shape = entry->vword.toShape();
1876 NATIVE_GET(cx, obj, obj2, shape,
1877 f.fp()->hasImacropc() ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER,
1878 &rval, return false);
1883 jsid id = ATOM_TO_JSID(atom);
1884 if (JS_LIKELY(!aobj->getOps()->getProperty)
1885 ? !js_GetPropertyHelper(cx, obj, id,
1886 f.fp()->hasImacropc()
1887 ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
1888 : JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
1890 : !obj->getProperty(cx, id, &rval)) {
1900 stubs::GetProp(VMFrame &f)
1902 if (!InlineGetProp(f))
1907 stubs::GetPropNoCache(VMFrame &f, JSAtom *atom)
1909 JSContext *cx = f.cx;
1911 Value *vp = &f.regs.sp[-1];
1912 JSObject *obj = ValueToObject(cx, vp);
1916 if (!obj->getProperty(cx, ATOM_TO_JSID(atom), vp))
1921 stubs::CallProp(VMFrame &f, JSAtom *origAtom)
1923 JSContext *cx = f.cx;
1924 JSFrameRegs ®s = f.regs;
1930 if (lval.isObject()) {
1933 JSProtoKey protoKey;
1934 if (lval.isString()) {
1935 protoKey = JSProto_String;
1936 } else if (lval.isNumber()) {
1937 protoKey = JSProto_Number;
1938 } else if (lval.isBoolean()) {
1939 protoKey = JSProto_Boolean;
1941 JS_ASSERT(lval.isNull() || lval.isUndefined());
1942 js_ReportIsNullOrUndefined(cx, -1, lval, NULL);
1946 if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj))
1948 objv.setObject(*pobj);
1951 JSObject *aobj = js_GetProtoIfDenseArray(&objv.toObject());
1954 PropertyCacheEntry *entry;
1957 JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom);
1959 if (entry->vword.isFunObj()) {
1960 rval.setObject(entry->vword.toFunObj());
1961 } else if (entry->vword.isSlot()) {
1962 uint32 slot = entry->vword.toSlot();
1963 rval = obj2->nativeGetSlot(slot);
1965 JS_ASSERT(entry->vword.isShape());
1966 const Shape *shape = entry->vword.toShape();
1967 NATIVE_GET(cx, &objv.toObject(), obj2, shape, JSGET_NO_METHOD_BARRIER, &rval,
1975 * Cache miss: use the immediate atom that was loaded for us under
1976 * PropertyCache::test.
1979 id = ATOM_TO_JSID(origAtom);
1982 regs.sp[-1].setNull();
1983 if (lval.isObject()) {
1984 if (!js_GetMethod(cx, &objv.toObject(), id,
1985 JS_LIKELY(!aobj->getOps()->getProperty)
1986 ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
1987 : JSGET_NO_METHOD_BARRIER,
1994 JS_ASSERT(!objv.toObject().getOps()->getProperty);
1995 if (!js_GetPropertyHelper(cx, &objv.toObject(), id,
1996 JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER,
2004 #if JS_HAS_NO_SUCH_METHOD
2005 if (JS_UNLIKELY(rval.isUndefined()) && regs.sp[-1].isObject()) {
2006 regs.sp[-2].setString(ATOM_TO_STRING(origAtom));
2007 if (!js_OnUnknownMethod(cx, regs.sp - 2))
2014 stubs::Length(VMFrame &f)
2016 JSFrameRegs ®s = f.regs;
2017 Value *vp = ®s.sp[-1];
2019 if (vp->isString()) {
2020 vp->setInt32(vp->toString()->length());
2022 } else if (vp->isObject()) {
2023 JSObject *obj = &vp->toObject();
2024 if (obj->isArray()) {
2025 jsuint length = obj->getArrayLength();
2026 regs.sp[-1].setNumber(length);
2028 } else if (obj->isArguments() && !obj->isArgsLengthOverridden()) {
2029 uint32 length = obj->getArgsInitialLength();
2030 JS_ASSERT(length < INT32_MAX);
2031 regs.sp[-1].setInt32(int32_t(length));
2036 if (!InlineGetProp(f))
2041 stubs::Iter(VMFrame &f, uint32 flags)
2043 if (!js_ValueToIterator(f.cx, flags, &f.regs.sp[-1]))
2045 JS_ASSERT(!f.regs.sp[-1].isPrimitive());
2049 InitPropOrMethod(VMFrame &f, JSAtom *atom, JSOp op)
2051 JSContext *cx = f.cx;
2052 JSRuntime *rt = cx->runtime;
2053 JSFrameRegs ®s = f.regs;
2055 /* Load the property's initial value into rval. */
2056 JS_ASSERT(regs.sp - f.fp()->base() >= 2);
2060 /* Load the object being initialized into lval/obj. */
2061 JSObject *obj = ®s.sp[-2].toObject();
2062 JS_ASSERT(obj->isNative());
2065 * Probe the property cache.
2067 * We can not assume that the object created by JSOP_NEWINIT is still
2068 * single-threaded as the debugger can access it from other threads.
2071 * On a hit, if the cached shape has a non-default setter, it must be
2072 * __proto__. If shape->previous() != obj->lastProperty(), there must be a
2073 * repeated property name. The fast path does not handle these two cases.
2075 PropertyCacheEntry *entry;
2077 if (JS_PROPERTY_CACHE(cx).testForInit(rt, regs.pc, obj, &shape, &entry) &&
2078 shape->hasDefaultSetter() &&
2079 shape->previous() == obj->lastProperty())
2081 /* Fast path. Property cache hit. */
2082 uint32 slot = shape->slot;
2084 JS_ASSERT(slot == obj->slotSpan());
2085 JS_ASSERT(slot >= JSSLOT_FREE(obj->getClass()));
2086 if (slot < obj->numSlots()) {
2087 JS_ASSERT(obj->getSlot(slot).isUndefined());
2089 if (!obj->allocSlot(cx, &slot))
2091 JS_ASSERT(slot == shape->slot);
2094 /* A new object, or one we just extended in a recent initprop op. */
2095 JS_ASSERT(!obj->lastProperty() ||
2096 obj->shape() == obj->lastProperty()->shape);
2097 obj->extend(cx, shape);
2100 * No method change check here because here we are adding a new
2101 * property, not updating an existing slot's value that might
2102 * contain a method of a branded shape.
2104 obj->nativeSetSlot(slot, rval);
2106 PCMETER(JS_PROPERTY_CACHE(cx).inipcmisses++);
2108 /* Get the immediate property name into id. */
2109 jsid id = ATOM_TO_JSID(atom);
2111 uintN defineHow = (op == JSOP_INITMETHOD)
2112 ? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD
2113 : JSDNP_CACHE_RESULT;
2114 if (!(JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom)
2115 ? js_SetPropertyHelper(cx, obj, id, defineHow, &rval, false)
2116 : js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
2117 JSPROP_ENUMERATE, 0, 0, NULL,
2125 stubs::InitProp(VMFrame &f, JSAtom *atom)
2127 InitPropOrMethod(f, atom, JSOP_INITPROP);
2131 stubs::InitMethod(VMFrame &f, JSAtom *atom)
2133 InitPropOrMethod(f, atom, JSOP_INITMETHOD);
2137 stubs::IterNext(VMFrame &f)
2139 JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
2140 JS_ASSERT(f.regs.sp[-1].isObject());
2142 JSObject *iterobj = &f.regs.sp[-1].toObject();
2143 f.regs.sp[0].setNull();
2145 if (!js_IteratorNext(f.cx, iterobj, &f.regs.sp[-1]))
2150 stubs::IterMore(VMFrame &f)
2152 JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
2153 JS_ASSERT(f.regs.sp[-1].isObject());
2156 JSObject *iterobj = &f.regs.sp[-1].toObject();
2157 if (!js_IteratorMore(f.cx, iterobj, &v))
2160 return v.toBoolean();
2164 stubs::EndIter(VMFrame &f)
2166 JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
2167 if (!js_CloseIterator(f.cx, &f.regs.sp[-1].toObject()))
2171 JSString * JS_FASTCALL
2172 stubs::TypeOf(VMFrame &f)
2174 const Value &ref = f.regs.sp[-1];
2175 JSType type = JS_TypeOfValue(f.cx, Jsvalify(ref));
2176 JSAtom *atom = f.cx->runtime->atomState.typeAtoms[type];
2177 return ATOM_TO_STRING(atom);
2181 stubs::StrictEq(VMFrame &f)
2183 const Value &rhs = f.regs.sp[-1];
2184 const Value &lhs = f.regs.sp[-2];
2186 if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
2189 f.regs.sp[-1].setBoolean(equal == JS_TRUE);
2193 stubs::StrictNe(VMFrame &f)
2195 const Value &rhs = f.regs.sp[-1];
2196 const Value &lhs = f.regs.sp[-2];
2198 if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
2201 f.regs.sp[-1].setBoolean(equal != JS_TRUE);
2205 stubs::Throw(VMFrame &f)
2207 JSContext *cx = f.cx;
2209 JS_ASSERT(!cx->isExceptionPending());
2210 cx->setPendingException(f.regs.sp[-1]);
2214 JSObject * JS_FASTCALL
2215 stubs::FlatLambda(VMFrame &f, JSFunction *fun)
2217 JSObject *obj = js_NewFlatClosure(f.cx, fun, JSOP_LAMBDA_FC, JSOP_LAMBDA_FC_LENGTH);
2224 stubs::Arguments(VMFrame &f)
2227 if (!js_GetArgsValue(f.cx, f.fp(), &f.regs.sp[-1]))
2232 stubs::InstanceOf(VMFrame &f)
2234 JSContext *cx = f.cx;
2235 JSFrameRegs ®s = f.regs;
2237 const Value &rref = regs.sp[-1];
2238 if (rref.isPrimitive()) {
2239 js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
2243 JSObject *obj = &rref.toObject();
2244 const Value &lref = regs.sp[-2];
2245 JSBool cond = JS_FALSE;
2246 if (!HasInstance(cx, obj, &lref, &cond))
2248 f.regs.sp[-2].setBoolean(cond);
2253 stubs::FastInstanceOf(VMFrame &f)
2255 const Value &lref = f.regs.sp[-1];
2257 if (lref.isPrimitive()) {
2259 * Throw a runtime error if instanceof is called on a function that
2260 * has a non-object as its .prototype value.
2262 js_ReportValueError(f.cx, JSMSG_BAD_PROTOTYPE, -1, f.regs.sp[-2], NULL);
2266 f.regs.sp[-3].setBoolean(js_IsDelegate(f.cx, &lref.toObject(), f.regs.sp[-3]));
2270 stubs::ArgCnt(VMFrame &f)
2272 JSContext *cx = f.cx;
2273 JSRuntime *rt = cx->runtime;
2274 JSStackFrame *fp = f.fp();
2276 jsid id = ATOM_TO_JSID(rt->atomState.lengthAtom);
2278 if (!js_GetArgsProperty(cx, fp, id, &f.regs.sp[-1]))
2283 stubs::EnterBlock(VMFrame &f, JSObject *obj)
2285 JSFrameRegs ®s = f.regs;
2287 JSStackFrame *fp = f.fp();
2290 JS_ASSERT(obj->isStaticBlock());
2291 JS_ASSERT(fp->base() + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp);
2292 Value *vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj);
2293 JS_ASSERT(regs.sp < vp);
2294 JS_ASSERT(vp <= fp->slots() + fp->script()->nslots);
2295 SetValueRangeToUndefined(regs.sp, vp);
2299 JSContext *cx = f.cx;
2302 * The young end of fp->scopeChain() may omit blocks if we haven't closed
2303 * over them, but if there are any closure blocks on fp->scopeChain(), they'd
2304 * better be (clones of) ancestors of the block we're entering now;
2305 * anything else we should have popped off fp->scopeChain() when we left its
2308 JSObject *obj2 = &fp->scopeChain();
2310 while ((clasp = obj2->getClass()) == &js_WithClass)
2311 obj2 = obj2->getParent();
2312 if (clasp == &js_BlockClass &&
2313 obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, fp)) {
2314 JSObject *youngestProto = obj2->getProto();
2315 JS_ASSERT(youngestProto->isStaticBlock());
2316 JSObject *parent = obj;
2317 while ((parent = parent->getParent()) != youngestProto)
2324 stubs::LeaveBlock(VMFrame &f, JSObject *blockChain)
2326 JSContext *cx = f.cx;
2327 JSStackFrame *fp = f.fp();
2330 JS_ASSERT(blockChain->isStaticBlock());
2331 uintN blockDepth = OBJ_BLOCK_DEPTH(cx, blockChain);
2333 JS_ASSERT(blockDepth <= StackDepth(fp->script()));
2336 * If we're about to leave the dynamic scope of a block that has been
2337 * cloned onto fp->scopeChain(), clear its private data, move its locals from
2338 * the stack into the clone, and pop it off the chain.
2340 JSObject *obj = &fp->scopeChain();
2341 if (obj->getProto() == blockChain) {
2342 JS_ASSERT(obj->getClass() == &js_BlockClass);
2343 if (!js_PutBlockObject(cx, JS_TRUE))
2349 stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
2351 jsbytecode *jpc = pc;
2352 JSScript *script = f.fp()->script();
2353 bool ctor = f.fp()->isConstructing();
2355 /* This is correct because the compiler adjusts the stack beforehand. */
2356 Value lval = f.regs.sp[-1];
2358 if (!lval.isPrimitive()) {
2359 void* native = script->nativeCodeForPC(ctor, pc + GET_JUMP_OFFSET(pc));
2364 JS_ASSERT(pc[0] == JSOP_LOOKUPSWITCH);
2366 pc += JUMP_OFFSET_LEN;
2367 uint32 npairs = GET_UINT16(pc);
2372 if (lval.isString()) {
2373 JSLinearString *str = lval.toString()->ensureLinear(f.cx);
2376 for (uint32 i = 1; i <= npairs; i++) {
2377 Value rval = script->getConst(GET_INDEX(pc));
2379 if (rval.isString()) {
2380 JSLinearString *rhs = rval.toString()->assertIsLinear();
2381 if (rhs == str || EqualStrings(str, rhs)) {
2382 void* native = script->nativeCodeForPC(ctor,
2383 jpc + GET_JUMP_OFFSET(pc));
2388 pc += JUMP_OFFSET_LEN;
2390 } else if (lval.isNumber()) {
2391 double d = lval.toNumber();
2392 for (uint32 i = 1; i <= npairs; i++) {
2393 Value rval = script->getConst(GET_INDEX(pc));
2395 if (rval.isNumber() && d == rval.toNumber()) {
2396 void* native = script->nativeCodeForPC(ctor,
2397 jpc + GET_JUMP_OFFSET(pc));
2401 pc += JUMP_OFFSET_LEN;
2404 for (uint32 i = 1; i <= npairs; i++) {
2405 Value rval = script->getConst(GET_INDEX(pc));
2408 void* native = script->nativeCodeForPC(ctor,
2409 jpc + GET_JUMP_OFFSET(pc));
2413 pc += JUMP_OFFSET_LEN;
2417 void* native = script->nativeCodeForPC(ctor, jpc + GET_JUMP_OFFSET(jpc));
2423 stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
2425 jsbytecode * const originalPC = origPc;
2426 jsbytecode *pc = originalPC;
2427 uint32 jumpOffset = GET_JUMP_OFFSET(pc);
2428 pc += JUMP_OFFSET_LEN;
2430 /* Note: compiler adjusts the stack beforehand. */
2431 Value rval = f.regs.sp[-1];
2434 if (rval.isInt32()) {
2435 tableIdx = rval.toInt32();
2436 } else if (rval.isDouble()) {
2437 double d = rval.toDouble();
2439 /* Treat -0 (double) as 0. */
2441 } else if (!JSDOUBLE_IS_INT32(d, (int32_t *)&tableIdx)) {
2449 jsint low = GET_JUMP_OFFSET(pc);
2450 pc += JUMP_OFFSET_LEN;
2451 jsint high = GET_JUMP_OFFSET(pc);
2452 pc += JUMP_OFFSET_LEN;
2455 if ((jsuint) tableIdx < (jsuint)(high - low + 1)) {
2456 pc += JUMP_OFFSET_LEN * tableIdx;
2457 uint32 candidateOffset = GET_JUMP_OFFSET(pc);
2458 if (candidateOffset)
2459 jumpOffset = candidateOffset;
2464 /* Provide the native address. */
2465 JSScript* script = f.fp()->script();
2466 void* native = script->nativeCodeForPC(f.fp()->isConstructing(),
2467 originalPC + jumpOffset);
2473 stubs::Unbrand(VMFrame &f)
2475 const Value &thisv = f.regs.sp[-1];
2476 if (!thisv.isObject())
2478 JSObject *obj = &thisv.toObject();
2479 if (obj->isNative())
2484 stubs::Pos(VMFrame &f)
2486 if (!ValueToNumber(f.cx, &f.regs.sp[-1]))
2491 stubs::ArgSub(VMFrame &f, uint32 n)
2493 jsid id = INT_TO_JSID(n);
2495 if (!js_GetArgsProperty(f.cx, f.fp(), id, &rval))
2497 f.regs.sp[0] = rval;
2501 stubs::DelName(VMFrame &f, JSAtom *atom)
2503 jsid id = ATOM_TO_JSID(atom);
2504 JSObject *obj, *obj2;
2506 if (!js_FindProperty(f.cx, id, &obj, &obj2, &prop))
2509 /* Strict mode code should never contain JSOP_DELNAME opcodes. */
2510 JS_ASSERT(!f.fp()->script()->strictModeCode);
2512 /* ECMA says to return true if name is undefined or inherited. */
2514 f.regs.sp[-1] = BooleanValue(true);
2516 if (!obj->deleteProperty(f.cx, id, &f.regs.sp[-1], false))
2521 template<JSBool strict>
2523 stubs::DelProp(VMFrame &f, JSAtom *atom)
2525 JSContext *cx = f.cx;
2527 JSObject *obj = ValueToObject(cx, &f.regs.sp[-1]);
2532 if (!obj->deleteProperty(cx, ATOM_TO_JSID(atom), &rval, strict))
2535 f.regs.sp[-1] = rval;
2538 template void JS_FASTCALL stubs::DelProp<true>(VMFrame &f, JSAtom *atom);
2539 template void JS_FASTCALL stubs::DelProp<false>(VMFrame &f, JSAtom *atom);
2541 template<JSBool strict>
2543 stubs::DelElem(VMFrame &f)
2545 JSContext *cx = f.cx;
2547 JSObject *obj = ValueToObject(cx, &f.regs.sp[-2]);
2552 if (!FetchElementId(f, obj, f.regs.sp[-1], id, &f.regs.sp[-1]))
2555 if (!obj->deleteProperty(cx, id, &f.regs.sp[-2], strict))
2560 stubs::DefVarOrConst(VMFrame &f, JSAtom *atom)
2562 JSContext *cx = f.cx;
2563 JSStackFrame *fp = f.fp();
2565 JSObject *obj = &fp->varobj(cx);
2566 JS_ASSERT(!obj->getOps()->defineProperty);
2567 uintN attrs = JSPROP_ENUMERATE;
2568 if (!fp->isEvalFrame())
2569 attrs |= JSPROP_PERMANENT;
2571 /* Lookup id in order to check for redeclaration problems. */
2572 jsid id = ATOM_TO_JSID(atom);
2574 if (JSOp(*f.regs.pc) == JSOP_DEFVAR) {
2576 * Redundant declaration of a |var|, even one for a non-writable
2577 * property like |undefined| in ES5, does nothing.
2581 if (!obj->lookupProperty(cx, id, &obj2, &prop))
2583 shouldDefine = (!prop || obj2 != obj);
2585 JS_ASSERT(JSOp(*f.regs.pc) == JSOP_DEFCONST);
2586 attrs |= JSPROP_READONLY;
2587 if (!CheckRedeclaration(cx, obj, id, attrs))
2591 * As attrs includes readonly, CheckRedeclaration can succeed only
2592 * if prop does not exist.
2594 shouldDefine = true;
2597 /* Bind a variable only if it's not yet defined. */
2599 !js_DefineNativeProperty(cx, obj, id, UndefinedValue(), PropertyStub, StrictPropertyStub,
2600 attrs, 0, 0, NULL)) {
2606 stubs::SetConst(VMFrame &f, JSAtom *atom)
2608 JSContext *cx = f.cx;
2609 JSStackFrame *fp = f.fp();
2611 JSObject *obj = &fp->varobj(cx);
2612 const Value &ref = f.regs.sp[-1];
2613 if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), ref,
2614 PropertyStub, StrictPropertyStub,
2615 JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
2621 stubs::In(VMFrame &f)
2623 JSContext *cx = f.cx;
2625 const Value &rref = f.regs.sp[-1];
2626 if (!rref.isObject()) {
2627 js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
2631 JSObject *obj = &rref.toObject();
2633 if (!FetchElementId(f, obj, f.regs.sp[-2], id, &f.regs.sp[-2]))
2638 if (!obj->lookupProperty(cx, id, &obj2, &prop))
2644 template void JS_FASTCALL stubs::DelElem<true>(VMFrame &f);
2645 template void JS_FASTCALL stubs::DelElem<false>(VMFrame &f);
2648 stubs::Exception(VMFrame &f)
2650 f.regs.sp[0] = f.cx->getPendingException();
2651 f.cx->clearPendingException();
2653 template <bool Clamped>
2655 stubs::ConvertToTypedInt(JSContext *cx, Value *vp)
2657 JS_ASSERT(!vp->isInt32());
2659 if (vp->isDouble()) {
2661 return js_TypedArray_uint8_clamp_double(vp->toDouble());
2662 return js_DoubleToECMAInt32(vp->toDouble());
2665 if (vp->isNull() || vp->isObject() || vp->isUndefined())
2668 if (vp->isBoolean())
2669 return vp->toBoolean() ? 1 : 0;
2671 JS_ASSERT(vp->isString());
2677 StringToNumberType<jsint>(cx, vp->toString(), &i32);
2683 template int32 JS_FASTCALL stubs::ConvertToTypedInt<true>(JSContext *, Value *);
2684 template int32 JS_FASTCALL stubs::ConvertToTypedInt<false>(JSContext *, Value *);
2687 stubs::ConvertToTypedFloat(JSContext *cx, Value *vp)
2689 JS_ASSERT(!vp->isDouble() && !vp->isInt32());
2693 } else if (vp->isObject() || vp->isUndefined()) {
2694 vp->setDouble(js_NaN);
2695 } else if (vp->isBoolean()) {
2696 vp->setDouble(vp->toBoolean() ? 1 : 0);
2698 JS_ASSERT(vp->isString());
2703 StringToNumberType<double>(cx, vp->toString(), &d);