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 1180 : stubs::BindName(VMFrame &f, PropertyName *name)
85 : {
86 1180 : JSObject *obj = FindIdentifierBase(f.cx, &f.fp()->scopeChain(), name);
87 1180 : if (!obj)
88 0 : THROW();
89 1180 : 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 76307 : stubs::SetName(VMFrame &f, PropertyName *name)
101 : {
102 76307 : JSContext *cx = f.cx;
103 76307 : const Value &rval = f.regs.sp[-1];
104 76307 : const Value &lval = f.regs.sp[-2];
105 :
106 76307 : if (!SetPropertyOperation(cx, f.pc(), lval, rval))
107 70 : THROW();
108 :
109 76237 : 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 47724 : stubs::SetGlobalName(VMFrame &f, PropertyName *name)
118 : {
119 47724 : SetName<strict>(f, name);
120 47724 : }
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 157575 : stubs::Name(VMFrame &f)
127 : {
128 : Value rval;
129 157575 : if (!NameOperation(f.cx, f.pc(), &rval))
130 3298 : THROW();
131 154277 : f.regs.sp[0] = rval;
132 : }
133 :
134 : void JS_FASTCALL
135 825969 : stubs::GetElem(VMFrame &f)
136 : {
137 825969 : Value &lref = f.regs.sp[-2];
138 825969 : Value &rref = f.regs.sp[-1];
139 825969 : Value &rval = f.regs.sp[-2];
140 :
141 825969 : if (!GetElementOperation(f.cx, JSOp(*f.pc()), lref, rref, &rval))
142 45 : THROW();
143 : }
144 :
145 : template<JSBool strict>
146 : void JS_FASTCALL
147 1842887 : stubs::SetElem(VMFrame &f)
148 : {
149 1842887 : JSContext *cx = f.cx;
150 1842887 : FrameRegs ®s = f.regs;
151 :
152 1842887 : Value &objval = regs.sp[-3];
153 1842887 : Value &idval = regs.sp[-2];
154 1842887 : Value rval = regs.sp[-1];
155 :
156 : JSObject *obj;
157 : jsid id;
158 :
159 1842887 : obj = ValueToObject(cx, objval);
160 1842887 : if (!obj)
161 7 : THROW();
162 :
163 1842880 : if (!FetchElementId(f.cx, obj, idval, id, ®s.sp[-2]))
164 0 : THROW();
165 :
166 1842880 : TypeScript::MonitorAssign(cx, obj, id);
167 :
168 : do {
169 1842880 : if (obj->isDenseArray() && JSID_IS_INT(id)) {
170 1026676 : uint32_t length = obj->getDenseArrayInitializedLength();
171 1026676 : int32_t i = JSID_TO_INT(id);
172 1026676 : if ((uint32_t)i < length) {
173 19458 : if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
174 19410 : if (js_PrototypeHasIndexedProperties(cx, obj))
175 0 : break;
176 19410 : if ((uint32_t)i >= obj->getArrayLength())
177 0 : obj->setArrayLength(cx, i + 1);
178 : }
179 19458 : obj->setDenseArrayElementWithType(cx, i, rval);
180 19458 : goto end_setelem;
181 : } else {
182 1007218 : if (f.script()->hasAnalysis())
183 1007218 : f.script()->analysis()->getCode(f.pc()).arrayWriteHole = true;
184 : }
185 : }
186 : } while (0);
187 1823422 : if (!obj->setGeneric(cx, id, &rval, strict))
188 2905 : 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 1839975 : 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 1024 : stubs::ImplicitThis(VMFrame &f, PropertyName *name)
220 : {
221 : JSObject *obj, *obj2;
222 : JSProperty *prop;
223 1024 : if (!FindPropertyHelper(f.cx, name, false, f.cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
224 0 : THROW();
225 :
226 1024 : if (!ComputeImplicitThis(f.cx, obj, &f.regs.sp[0]))
227 0 : THROW();
228 : }
229 :
230 : void JS_FASTCALL
231 407742 : stubs::BitOr(VMFrame &f)
232 : {
233 : int32_t i, j;
234 :
235 407742 : if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
236 21 : THROW();
237 :
238 407721 : i = i | j;
239 407721 : f.regs.sp[-2].setInt32(i);
240 : }
241 :
242 : void JS_FASTCALL
243 20783 : stubs::BitXor(VMFrame &f)
244 : {
245 : int32_t i, j;
246 :
247 20783 : if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
248 0 : THROW();
249 :
250 20783 : i = i ^ j;
251 20783 : f.regs.sp[-2].setInt32(i);
252 : }
253 :
254 : void JS_FASTCALL
255 64504 : stubs::BitAnd(VMFrame &f)
256 : {
257 : int32_t i, j;
258 :
259 64504 : if (!ToInt32(f.cx, f.regs.sp[-2], &i) || !ToInt32(f.cx, f.regs.sp[-1], &j))
260 0 : THROW();
261 :
262 64504 : i = i & j;
263 64504 : 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 388 : stubs::Ursh(VMFrame &f)
303 : {
304 : uint32_t u;
305 388 : if (!ToUint32(f.cx, f.regs.sp[-2], &u))
306 0 : THROW();
307 : int32_t j;
308 388 : if (!ToInt32(f.cx, f.regs.sp[-1], &j))
309 0 : THROW();
310 :
311 388 : u >>= (j & 31);
312 :
313 388 : if (!f.regs.sp[-2].setNumber(uint32_t(u)))
314 255 : TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
315 : }
316 :
317 : template<JSBool strict>
318 : void JS_FASTCALL
319 1739 : stubs::DefFun(VMFrame &f, JSFunction *fun)
320 : {
321 : JSObject *obj2;
322 :
323 1739 : JSContext *cx = f.cx;
324 1739 : 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 1739 : JSObject *obj = fun;
333 :
334 1739 : 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 865 : obj2 = &fp->scopeChain();
341 : } else {
342 874 : obj2 = GetScopeChain(cx, fp);
343 874 : if (!obj2)
344 0 : THROW();
345 : }
346 :
347 : /*
348 : * If static link is not current scope, clone fun's object to link to the
349 : * current scope via parent. We do this to enable sharing of compiled
350 : * functions among multiple equivalent scopes, amortizing the cost of
351 : * compilation over a number of executions. Examples include XUL scripts
352 : * and event handlers shared among Firefox or other Mozilla app chrome
353 : * windows, and user-defined JS functions precompiled and then shared among
354 : * requests in server-side JS.
355 : */
356 1739 : if (obj->toFunction()->environment() != obj2) {
357 306 : obj = CloneFunctionObjectIfNotSingleton(cx, fun, obj2);
358 306 : if (!obj)
359 0 : THROW();
360 306 : JS_ASSERT_IF(f.script()->compileAndGo, obj->global() == fun->global());
361 : }
362 :
363 : /*
364 : * ECMA requires functions defined when entering Eval code to be
365 : * impermanent.
366 : */
367 : unsigned attrs = fp->isEvalFrame()
368 : ? JSPROP_ENUMERATE
369 1739 : : JSPROP_ENUMERATE | JSPROP_PERMANENT;
370 :
371 : /*
372 : * We define the function as a property of the variable object and not the
373 : * current scope chain even for the case of function expression statements
374 : * and functions defined by eval inside let or with blocks.
375 : */
376 1739 : JSObject *parent = &fp->varObj();
377 :
378 : /* ES5 10.5 (NB: with subsequent errata). */
379 1739 : PropertyName *name = fun->atom->asPropertyName();
380 1739 : JSProperty *prop = NULL;
381 : JSObject *pobj;
382 1739 : if (!parent->lookupProperty(cx, name, &pobj, &prop))
383 0 : THROW();
384 :
385 1739 : Value rval = ObjectValue(*obj);
386 :
387 : do {
388 : /* Steps 5d, 5f. */
389 1739 : if (!prop || pobj != parent) {
390 1114 : if (!parent->defineProperty(cx, name, rval,
391 : JS_PropertyStub, JS_StrictPropertyStub, attrs))
392 : {
393 0 : THROW();
394 : }
395 1114 : break;
396 : }
397 :
398 : /* Step 5e. */
399 625 : JS_ASSERT(parent->isNative());
400 625 : Shape *shape = reinterpret_cast<Shape *>(prop);
401 625 : if (parent->isGlobal()) {
402 475 : if (shape->configurable()) {
403 130 : if (!parent->defineProperty(cx, name, rval,
404 : JS_PropertyStub, JS_StrictPropertyStub, attrs))
405 : {
406 0 : THROW();
407 : }
408 130 : break;
409 : }
410 :
411 345 : if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
412 8 : JSAutoByteString bytes;
413 4 : if (js_AtomToPrintableString(cx, name, &bytes)) {
414 4 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
415 : JSMSG_CANT_REDEFINE_PROP, bytes.ptr());
416 : }
417 4 : THROW();
418 : }
419 : }
420 :
421 : /*
422 : * Non-global properties, and global properties which we aren't simply
423 : * redefining, must be set. First, this preserves their attributes.
424 : * Second, this will produce warnings and/or errors as necessary if the
425 : * specified Call object property is not writable (const).
426 : */
427 :
428 : /* Step 5f. */
429 491 : if (!parent->setProperty(cx, name, &rval, strict))
430 0 : THROW();
431 : } while (false);
432 : }
433 :
434 : template void JS_FASTCALL stubs::DefFun<true>(VMFrame &f, JSFunction *fun);
435 : template void JS_FASTCALL stubs::DefFun<false>(VMFrame &f, JSFunction *fun);
436 :
437 : #define RELATIONAL(OP) \
438 : JS_BEGIN_MACRO \
439 : JSContext *cx = f.cx; \
440 : FrameRegs ®s = f.regs; \
441 : Value &rval = regs.sp[-1]; \
442 : Value &lval = regs.sp[-2]; \
443 : bool cond; \
444 : if (!ToPrimitive(cx, JSTYPE_NUMBER, &lval)) \
445 : THROWV(JS_FALSE); \
446 : if (!ToPrimitive(cx, JSTYPE_NUMBER, &rval)) \
447 : THROWV(JS_FALSE); \
448 : if (lval.isString() && rval.isString()) { \
449 : JSString *l = lval.toString(), *r = rval.toString(); \
450 : int32_t cmp; \
451 : if (!CompareStrings(cx, l, r, &cmp)) \
452 : THROWV(JS_FALSE); \
453 : cond = cmp OP 0; \
454 : } else { \
455 : double l, r; \
456 : if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r)) \
457 : THROWV(JS_FALSE); \
458 : cond = (l OP r); \
459 : } \
460 : regs.sp[-2].setBoolean(cond); \
461 : return cond; \
462 : JS_END_MACRO
463 :
464 : JSBool JS_FASTCALL
465 402239 : stubs::LessThan(VMFrame &f)
466 : {
467 402239 : RELATIONAL(<);
468 : }
469 :
470 : JSBool JS_FASTCALL
471 17849 : stubs::LessEqual(VMFrame &f)
472 : {
473 17849 : RELATIONAL(<=);
474 : }
475 :
476 : JSBool JS_FASTCALL
477 154450 : stubs::GreaterThan(VMFrame &f)
478 : {
479 154450 : RELATIONAL(>);
480 : }
481 :
482 : JSBool JS_FASTCALL
483 17849 : stubs::GreaterEqual(VMFrame &f)
484 : {
485 17849 : RELATIONAL(>=);
486 : }
487 :
488 : JSBool JS_FASTCALL
489 3927492 : stubs::ValueToBoolean(VMFrame &f)
490 : {
491 3927492 : return js_ValueToBoolean(f.regs.sp[-1]);
492 : }
493 :
494 : void JS_FASTCALL
495 117304 : stubs::Not(VMFrame &f)
496 : {
497 117304 : JSBool b = !js_ValueToBoolean(f.regs.sp[-1]);
498 117304 : f.regs.sp[-1].setBoolean(b);
499 117304 : }
500 :
501 : template <bool EQ>
502 : static inline bool
503 380895 : StubEqualityOp(VMFrame &f)
504 : {
505 380895 : JSContext *cx = f.cx;
506 380895 : FrameRegs ®s = f.regs;
507 :
508 380895 : Value rval = regs.sp[-1];
509 380895 : Value lval = regs.sp[-2];
510 :
511 : bool cond;
512 :
513 : /* The string==string case is easily the hottest; try it first. */
514 380895 : if (lval.isString() && rval.isString()) {
515 111211 : JSString *l = lval.toString();
516 111211 : JSString *r = rval.toString();
517 : bool equal;
518 111211 : if (!EqualStrings(cx, l, r, &equal))
519 0 : return false;
520 111211 : cond = equal == EQ;
521 : } else
522 : #if JS_HAS_XML_SUPPORT
523 269684 : if ((lval.isObject() && lval.toObject().isXML()) ||
524 : (rval.isObject() && rval.toObject().isXML()))
525 : {
526 : JSBool equal;
527 0 : if (!js_TestXMLEquality(cx, lval, rval, &equal))
528 0 : return false;
529 0 : cond = !!equal == EQ;
530 : } else
531 : #endif
532 :
533 269684 : if (SameType(lval, rval)) {
534 195312 : JS_ASSERT(!lval.isString()); /* this case is handled above */
535 195312 : if (lval.isDouble()) {
536 123658 : double l = lval.toDouble();
537 123658 : double r = rval.toDouble();
538 : if (EQ)
539 115481 : cond = (l == r);
540 : else
541 8177 : cond = (l != r);
542 71654 : } else if (lval.isObject()) {
543 31564 : JSObject *l = &lval.toObject(), *r = &rval.toObject();
544 31564 : if (JSEqualityOp eq = l->getClass()->ext.equality) {
545 : JSBool equal;
546 0 : if (!eq(cx, l, &rval, &equal))
547 0 : return false;
548 0 : cond = !!equal == EQ;
549 : } else {
550 31564 : cond = (l == r) == EQ;
551 : }
552 40090 : } else if (lval.isNullOrUndefined()) {
553 32936 : cond = EQ;
554 : } else {
555 7154 : cond = (lval.payloadAsRawUint32() == rval.payloadAsRawUint32()) == EQ;
556 : }
557 : } else {
558 74372 : if (lval.isNullOrUndefined()) {
559 15034 : cond = rval.isNullOrUndefined() == EQ;
560 59338 : } else if (rval.isNullOrUndefined()) {
561 13139 : cond = !EQ;
562 : } else {
563 46199 : if (!ToPrimitive(cx, &lval))
564 4 : return false;
565 46195 : if (!ToPrimitive(cx, &rval))
566 0 : return false;
567 :
568 : /*
569 : * The string==string case is repeated because ToPrimitive can
570 : * convert lval/rval to strings.
571 : */
572 46195 : if (lval.isString() && rval.isString()) {
573 2632 : JSString *l = lval.toString();
574 2632 : JSString *r = rval.toString();
575 : bool equal;
576 2632 : if (!EqualStrings(cx, l, r, &equal))
577 0 : return false;
578 2632 : cond = equal == EQ;
579 : } else {
580 : double l, r;
581 43563 : if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
582 0 : return false;
583 :
584 : if (EQ)
585 27989 : cond = (l == r);
586 : else
587 15574 : cond = (l != r);
588 : }
589 : }
590 : }
591 :
592 380891 : regs.sp[-2].setBoolean(cond);
593 380891 : return true;
594 : }
595 :
596 : JSBool JS_FASTCALL
597 260674 : stubs::Equal(VMFrame &f)
598 : {
599 260674 : if (!StubEqualityOp<true>(f))
600 4 : THROWV(JS_FALSE);
601 260670 : return f.regs.sp[-2].toBoolean();
602 : }
603 :
604 : JSBool JS_FASTCALL
605 120221 : stubs::NotEqual(VMFrame &f)
606 : {
607 120221 : if (!StubEqualityOp<false>(f))
608 0 : THROWV(JS_FALSE);
609 120221 : return f.regs.sp[-2].toBoolean();
610 : }
611 :
612 : void JS_FASTCALL
613 15707038 : stubs::Add(VMFrame &f)
614 : {
615 15707038 : JSContext *cx = f.cx;
616 15707038 : FrameRegs ®s = f.regs;
617 15707038 : Value rval = regs.sp[-1];
618 15707038 : Value lval = regs.sp[-2];
619 :
620 : /* The string + string case is easily the hottest; try it first. */
621 15707038 : bool lIsString = lval.isString();
622 15707038 : bool rIsString = rval.isString();
623 : JSString *lstr, *rstr;
624 15707038 : if (lIsString && rIsString) {
625 12739443 : lstr = lval.toString();
626 12739443 : rstr = rval.toString();
627 12739443 : goto string_concat;
628 :
629 : } else
630 : #if JS_HAS_XML_SUPPORT
631 2967595 : if (lval.isObject() && lval.toObject().isXML() &&
632 0 : rval.isObject() && rval.toObject().isXML()) {
633 0 : if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), &rval))
634 0 : THROW();
635 0 : regs.sp[-2] = rval;
636 0 : regs.sp--;
637 0 : TypeScript::MonitorUnknown(cx, f.script(), f.pc());
638 : } else
639 : #endif
640 : {
641 2967595 : bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
642 2967595 : if (!ToPrimitive(f.cx, &lval))
643 16 : THROW();
644 2967579 : if (!ToPrimitive(f.cx, &rval))
645 13 : THROW();
646 2967566 : if ((lIsString = lval.isString()) || (rIsString = rval.isString())) {
647 2687059 : if (lIsString) {
648 2184360 : lstr = lval.toString();
649 : } else {
650 502699 : lstr = ToString(cx, lval);
651 502699 : if (!lstr)
652 0 : THROW();
653 502699 : regs.sp[-2].setString(lstr);
654 : }
655 2687059 : if (rIsString) {
656 504101 : rstr = rval.toString();
657 : } else {
658 2182958 : rstr = ToString(cx, rval);
659 2182958 : if (!rstr)
660 0 : THROW();
661 2182958 : regs.sp[-1].setString(rstr);
662 : }
663 2687059 : if (lIsObject || rIsObject)
664 391309 : TypeScript::MonitorString(cx, f.script(), f.pc());
665 2687059 : goto string_concat;
666 :
667 : } else {
668 : double l, r;
669 280507 : if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
670 0 : THROW();
671 280507 : l += r;
672 837970 : if (!regs.sp[-2].setNumber(l) &&
673 557463 : (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
674 278020 : TypeScript::MonitorOverflow(cx, f.script(), f.pc());
675 : }
676 : }
677 : }
678 280507 : return;
679 :
680 : string_concat:
681 15426502 : JSString *str = js_ConcatStrings(cx, lstr, rstr);
682 15426502 : if (!str)
683 5 : THROW();
684 15426497 : regs.sp[-2].setString(str);
685 15426497 : regs.sp--;
686 : }
687 :
688 :
689 : void JS_FASTCALL
690 163 : stubs::Sub(VMFrame &f)
691 : {
692 163 : JSContext *cx = f.cx;
693 163 : FrameRegs ®s = f.regs;
694 : double d1, d2;
695 163 : if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
696 0 : THROW();
697 163 : double d = d1 - d2;
698 163 : if (!regs.sp[-2].setNumber(d))
699 109 : TypeScript::MonitorOverflow(cx, f.script(), f.pc());
700 : }
701 :
702 : void JS_FASTCALL
703 78337 : stubs::Mul(VMFrame &f)
704 : {
705 78337 : JSContext *cx = f.cx;
706 78337 : FrameRegs ®s = f.regs;
707 : double d1, d2;
708 78337 : if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
709 0 : THROW();
710 78337 : double d = d1 * d2;
711 78337 : if (!regs.sp[-2].setNumber(d))
712 78199 : TypeScript::MonitorOverflow(cx, f.script(), f.pc());
713 : }
714 :
715 : void JS_FASTCALL
716 730 : stubs::Div(VMFrame &f)
717 : {
718 730 : JSContext *cx = f.cx;
719 730 : JSRuntime *rt = cx->runtime;
720 730 : FrameRegs ®s = f.regs;
721 :
722 : double d1, d2;
723 730 : if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
724 0 : THROW();
725 730 : if (d2 == 0) {
726 : const Value *vp;
727 : #ifdef XP_WIN
728 : /* XXX MSVC miscompiles such that (NaN == 0) */
729 : if (JSDOUBLE_IS_NaN(d2))
730 : vp = &rt->NaNValue;
731 : else
732 : #endif
733 2 : if (d1 == 0 || JSDOUBLE_IS_NaN(d1))
734 2 : vp = &rt->NaNValue;
735 0 : else if (JSDOUBLE_IS_NEG(d1) != JSDOUBLE_IS_NEG(d2))
736 0 : vp = &rt->negativeInfinityValue;
737 : else
738 0 : vp = &rt->positiveInfinityValue;
739 2 : regs.sp[-2] = *vp;
740 2 : TypeScript::MonitorOverflow(cx, f.script(), f.pc());
741 : } else {
742 728 : d1 /= d2;
743 728 : if (!regs.sp[-2].setNumber(d1))
744 22 : TypeScript::MonitorOverflow(cx, f.script(), f.pc());
745 : }
746 : }
747 :
748 : void JS_FASTCALL
749 30492 : stubs::Mod(VMFrame &f)
750 : {
751 30492 : JSContext *cx = f.cx;
752 30492 : FrameRegs ®s = f.regs;
753 :
754 30492 : Value &lref = regs.sp[-2];
755 30492 : Value &rref = regs.sp[-1];
756 : int32_t l, r;
757 30492 : if (lref.isInt32() && rref.isInt32() &&
758 : (l = lref.toInt32()) >= 0 && (r = rref.toInt32()) > 0) {
759 0 : int32_t mod = l % r;
760 0 : regs.sp[-2].setInt32(mod);
761 : } else {
762 : double d1, d2;
763 30492 : if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
764 0 : THROW();
765 30492 : if (d2 == 0) {
766 97 : regs.sp[-2].setDouble(js_NaN);
767 : } else {
768 30395 : d1 = js_fmod(d1, d2);
769 30395 : regs.sp[-2].setDouble(d1);
770 : }
771 30492 : TypeScript::MonitorOverflow(cx, f.script(), f.pc());
772 : }
773 : }
774 :
775 : void JS_FASTCALL
776 3382 : stubs::DebuggerStatement(VMFrame &f, jsbytecode *pc)
777 : {
778 3382 : JSDebuggerHandler handler = f.cx->runtime->debugHooks.debuggerHandler;
779 3382 : if (handler || !f.cx->compartment->getDebuggees().empty()) {
780 3352 : JSTrapStatus st = JSTRAP_CONTINUE;
781 : Value rval;
782 3352 : if (handler)
783 8 : st = handler(f.cx, f.script(), pc, &rval, f.cx->runtime->debugHooks.debuggerHandlerData);
784 3352 : if (st == JSTRAP_CONTINUE)
785 3348 : st = Debugger::onDebuggerStatement(f.cx, &rval);
786 :
787 3352 : switch (st) {
788 : case JSTRAP_THROW:
789 60 : f.cx->setPendingException(rval);
790 60 : THROW();
791 :
792 : case JSTRAP_RETURN:
793 112 : f.cx->clearPendingException();
794 112 : f.cx->fp()->setReturnValue(rval);
795 112 : *f.returnAddressLocation() = f.cx->jaegerCompartment()->forceReturnFromFastCall();
796 112 : break;
797 :
798 : case JSTRAP_ERROR:
799 80 : f.cx->clearPendingException();
800 80 : THROW();
801 :
802 : default:
803 3100 : break;
804 : }
805 : }
806 : }
807 :
808 : void JS_FASTCALL
809 354 : stubs::Interrupt(VMFrame &f, jsbytecode *pc)
810 : {
811 354 : gc::MaybeVerifyBarriers(f.cx);
812 :
813 354 : if (!js_HandleExecutionInterrupt(f.cx))
814 0 : THROW();
815 : }
816 :
817 : void JS_FASTCALL
818 93 : stubs::RecompileForInline(VMFrame &f)
819 : {
820 93 : ExpandInlineFrames(f.cx->compartment);
821 : Recompiler::clearStackReferencesAndChunk(f.cx->runtime->defaultFreeOp(), f.script(), f.jit(),
822 93 : f.chunkIndex(), /* resetUses = */ false);
823 93 : }
824 :
825 : void JS_FASTCALL
826 594 : stubs::Trap(VMFrame &f, uint32_t trapTypes)
827 : {
828 : Value rval;
829 :
830 : /*
831 : * Trap may be called for a single-step interrupt trap and/or a
832 : * regular trap. Try the single-step first, and if it lets control
833 : * flow through or does not exist, do the regular trap.
834 : */
835 594 : JSTrapStatus result = JSTRAP_CONTINUE;
836 594 : if (trapTypes & JSTRAP_SINGLESTEP) {
837 : /*
838 : * single step mode may be paused without recompiling by
839 : * setting the interruptHook to NULL.
840 : */
841 299 : JSInterruptHook hook = f.cx->runtime->debugHooks.interruptHook;
842 299 : if (hook)
843 0 : result = hook(f.cx, f.script(), f.pc(), &rval, f.cx->runtime->debugHooks.interruptHookData);
844 :
845 299 : if (result == JSTRAP_CONTINUE)
846 299 : result = Debugger::onSingleStep(f.cx, &rval);
847 : }
848 :
849 594 : if (result == JSTRAP_CONTINUE && (trapTypes & JSTRAP_TRAP))
850 295 : result = Debugger::onTrap(f.cx, &rval);
851 :
852 594 : switch (result) {
853 : case JSTRAP_THROW:
854 0 : f.cx->setPendingException(rval);
855 0 : THROW();
856 :
857 : case JSTRAP_RETURN:
858 24 : f.cx->clearPendingException();
859 24 : f.cx->fp()->setReturnValue(rval);
860 24 : *f.returnAddressLocation() = f.cx->jaegerCompartment()->forceReturnFromFastCall();
861 24 : break;
862 :
863 : case JSTRAP_ERROR:
864 4 : f.cx->clearPendingException();
865 4 : THROW();
866 :
867 : default:
868 566 : break;
869 : }
870 : }
871 :
872 : void JS_FASTCALL
873 40573 : stubs::This(VMFrame &f)
874 : {
875 : /*
876 : * We can't yet inline scripts which need to compute their 'this' object
877 : * from a primitive; the frame we are computing 'this' for does not exist yet.
878 : */
879 40573 : if (f.regs.inlined()) {
880 0 : f.script()->uninlineable = true;
881 0 : MarkTypeObjectFlags(f.cx, &f.fp()->callee(), OBJECT_FLAG_UNINLINEABLE);
882 : }
883 :
884 40573 : if (!ComputeThis(f.cx, f.fp()))
885 0 : THROW();
886 40573 : f.regs.sp[-1] = f.fp()->thisValue();
887 : }
888 :
889 : void JS_FASTCALL
890 1905 : stubs::Neg(VMFrame &f)
891 : {
892 : double d;
893 1905 : if (!ToNumber(f.cx, f.regs.sp[-1], &d))
894 0 : THROW();
895 1905 : d = -d;
896 1905 : if (!f.regs.sp[-1].setNumber(d))
897 1845 : TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
898 : }
899 :
900 : void JS_FASTCALL
901 1210617 : stubs::NewInitArray(VMFrame &f, uint32_t count)
902 : {
903 1210617 : JSObject *obj = NewDenseAllocatedArray(f.cx, count);
904 1210617 : if (!obj)
905 0 : THROW();
906 :
907 1210617 : TypeObject *type = (TypeObject *) f.scratch;
908 1210617 : if (type) {
909 1210421 : obj->setType(type);
910 : } else {
911 196 : if (!SetInitializerObjectType(f.cx, f.script(), f.pc(), obj))
912 0 : THROW();
913 : }
914 :
915 1210617 : f.regs.sp[0].setObject(*obj);
916 : }
917 :
918 : void JS_FASTCALL
919 1552128 : stubs::NewInitObject(VMFrame &f, JSObject *baseobj)
920 : {
921 1552128 : JSContext *cx = f.cx;
922 1552128 : TypeObject *type = (TypeObject *) f.scratch;
923 :
924 : JSObject *obj;
925 :
926 1552128 : if (baseobj) {
927 1551601 : obj = CopyInitializerObject(cx, baseobj);
928 : } else {
929 527 : gc::AllocKind kind = GuessObjectGCKind(0);
930 527 : obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
931 : }
932 :
933 1552128 : if (!obj)
934 0 : THROW();
935 :
936 1552128 : if (type) {
937 1551724 : obj->setType(type);
938 : } else {
939 404 : if (!SetInitializerObjectType(cx, f.script(), f.pc(), obj))
940 0 : THROW();
941 : }
942 :
943 1552128 : f.regs.sp[0].setObject(*obj);
944 : }
945 :
946 : void JS_FASTCALL
947 638 : stubs::InitElem(VMFrame &f, uint32_t last)
948 : {
949 638 : JSContext *cx = f.cx;
950 638 : FrameRegs ®s = f.regs;
951 :
952 : /* Pop the element's value into rval. */
953 638 : JS_ASSERT(regs.sp - f.fp()->base() >= 3);
954 638 : const Value &rref = regs.sp[-1];
955 :
956 : /* Find the object being initialized at top of stack. */
957 638 : const Value &lref = regs.sp[-3];
958 638 : JS_ASSERT(lref.isObject());
959 638 : JSObject *obj = &lref.toObject();
960 :
961 : /* Fetch id now that we have obj. */
962 : jsid id;
963 638 : const Value &idval = regs.sp[-2];
964 638 : if (!FetchElementId(f.cx, obj, idval, id, ®s.sp[-2]))
965 0 : THROW();
966 :
967 : /*
968 : * If rref is a hole, do not call JSObject::defineProperty. In this case,
969 : * obj must be an array, so if the current op is the last element
970 : * initialiser, set the array length to one greater than id.
971 : */
972 638 : if (rref.isMagic(JS_ARRAY_HOLE)) {
973 0 : JS_ASSERT(obj->isArray());
974 0 : JS_ASSERT(JSID_IS_INT(id));
975 0 : JS_ASSERT(uint32_t(JSID_TO_INT(id)) < StackSpace::ARGS_LENGTH_MAX);
976 0 : if (last && !js_SetLengthProperty(cx, obj, (uint32_t) (JSID_TO_INT(id) + 1)))
977 0 : THROW();
978 : } else {
979 638 : if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
980 0 : THROW();
981 : }
982 : }
983 :
984 : void JS_FASTCALL
985 107872 : stubs::RegExp(VMFrame &f, JSObject *regex)
986 : {
987 : /*
988 : * Push a regexp object cloned from the regexp literal object mapped by the
989 : * bytecode at pc.
990 : */
991 107872 : JSObject *proto = f.fp()->scopeChain().global().getOrCreateRegExpPrototype(f.cx);
992 107872 : if (!proto)
993 0 : THROW();
994 107872 : JS_ASSERT(proto);
995 107872 : JSObject *obj = CloneRegExpObject(f.cx, regex, proto);
996 107872 : if (!obj)
997 0 : THROW();
998 107872 : f.regs.sp[0].setObject(*obj);
999 : }
1000 :
1001 : JSObject * JS_FASTCALL
1002 733251 : stubs::Lambda(VMFrame &f, JSFunction *fun)
1003 : {
1004 : JSObject *parent;
1005 733251 : if (fun->isNullClosure()) {
1006 214137 : parent = &f.fp()->scopeChain();
1007 : } else {
1008 519114 : parent = GetScopeChain(f.cx, f.fp());
1009 519114 : if (!parent)
1010 0 : THROWV(NULL);
1011 : }
1012 :
1013 733251 : JSObject *obj = CloneFunctionObjectIfNotSingleton(f.cx, fun, parent);
1014 733251 : if (!obj)
1015 0 : THROWV(NULL);
1016 :
1017 733251 : JS_ASSERT_IF(f.script()->compileAndGo, obj->global() == fun->global());
1018 733251 : return obj;
1019 : }
1020 :
1021 : void JS_FASTCALL
1022 430799 : stubs::GetProp(VMFrame &f, PropertyName *name)
1023 : {
1024 430799 : JSContext *cx = f.cx;
1025 430799 : FrameRegs ®s = f.regs;
1026 :
1027 : Value rval;
1028 430799 : if (!GetPropertyOperation(cx, f.pc(), f.regs.sp[-1], &rval))
1029 19 : THROW();
1030 :
1031 430780 : regs.sp[-1] = rval;
1032 : }
1033 :
1034 : void JS_FASTCALL
1035 0 : stubs::GetPropNoCache(VMFrame &f, PropertyName *name)
1036 : {
1037 0 : JSContext *cx = f.cx;
1038 0 : FrameRegs ®s = f.regs;
1039 :
1040 0 : const Value &lval = f.regs.sp[-1];
1041 :
1042 : // Uncached lookups are only used for .prototype accesses at the start of constructors.
1043 0 : JS_ASSERT(lval.isObject());
1044 0 : JS_ASSERT(name == cx->runtime->atomState.classPrototypeAtom);
1045 :
1046 0 : JSObject *obj = &lval.toObject();
1047 :
1048 : Value rval;
1049 0 : if (!obj->getProperty(cx, name, &rval))
1050 0 : THROW();
1051 :
1052 0 : regs.sp[-1] = rval;
1053 : }
1054 :
1055 : void JS_FASTCALL
1056 301557 : stubs::Iter(VMFrame &f, uint32_t flags)
1057 : {
1058 301557 : if (!ValueToIterator(f.cx, flags, &f.regs.sp[-1]))
1059 57 : THROW();
1060 301500 : JS_ASSERT(!f.regs.sp[-1].isPrimitive());
1061 : }
1062 :
1063 : static void
1064 1541 : InitPropOrMethod(VMFrame &f, PropertyName *name, JSOp op)
1065 : {
1066 1541 : JSContext *cx = f.cx;
1067 1541 : FrameRegs ®s = f.regs;
1068 :
1069 : /* Load the property's initial value into rval. */
1070 1541 : JS_ASSERT(regs.sp - f.fp()->base() >= 2);
1071 : Value rval;
1072 1541 : rval = regs.sp[-1];
1073 :
1074 : /* Load the object being initialized into lval/obj. */
1075 1541 : JSObject *obj = ®s.sp[-2].toObject();
1076 1541 : JS_ASSERT(obj->isNative());
1077 :
1078 : /* Get the immediate property name into id. */
1079 1541 : jsid id = ATOM_TO_JSID(name);
1080 :
1081 3082 : if (JS_UNLIKELY(name == cx->runtime->atomState.protoAtom)
1082 61 : ? !js_SetPropertyHelper(cx, obj, id, 0, &rval, false)
1083 : : !DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
1084 1480 : JSPROP_ENUMERATE, 0, 0, 0)) {
1085 0 : THROW();
1086 : }
1087 : }
1088 :
1089 : void JS_FASTCALL
1090 1541 : stubs::InitProp(VMFrame &f, PropertyName *name)
1091 : {
1092 1541 : InitPropOrMethod(f, name, JSOP_INITPROP);
1093 1541 : }
1094 :
1095 : void JS_FASTCALL
1096 9307099 : stubs::IterNext(VMFrame &f, int32_t offset)
1097 : {
1098 9307099 : JS_ASSERT(f.regs.sp - offset >= f.fp()->base());
1099 9307099 : JS_ASSERT(f.regs.sp[-offset].isObject());
1100 :
1101 9307099 : JSObject *iterobj = &f.regs.sp[-offset].toObject();
1102 9307099 : f.regs.sp[0].setNull();
1103 9307099 : f.regs.sp++;
1104 9307099 : if (!js_IteratorNext(f.cx, iterobj, &f.regs.sp[-1]))
1105 0 : THROW();
1106 : }
1107 :
1108 : JSBool JS_FASTCALL
1109 9420833 : stubs::IterMore(VMFrame &f)
1110 : {
1111 9420833 : JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
1112 9420833 : JS_ASSERT(f.regs.sp[-1].isObject());
1113 :
1114 : Value v;
1115 9420833 : JSObject *iterobj = &f.regs.sp[-1].toObject();
1116 9420833 : if (!js_IteratorMore(f.cx, iterobj, &v))
1117 14 : THROWV(JS_FALSE);
1118 :
1119 9420819 : return v.toBoolean();
1120 : }
1121 :
1122 : void JS_FASTCALL
1123 917 : stubs::EndIter(VMFrame &f)
1124 : {
1125 917 : JS_ASSERT(f.regs.sp - 1 >= f.fp()->base());
1126 917 : if (!CloseIterator(f.cx, &f.regs.sp[-1].toObject()))
1127 0 : THROW();
1128 : }
1129 :
1130 : JSString * JS_FASTCALL
1131 65632 : stubs::TypeOf(VMFrame &f)
1132 : {
1133 65632 : const Value &ref = f.regs.sp[-1];
1134 65632 : JSType type = JS_TypeOfValue(f.cx, ref);
1135 65632 : return f.cx->runtime->atomState.typeAtoms[type];
1136 : }
1137 :
1138 : void JS_FASTCALL
1139 701110 : stubs::StrictEq(VMFrame &f)
1140 : {
1141 701110 : const Value &rhs = f.regs.sp[-1];
1142 701110 : const Value &lhs = f.regs.sp[-2];
1143 : bool equal;
1144 701110 : if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
1145 0 : THROW();
1146 701110 : f.regs.sp--;
1147 701110 : f.regs.sp[-1].setBoolean(equal == JS_TRUE);
1148 : }
1149 :
1150 : void JS_FASTCALL
1151 236164 : stubs::StrictNe(VMFrame &f)
1152 : {
1153 236164 : const Value &rhs = f.regs.sp[-1];
1154 236164 : const Value &lhs = f.regs.sp[-2];
1155 : bool equal;
1156 236164 : if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
1157 0 : THROW();
1158 236164 : f.regs.sp--;
1159 236164 : f.regs.sp[-1].setBoolean(equal != JS_TRUE);
1160 : }
1161 :
1162 : void JS_FASTCALL
1163 501 : stubs::Throw(VMFrame &f)
1164 : {
1165 501 : JSContext *cx = f.cx;
1166 :
1167 501 : JS_ASSERT(!cx->isExceptionPending());
1168 501 : cx->setPendingException(f.regs.sp[-1]);
1169 501 : THROW();
1170 : }
1171 :
1172 : void JS_FASTCALL
1173 302545 : stubs::Arguments(VMFrame &f)
1174 : {
1175 302545 : if (!f.fp()->hasArgsObj()) {
1176 : /*
1177 : * This case occurs when checkCallApplySpeculation detects that
1178 : * 'f.apply' is not actually js_fun_apply. In this case, we need to
1179 : * report the mis-speculation which will bail
1180 : */
1181 1 : if (!f.fp()->script()->applySpeculationFailed(f.cx))
1182 0 : THROW();
1183 : }
1184 302545 : f.regs.sp[0] = ObjectValue(f.fp()->argsObj());
1185 : }
1186 :
1187 : JSBool JS_FASTCALL
1188 40420 : stubs::InstanceOf(VMFrame &f)
1189 : {
1190 40420 : JSContext *cx = f.cx;
1191 40420 : FrameRegs ®s = f.regs;
1192 :
1193 40420 : const Value &rref = regs.sp[-1];
1194 40420 : if (rref.isPrimitive()) {
1195 : js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
1196 0 : -1, rref, NULL);
1197 0 : THROWV(JS_FALSE);
1198 : }
1199 40420 : JSObject *obj = &rref.toObject();
1200 40420 : const Value &lref = regs.sp[-2];
1201 40420 : JSBool cond = JS_FALSE;
1202 40420 : if (!HasInstance(cx, obj, &lref, &cond))
1203 6 : THROWV(JS_FALSE);
1204 40414 : f.regs.sp[-2].setBoolean(cond);
1205 40414 : return cond;
1206 : }
1207 :
1208 : void JS_FASTCALL
1209 2 : stubs::FastInstanceOf(VMFrame &f)
1210 : {
1211 2 : const Value &lref = f.regs.sp[-1];
1212 :
1213 2 : if (lref.isPrimitive()) {
1214 : /*
1215 : * Throw a runtime error if instanceof is called on a function that
1216 : * has a non-object as its .prototype value.
1217 : */
1218 2 : js_ReportValueError(f.cx, JSMSG_BAD_PROTOTYPE, -1, f.regs.sp[-2], NULL);
1219 2 : THROW();
1220 : }
1221 :
1222 0 : f.regs.sp[-3].setBoolean(js_IsDelegate(f.cx, &lref.toObject(), f.regs.sp[-3]));
1223 : }
1224 :
1225 : void JS_FASTCALL
1226 32163 : stubs::EnterBlock(VMFrame &f, JSObject *obj)
1227 : {
1228 32163 : FrameRegs ®s = f.regs;
1229 32163 : StackFrame *fp = f.fp();
1230 32163 : StaticBlockObject &blockObj = obj->asStaticBlock();
1231 :
1232 32163 : JS_ASSERT(!f.regs.inlined());
1233 :
1234 32163 : if (*regs.pc == JSOP_ENTERBLOCK) {
1235 29096 : JS_ASSERT(fp->base() + blockObj.stackDepth() == regs.sp);
1236 29096 : Value *vp = regs.sp + blockObj.slotCount();
1237 29096 : JS_ASSERT(regs.sp < vp);
1238 29096 : JS_ASSERT(vp <= fp->slots() + fp->script()->nslots);
1239 29096 : SetValueRangeToUndefined(regs.sp, vp);
1240 29096 : regs.sp = vp;
1241 : }
1242 :
1243 : #ifdef DEBUG
1244 32163 : JSContext *cx = f.cx;
1245 32163 : JS_ASSERT(fp->maybeBlockChain() == blockObj.enclosingBlock());
1246 :
1247 : /*
1248 : * The young end of fp->scopeChain() may omit blocks if we haven't closed
1249 : * over them, but if there are any closure blocks on fp->scopeChain(), they'd
1250 : * better be (clones of) ancestors of the block we're entering now;
1251 : * anything else we should have popped off fp->scopeChain() when we left its
1252 : * static scope.
1253 : */
1254 32163 : JSObject *obj2 = &fp->scopeChain();
1255 64326 : while (obj2->isWith())
1256 0 : obj2 = &obj2->asWith().enclosingScope();
1257 32589 : if (obj2->isBlock() &&
1258 426 : obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, fp)) {
1259 0 : JSObject &youngestProto = obj2->asClonedBlock().staticBlock();
1260 0 : StaticBlockObject *parent = &blockObj;
1261 0 : while ((parent = parent->enclosingBlock()) != &youngestProto)
1262 0 : JS_ASSERT(parent);
1263 : }
1264 : #endif
1265 :
1266 32163 : fp->setBlockChain(&blockObj);
1267 32163 : }
1268 :
1269 : void JS_FASTCALL
1270 31730 : stubs::LeaveBlock(VMFrame &f)
1271 : {
1272 31730 : JSContext *cx = f.cx;
1273 31730 : StackFrame *fp = f.fp();
1274 :
1275 31730 : StaticBlockObject &blockObj = fp->blockChain();
1276 31730 : JS_ASSERT(blockObj.stackDepth() <= StackDepth(fp->script()));
1277 :
1278 : /*
1279 : * If we're about to leave the dynamic scope of a block that has been
1280 : * cloned onto fp->scopeChain(), clear its private data, move its locals from
1281 : * the stack into the clone, and pop it off the chain.
1282 : */
1283 31730 : JSObject &obj = fp->scopeChain();
1284 31730 : if (obj.getProto() == &blockObj)
1285 252 : obj.asClonedBlock().put(cx);
1286 :
1287 31730 : fp->setBlockChain(blockObj.enclosingBlock());
1288 31730 : }
1289 :
1290 : inline void *
1291 2119 : FindNativeCode(VMFrame &f, jsbytecode *target)
1292 : {
1293 2119 : void* native = f.fp()->script()->nativeCodeForPC(f.fp()->isConstructing(), target);
1294 2119 : if (native)
1295 2119 : return native;
1296 :
1297 0 : uint32_t sourceOffset = f.pc() - f.script()->code;
1298 0 : uint32_t targetOffset = target - f.script()->code;
1299 :
1300 0 : CrossChunkEdge *edges = f.jit()->edges();
1301 0 : for (size_t i = 0; i < f.jit()->nedges; i++) {
1302 0 : const CrossChunkEdge &edge = edges[i];
1303 0 : if (edge.source == sourceOffset && edge.target == targetOffset)
1304 0 : return edge.shimLabel;
1305 : }
1306 :
1307 0 : JS_NOT_REACHED("Missing edge");
1308 : return NULL;
1309 : }
1310 :
1311 : void * JS_FASTCALL
1312 1441 : stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
1313 : {
1314 1441 : jsbytecode *jpc = pc;
1315 1441 : JSScript *script = f.fp()->script();
1316 :
1317 : /* This is correct because the compiler adjusts the stack beforehand. */
1318 1441 : Value lval = f.regs.sp[-1];
1319 :
1320 1441 : if (!lval.isPrimitive())
1321 0 : return FindNativeCode(f, pc + GET_JUMP_OFFSET(pc));
1322 :
1323 1441 : JS_ASSERT(pc[0] == JSOP_LOOKUPSWITCH);
1324 :
1325 1441 : pc += JUMP_OFFSET_LEN;
1326 1441 : uint32_t npairs = GET_UINT16(pc);
1327 1441 : pc += UINT16_LEN;
1328 :
1329 1441 : JS_ASSERT(npairs);
1330 :
1331 1441 : if (lval.isString()) {
1332 1086 : JSLinearString *str = lval.toString()->ensureLinear(f.cx);
1333 1086 : if (!str)
1334 0 : THROWV(NULL);
1335 4475 : for (uint32_t i = 1; i <= npairs; i++) {
1336 4305 : Value rval = script->getConst(GET_UINT32_INDEX(pc));
1337 4305 : pc += UINT32_INDEX_LEN;
1338 4305 : if (rval.isString()) {
1339 4305 : JSLinearString *rhs = &rval.toString()->asLinear();
1340 4305 : if (rhs == str || EqualStrings(str, rhs))
1341 916 : return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
1342 : }
1343 3389 : pc += JUMP_OFFSET_LEN;
1344 : }
1345 355 : } else if (lval.isNumber()) {
1346 0 : double d = lval.toNumber();
1347 0 : for (uint32_t i = 1; i <= npairs; i++) {
1348 0 : Value rval = script->getConst(GET_UINT32_INDEX(pc));
1349 0 : pc += UINT32_INDEX_LEN;
1350 0 : if (rval.isNumber() && d == rval.toNumber())
1351 0 : return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
1352 0 : pc += JUMP_OFFSET_LEN;
1353 : }
1354 : } else {
1355 710 : for (uint32_t i = 1; i <= npairs; i++) {
1356 355 : Value rval = script->getConst(GET_UINT32_INDEX(pc));
1357 355 : pc += UINT32_INDEX_LEN;
1358 355 : if (lval == rval)
1359 0 : return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc));
1360 355 : pc += JUMP_OFFSET_LEN;
1361 : }
1362 : }
1363 :
1364 525 : return FindNativeCode(f, jpc + GET_JUMP_OFFSET(jpc));
1365 : }
1366 :
1367 : void * JS_FASTCALL
1368 678 : stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
1369 : {
1370 678 : jsbytecode * const originalPC = origPc;
1371 :
1372 1356 : DebugOnly<JSOp> op = JSOp(*originalPC);
1373 678 : JS_ASSERT(op == JSOP_TABLESWITCH);
1374 :
1375 678 : uint32_t jumpOffset = GET_JUMP_OFFSET(originalPC);
1376 678 : jsbytecode *pc = originalPC + JUMP_OFFSET_LEN;
1377 :
1378 : /* Note: compiler adjusts the stack beforehand. */
1379 678 : Value rval = f.regs.sp[-1];
1380 :
1381 : int32_t tableIdx;
1382 678 : if (rval.isInt32()) {
1383 0 : tableIdx = rval.toInt32();
1384 678 : } else if (rval.isDouble()) {
1385 199 : double d = rval.toDouble();
1386 199 : if (d == 0) {
1387 : /* Treat -0 (double) as 0. */
1388 93 : tableIdx = 0;
1389 106 : } else if (!JSDOUBLE_IS_INT32(d, &tableIdx)) {
1390 88 : goto finally;
1391 : }
1392 : } else {
1393 479 : goto finally;
1394 : }
1395 :
1396 : {
1397 111 : int32_t low = GET_JUMP_OFFSET(pc);
1398 111 : pc += JUMP_OFFSET_LEN;
1399 111 : int32_t high = GET_JUMP_OFFSET(pc);
1400 111 : pc += JUMP_OFFSET_LEN;
1401 :
1402 111 : tableIdx -= low;
1403 111 : if ((uint32_t) tableIdx < (uint32_t)(high - low + 1)) {
1404 69 : pc += JUMP_OFFSET_LEN * tableIdx;
1405 69 : if (uint32_t candidateOffset = GET_JUMP_OFFSET(pc))
1406 69 : jumpOffset = candidateOffset;
1407 : }
1408 : }
1409 :
1410 : finally:
1411 : /* Provide the native address. */
1412 678 : return FindNativeCode(f, originalPC + jumpOffset);
1413 : }
1414 :
1415 : void JS_FASTCALL
1416 1105 : stubs::Pos(VMFrame &f)
1417 : {
1418 1105 : if (!ToNumber(f.cx, &f.regs.sp[-1]))
1419 0 : THROW();
1420 1105 : if (!f.regs.sp[-1].isInt32())
1421 436 : TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
1422 : }
1423 :
1424 : void JS_FASTCALL
1425 137 : stubs::DelName(VMFrame &f, PropertyName *name)
1426 : {
1427 : JSObject *obj, *obj2;
1428 : JSProperty *prop;
1429 137 : if (!FindProperty(f.cx, name, f.cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
1430 0 : THROW();
1431 :
1432 : /* Strict mode code should never contain JSOP_DELNAME opcodes. */
1433 137 : JS_ASSERT(!f.script()->strictModeCode);
1434 :
1435 : /* ECMA says to return true if name is undefined or inherited. */
1436 137 : f.regs.sp++;
1437 137 : f.regs.sp[-1] = BooleanValue(true);
1438 137 : if (prop) {
1439 85 : if (!obj->deleteProperty(f.cx, name, &f.regs.sp[-1], false))
1440 0 : THROW();
1441 : }
1442 : }
1443 :
1444 : template<JSBool strict>
1445 : void JS_FASTCALL
1446 266 : stubs::DelProp(VMFrame &f, PropertyName *name)
1447 : {
1448 266 : JSContext *cx = f.cx;
1449 :
1450 266 : JSObject *obj = ValueToObject(cx, f.regs.sp[-1]);
1451 266 : if (!obj)
1452 0 : THROW();
1453 :
1454 : Value rval;
1455 266 : if (!obj->deleteProperty(cx, name, &rval, strict))
1456 0 : THROW();
1457 :
1458 266 : f.regs.sp[-1] = rval;
1459 : }
1460 :
1461 : template void JS_FASTCALL stubs::DelProp<true>(VMFrame &f, PropertyName *name);
1462 : template void JS_FASTCALL stubs::DelProp<false>(VMFrame &f, PropertyName *name);
1463 :
1464 : template<JSBool strict>
1465 : void JS_FASTCALL
1466 1351 : stubs::DelElem(VMFrame &f)
1467 : {
1468 1351 : JSContext *cx = f.cx;
1469 :
1470 1351 : JSObject *obj = ValueToObject(cx, f.regs.sp[-2]);
1471 1351 : if (!obj)
1472 0 : THROW();
1473 :
1474 1351 : const Value &propval = f.regs.sp[-1];
1475 1351 : Value &rval = f.regs.sp[-2];
1476 :
1477 1351 : if (!obj->deleteByValue(cx, propval, &rval, strict))
1478 2 : THROW();
1479 : }
1480 :
1481 : void JS_FASTCALL
1482 26250 : stubs::DefVarOrConst(VMFrame &f, PropertyName *dn)
1483 : {
1484 26250 : unsigned attrs = JSPROP_ENUMERATE;
1485 26250 : if (!f.fp()->isEvalFrame())
1486 25488 : attrs |= JSPROP_PERMANENT;
1487 26250 : if (JSOp(*f.regs.pc) == JSOP_DEFCONST)
1488 25076 : attrs |= JSPROP_READONLY;
1489 :
1490 26250 : JSObject &obj = f.fp()->varObj();
1491 :
1492 26250 : if (!DefVarOrConstOperation(f.cx, obj, dn, attrs))
1493 0 : THROW();
1494 : }
1495 :
1496 : void JS_FASTCALL
1497 25062 : stubs::SetConst(VMFrame &f, PropertyName *name)
1498 : {
1499 25062 : JSContext *cx = f.cx;
1500 :
1501 25062 : JSObject *obj = &f.fp()->varObj();
1502 25062 : const Value &ref = f.regs.sp[-1];
1503 :
1504 25062 : if (!obj->defineProperty(cx, name, ref, JS_PropertyStub, JS_StrictPropertyStub,
1505 25062 : JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY))
1506 : {
1507 0 : THROW();
1508 : }
1509 : }
1510 :
1511 : JSBool JS_FASTCALL
1512 383951 : stubs::In(VMFrame &f)
1513 : {
1514 383951 : JSContext *cx = f.cx;
1515 :
1516 383951 : const Value &rref = f.regs.sp[-1];
1517 383951 : if (!rref.isObject()) {
1518 7 : js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
1519 7 : THROWV(JS_FALSE);
1520 : }
1521 :
1522 383944 : JSObject *obj = &rref.toObject();
1523 : jsid id;
1524 383944 : if (!FetchElementId(f.cx, obj, f.regs.sp[-2], id, &f.regs.sp[-2]))
1525 0 : THROWV(JS_FALSE);
1526 :
1527 : JSObject *obj2;
1528 : JSProperty *prop;
1529 383944 : if (!obj->lookupGeneric(cx, id, &obj2, &prop))
1530 0 : THROWV(JS_FALSE);
1531 :
1532 383944 : return !!prop;
1533 : }
1534 :
1535 : template void JS_FASTCALL stubs::DelElem<true>(VMFrame &f);
1536 : template void JS_FASTCALL stubs::DelElem<false>(VMFrame &f);
1537 :
1538 : void JS_FASTCALL
1539 14673 : stubs::TypeBarrierHelper(VMFrame &f, uint32_t which)
1540 : {
1541 14673 : JS_ASSERT(which == 0 || which == 1);
1542 :
1543 : /* The actual pushed value is at sp[0], fix up the stack. See finishBarrier. */
1544 14673 : Value &result = f.regs.sp[-1 - (int)which];
1545 14673 : result = f.regs.sp[0];
1546 :
1547 : /*
1548 : * Break type barriers at this bytecode if we have added many objects to
1549 : * the target already. This isn't needed if inference results for the
1550 : * script have been destroyed, as we will reanalyze and prune type barriers
1551 : * as they are regenerated.
1552 : */
1553 14673 : if (f.script()->hasAnalysis() && f.script()->analysis()->ranInference()) {
1554 29346 : AutoEnterTypeInference enter(f.cx);
1555 14673 : f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
1556 : }
1557 :
1558 14673 : TypeScript::Monitor(f.cx, f.script(), f.pc(), result);
1559 14673 : }
1560 :
1561 : void JS_FASTCALL
1562 13298 : stubs::StubTypeHelper(VMFrame &f, int32_t which)
1563 : {
1564 13298 : const Value &result = f.regs.sp[which];
1565 :
1566 13298 : if (f.script()->hasAnalysis() && f.script()->analysis()->ranInference()) {
1567 26596 : AutoEnterTypeInference enter(f.cx);
1568 13298 : f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
1569 : }
1570 :
1571 13298 : TypeScript::Monitor(f.cx, f.script(), f.pc(), result);
1572 13298 : }
1573 :
1574 : /*
1575 : * Variant of TypeBarrierHelper for checking types after making a native call.
1576 : * The stack is already correct, and no fixup should be performed.
1577 : */
1578 : void JS_FASTCALL
1579 287 : stubs::TypeBarrierReturn(VMFrame &f, Value *vp)
1580 : {
1581 287 : TypeScript::Monitor(f.cx, f.script(), f.pc(), vp[0]);
1582 287 : }
1583 :
1584 : void JS_FASTCALL
1585 100 : stubs::NegZeroHelper(VMFrame &f)
1586 : {
1587 100 : f.regs.sp[-1].setDouble(-0.0);
1588 100 : TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
1589 100 : }
1590 :
1591 : void JS_FASTCALL
1592 916 : stubs::CheckArgumentTypes(VMFrame &f)
1593 : {
1594 916 : StackFrame *fp = f.fp();
1595 916 : JSFunction *fun = fp->fun();
1596 916 : JSScript *script = fun->script();
1597 916 : RecompilationMonitor monitor(f.cx);
1598 :
1599 : {
1600 : /* Postpone recompilations until all args have been updated. */
1601 1832 : types::AutoEnterTypeInference enter(f.cx);
1602 :
1603 916 : if (!f.fp()->isConstructing())
1604 898 : TypeScript::SetThis(f.cx, script, fp->thisValue());
1605 2337 : for (unsigned i = 0; i < fun->nargs; i++)
1606 1421 : TypeScript::SetArgument(f.cx, script, i, fp->formalArg(i));
1607 : }
1608 :
1609 916 : if (monitor.recompiled())
1610 23 : return;
1611 :
1612 : #ifdef JS_MONOIC
1613 893 : ic::GenerateArgumentCheckStub(f);
1614 : #endif
1615 : }
1616 :
1617 : #ifdef DEBUG
1618 : void JS_FASTCALL
1619 14134094 : stubs::AssertArgumentTypes(VMFrame &f)
1620 : {
1621 14134094 : StackFrame *fp = f.fp();
1622 14134094 : JSFunction *fun = fp->fun();
1623 14134094 : JSScript *script = fun->script();
1624 :
1625 : /*
1626 : * Don't check the type of 'this' for constructor frames, the 'this' value
1627 : * has not been constructed yet.
1628 : */
1629 14134094 : if (!fp->isConstructing()) {
1630 12397874 : Type type = GetValueType(f.cx, fp->thisValue());
1631 12397874 : if (!TypeScript::ThisTypes(script)->hasType(type))
1632 0 : TypeFailure(f.cx, "Missing type for this: %s", TypeString(type));
1633 : }
1634 :
1635 38256008 : for (unsigned i = 0; i < fun->nargs; i++) {
1636 24121914 : Type type = GetValueType(f.cx, fp->formalArg(i));
1637 24121914 : if (!TypeScript::ArgTypes(script, i)->hasType(type))
1638 0 : TypeFailure(f.cx, "Missing type for arg %d: %s", i, TypeString(type));
1639 : }
1640 14134094 : }
1641 : #endif
1642 :
1643 : /*
1644 : * These two are never actually called, they just give us a place to rejoin if
1645 : * there is an invariant failure when initially entering a loop.
1646 : */
1647 0 : void JS_FASTCALL stubs::MissedBoundsCheckEntry(VMFrame &f) {}
1648 0 : void JS_FASTCALL stubs::MissedBoundsCheckHead(VMFrame &f) {}
1649 :
1650 : void * JS_FASTCALL
1651 66 : stubs::InvariantFailure(VMFrame &f, void *rval)
1652 : {
1653 : /*
1654 : * Patch this call to the return site of the call triggering the invariant
1655 : * failure (or a MissedBoundsCheck* function if the failure occurred on
1656 : * initial loop entry), and trigger a recompilation which will then
1657 : * redirect to the rejoin point for that call. We want to make things look
1658 : * to the recompiler like we are still inside that call, and that after
1659 : * recompilation we will return to the call's rejoin point.
1660 : */
1661 66 : void *repatchCode = f.scratch;
1662 66 : JS_ASSERT(repatchCode);
1663 66 : void **frameAddr = f.returnAddressLocation();
1664 66 : *frameAddr = repatchCode;
1665 :
1666 : /* Recompile the outermost script, and don't hoist any bounds checks. */
1667 66 : JSScript *script = f.fp()->script();
1668 66 : JS_ASSERT(!script->failedBoundsCheck);
1669 66 : script->failedBoundsCheck = true;
1670 :
1671 66 : ExpandInlineFrames(f.cx->compartment);
1672 :
1673 66 : mjit::Recompiler::clearStackReferences(f.cx->runtime->defaultFreeOp(), script);
1674 66 : mjit::ReleaseScriptCode(f.cx->runtime->defaultFreeOp(), script);
1675 :
1676 : /* Return the same value (if any) as the call triggering the invariant failure. */
1677 66 : return rval;
1678 : }
1679 :
1680 : void JS_FASTCALL
1681 0 : stubs::Exception(VMFrame &f)
1682 : {
1683 : // Check the interrupt flag to allow interrupting deeply nested exception
1684 : // handling.
1685 0 : if (f.cx->runtime->interrupt && !js_HandleExecutionInterrupt(f.cx))
1686 0 : THROW();
1687 :
1688 0 : f.regs.sp[0] = f.cx->getPendingException();
1689 0 : f.cx->clearPendingException();
1690 : }
1691 :
1692 : void JS_FASTCALL
1693 369352 : stubs::FunctionFramePrologue(VMFrame &f)
1694 : {
1695 369352 : if (!f.fp()->functionPrologue(f.cx))
1696 0 : THROW();
1697 : }
1698 :
1699 : void JS_FASTCALL
1700 687190 : stubs::FunctionFrameEpilogue(VMFrame &f)
1701 : {
1702 687190 : f.fp()->functionEpilogue();
1703 687190 : }
1704 :
1705 : void JS_FASTCALL
1706 202 : stubs::AnyFrameEpilogue(VMFrame &f)
1707 : {
1708 : /*
1709 : * On the normal execution path, emitReturn calls ScriptDebugEpilogue
1710 : * and inlines ScriptEpilogue. This function implements forced early
1711 : * returns, so it must have the same effect.
1712 : */
1713 202 : bool ok = true;
1714 202 : if (f.cx->compartment->debugMode())
1715 202 : ok = js::ScriptDebugEpilogue(f.cx, f.fp(), ok);
1716 202 : ok = ScriptEpilogue(f.cx, f.fp(), ok);
1717 202 : if (!ok)
1718 0 : THROW();
1719 202 : if (f.fp()->isNonEvalFunctionFrame())
1720 162 : f.fp()->functionEpilogue();
1721 : }
1722 :
1723 : template <bool Clamped>
1724 : int32_t JS_FASTCALL
1725 489 : stubs::ConvertToTypedInt(JSContext *cx, Value *vp)
1726 : {
1727 489 : JS_ASSERT(!vp->isInt32());
1728 :
1729 489 : if (vp->isDouble()) {
1730 : if (Clamped)
1731 93 : return js_TypedArray_uint8_clamp_double(vp->toDouble());
1732 276 : return js_DoubleToECMAInt32(vp->toDouble());
1733 : }
1734 :
1735 120 : if (vp->isNull() || vp->isObject() || vp->isUndefined())
1736 120 : return 0;
1737 :
1738 0 : if (vp->isBoolean())
1739 0 : return vp->toBoolean() ? 1 : 0;
1740 :
1741 0 : JS_ASSERT(vp->isString());
1742 :
1743 0 : int32_t i32 = 0;
1744 : #ifdef DEBUG
1745 : bool success =
1746 : #endif
1747 0 : StringToNumberType<int32_t>(cx, vp->toString(), &i32);
1748 0 : JS_ASSERT(success);
1749 :
1750 0 : return i32;
1751 : }
1752 :
1753 : template int32_t JS_FASTCALL stubs::ConvertToTypedInt<true>(JSContext *, Value *);
1754 : template int32_t JS_FASTCALL stubs::ConvertToTypedInt<false>(JSContext *, Value *);
1755 :
1756 : void JS_FASTCALL
1757 56 : stubs::ConvertToTypedFloat(JSContext *cx, Value *vp)
1758 : {
1759 56 : JS_ASSERT(!vp->isDouble() && !vp->isInt32());
1760 :
1761 56 : if (vp->isNull()) {
1762 0 : vp->setDouble(0);
1763 56 : } else if (vp->isObject() || vp->isUndefined()) {
1764 28 : vp->setDouble(js_NaN);
1765 28 : } else if (vp->isBoolean()) {
1766 0 : vp->setDouble(vp->toBoolean() ? 1 : 0);
1767 : } else {
1768 28 : JS_ASSERT(vp->isString());
1769 28 : double d = 0;
1770 : #ifdef DEBUG
1771 : bool success =
1772 : #endif
1773 28 : StringToNumberType<double>(cx, vp->toString(), &d);
1774 28 : JS_ASSERT(success);
1775 28 : vp->setDouble(d);
1776 : }
1777 56 : }
1778 :
1779 : void JS_FASTCALL
1780 48 : stubs::WriteBarrier(VMFrame &f, Value *addr)
1781 : {
1782 48 : gc::MarkValueUnbarriered(f.cx->compartment->barrierTracer(), addr, "write barrier");
1783 48 : }
1784 :
1785 : void JS_FASTCALL
1786 2 : stubs::GCThingWriteBarrier(VMFrame &f, Value *addr)
1787 : {
1788 2 : gc::Cell *cell = (gc::Cell *)addr->toGCThing();
1789 2 : if (cell && !cell->isMarked())
1790 2 : gc::MarkValueUnbarriered(f.cx->compartment->barrierTracer(), addr, "write barrier");
1791 2 : }
|