1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=4 sw=4 et tw=99:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
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/
11 : *
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
15 : * License.
16 : *
17 : * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18 : * May 28, 2008.
19 : *
20 : * The Initial Developer of the Original Code is
21 : * Brendan Eich <brendan@mozilla.org>
22 : *
23 : * Contributor(s):
24 : * David Anderson <danderson@mozilla.com>
25 : * David Mandelin <dmandelin@mozilla.com>
26 : *
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.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #include "jscntxt.h"
42 : #include "jsscope.h"
43 : #include "jsobj.h"
44 : #include "jslibmath.h"
45 : #include "jsiter.h"
46 : #include "jsgcmark.h"
47 : #include "jsnum.h"
48 : #include "jsxml.h"
49 : #include "jsbool.h"
50 : #include "assembler/assembler/MacroAssemblerCodeRef.h"
51 : #include "jstypes.h"
52 : #include "vm/Debugger.h"
53 : #include "vm/String.h"
54 : #include "methodjit/Compiler.h"
55 : #include "methodjit/StubCalls.h"
56 : #include "methodjit/Retcon.h"
57 :
58 : #include "jsinterpinlines.h"
59 : #include "jsscopeinlines.h"
60 : #include "jsscriptinlines.h"
61 : #include "jsnuminlines.h"
62 : #include "jsobjinlines.h"
63 : #include "jscntxtinlines.h"
64 : #include "jsatominlines.h"
65 : #include "StubCalls-inl.h"
66 : #include "jsfuninlines.h"
67 : #include "jstypedarray.h"
68 :
69 : #include "vm/RegExpObject-inl.h"
70 : #include "vm/String-inl.h"
71 :
72 : #ifdef XP_WIN
73 : # include "jswin.h"
74 : #endif
75 :
76 : #include "jsautooplen.h"
77 :
78 : using namespace js;
79 : using namespace js::mjit;
80 : using namespace js::types;
81 : using namespace JSC;
82 :
83 : void JS_FASTCALL
84 1439 : stubs::BindName(VMFrame &f, PropertyName *name)
85 : {
86 1439 : JSObject *obj = FindIdentifierBase(f.cx, &f.fp()->scopeChain(), name);
87 1439 : if (!obj)
88 0 : THROW();
89 1439 : f.regs.sp[0].setObject(*obj);
90 : }
91 :
92 : JSObject * JS_FASTCALL
93 0 : stubs::BindGlobalName(VMFrame &f)
94 : {
95 0 : return &f.fp()->scopeChain().global();
96 : }
97 :
98 : template<JSBool strict>
99 : void JS_FASTCALL
100 135441 : stubs::SetName(VMFrame &f, PropertyName *name)
101 : {
102 135441 : JSContext *cx = f.cx;
103 135441 : const Value &rval = f.regs.sp[-1];
104 135441 : const Value &lval = f.regs.sp[-2];
105 :
106 135441 : if (!SetPropertyOperation(cx, f.pc(), lval, rval))
107 425 : THROW();
108 :
109 135016 : f.regs.sp[-2] = f.regs.sp[-1];
110 : }
111 :
112 : template void JS_FASTCALL stubs::SetName<true>(VMFrame &f, PropertyName *origName);
113 : template void JS_FASTCALL stubs::SetName<false>(VMFrame &f, PropertyName *origName);
114 :
115 : template<JSBool strict>
116 : void JS_FASTCALL
117 47472 : stubs::SetGlobalName(VMFrame &f, PropertyName *name)
118 : {
119 47472 : SetName<strict>(f, name);
120 47472 : }
121 :
122 : template void JS_FASTCALL stubs::SetGlobalName<true>(VMFrame &f, PropertyName *name);
123 : template void JS_FASTCALL stubs::SetGlobalName<false>(VMFrame &f, PropertyName *name);
124 :
125 : void JS_FASTCALL
126 781215 : stubs::Name(VMFrame &f)
127 : {
128 : Value rval;
129 781215 : if (!NameOperation(f.cx, f.pc(), &rval))
130 3359 : THROW();
131 777856 : f.regs.sp[0] = rval;
132 : }
133 :
134 : void JS_FASTCALL
135 9431373 : stubs::GetElem(VMFrame &f)
136 : {
137 9431373 : Value &lref = f.regs.sp[-2];
138 9431373 : Value &rref = f.regs.sp[-1];
139 9431373 : Value &rval = f.regs.sp[-2];
140 :
141 9431373 : if (!GetElementOperation(f.cx, JSOp(*f.pc()), lref, rref, &rval))
142 45 : THROW();
143 : }
144 :
145 : template<JSBool strict>
146 : void JS_FASTCALL
147 8713438 : stubs::SetElem(VMFrame &f)
148 : {
149 8713438 : JSContext *cx = f.cx;
150 8713438 : FrameRegs ®s = f.regs;
151 :
152 8713438 : Value &objval = regs.sp[-3];
153 8713438 : Value &idval = regs.sp[-2];
154 8713438 : Value rval = regs.sp[-1];
155 :
156 : JSObject *obj;
157 : jsid id;
158 :
159 8713438 : obj = ValueToObject(cx, objval);
160 8713438 : if (!obj)
161 7 : THROW();
162 :
163 8713431 : if (!FetchElementId(f.cx, obj, idval, id, ®s.sp[-2]))
164 0 : THROW();
165 :
166 8713431 : TypeScript::MonitorAssign(cx, obj, id);
167 :
168 : do {
169 8713431 : if (obj->isDenseArray() && JSID_IS_INT(id)) {
170 1529028 : uint32_t length = obj->getDenseArrayInitializedLength();
171 1529028 : int32_t i = JSID_TO_INT(id);
172 1529028 : if ((uint32_t)i < length) {
173 23520 : if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
174 19469 : if (js_PrototypeHasIndexedProperties(cx, obj))
175 0 : break;
176 19469 : if ((uint32_t)i >= obj->getArrayLength())
177 0 : obj->setArrayLength(cx, i + 1);
178 : }
179 23520 : obj->setDenseArrayElementWithType(cx, i, rval);
180 23520 : goto end_setelem;
181 : } else {
182 1505508 : if (f.script()->hasAnalysis())
183 1505508 : f.script()->analysis()->getCode(f.pc()).arrayWriteHole = true;
184 : }
185 : }
186 : } while (0);
187 8689911 : if (!obj->setGeneric(cx, id, &rval, strict))
188 2428 : THROW();
189 : end_setelem:
190 : /* :FIXME: Moving the assigned object into the lowest stack slot
191 : * is a temporary hack. What we actually want is an implementation
192 : * of popAfterSet() that allows popping more than one value;
193 : * this logic can then be handled in Compiler.cpp. */
194 8711003 : regs.sp[-3] = regs.sp[-1];
195 : }
196 :
197 : template void JS_FASTCALL stubs::SetElem<true>(VMFrame &f);
198 : template void JS_FASTCALL stubs::SetElem<false>(VMFrame &f);
199 :
200 : void JS_FASTCALL
201 1126 : stubs::ToId(VMFrame &f)
202 : {
203 1126 : Value &objval = f.regs.sp[-2];
204 1126 : Value &idval = f.regs.sp[-1];
205 :
206 1126 : JSObject *obj = ValueToObject(f.cx, objval);
207 1126 : if (!obj)
208 0 : THROW();
209 :
210 : jsid id;
211 1126 : if (!FetchElementId(f.cx, obj, idval, id, &idval))
212 0 : THROW();
213 :
214 1126 : if (!idval.isInt32())
215 1126 : TypeScript::MonitorUnknown(f.cx, f.script(), f.pc());
216 : }
217 :
218 : void JS_FASTCALL
219 1950398 : stubs::ImplicitThis(VMFrame &f, PropertyName *name)
220 : {
221 : JSObject *obj, *obj2;
222 : JSProperty *prop;
223 1950398 : if (!FindPropertyHelper(f.cx, name, false, f.cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
224 0 : THROW();
225 :
226 1950398 : if (!ComputeImplicitThis(f.cx, obj, &f.regs.sp[0]))
227 0 : THROW();
228 : }
229 :
230 : void JS_FASTCALL
231 409108 : stubs::BitOr(VMFrame &f)
232 : {
233 : int32_t i, j;
234 :
235 409108 : if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
236 21 : THROW();
237 :
238 409087 : i = i | j;
239 409087 : f.regs.sp[-2].setInt32(i);
240 : }
241 :
242 : void JS_FASTCALL
243 22203 : stubs::BitXor(VMFrame &f)
244 : {
245 : int32_t i, j;
246 :
247 22203 : if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
248 0 : THROW();
249 :
250 22203 : i = i ^ j;
251 22203 : f.regs.sp[-2].setInt32(i);
252 : }
253 :
254 : void JS_FASTCALL
255 64586 : stubs::BitAnd(VMFrame &f)
256 : {
257 : int32_t i, j;
258 :
259 64586 : if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
260 0 : THROW();
261 :
262 64586 : i = i & j;
263 64586 : f.regs.sp[-2].setInt32(i);
264 : }
265 :
266 : void JS_FASTCALL
267 2 : stubs::BitNot(VMFrame &f)
268 : {
269 : int32_t i;
270 :
271 2 : if (!ToInt32(f.cx, f.regs.sp[-1], &i))
272 0 : THROW();
273 2 : i = ~i;
274 2 : f.regs.sp[-1].setInt32(i);
275 : }
276 :
277 : void JS_FASTCALL
278 453 : stubs::Lsh(VMFrame &f)
279 : {
280 : int32_t i, j;
281 453 : if (!ToInt32(f.cx, f.regs.sp[-2], &i))
282 0 : THROW();
283 453 : if (!ToInt32(f.cx, f.regs.sp[-1], &j))
284 0 : THROW();
285 453 : i = i << (j & 31);
286 453 : f.regs.sp[-2].setInt32(i);
287 : }
288 :
289 : void JS_FASTCALL
290 509 : stubs::Rsh(VMFrame &f)
291 : {
292 : int32_t i, j;
293 509 : if (!ToInt32(f.cx, f.regs.sp[-2], &i))
294 0 : THROW();
295 509 : if (!ToInt32(f.cx, f.regs.sp[-1], &j))
296 0 : THROW();
297 509 : i = i >> (j & 31);
298 509 : f.regs.sp[-2].setInt32(i);
299 : }
300 :
301 : void JS_FASTCALL
302 705 : stubs::Ursh(VMFrame &f)
303 : {
304 : uint32_t u;
305 705 : if (!ToUint32(f.cx, f.regs.sp[-2], &u))
306 0 : THROW();
307 : int32_t j;
308 705 : if (!ToInt32(f.cx, f.regs.sp[-1], &j))
309 0 : THROW();
310 :
311 705 : u >>= (j & 31);
312 :
313 705 : if (!f.regs.sp[-2].setNumber(uint32_t(u)))
314 423 : TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
315 : }
316 :
317 : template<JSBool strict>
318 : void JS_FASTCALL
319 1755 : stubs::DefFun(VMFrame &f, JSFunction *fun)
320 : {
321 : JSObject *obj2;
322 :
323 1755 : JSContext *cx = f.cx;
324 1755 : StackFrame *fp = f.fp();
325 :
326 : /*
327 : * A top-level function defined in Global or Eval code (see ECMA-262
328 : * Ed. 3), or else a SpiderMonkey extension: a named function statement in
329 : * a compound statement (not at the top statement level of global code, or
330 : * at the top level of a function body).
331 : */
332 1755 : JSObject *obj = fun;
333 :
334 1755 : if (fun->isNullClosure()) {
335 : /*
336 : * Even a null closure needs a parent for principals finding.
337 : * FIXME: bug 476950, although debugger users may also demand some kind
338 : * of scope link for debugger-assisted eval-in-frame.
339 : */
340 867 : obj2 = &fp->scopeChain();
341 : } else {
342 888 : JS_ASSERT(!fun->isFlatClosure());
343 :
344 888 : obj2 = GetScopeChain(cx, fp);
345 888 : if (!obj2)
346 0 : THROW();
347 : }
348 :
349 : /*
350 : * If static link is not current scope, clone fun's object to link to the
351 : * current scope via parent. We do this to enable sharing of compiled
352 : * functions among multiple equivalent scopes, amortizing the cost of
353 : * compilation over a number of executions. Examples include XUL scripts
354 : * and event handlers shared among Firefox or other Mozilla app chrome
355 : * windows, and user-defined JS functions precompiled and then shared among
356 : * requests in server-side JS.
357 : */
358 1755 : if (obj->toFunction()->environment() != obj2) {
359 356 : obj = CloneFunctionObjectIfNotSingleton(cx, fun, obj2);
360 356 : if (!obj)
361 0 : THROW();
362 356 : JS_ASSERT_IF(f.script()->compileAndGo, obj->global() == fun->global());
363 : }
364 :
365 : /*
366 : * ECMA requires functions defined when entering Eval code to be
367 : * impermanent.
368 : */
369 : unsigned attrs = fp->isEvalFrame()
370 : ? JSPROP_ENUMERATE
371 1755 : : JSPROP_ENUMERATE | JSPROP_PERMANENT;
372 :
373 : /*
374 : * We define the function as a property of the variable object and not the
375 : * current scope chain even for the case of function expression statements
376 : * and functions defined by eval inside let or with blocks.
377 : */
378 1755 : JSObject *parent = &fp->varObj();
379 :
380 : /* ES5 10.5 (NB: with subsequent errata). */
381 1755 : PropertyName *name = fun->atom->asPropertyName();
382 1755 : JSProperty *prop = NULL;
383 : JSObject *pobj;
384 1755 : if (!parent->lookupProperty(cx, name, &pobj, &prop))
385 0 : THROW();
386 :
387 1755 : Value rval = ObjectValue(*obj);
388 :
389 : do {
390 : /* Steps 5d, 5f. */
391 1755 : if (!prop || pobj != parent) {
392 1115 : if (!parent->defineProperty(cx, name, rval,
393 : JS_PropertyStub, JS_StrictPropertyStub, attrs))
394 : {
395 0 : THROW();
396 : }
397 1115 : break;
398 : }
399 :
400 : /* Step 5e. */
401 640 : JS_ASSERT(parent->isNative());
402 640 : Shape *shape = reinterpret_cast<Shape *>(prop);
403 640 : if (parent->isGlobal()) {
404 475 : if (shape->configurable()) {
405 130 : if (!parent->defineProperty(cx, name, rval,
406 : JS_PropertyStub, JS_StrictPropertyStub, attrs))
407 : {
408 0 : THROW();
409 : }
410 130 : break;
411 : }
412 :
413 345 : if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
414 8 : JSAutoByteString bytes;
415 4 : if (js_AtomToPrintableString(cx, name, &bytes)) {
416 4 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
417 : JSMSG_CANT_REDEFINE_PROP, bytes.ptr());
418 : }
419 4 : THROW();
420 : }
421 : }
422 :
423 : /*
424 : * Non-global properties, and global properties which we aren't simply
425 : * redefining, must be set. First, this preserves their attributes.
426 : * Second, this will produce warnings and/or errors as necessary if the
427 : * specified Call object property is not writable (const).
428 : */
429 :
430 : /* Step 5f. */
431 506 : if (!parent->setProperty(cx, name, &rval, strict))
432 0 : THROW();
433 : } while (false);
434 : }
435 :
436 : template void JS_FASTCALL stubs::DefFun<true>(VMFrame &f, JSFunction *fun);
437 : template void JS_FASTCALL stubs::DefFun<false>(VMFrame &f, JSFunction *fun);
438 :
439 : #define RELATIONAL(OP) \
440 : JS_BEGIN_MACRO \
441 : JSContext *cx = f.cx; \
442 : FrameRegs ®s = f.regs; \
443 : Value &rval = regs.sp[-1]; \
444 : Value &lval = regs.sp[-2]; \
445 : bool cond; \
446 : if (!ToPrimitive(cx, JSTYPE_NUMBER, &lval)) \
447 : THROWV(JS_FALSE); \
448 : if (!ToPrimitive(cx, JSTYPE_NUMBER, &rval)) \
449 : THROWV(JS_FALSE); \
450 : if (lval.isString() && rval.isString()) { \
451 : JSString *l = lval.toString(), *r = rval.toString(); \
452 : int32_t cmp; \
453 : if (!CompareStrings(cx, l, r, &cmp)) \
454 : THROWV(JS_FALSE); \
455 : cond = cmp OP 0; \
456 : } else { \
457 : double l, r; \
458 : if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r)) \
459 : THROWV(JS_FALSE); \
460 : cond = (l OP r); \
461 : } \
462 : regs.sp[-2].setBoolean(cond); \
463 : return cond; \
464 : JS_END_MACRO
465 :
466 : JSBool JS_FASTCALL
467 402822 : stubs::LessThan(VMFrame &f)
468 : {
469 402822 : RELATIONAL(<);
470 : }
471 :
472 : JSBool JS_FASTCALL
473 17849 : stubs::LessEqual(VMFrame &f)
474 : {
475 17849 : RELATIONAL(<=);
476 : }
477 :
478 : JSBool JS_FASTCALL
479 154681 : stubs::GreaterThan(VMFrame &f)
480 : {
481 154681 : RELATIONAL(>);
482 : }
483 :
484 : JSBool JS_FASTCALL
485 17862 : stubs::GreaterEqual(VMFrame &f)
486 : {
487 17862 : RELATIONAL(>=);
488 : }
489 :
490 : JSBool JS_FASTCALL
491 4444661 : stubs::ValueToBoolean(VMFrame &f)
492 : {
493 4444661 : return js_ValueToBoolean(f.regs.sp[-1]);
494 : }
495 :
496 : void JS_FASTCALL
497 299978 : stubs::Not(VMFrame &f)
498 : {
499 299978 : JSBool b = !js_ValueToBoolean(f.regs.sp[-1]);
500 299978 : f.regs.sp[-1].setBoolean(b);
501 299978 : }
502 :
503 : template <bool EQ>
504 : static inline bool
505 2318588 : StubEqualityOp(VMFrame &f)
506 : {
507 2318588 : JSContext *cx = f.cx;
508 2318588 : FrameRegs ®s = f.regs;
509 :
510 2318588 : Value rval = regs.sp[-1];
511 2318588 : Value lval = regs.sp[-2];
512 :
513 : bool cond;
514 :
515 : /* The string==string case is easily the hottest; try it first. */
516 2318588 : if (lval.isString() && rval.isString()) {
517 1919593 : JSString *l = lval.toString();
518 1919593 : JSString *r = rval.toString();
519 : bool equal;
520 1919593 : if (!EqualStrings(cx, l, r, &equal))
521 0 : return false;
522 1919593 : cond = equal == EQ;
523 : } else
524 : #if JS_HAS_XML_SUPPORT
525 398995 : if ((lval.isObject() && lval.toObject().isXML()) ||
526 : (rval.isObject() && rval.toObject().isXML()))
527 : {
528 : JSBool equal;
529 0 : if (!js_TestXMLEquality(cx, lval, rval, &equal))
530 0 : return false;
531 0 : cond = !!equal == EQ;
532 : } else
533 : #endif
534 :
535 398995 : if (SameType(lval, rval)) {
536 310060 : JS_ASSERT(!lval.isString()); /* this case is handled above */
537 310060 : if (lval.isDouble()) {
538 128020 : double l = lval.toDouble();
539 128020 : double r = rval.toDouble();
540 : if (EQ)
541 116941 : cond = (l == r);
542 : else
543 11079 : cond = (l != r);
544 182040 : } else if (lval.isObject()) {
545 35832 : JSObject *l = &lval.toObject(), *r = &rval.toObject();
546 35832 : if (JSEqualityOp eq = l->getClass()->ext.equality) {
547 : JSBool equal;
548 42 : if (!eq(cx, l, &rval, &equal))
549 0 : return false;
550 42 : cond = !!equal == EQ;
551 : } else {
552 35790 : cond = (l == r) == EQ;
553 : }
554 146208 : } else if (lval.isNullOrUndefined()) {
555 98260 : cond = EQ;
556 : } else {
557 47948 : cond = (lval.payloadAsRawUint32() == rval.payloadAsRawUint32()) == EQ;
558 : }
559 : } else {
560 88935 : if (lval.isNullOrUndefined()) {
561 15389 : cond = rval.isNullOrUndefined() == EQ;
562 73546 : } else if (rval.isNullOrUndefined()) {
563 18914 : cond = !EQ;
564 : } else {
565 54632 : if (!ToPrimitive(cx, &lval))
566 4 : return false;
567 54628 : if (!ToPrimitive(cx, &rval))
568 0 : return false;
569 :
570 : /*
571 : * The string==string case is repeated because ToPrimitive can
572 : * convert lval/rval to strings.
573 : */
574 54628 : if (lval.isString() && rval.isString()) {
575 2850 : JSString *l = lval.toString();
576 2850 : JSString *r = rval.toString();
577 : bool equal;
578 2850 : if (!EqualStrings(cx, l, r, &equal))
579 0 : return false;
580 2850 : cond = equal == EQ;
581 : } else {
582 : double l, r;
583 51778 : if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
584 0 : return false;
585 :
586 : if (EQ)
587 28838 : cond = (l == r);
588 : else
589 22940 : cond = (l != r);
590 : }
591 : }
592 : }
593 :
594 2318584 : regs.sp[-2].setBoolean(cond);
595 2318584 : return true;
596 : }
597 :
598 : JSBool JS_FASTCALL
599 663664 : stubs::Equal(VMFrame &f)
600 : {
601 663664 : if (!StubEqualityOp<true>(f))
602 4 : THROWV(JS_FALSE);
603 663660 : return f.regs.sp[-2].toBoolean();
604 : }
605 :
606 : JSBool JS_FASTCALL
607 1654924 : stubs::NotEqual(VMFrame &f)
608 : {
609 1654924 : if (!StubEqualityOp<false>(f))
610 0 : THROWV(JS_FALSE);
611 1654924 : return f.regs.sp[-2].toBoolean();
612 : }
613 :
614 : void JS_FASTCALL
615 18873754 : stubs::Add(VMFrame &f)
616 : {
617 18873754 : JSContext *cx = f.cx;
618 18873754 : FrameRegs ®s = f.regs;
619 18873754 : Value rval = regs.sp[-1];
620 18873754 : Value lval = regs.sp[-2];
621 :
622 : /* The string + string case is easily the hottest; try it first. */
623 18873754 : bool lIsString = lval.isString();
624 18873754 : bool rIsString = rval.isString();
625 : JSString *lstr, *rstr;
626 18873754 : if (lIsString && rIsString) {
627 15592648 : lstr = lval.toString();
628 15592648 : rstr = rval.toString();
629 15592648 : goto string_concat;
630 :
631 : } else
632 : #if JS_HAS_XML_SUPPORT
633 3281106 : if (lval.isObject() && lval.toObject().isXML() &&
634 0 : rval.isObject() && rval.toObject().isXML()) {
635 0 : if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), &rval))
636 0 : THROW();
637 0 : regs.sp[-2] = rval;
638 0 : regs.sp--;
639 0 : TypeScript::MonitorUnknown(cx, f.script(), f.pc());
640 : } else
641 : #endif
642 : {
643 3281106 : bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
644 3281106 : if (!ToPrimitive(f.cx, &lval))
645 16 : THROW();
646 3281090 : if (!ToPrimitive(f.cx, &rval))
647 11 : THROW();
648 3281079 : if ((lIsString = lval.isString()) || (rIsString = rval.isString())) {
649 3000569 : if (lIsString) {
650 2420542 : lstr = lval.toString();
651 : } else {
652 580027 : lstr = ToString(cx, lval);
653 580027 : if (!lstr)
654 0 : THROW();
655 580027 : regs.sp[-2].setString(lstr);
656 : }
657 3000569 : if (rIsString) {
658 582096 : rstr = rval.toString();
659 : } else {
660 2418473 : rstr = ToString(cx, rval);
661 2418473 : if (!rstr)
662 0 : THROW();
663 2418473 : regs.sp[-1].setString(rstr);
664 : }
665 3000569 : if (lIsObject || rIsObject)
666 394405 : TypeScript::MonitorString(cx, f.script(), f.pc());
667 3000569 : goto string_concat;
668 :
669 : } else {
670 : double l, r;
671 280510 : if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
672 0 : THROW();
673 280510 : l += r;
674 837979 : if (!regs.sp[-2].setNumber(l) &&
675 557469 : (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
676 278023 : TypeScript::MonitorOverflow(cx, f.script(), f.pc());
677 : }
678 : }
679 : }
680 280510 : return;
681 :
682 : string_concat:
683 18593217 : JSString *str = js_ConcatStrings(cx, lstr, rstr);
684 18593217 : if (!str)
685 5 : THROW();
686 18593212 : regs.sp[-2].setString(str);
687 18593212 : regs.sp--;
688 : }
689 :
690 :
691 : void JS_FASTCALL
692 213 : stubs::Sub(VMFrame &f)
693 : {
694 213 : JSContext *cx = f.cx;
695 213 : FrameRegs ®s = f.regs;
696 : double d1, d2;
697 213 : if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
698 0 : THROW();
699 213 : double d = d1 - d2;
700 213 : if (!regs.sp[-2].setNumber(d))
701 159 : TypeScript::MonitorOverflow(cx, f.script(), f.pc());
702 : }
703 :
704 : void JS_FASTCALL
705 78369 : stubs::Mul(VMFrame &f)
706 : {
707 78369 : JSContext *cx = f.cx;
708 78369 : FrameRegs ®s = f.regs;
709 : double d1, d2;
710 78369 : if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
711 0 : THROW();
712 78369 : double d = d1 * d2;
713 78369 : if (!regs.sp[-2].setNumber(d))
714 78231 : TypeScript::MonitorOverflow(cx, f.script(), f.pc());
715 : }
716 :
717 : void JS_FASTCALL
718 739 : stubs::Div(VMFrame &f)
719 : {
720 739 : JSContext *cx = f.cx;
721 739 : JSRuntime *rt = cx->runtime;
722 739 : FrameRegs ®s = f.regs;
723 :
724 : double d1, d2;
725 739 : if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
726 0 : THROW();
727 739 : if (d2 == 0) {
728 : const Value *vp;
729 : #ifdef XP_WIN
730 : /* XXX MSVC miscompiles such that (NaN == 0) */
731 : if (JSDOUBLE_IS_NaN(d2))
732 : vp = &rt->NaNValue;
733 : else
734 : #endif
735 11 : if (d1 == 0 || JSDOUBLE_IS_NaN(d1))
736 2 : vp = &rt->NaNValue;
737 9 : else if (JSDOUBLE_IS_NEG(d1) != JSDOUBLE_IS_NEG(d2))
738 0 : vp = &rt->negativeInfinityValue;
739 : else
740 9 : vp = &rt->positiveInfinityValue;
741 11 : regs.sp[-2] = *vp;
742 11 : TypeScript::MonitorOverflow(cx, f.script(), f.pc());
743 : } else {
744 728 : d1 /= d2;
745 728 : if (!regs.sp[-2].setNumber(d1))
746 22 : TypeScript::MonitorOverflow(cx, f.script(), f.pc());
747 : }
748 : }
749 :
750 : void JS_FASTCALL
751 30492 : stubs::Mod(VMFrame &f)
752 : {
753 30492 : JSContext *cx = f.cx;
754 30492 : FrameRegs ®s = f.regs;
755 :
756 30492 : Value &lref = regs.sp[-2];
757 30492 : Value &rref = regs.sp[-1];
758 : int32_t l, r;
759 30492 : if (lref.isInt32() && rref.isInt32() &&
760 : (l = lref.toInt32()) >= 0 && (r = rref.toInt32()) > 0) {
761 0 : int32_t mod = l % r;
762 0 : regs.sp[-2].setInt32(mod);
763 : } else {
764 : double d1, d2;
765 30492 : if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
766 0 : THROW();
767 30492 : if (d2 == 0) {
768 97 : regs.sp[-2].setDouble(js_NaN);
769 : } else {
770 30395 : d1 = js_fmod(d1, d2);
771 30395 : regs.sp[-2].setDouble(d1);
772 : }
773 30492 : TypeScript::MonitorOverflow(cx, f.script(), f.pc());
774 : }
775 : }
776 :
777 : void JS_FASTCALL
778 3378 : stubs::DebuggerStatement(VMFrame &f, jsbytecode *pc)
779 : {
780 3378 : JSDebuggerHandler handler = f.cx->runtime->debugHooks.debuggerHandler;
781 3378 : if (handler || !f.cx->compartment->getDebuggees().empty()) {
782 3348 : JSTrapStatus st = JSTRAP_CONTINUE;
783 : Value rval;
784 3348 : if (handler)
785 8 : st = handler(f.cx, f.script(), pc, &rval, f.cx->runtime->debugHooks.debuggerHandlerData);
786 3348 : if (st == JSTRAP_CONTINUE)
787 3344 : st = Debugger::onDebuggerStatement(f.cx, &rval);
788 :
789 3348 : switch (st) {
790 : case JSTRAP_THROW:
791 60 : f.cx->setPendingException(rval);
792 60 : THROW();
793 :
794 : case JSTRAP_RETURN:
795 112 : f.cx->clearPendingException();
796 112 : f.cx->fp()->setReturnValue(rval);
797 112 : *f.returnAddressLocation() = f.cx->jaegerCompartment()->forceReturnFromFastCall();
798 112 : break;
799 :
800 : case JSTRAP_ERROR:
801 80 : f.cx->clearPendingException();
802 80 : THROW();
803 :
804 : default:
805 3096 : break;
806 : }
807 : }
808 : }
809 :
810 : void JS_FASTCALL
811 878 : stubs::Interrupt(VMFrame &f, jsbytecode *pc)
812 : {
813 878 : gc::MaybeVerifyBarriers(f.cx);
814 :
815 878 : if (!js_HandleExecutionInterrupt(f.cx))
816 0 : THROW();
817 : }
818 :
819 : void JS_FASTCALL
820 93 : stubs::RecompileForInline(VMFrame &f)
821 : {
822 93 : ExpandInlineFrames(f.cx->compartment);
823 : Recompiler::clearStackReferencesAndChunk(f.cx, f.script(), f.jit(), f.chunkIndex(),
824 93 : /* resetUses = */ false);
825 93 : }
826 :
827 : void JS_FASTCALL
828 594 : stubs::Trap(VMFrame &f, uint32_t trapTypes)
829 : {
830 : Value rval;
831 :
832 : /*
833 : * Trap may be called for a single-step interrupt trap and/or a
834 : * regular trap. Try the single-step first, and if it lets control
835 : * flow through or does not exist, do the regular trap.
836 : */
837 594 : JSTrapStatus result = JSTRAP_CONTINUE;
838 594 : if (trapTypes & JSTRAP_SINGLESTEP) {
839 : /*
840 : * single step mode may be paused without recompiling by
841 : * setting the interruptHook to NULL.
842 : */
843 299 : JSInterruptHook hook = f.cx->runtime->debugHooks.interruptHook;
844 299 : if (hook)
845 0 : result = hook(f.cx, f.script(), f.pc(), &rval, f.cx->runtime->debugHooks.interruptHookData);
846 :
847 299 : if (result == JSTRAP_CONTINUE)
848 299 : result = Debugger::onSingleStep(f.cx, &rval);
849 : }
850 :
851 594 : if (result == JSTRAP_CONTINUE && (trapTypes & JSTRAP_TRAP))
852 295 : result = Debugger::onTrap(f.cx, &rval);
853 :
854 594 : switch (result) {
855 : case JSTRAP_THROW:
856 0 : f.cx->setPendingException(rval);
857 0 : THROW();
858 :
859 : case JSTRAP_RETURN:
860 24 : f.cx->clearPendingException();
861 24 : f.cx->fp()->setReturnValue(rval);
862 24 : *f.returnAddressLocation() = f.cx->jaegerCompartment()->forceReturnFromFastCall();
863 24 : break;
864 :
865 : case JSTRAP_ERROR:
866 4 : f.cx->clearPendingException();
867 4 : THROW();
868 :
869 : default:
870 566 : break;
871 : }
872 : }
873 :
874 : void JS_FASTCALL
875 40583 : stubs::This(VMFrame &f)
876 : {
877 : /*
878 : * We can't yet inline scripts which need to compute their 'this' object
879 : * from a primitive; the frame we are computing 'this' for does not exist yet.
880 : */
881 40583 : if (f.regs.inlined()) {
882 0 : f.script()->uninlineable = true;
883 0 : MarkTypeObjectFlags(f.cx, &f.fp()->callee(), OBJECT_FLAG_UNINLINEABLE);
884 : }
885 :
886 40583 : if (!ComputeThis(f.cx, f.fp()))
887 0 : THROW();
888 40583 : f.regs.sp[-1] = f.fp()->thisValue();
889 : }
890 :
891 : void JS_FASTCALL
892 1915 : stubs::Neg(VMFrame &f)
893 : {
894 : double d;
895 1915 : if (!ToNumber(f.cx, f.regs.sp[-1], &d))
896 0 : THROW();
897 1915 : d = -d;
898 1915 : if (!f.regs.sp[-1].setNumber(d))
899 1855 : TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
900 : }
901 :
902 : void JS_FASTCALL
903 1256740 : stubs::NewInitArray(VMFrame &f, uint32_t count)
904 : {
905 1256740 : JSObject *obj = NewDenseAllocatedArray(f.cx, count);
906 1256740 : if (!obj)
907 0 : THROW();
908 :
909 1256740 : TypeObject *type = (TypeObject *) f.scratch;
910 1256740 : if (type)
911 1207426 : obj->setType(type);
912 :
913 1256740 : f.regs.sp[0].setObject(*obj);
914 : }
915 :
916 : void JS_FASTCALL
917 1573985 : stubs::NewInitObject(VMFrame &f, JSObject *baseobj)
918 : {
919 1573985 : JSContext *cx = f.cx;
920 1573985 : TypeObject *type = (TypeObject *) f.scratch;
921 :
922 1573985 : if (!baseobj) {
923 22883 : gc::AllocKind kind = GuessObjectGCKind(0);
924 22883 : JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
925 22883 : if (!obj)
926 0 : THROW();
927 22883 : if (type)
928 395 : obj->setType(type);
929 22883 : f.regs.sp[0].setObject(*obj);
930 22883 : return;
931 : }
932 :
933 1551102 : JS_ASSERT(type);
934 1551102 : JSObject *obj = CopyInitializerObject(cx, baseobj, type);
935 :
936 1551102 : if (!obj)
937 0 : THROW();
938 1551102 : f.regs.sp[0].setObject(*obj);
939 : }
940 :
941 : void JS_FASTCALL
942 1316 : stubs::InitElem(VMFrame &f, uint32_t last)
943 : {
944 1316 : JSContext *cx = f.cx;
945 1316 : FrameRegs ®s = f.regs;
946 :
947 : /* Pop the element's value into rval. */
948 1316 : JS_ASSERT(regs.sp - f.fp()->base() >= 3);
949 1316 : const Value &rref = regs.sp[-1];
950 :
951 : /* Find the object being initialized at top of stack. */
952 1316 : const Value &lref = regs.sp[-3];
953 1316 : JS_ASSERT(lref.isObject());
954 1316 : JSObject *obj = &lref.toObject();
955 :
956 : /* Fetch id now that we have obj. */
957 : jsid id;
958 1316 : const Value &idval = regs.sp[-2];
959 1316 : if (!FetchElementId(f.cx, obj, idval, id, ®s.sp[-2]))
960 0 : THROW();
961 :
962 : /*
963 : * If rref is a hole, do not call JSObject::defineProperty. In this case,
964 : * obj must be an array, so if the current op is the last element
965 : * initialiser, set the array length to one greater than id.
966 : */
967 1316 : if (rref.isMagic(JS_ARRAY_HOLE)) {
968 0 : JS_ASSERT(obj->isArray());
969 0 : JS_ASSERT(JSID_IS_INT(id));
970 0 : JS_ASSERT(uint32_t(JSID_TO_INT(id)) < StackSpace::ARGS_LENGTH_MAX);
971 0 : if (last && !js_SetLengthProperty(cx, obj, (uint32_t) (JSID_TO_INT(id) + 1)))
972 0 : THROW();
973 : } else {
974 1316 : if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
975 0 : THROW();
976 : }
977 : }
978 :
979 : void JS_FASTCALL
980 0 : stubs::GetUpvar(VMFrame &f, uint32_t ck)
981 : {
982 : /* :FIXME: We can do better, this stub isn't needed. */
983 0 : uint32_t staticLevel = f.script()->staticLevel;
984 : UpvarCookie cookie;
985 0 : cookie.fromInteger(ck);
986 0 : f.regs.sp[0] = GetUpvar(f.cx, staticLevel, cookie);
987 0 : }
988 :
989 : JSObject * JS_FASTCALL
990 207700 : stubs::DefLocalFun(VMFrame &f, JSFunction *fun)
991 : {
992 : /*
993 : * Define a local function (i.e., one nested at the top level of another
994 : * function), parented by the current scope chain, stored in a local
995 : * variable slot that the compiler allocated. This is an optimization over
996 : * JSOP_DEFFUN that avoids requiring a call object for the outer function's
997 : * activation.
998 : */
999 207700 : JS_ASSERT(fun->isInterpreted());
1000 207700 : JS_ASSERT(!fun->isFlatClosure());
1001 :
1002 : JSObject *parent;
1003 207700 : if (fun->isNullClosure()) {
1004 2959 : parent = &f.fp()->scopeChain();
1005 : } else {
1006 204741 : parent = GetScopeChain(f.cx, f.fp());
1007 204741 : if (!parent)
1008 0 : THROWV(NULL);
1009 : }
1010 207700 : JSObject *obj = CloneFunctionObjectIfNotSingleton(f.cx, fun, parent);
1011 207700 : if (!obj)
1012 0 : THROWV(NULL);
1013 :
1014 207700 : JS_ASSERT_IF(f.script()->compileAndGo, obj->global() == fun->global());
1015 :
1016 207700 : return obj;
1017 : }
1018 :
1019 : JSObject * JS_FASTCALL
1020 7182 : stubs::DefLocalFun_FC(VMFrame &f, JSFunction *fun)
1021 : {
1022 7182 : JSObject *obj = js_NewFlatClosure(f.cx, fun);
1023 7182 : if (!obj)
1024 0 : THROWV(NULL);
1025 7182 : return obj;
1026 : }
1027 :
1028 : void JS_FASTCALL
1029 347887 : stubs::RegExp(VMFrame &f, JSObject *regex)
1030 : {
1031 : /*
1032 : * Push a regexp object cloned from the regexp literal object mapped by the
1033 : * bytecode at pc.
1034 : */
1035 347887 : JSObject *proto = f.fp()->scopeChain().global().getOrCreateRegExpPrototype(f.cx);
1036 347887 : if (!proto)
1037 0 : THROW();
1038 347887 : JS_ASSERT(proto);
1039 347887 : JSObject *obj = CloneRegExpObject(f.cx, regex, proto);
1040 347887 : if (!obj)
1041 0 : THROW();
1042 347887 : f.regs.sp[0].setObject(*obj);
1043 : }
1044 :
1045 : JSObject * JS_FASTCALL
1046 0 : stubs::LambdaJoinableForInit(VMFrame &f, JSFunction *fun)
1047 : {
1048 0 : JS_ASSERT(fun->joinable());
1049 0 : DebugOnly<jsbytecode*> nextpc = f.regs.pc + JSOP_LAMBDA_LENGTH;
1050 0 : JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_UINT32_INDEX(nextpc)));
1051 0 : return fun;
1052 : }
1053 :
1054 : JSObject * JS_FASTCALL
1055 0 : stubs::LambdaJoinableForSet(VMFrame &f, JSFunction *fun)
1056 : {
1057 0 : JS_ASSERT(fun->joinable());
1058 0 : const Value &lref = f.regs.sp[-1];
1059 0 : if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) {
1060 0 : DebugOnly<jsbytecode*> nextpc = f.regs.pc + JSOP_LAMBDA_LENGTH;
1061 0 : JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_UINT32_INDEX(nextpc)));
1062 0 : return fun;
1063 : }
1064 0 : return Lambda(f, fun);
1065 : }
1066 :
1067 : JSObject * JS_FASTCALL
1068 0 : stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *fun)
1069 : {
1070 0 : JS_ASSERT(fun->joinable());
1071 :
1072 : /*
1073 : * Array.prototype.sort and String.prototype.replace are optimized as if
1074 : * they are special form. We know that they won't leak the joined function
1075 : * object fun, therefore we don't need to clone that compiler-created
1076 : * function object for identity/mutation reasons.
1077 : */
1078 0 : int iargc = GET_ARGC(f.regs.pc + JSOP_LAMBDA_LENGTH);
1079 :
1080 : /*
1081 : * Note that we have not yet pushed fun as the final argument, so
1082 : * regs.sp[1 - (iargc + 2)], and not regs.sp[-(iargc + 2)], is the callee
1083 : * for this JSOP_CALL.
1084 : */
1085 0 : const Value &cref = f.regs.sp[1 - (iargc + 2)];
1086 : JSFunction *callee;
1087 :
1088 0 : if (IsFunctionObject(cref, &callee)) {
1089 0 : Native native = callee->maybeNative();
1090 :
1091 0 : if (native) {
1092 0 : if (iargc == 1 && native == array_sort)
1093 0 : return fun;
1094 0 : if (iargc == 2 && native == str_replace)
1095 0 : return fun;
1096 : }
1097 : }
1098 0 : return Lambda(f, fun);
1099 : }
1100 :
1101 : JSObject * JS_FASTCALL
1102 0 : stubs::LambdaJoinableForNull(VMFrame &f, JSFunction *fun)
1103 : {
1104 0 : JS_ASSERT(fun->joinable());
1105 0 : return fun;
1106 : }
1107 :
1108 : JSObject * JS_FASTCALL
1109 305808 : stubs::Lambda(VMFrame &f, JSFunction *fun)
1110 : {
1111 : JSObject *parent;
1112 305808 : if (fun->isNullClosure()) {
1113 221995 : parent = &f.fp()->scopeChain();
1114 : } else {
1115 83813 : parent = GetScopeChain(f.cx, f.fp());
1116 83813 : if (!parent)
1117 0 : THROWV(NULL);
1118 : }
1119 :
1120 305808 : JSObject *obj = CloneFunctionObjectIfNotSingleton(f.cx, fun, parent);
1121 305808 : if (!obj)
1122 0 : THROWV(NULL);
1123 :
1124 305808 : JS_ASSERT_IF(f.script()->compileAndGo, obj->global() == fun->global());
1125 305808 : return obj;
1126 : }
1127 :
1128 : void JS_FASTCALL
1129 5184112 : stubs::GetProp(VMFrame &f, PropertyName *name)
1130 : {
1131 5184112 : JSContext *cx = f.cx;
1132 5184112 : FrameRegs ®s = f.regs;
1133 :
1134 : Value rval;
1135 5184112 : if (!GetPropertyOperation(cx, f.pc(), f.regs.sp[-1], &rval))
1136 19 : THROW();
1137 :
1138 5184093 : regs.sp[-1] = rval;
1139 : }
1140 :
1141 : void JS_FASTCALL
1142 0 : stubs::GetPropNoCache(VMFrame &f, PropertyName *name)
1143 : {
1144 0 : JSContext *cx = f.cx;
1145 0 : FrameRegs ®s = f.regs;
1146 :
1147 0 : const Value &lval = f.regs.sp[-1];
1148 :
1149 : // Uncached lookups are only used for .prototype accesses at the start of constructors.
1150 0 : JS_ASSERT(lval.isObject());
1151 0 : JS_ASSERT(name == cx->runtime->atomState.classPrototypeAtom);
1152 :
1153 0 : JSObject *obj = &lval.toObject();
1154 :
1155 : Value rval;
1156 0 : if (!obj->getProperty(cx, name, &rval))
1157 0 : THROW();
1158 :
1159 0 : regs.sp[-1] = rval;
1160 : }
1161 :
1162 : void JS_FASTCALL
1163 306710 : stubs::Iter(VMFrame &f, uint32_t flags)
1164 : {
1165 306710 : if (!ValueToIterator(f.cx, flags, &f.regs.sp[-1]))
1166 57 : THROW();
1167 306653 : JS_ASSERT(!f.regs.sp[-1].isPrimitive());
1168 : }
1169 :
1170 : static void
1171 15740 : InitPropOrMethod(VMFrame &f, PropertyName *name, JSOp op)
1172 : {
1173 15740 : JSContext *cx = f.cx;
1174 15740 : FrameRegs ®s = f.regs;
1175 :
1176 : /* Load the property's initial value into rval. */
1177 15740 : JS_ASSERT(regs.sp - f.fp()->base() >= 2);
1178 : Value rval;
1179 15740 : rval = regs.sp[-1];
1180 :
1181 : /* Load the object being initialized into lval/obj. */
1182 15740 : JSObject *obj = ®s.sp[-2].toObject();
1183 15740 : JS_ASSERT(obj->isNative());
1184 :
1185 : /* Get the immediate property name into id. */
1186 15740 : jsid id = ATOM_TO_JSID(name);
1187 :
1188 15740 : unsigned defineHow = (op == JSOP_INITMETHOD) ? DNP_SET_METHOD : 0;
1189 31480 : if (JS_UNLIKELY(name == cx->runtime->atomState.protoAtom)
1190 61 : ? !js_SetPropertyHelper(cx, obj, id, defineHow, &rval, false)
1191 : : !DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
1192 15679 : JSPROP_ENUMERATE, 0, 0, defineHow)) {
1193 0 : THROW();
1194 : }
1195 : }
1196 :
1197 : void JS_FASTCALL
1198 15740 : stubs::InitProp(VMFrame &f, PropertyName *name)
1199 : {
1200 15740 : InitPropOrMethod(f, name, JSOP_INITPROP);
1201 15740 : }
1202 :
1203 : void JS_FASTCALL
1204 0 : stubs::InitMethod(VMFrame &f, PropertyName *name)
1205 : {
1206 0 : InitPropOrMethod(f, name, JSOP_INITMETHOD);
1207 0 : }
1208 :
1209 : void JS_FASTCALL
1210 9090683 : stubs::IterNext(VMFrame &f, int32_t offset)
1211 : {
1212 9090683 : JS_ASSERT(f.regs.sp - offset >= f.fp()->base());
1213 9090683 : JS_ASSERT(f.regs.sp[-offset].isObject());
1214 :
1215 9090683 : JSObject *iterobj = &f.regs.sp[-offset].toObject();
1216 9090683 : f.regs.sp[0].setNull();
1217 9090683 : f.regs.sp++;
1218 9090683 : if (!js_IteratorNext(f.cx, iterobj, &f.regs.sp[-1]))
1219 0 : THROW();
1220 : }
1221 :
1222 : JSBool JS_FASTCALL
1223 9207390 : stubs::IterMore(VMFrame &f)
1224 : {
1225 9207390 : JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
1226 9207390 : JS_ASSERT(f.regs.sp[-1].isObject());
1227 :
1228 : Value v;
1229 9207390 : JSObject *iterobj = &f.regs.sp[-1].toObject();
1230 9207390 : if (!js_IteratorMore(f.cx, iterobj, &v))
1231 12 : THROWV(JS_FALSE);
1232 :
1233 9207378 : return v.toBoolean();
1234 : }
1235 :
1236 : void JS_FASTCALL
1237 1187 : stubs::EndIter(VMFrame &f)
1238 : {
1239 1187 : JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
1240 1187 : if (!CloseIterator(f.cx, &f.regs.sp[-1].toObject()))
1241 0 : THROW();
1242 : }
1243 :
1244 : JSString * JS_FASTCALL
1245 70160 : stubs::TypeOf(VMFrame &f)
1246 : {
1247 70160 : const Value &ref = f.regs.sp[-1];
1248 70160 : JSType type = JS_TypeOfValue(f.cx, ref);
1249 70160 : return f.cx->runtime->atomState.typeAtoms[type];
1250 : }
1251 :
1252 : void JS_FASTCALL
1253 730550 : stubs::StrictEq(VMFrame &f)
1254 : {
1255 730550 : const Value &rhs = f.regs.sp[-1];
1256 730550 : const Value &lhs = f.regs.sp[-2];
1257 : bool equal;
1258 730550 : if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
1259 0 : THROW();
1260 730550 : f.regs.sp--;
1261 730550 : f.regs.sp[-1].setBoolean(equal == JS_TRUE);
1262 : }
1263 :
1264 : void JS_FASTCALL
1265 240223 : stubs::StrictNe(VMFrame &f)
1266 : {
1267 240223 : const Value &rhs = f.regs.sp[-1];
1268 240223 : const Value &lhs = f.regs.sp[-2];
1269 : bool equal;
1270 240223 : if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
1271 0 : THROW();
1272 240223 : f.regs.sp--;
1273 240223 : f.regs.sp[-1].setBoolean(equal != JS_TRUE);
1274 : }
1275 :
1276 : void JS_FASTCALL
1277 1042 : stubs::Throw(VMFrame &f)
1278 : {
1279 1042 : JSContext *cx = f.cx;
1280 :
1281 1042 : JS_ASSERT(!cx->isExceptionPending());
1282 1042 : cx->setPendingException(f.regs.sp[-1]);
1283 1042 : THROW();
1284 : }
1285 :
1286 : JSObject * JS_FASTCALL
1287 244438 : stubs::FlatLambda(VMFrame &f, JSFunction *fun)
1288 : {
1289 244438 : JSObject *obj = js_NewFlatClosure(f.cx, fun);
1290 244438 : if (!obj)
1291 0 : THROWV(NULL);
1292 244438 : return obj;
1293 : }
1294 :
1295 : void JS_FASTCALL
1296 428382 : stubs::Arguments(VMFrame &f)
1297 : {
1298 428382 : ArgumentsObject *arguments = js_GetArgsObject(f.cx, f.fp());
1299 428382 : if (!arguments)
1300 0 : THROW();
1301 428382 : f.regs.sp[0] = ObjectValue(*arguments);
1302 : }
1303 :
1304 : JSBool JS_FASTCALL
1305 91701 : stubs::InstanceOf(VMFrame &f)
1306 : {
1307 91701 : JSContext *cx = f.cx;
1308 91701 : FrameRegs ®s = f.regs;
1309 :
1310 91701 : const Value &rref = regs.sp[-1];
1311 91701 : if (rref.isPrimitive()) {
1312 : js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
1313 0 : -1, rref, NULL);
1314 0 : THROWV(JS_FALSE);
1315 : }
1316 91701 : JSObject *obj = &rref.toObject();
1317 91701 : const Value &lref = regs.sp[-2];
1318 91701 : JSBool cond = JS_FALSE;
1319 91701 : if (!HasInstance(cx, obj, &lref, &cond))
1320 6 : THROWV(JS_FALSE);
1321 91695 : f.regs.sp[-2].setBoolean(cond);
1322 91695 : return cond;
1323 : }
1324 :
1325 : void JS_FASTCALL
1326 2 : stubs::FastInstanceOf(VMFrame &f)
1327 : {
1328 2 : const Value &lref = f.regs.sp[-1];
1329 :
1330 2 : if (lref.isPrimitive()) {
1331 : /*
1332 : * Throw a runtime error if instanceof is called on a function that
1333 : * has a non-object as its .prototype value.
1334 : */
1335 2 : js_ReportValueError(f.cx, JSMSG_BAD_PROTOTYPE, -1, f.regs.sp[-2], NULL);
1336 2 : THROW();
1337 : }
1338 :
1339 0 : f.regs.sp[-3].setBoolean(js_IsDelegate(f.cx, &lref.toObject(), f.regs.sp[-3]));
1340 : }
1341 :
1342 : void JS_FASTCALL
1343 246072 : stubs::EnterBlock(VMFrame &f, JSObject *obj)
1344 : {
1345 246072 : FrameRegs ®s = f.regs;
1346 246072 : StackFrame *fp = f.fp();
1347 246072 : StaticBlockObject &blockObj = obj->asStaticBlock();
1348 :
1349 246072 : JS_ASSERT(!f.regs.inlined());
1350 :
1351 246072 : if (*regs.pc == JSOP_ENTERBLOCK) {
1352 164469 : JS_ASSERT(fp->base() + blockObj.stackDepth() == regs.sp);
1353 164469 : Value *vp = regs.sp + blockObj.slotCount();
1354 164469 : JS_ASSERT(regs.sp < vp);
1355 164469 : JS_ASSERT(vp <= fp->slots() + fp->script()->nslots);
1356 164469 : SetValueRangeToUndefined(regs.sp, vp);
1357 164469 : regs.sp = vp;
1358 : }
1359 :
1360 : #ifdef DEBUG
1361 246072 : JSContext *cx = f.cx;
1362 246072 : JS_ASSERT(fp->maybeBlockChain() == blockObj.enclosingBlock());
1363 :
1364 : /*
1365 : * The young end of fp->scopeChain() may omit blocks if we haven't closed
1366 : * over them, but if there are any closure blocks on fp->scopeChain(), they'd
1367 : * better be (clones of) ancestors of the block we're entering now;
1368 : * anything else we should have popped off fp->scopeChain() when we left its
1369 : * static scope.
1370 : */
1371 246072 : JSObject *obj2 = &fp->scopeChain();
1372 492144 : while (obj2->isWith())
1373 0 : obj2 = &obj2->asWith().enclosingScope();
1374 249143 : if (obj2->isBlock() &&
1375 3071 : obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, fp)) {
1376 985 : JSObject &youngestProto = obj2->asClonedBlock().staticBlock();
1377 985 : StaticBlockObject *parent = &blockObj;
1378 1970 : while ((parent = parent->enclosingBlock()) != &youngestProto)
1379 0 : JS_ASSERT(parent);
1380 : }
1381 : #endif
1382 :
1383 246072 : fp->setBlockChain(&blockObj);
1384 246072 : }
1385 :
1386 : void JS_FASTCALL
1387 246744 : stubs::LeaveBlock(VMFrame &f)
1388 : {
1389 246744 : JSContext *cx = f.cx;
1390 246744 : StackFrame *fp = f.fp();
1391 :
1392 246744 : StaticBlockObject &blockObj = fp->blockChain();
1393 246744 : JS_ASSERT(blockObj.stackDepth() <= StackDepth(fp->script()));
1394 :
1395 : /*
1396 : * If we're about to leave the dynamic scope of a block that has been
1397 : * cloned onto fp->scopeChain(), clear its private data, move its locals from
1398 : * the stack into the clone, and pop it off the chain.
1399 : */
1400 246744 : JSObject &obj = fp->scopeChain();
1401 246744 : if (obj.getProto() == &blockObj)
1402 1328 : obj.asClonedBlock().put(cx);
1403 :
1404 246744 : fp->setBlockChain(blockObj.enclosingBlock());
1405 246744 : }
1406 :
1407 : inline void *
1408 6789 : FindNativeCode(VMFrame &f, jsbytecode *target)
1409 : {
1410 6789 : void* native = f.fp()->script()->nativeCodeForPC(f.fp()->isConstructing(), target);
1411 6789 : if (native)
1412 6789 : return native;
1413 :
1414 0 : uint32_t sourceOffset = f.pc() - f.script()->code;
1415 0 : uint32_t targetOffset = target - f.script()->code;
1416 :
1417 0 : CrossChunkEdge *edges = f.jit()->edges();
1418 0 : for (size_t i = 0; i < f.jit()->nedges; i++) {
1419 0 : const CrossChunkEdge &edge = edges[i];
1420 0 : if (edge.source == sourceOffset && edge.target == targetOffset)
1421 0 : return edge.shimLabel;
1422 : }
1423 :
1424 0 : JS_NOT_REACHED("Missing edge");
1425 : return NULL;
1426 : }
1427 :
1428 : void * JS_FASTCALL
1429 6111 : stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
1430 : {
1431 6111 : jsbytecode *jpc = pc;
1432 6111 : JSScript *script = f.fp()->script();
1433 :
1434 : /* This is correct because the compiler adjusts the stack beforehand. */
1435 6111 : Value lval = f.regs.sp[-1];
1436 :
1437 6111 : if (!lval.isPrimitive())
1438 0 : return FindNativeCode(f, pc + GET_JUMP_OFFSET(pc));
1439 :
1440 6111 : JS_ASSERT(pc[0] == JSOP_LOOKUPSWITCH);
1441 :
1442 6111 : pc += JUMP_OFFSET_LEN;
1443 6111 : uint32_t npairs = GET_UINT16(pc);
1444 6111 : pc += UINT16_LEN;
1445 :
1446 6111 : JS_ASSERT(npairs);
1447 :
1448 6111 : if (lval.isString()) {
1449 5696 : JSLinearString *str = lval.toString()->ensureLinear(f.cx);
1450 5696 : if (!str)
1451 0 : THROWV(NULL);
1452 35885 : for (uint32_t i = 1; i <= npairs; i++) {
1453 34397 : Value rval = script->getConst(GET_UINT32_INDEX(pc));
1454 34397 : pc += UINT32_INDEX_LEN;
1455 34397 : if (rval.isString()) {
1456 34397 : JSLinearString *rhs = &rval.toString()->asLinear();
1457 34397 : if (rhs == str || EqualStrings(str, rhs))
1458 4208 : return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
1459 : }
1460 30189 : pc += JUMP_OFFSET_LEN;
1461 : }
1462 415 : } else if (lval.isNumber()) {
1463 0 : double d = lval.toNumber();
1464 0 : for (uint32_t i = 1; i <= npairs; i++) {
1465 0 : Value rval = script->getConst(GET_UINT32_INDEX(pc));
1466 0 : pc += UINT32_INDEX_LEN;
1467 0 : if (rval.isNumber() && d == rval.toNumber())
1468 0 : return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
1469 0 : pc += JUMP_OFFSET_LEN;
1470 : }
1471 : } else {
1472 1310 : for (uint32_t i = 1; i <= npairs; i++) {
1473 895 : Value rval = script->getConst(GET_UINT32_INDEX(pc));
1474 895 : pc += UINT32_INDEX_LEN;
1475 895 : if (lval == rval)
1476 0 : return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
1477 895 : pc += JUMP_OFFSET_LEN;
1478 : }
1479 : }
1480 :
1481 1903 : return FindNativeCode(f, jpc + GET_JUMP_OFFSET(jpc));
1482 : }
1483 :
1484 : void * JS_FASTCALL
1485 678 : stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
1486 : {
1487 678 : jsbytecode * const originalPC = origPc;
1488 :
1489 1356 : DebugOnly<JSOp> op = JSOp(*originalPC);
1490 678 : JS_ASSERT(op == JSOP_TABLESWITCH);
1491 :
1492 678 : uint32_t jumpOffset = GET_JUMP_OFFSET(originalPC);
1493 678 : jsbytecode *pc = originalPC + JUMP_OFFSET_LEN;
1494 :
1495 : /* Note: compiler adjusts the stack beforehand. */
1496 678 : Value rval = f.regs.sp[-1];
1497 :
1498 : int32_t tableIdx;
1499 678 : if (rval.isInt32()) {
1500 0 : tableIdx = rval.toInt32();
1501 678 : } else if (rval.isDouble()) {
1502 199 : double d = rval.toDouble();
1503 199 : if (d == 0) {
1504 : /* Treat -0 (double) as 0. */
1505 93 : tableIdx = 0;
1506 106 : } else if (!JSDOUBLE_IS_INT32(d, &tableIdx)) {
1507 88 : goto finally;
1508 : }
1509 : } else {
1510 479 : goto finally;
1511 : }
1512 :
1513 : {
1514 111 : int32_t low = GET_JUMP_OFFSET(pc);
1515 111 : pc += JUMP_OFFSET_LEN;
1516 111 : int32_t high = GET_JUMP_OFFSET(pc);
1517 111 : pc += JUMP_OFFSET_LEN;
1518 :
1519 111 : tableIdx -= low;
1520 111 : if ((uint32_t) tableIdx < (uint32_t)(high - low + 1)) {
1521 69 : pc += JUMP_OFFSET_LEN * tableIdx;
1522 69 : if (uint32_t candidateOffset = GET_JUMP_OFFSET(pc))
1523 69 : jumpOffset = candidateOffset;
1524 : }
1525 : }
1526 :
1527 : finally:
1528 : /* Provide the native address. */
1529 678 : return FindNativeCode(f, originalPC + jumpOffset);
1530 : }
1531 :
1532 : void JS_FASTCALL
1533 1105 : stubs::Pos(VMFrame &f)
1534 : {
1535 1105 : if (!ToNumber(f.cx, &f.regs.sp[-1]))
1536 0 : THROW();
1537 1105 : if (!f.regs.sp[-1].isInt32())
1538 436 : TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
1539 : }
1540 :
1541 : void JS_FASTCALL
1542 137 : stubs::DelName(VMFrame &f, PropertyName *name)
1543 : {
1544 : JSObject *obj, *obj2;
1545 : JSProperty *prop;
1546 137 : if (!FindProperty(f.cx, name, f.cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
1547 0 : THROW();
1548 :
1549 : /* Strict mode code should never contain JSOP_DELNAME opcodes. */
1550 137 : JS_ASSERT(!f.script()->strictModeCode);
1551 :
1552 : /* ECMA says to return true if name is undefined or inherited. */
1553 137 : f.regs.sp++;
1554 137 : f.regs.sp[-1] = BooleanValue(true);
1555 137 : if (prop) {
1556 85 : if (!obj->deleteProperty(f.cx, name, &f.regs.sp[-1], false))
1557 0 : THROW();
1558 : }
1559 : }
1560 :
1561 : template<JSBool strict>
1562 : void JS_FASTCALL
1563 653 : stubs::DelProp(VMFrame &f, PropertyName *name)
1564 : {
1565 653 : JSContext *cx = f.cx;
1566 :
1567 653 : JSObject *obj = ValueToObject(cx, f.regs.sp[-1]);
1568 653 : if (!obj)
1569 0 : THROW();
1570 :
1571 : Value rval;
1572 653 : if (!obj->deleteProperty(cx, name, &rval, strict))
1573 0 : THROW();
1574 :
1575 653 : f.regs.sp[-1] = rval;
1576 : }
1577 :
1578 : template void JS_FASTCALL stubs::DelProp<true>(VMFrame &f, PropertyName *name);
1579 : template void JS_FASTCALL stubs::DelProp<false>(VMFrame &f, PropertyName *name);
1580 :
1581 : template<JSBool strict>
1582 : void JS_FASTCALL
1583 1631 : stubs::DelElem(VMFrame &f)
1584 : {
1585 1631 : JSContext *cx = f.cx;
1586 :
1587 1631 : JSObject *obj = ValueToObject(cx, f.regs.sp[-2]);
1588 1631 : if (!obj)
1589 0 : THROW();
1590 :
1591 1631 : const Value &propval = f.regs.sp[-1];
1592 1631 : Value &rval = f.regs.sp[-2];
1593 :
1594 1631 : if (!obj->deleteByValue(cx, propval, &rval, strict))
1595 2 : THROW();
1596 : }
1597 :
1598 : void JS_FASTCALL
1599 17662 : stubs::DefVarOrConst(VMFrame &f, PropertyName *dn)
1600 : {
1601 17662 : unsigned attrs = JSPROP_ENUMERATE;
1602 17662 : if (!f.fp()->isEvalFrame())
1603 16912 : attrs |= JSPROP_PERMANENT;
1604 17662 : if (JSOp(*f.regs.pc) == JSOP_DEFCONST)
1605 16500 : attrs |= JSPROP_READONLY;
1606 :
1607 17662 : JSObject &obj = f.fp()->varObj();
1608 :
1609 17662 : if (!DefVarOrConstOperation(f.cx, obj, dn, attrs))
1610 0 : THROW();
1611 : }
1612 :
1613 : void JS_FASTCALL
1614 16486 : stubs::SetConst(VMFrame &f, PropertyName *name)
1615 : {
1616 16486 : JSContext *cx = f.cx;
1617 :
1618 16486 : JSObject *obj = &f.fp()->varObj();
1619 16486 : const Value &ref = f.regs.sp[-1];
1620 :
1621 16486 : if (!obj->defineProperty(cx, name, ref, JS_PropertyStub, JS_StrictPropertyStub,
1622 16486 : JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY))
1623 : {
1624 0 : THROW();
1625 : }
1626 : }
1627 :
1628 : JSBool JS_FASTCALL
1629 403280 : stubs::In(VMFrame &f)
1630 : {
1631 403280 : JSContext *cx = f.cx;
1632 :
1633 403280 : const Value &rref = f.regs.sp[-1];
1634 403280 : if (!rref.isObject()) {
1635 7 : js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
1636 7 : THROWV(JS_FALSE);
1637 : }
1638 :
1639 403273 : JSObject *obj = &rref.toObject();
1640 : jsid id;
1641 403273 : if (!FetchElementId(f.cx, obj, f.regs.sp[-2], id, &f.regs.sp[-2]))
1642 0 : THROWV(JS_FALSE);
1643 :
1644 : JSObject *obj2;
1645 : JSProperty *prop;
1646 403273 : if (!obj->lookupGeneric(cx, id, &obj2, &prop))
1647 0 : THROWV(JS_FALSE);
1648 :
1649 403273 : return !!prop;
1650 : }
1651 :
1652 : template void JS_FASTCALL stubs::DelElem<true>(VMFrame &f);
1653 : template void JS_FASTCALL stubs::DelElem<false>(VMFrame &f);
1654 :
1655 : void JS_FASTCALL
1656 14553 : stubs::TypeBarrierHelper(VMFrame &f, uint32_t which)
1657 : {
1658 14553 : JS_ASSERT(which == 0 || which == 1);
1659 :
1660 : /* The actual pushed value is at sp[0], fix up the stack. See finishBarrier. */
1661 14553 : Value &result = f.regs.sp[-1 - (int)which];
1662 14553 : result = f.regs.sp[0];
1663 :
1664 : /*
1665 : * Break type barriers at this bytecode if we have added many objects to
1666 : * the target already. This isn't needed if inference results for the
1667 : * script have been destroyed, as we will reanalyze and prune type barriers
1668 : * as they are regenerated.
1669 : */
1670 14553 : if (f.script()->hasAnalysis() && f.script()->analysis()->ranInference()) {
1671 29106 : AutoEnterTypeInference enter(f.cx);
1672 14553 : f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
1673 : }
1674 :
1675 14553 : TypeScript::Monitor(f.cx, f.script(), f.pc(), result);
1676 14553 : }
1677 :
1678 : void JS_FASTCALL
1679 13172 : stubs::StubTypeHelper(VMFrame &f, int32_t which)
1680 : {
1681 13172 : const Value &result = f.regs.sp[which];
1682 :
1683 13172 : if (f.script()->hasAnalysis() && f.script()->analysis()->ranInference()) {
1684 26344 : AutoEnterTypeInference enter(f.cx);
1685 13172 : f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
1686 : }
1687 :
1688 13172 : TypeScript::Monitor(f.cx, f.script(), f.pc(), result);
1689 13172 : }
1690 :
1691 : /*
1692 : * Variant of TypeBarrierHelper for checking types after making a native call.
1693 : * The stack is already correct, and no fixup should be performed.
1694 : */
1695 : void JS_FASTCALL
1696 287 : stubs::TypeBarrierReturn(VMFrame &f, Value *vp)
1697 : {
1698 287 : TypeScript::Monitor(f.cx, f.script(), f.pc(), vp[0]);
1699 287 : }
1700 :
1701 : void JS_FASTCALL
1702 100 : stubs::NegZeroHelper(VMFrame &f)
1703 : {
1704 100 : f.regs.sp[-1].setDouble(-0.0);
1705 100 : TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
1706 100 : }
1707 :
1708 : void JS_FASTCALL
1709 912 : stubs::CheckArgumentTypes(VMFrame &f)
1710 : {
1711 912 : StackFrame *fp = f.fp();
1712 912 : JSFunction *fun = fp->fun();
1713 912 : JSScript *script = fun->script();
1714 912 : RecompilationMonitor monitor(f.cx);
1715 :
1716 : {
1717 : /* Postpone recompilations until all args have been updated. */
1718 1824 : types::AutoEnterTypeInference enter(f.cx);
1719 :
1720 912 : if (!f.fp()->isConstructing())
1721 894 : TypeScript::SetThis(f.cx, script, fp->thisValue());
1722 2330 : for (unsigned i = 0; i < fun->nargs; i++)
1723 1418 : TypeScript::SetArgument(f.cx, script, i, fp->formalArg(i));
1724 : }
1725 :
1726 912 : if (monitor.recompiled())
1727 22 : return;
1728 :
1729 : #ifdef JS_MONOIC
1730 890 : ic::GenerateArgumentCheckStub(f);
1731 : #endif
1732 : }
1733 :
1734 : #ifdef DEBUG
1735 : void JS_FASTCALL
1736 14122535 : stubs::AssertArgumentTypes(VMFrame &f)
1737 : {
1738 14122535 : StackFrame *fp = f.fp();
1739 14122535 : JSFunction *fun = fp->fun();
1740 14122535 : JSScript *script = fun->script();
1741 :
1742 : /*
1743 : * Don't check the type of 'this' for constructor frames, the 'this' value
1744 : * has not been constructed yet.
1745 : */
1746 14122535 : if (!fp->isConstructing()) {
1747 12386317 : Type type = GetValueType(f.cx, fp->thisValue());
1748 12386317 : if (!TypeScript::ThisTypes(script)->hasType(type))
1749 0 : TypeFailure(f.cx, "Missing type for this: %s", TypeString(type));
1750 : }
1751 :
1752 38229237 : for (unsigned i = 0; i < fun->nargs; i++) {
1753 24106702 : Type type = GetValueType(f.cx, fp->formalArg(i));
1754 24106702 : if (!TypeScript::ArgTypes(script, i)->hasType(type))
1755 0 : TypeFailure(f.cx, "Missing type for arg %d: %s", i, TypeString(type));
1756 : }
1757 14122535 : }
1758 : #endif
1759 :
1760 : /*
1761 : * These two are never actually called, they just give us a place to rejoin if
1762 : * there is an invariant failure when initially entering a loop.
1763 : */
1764 0 : void JS_FASTCALL stubs::MissedBoundsCheckEntry(VMFrame &f) {}
1765 0 : void JS_FASTCALL stubs::MissedBoundsCheckHead(VMFrame &f) {}
1766 :
1767 : void * JS_FASTCALL
1768 66 : stubs::InvariantFailure(VMFrame &f, void *rval)
1769 : {
1770 : /*
1771 : * Patch this call to the return site of the call triggering the invariant
1772 : * failure (or a MissedBoundsCheck* function if the failure occurred on
1773 : * initial loop entry), and trigger a recompilation which will then
1774 : * redirect to the rejoin point for that call. We want to make things look
1775 : * to the recompiler like we are still inside that call, and that after
1776 : * recompilation we will return to the call's rejoin point.
1777 : */
1778 66 : void *repatchCode = f.scratch;
1779 66 : JS_ASSERT(repatchCode);
1780 66 : void **frameAddr = f.returnAddressLocation();
1781 66 : *frameAddr = repatchCode;
1782 :
1783 : /* Recompile the outermost script, and don't hoist any bounds checks. */
1784 66 : JSScript *script = f.fp()->script();
1785 66 : JS_ASSERT(!script->failedBoundsCheck);
1786 66 : script->failedBoundsCheck = true;
1787 :
1788 66 : ExpandInlineFrames(f.cx->compartment);
1789 :
1790 66 : mjit::Recompiler::clearStackReferences(f.cx, script);
1791 66 : mjit::ReleaseScriptCode(f.cx, script);
1792 :
1793 : /* Return the same value (if any) as the call triggering the invariant failure. */
1794 66 : return rval;
1795 : }
1796 :
1797 : void JS_FASTCALL
1798 0 : stubs::Exception(VMFrame &f)
1799 : {
1800 : // Check the interrupt flag to allow interrupting deeply nested exception
1801 : // handling.
1802 0 : if (f.cx->runtime->interrupt && !js_HandleExecutionInterrupt(f.cx))
1803 0 : THROW();
1804 :
1805 0 : f.regs.sp[0] = f.cx->getPendingException();
1806 0 : f.cx->clearPendingException();
1807 : }
1808 :
1809 : void JS_FASTCALL
1810 188736 : stubs::FunctionFramePrologue(VMFrame &f)
1811 : {
1812 188736 : if (!f.fp()->functionPrologue(f.cx))
1813 0 : THROW();
1814 : }
1815 :
1816 : void JS_FASTCALL
1817 535260 : stubs::FunctionFrameEpilogue(VMFrame &f)
1818 : {
1819 535260 : f.fp()->functionEpilogue();
1820 535260 : }
1821 :
1822 : void JS_FASTCALL
1823 202 : stubs::AnyFrameEpilogue(VMFrame &f)
1824 : {
1825 : /*
1826 : * On the normal execution path, emitReturn calls ScriptDebugEpilogue
1827 : * and inlines ScriptEpilogue. This function implements forced early
1828 : * returns, so it must have the same effect.
1829 : */
1830 202 : bool ok = true;
1831 202 : if (f.cx->compartment->debugMode())
1832 202 : ok = js::ScriptDebugEpilogue(f.cx, f.fp(), ok);
1833 202 : ok = ScriptEpilogue(f.cx, f.fp(), ok);
1834 202 : if (!ok)
1835 0 : THROW();
1836 202 : if (f.fp()->isNonEvalFunctionFrame())
1837 162 : f.fp()->functionEpilogue();
1838 : }
1839 :
1840 : template <bool Clamped>
1841 : int32_t JS_FASTCALL
1842 489 : stubs::ConvertToTypedInt(JSContext *cx, Value *vp)
1843 : {
1844 489 : JS_ASSERT(!vp->isInt32());
1845 :
1846 489 : if (vp->isDouble()) {
1847 : if (Clamped)
1848 93 : return js_TypedArray_uint8_clamp_double(vp->toDouble());
1849 276 : return js_DoubleToECMAInt32(vp->toDouble());
1850 : }
1851 :
1852 120 : if (vp->isNull() || vp->isObject() || vp->isUndefined())
1853 120 : return 0;
1854 :
1855 0 : if (vp->isBoolean())
1856 0 : return vp->toBoolean() ? 1 : 0;
1857 :
1858 0 : JS_ASSERT(vp->isString());
1859 :
1860 0 : int32_t i32 = 0;
1861 : #ifdef DEBUG
1862 : bool success =
1863 : #endif
1864 0 : StringToNumberType<int32_t>(cx, vp->toString(), &i32);
1865 0 : JS_ASSERT(success);
1866 :
1867 0 : return i32;
1868 : }
1869 :
1870 : template int32_t JS_FASTCALL stubs::ConvertToTypedInt<true>(JSContext *, Value *);
1871 : template int32_t JS_FASTCALL stubs::ConvertToTypedInt<false>(JSContext *, Value *);
1872 :
1873 : void JS_FASTCALL
1874 56 : stubs::ConvertToTypedFloat(JSContext *cx, Value *vp)
1875 : {
1876 56 : JS_ASSERT(!vp->isDouble() && !vp->isInt32());
1877 :
1878 56 : if (vp->isNull()) {
1879 0 : vp->setDouble(0);
1880 56 : } else if (vp->isObject() || vp->isUndefined()) {
1881 28 : vp->setDouble(js_NaN);
1882 28 : } else if (vp->isBoolean()) {
1883 0 : vp->setDouble(vp->toBoolean() ? 1 : 0);
1884 : } else {
1885 28 : JS_ASSERT(vp->isString());
1886 28 : double d = 0;
1887 : #ifdef DEBUG
1888 : bool success =
1889 : #endif
1890 28 : StringToNumberType<double>(cx, vp->toString(), &d);
1891 28 : JS_ASSERT(success);
1892 28 : vp->setDouble(d);
1893 : }
1894 56 : }
1895 :
1896 : void JS_FASTCALL
1897 48 : stubs::WriteBarrier(VMFrame &f, Value *addr)
1898 : {
1899 48 : gc::MarkValueUnbarriered(f.cx->compartment->barrierTracer(), addr, "write barrier");
1900 48 : }
1901 :
1902 : void JS_FASTCALL
1903 2 : stubs::GCThingWriteBarrier(VMFrame &f, Value *addr)
1904 : {
1905 2 : gc::Cell *cell = (gc::Cell *)addr->toGCThing();
1906 2 : if (cell && !cell->isMarked())
1907 2 : gc::MarkValueUnbarriered(f.cx->compartment->barrierTracer(), addr, "write barrier");
1908 2 : }
|