1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 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 Communicator client code, released
18 : * March 31, 1998.
19 : *
20 : * The Initial Developer of the Original Code is
21 : * Netscape Communications Corporation.
22 : * Portions created by the Initial Developer are Copyright (C) 1998
23 : * the Initial Developer. All Rights Reserved.
24 : *
25 : * Contributor(s):
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 : /*
42 : * JavaScript bytecode interpreter.
43 : */
44 : #include <stdio.h>
45 : #include <string.h>
46 : #include <math.h>
47 : #include "jstypes.h"
48 : #include "jsutil.h"
49 : #include "jsprf.h"
50 : #include "jsapi.h"
51 : #include "jsarray.h"
52 : #include "jsatom.h"
53 : #include "jsbool.h"
54 : #include "jscntxt.h"
55 : #include "jsdate.h"
56 : #include "jsversion.h"
57 : #include "jsdbgapi.h"
58 : #include "jsfun.h"
59 : #include "jsgc.h"
60 : #include "jsgcmark.h"
61 : #include "jsinterp.h"
62 : #include "jsiter.h"
63 : #include "jslock.h"
64 : #include "jsnum.h"
65 : #include "jsobj.h"
66 : #include "jsopcode.h"
67 : #include "jspropertycache.h"
68 : #include "jsscope.h"
69 : #include "jsscript.h"
70 : #include "jsstr.h"
71 : #include "jslibmath.h"
72 :
73 : #include "frontend/BytecodeEmitter.h"
74 : #ifdef JS_METHODJIT
75 : #include "methodjit/MethodJIT.h"
76 : #include "methodjit/Logging.h"
77 : #endif
78 : #include "vm/Debugger.h"
79 :
80 : #include "jsatominlines.h"
81 : #include "jsinferinlines.h"
82 : #include "jsinterpinlines.h"
83 : #include "jsobjinlines.h"
84 : #include "jsopcodeinlines.h"
85 : #include "jsprobes.h"
86 : #include "jspropertycacheinlines.h"
87 : #include "jsscopeinlines.h"
88 : #include "jsscriptinlines.h"
89 : #include "jstypedarrayinlines.h"
90 :
91 : #include "vm/Stack-inl.h"
92 : #include "vm/String-inl.h"
93 :
94 : #if JS_HAS_XML_SUPPORT
95 : #include "jsxml.h"
96 : #endif
97 :
98 : #include "jsautooplen.h"
99 :
100 : #if defined(JS_METHODJIT) && defined(JS_MONOIC)
101 : #include "methodjit/MonoIC.h"
102 : #endif
103 :
104 : using namespace js;
105 : using namespace js::gc;
106 : using namespace js::types;
107 :
108 : /*
109 : * We can't determine in advance which local variables can live on the stack and
110 : * be freed when their dynamic scope ends, and which will be closed over and
111 : * need to live in the heap. So we place variables on the stack initially, note
112 : * when they are closed over, and copy those that are out to the heap when we
113 : * leave their dynamic scope.
114 : *
115 : * The bytecode compiler produces a tree of block objects accompanying each
116 : * JSScript representing those lexical blocks in the script that have let-bound
117 : * variables associated with them. These block objects are never modified, and
118 : * never become part of any function's scope chain. Their parent slots point to
119 : * the innermost block that encloses them, or are NULL in the outermost blocks
120 : * within a function or in eval or global code.
121 : *
122 : * When we are in the static scope of such a block, blockChain points to its
123 : * compiler-allocated block object; otherwise, it is NULL.
124 : *
125 : * scopeChain is the current scope chain, including 'call' and 'block' objects
126 : * for those function calls and lexical blocks whose static scope we are
127 : * currently executing in, and 'with' objects for with statements; the chain is
128 : * typically terminated by a global object. However, as an optimization, the
129 : * young end of the chain omits block objects we have not yet cloned. To create
130 : * a closure, we clone the missing blocks from blockChain (which is always
131 : * current), place them at the head of scopeChain, and use that for the
132 : * closure's scope chain. If we never close over a lexical block, we never
133 : * place a mutable clone of it on scopeChain.
134 : *
135 : * This lazy cloning is implemented in GetScopeChain, which is also used in
136 : * some other cases --- entering 'with' blocks, for example.
137 : */
138 : JSObject *
139 783158 : js::GetScopeChain(JSContext *cx, StackFrame *fp)
140 : {
141 783158 : StaticBlockObject *sharedBlock = fp->maybeBlockChain();
142 :
143 783158 : if (!sharedBlock) {
144 : /*
145 : * Don't force a call object for a lightweight function call, but do
146 : * insist that there is a call object for a heavyweight function call.
147 : */
148 2301198 : JS_ASSERT_IF(fp->isNonEvalFunctionFrame() && fp->fun()->isHeavyweight(),
149 2301198 : fp->hasCallObj());
150 779557 : return &fp->scopeChain();
151 : }
152 :
153 : /*
154 : * We have one or more lexical scopes to reflect into fp->scopeChain, so
155 : * make sure there's a call object at the current head of the scope chain,
156 : * if this frame is a call frame.
157 : *
158 : * Also, identify the innermost compiler-allocated block we needn't clone.
159 : */
160 : JSObject *limitBlock, *limitClone;
161 3601 : if (fp->isNonEvalFunctionFrame() && !fp->hasCallObj()) {
162 0 : JS_ASSERT_IF(fp->scopeChain().isClonedBlock(), fp->scopeChain().getPrivate() != fp);
163 0 : if (!CallObject::createForFunction(cx, fp))
164 0 : return NULL;
165 :
166 : /* We know we must clone everything on blockChain. */
167 0 : limitBlock = limitClone = NULL;
168 : } else {
169 : /*
170 : * scopeChain includes all blocks whose static scope we're within that
171 : * have already been cloned. Find the innermost such block. Its
172 : * prototype should appear on blockChain; we'll clone blockChain up
173 : * to, but not including, that prototype.
174 : */
175 3601 : limitClone = &fp->scopeChain();
176 7274 : while (limitClone->isWith())
177 72 : limitClone = &limitClone->asWith().enclosingScope();
178 3601 : JS_ASSERT(limitClone);
179 :
180 : /*
181 : * It may seem like we don't know enough about limitClone to be able
182 : * to just grab its prototype as we do here, but it's actually okay.
183 : *
184 : * If limitClone is a block object belonging to this frame, then its
185 : * prototype is the innermost entry in blockChain that we have already
186 : * cloned, and is thus the place to stop when we clone below.
187 : *
188 : * Otherwise, there are no blocks for this frame on scopeChain, and we
189 : * need to clone the whole blockChain. In this case, limitBlock can
190 : * point to any object known not to be on blockChain, since we simply
191 : * loop until we hit limitBlock or NULL. If limitClone is a block, it
192 : * isn't a block from this function, since blocks can't be nested
193 : * within themselves on scopeChain (recursion is dynamic nesting, not
194 : * static nesting). If limitClone isn't a block, its prototype won't
195 : * be a block either. So we can just grab limitClone's prototype here
196 : * regardless of its type or which frame it belongs to.
197 : */
198 3601 : limitBlock = limitClone->getProto();
199 :
200 : /* If the innermost block has already been cloned, we are done. */
201 3601 : if (limitBlock == sharedBlock)
202 1746 : return &fp->scopeChain();
203 : }
204 :
205 : /*
206 : * Special-case cloning the innermost block; this doesn't have enough in
207 : * common with subsequent steps to include in the loop.
208 : *
209 : * create() leaves the clone's enclosingScope unset. We set it below.
210 : */
211 1855 : ClonedBlockObject *innermostNewChild = ClonedBlockObject::create(cx, *sharedBlock, fp);
212 1855 : if (!innermostNewChild)
213 0 : return NULL;
214 :
215 : /*
216 : * Clone our way towards outer scopes until we reach the innermost
217 : * enclosing function, or the innermost block we've already cloned.
218 : */
219 1855 : ClonedBlockObject *newChild = innermostNewChild;
220 72 : for (;;) {
221 1927 : JS_ASSERT(newChild->getProto() == sharedBlock);
222 1927 : sharedBlock = sharedBlock->enclosingBlock();
223 :
224 : /* Sometimes limitBlock will be NULL, so check that first. */
225 1927 : if (sharedBlock == limitBlock || !sharedBlock)
226 : break;
227 :
228 : /* As in the call above, we don't know the real parent yet. */
229 72 : ClonedBlockObject *clone = ClonedBlockObject::create(cx, *sharedBlock, fp);
230 72 : if (!clone)
231 0 : return NULL;
232 :
233 72 : if (!newChild->setEnclosingScope(cx, *clone))
234 0 : return NULL;
235 72 : newChild = clone;
236 : }
237 1855 : if (!newChild->setEnclosingScope(cx, fp->scopeChain()))
238 0 : return NULL;
239 :
240 :
241 : /*
242 : * If we found a limit block belonging to this frame, then we should have
243 : * found it in blockChain.
244 : */
245 936 : JS_ASSERT_IF(limitBlock &&
246 : limitBlock->isClonedBlock() &&
247 : limitClone->getPrivate() == js_FloatingFrameIfGenerator(cx, fp),
248 2791 : sharedBlock);
249 :
250 : /* Place our newly cloned blocks at the head of the scope chain. */
251 1855 : fp->setScopeChainNoCallObj(*innermostNewChild);
252 1855 : return innermostNewChild;
253 : }
254 :
255 : JSObject *
256 0 : js::GetScopeChain(JSContext *cx)
257 : {
258 : /*
259 : * Note: we don't need to expand inline frames here, because frames are
260 : * only inlined when the caller and callee share the same scope chain.
261 : */
262 0 : StackFrame *fp = js_GetTopStackFrame(cx, FRAME_EXPAND_NONE);
263 0 : if (!fp) {
264 : /*
265 : * There is no code active on this context. In place of an actual
266 : * scope chain, use the context's global object, which is set in
267 : * js_InitFunctionAndObjectClasses, and which represents the default
268 : * scope chain for the embedding. See also js_FindClassObject.
269 : *
270 : * For embeddings that use the inner and outer object hooks, the inner
271 : * object represents the ultimate global object, with the outer object
272 : * acting as a stand-in.
273 : */
274 0 : JSObject *obj = cx->globalObject;
275 0 : if (!obj) {
276 0 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
277 0 : return NULL;
278 : }
279 :
280 0 : OBJ_TO_INNER_OBJECT(cx, obj);
281 0 : return obj;
282 : }
283 0 : return GetScopeChain(cx, fp);
284 : }
285 :
286 : /* Some objects (e.g., With) delegate 'this' to another object. */
287 : static inline JSObject *
288 : CallThisObjectHook(JSContext *cx, JSObject *obj, Value *argv)
289 : {
290 : JSObject *thisp = obj->thisObject(cx);
291 : if (!thisp)
292 : return NULL;
293 : argv[-1].setObject(*thisp);
294 : return thisp;
295 : }
296 :
297 : /*
298 : * ECMA requires "the global object", but in embeddings such as the browser,
299 : * which have multiple top-level objects (windows, frames, etc. in the DOM),
300 : * we prefer fun's parent. An example that causes this code to run:
301 : *
302 : * // in window w1
303 : * function f() { return this }
304 : * function g() { return f }
305 : *
306 : * // in window w2
307 : * var h = w1.g()
308 : * alert(h() == w1)
309 : *
310 : * The alert should display "true".
311 : */
312 : bool
313 61048 : js::BoxNonStrictThis(JSContext *cx, const CallReceiver &call)
314 : {
315 : /*
316 : * Check for SynthesizeFrame poisoning and fast constructors which
317 : * didn't check their callee properly.
318 : */
319 61048 : Value &thisv = call.thisv();
320 61048 : JS_ASSERT(!thisv.isMagic());
321 :
322 : #ifdef DEBUG
323 61048 : JSFunction *fun = call.callee().isFunction() ? call.callee().toFunction() : NULL;
324 61048 : JS_ASSERT_IF(fun && fun->isInterpreted(), !fun->inStrictMode());
325 : #endif
326 :
327 61048 : if (thisv.isNullOrUndefined()) {
328 59998 : JSObject *thisp = call.callee().global().thisObject(cx);
329 59998 : if (!thisp)
330 0 : return false;
331 59998 : call.thisv().setObject(*thisp);
332 59998 : return true;
333 : }
334 :
335 1050 : if (!thisv.isObject())
336 447 : return !!js_PrimitiveToObject(cx, &thisv);
337 :
338 603 : return true;
339 : }
340 :
341 : #if JS_HAS_NO_SUCH_METHOD
342 :
343 : const uint32_t JSSLOT_FOUND_FUNCTION = 0;
344 : const uint32_t JSSLOT_SAVED_ID = 1;
345 :
346 : Class js_NoSuchMethodClass = {
347 : "NoSuchMethod",
348 : JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
349 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
350 : JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
351 : };
352 :
353 : /*
354 : * When JSOP_CALLPROP or JSOP_CALLELEM does not find the method property of
355 : * the base object, we search for the __noSuchMethod__ method in the base.
356 : * If it exists, we store the method and the property's id into an object of
357 : * NoSuchMethod class and store this object into the callee's stack slot.
358 : * Later, Invoke will recognise such an object and transfer control to
359 : * NoSuchMethod that invokes the method like:
360 : *
361 : * this.__noSuchMethod__(id, args)
362 : *
363 : * where id is the name of the method that this invocation attempted to
364 : * call by name, and args is an Array containing this invocation's actual
365 : * parameters.
366 : */
367 : bool
368 826 : js::OnUnknownMethod(JSContext *cx, JSObject *obj, Value idval, Value *vp)
369 : {
370 826 : jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);
371 1652 : AutoValueRooter tvr(cx);
372 826 : if (!js_GetMethod(cx, obj, id, 0, tvr.addr()))
373 0 : return false;
374 826 : TypeScript::MonitorUnknown(cx, cx->fp()->script(), cx->regs().pc);
375 :
376 826 : if (tvr.value().isPrimitive()) {
377 97 : *vp = tvr.value();
378 : } else {
379 : #if JS_HAS_XML_SUPPORT
380 : /* Extract the function name from function::name qname. */
381 729 : if (idval.isObject()) {
382 0 : obj = &idval.toObject();
383 0 : if (js_GetLocalNameFromFunctionQName(obj, &id, cx))
384 0 : idval = IdToValue(id);
385 : }
386 : #endif
387 :
388 729 : obj = NewObjectWithClassProto(cx, &js_NoSuchMethodClass, NULL, NULL);
389 729 : if (!obj)
390 0 : return false;
391 :
392 729 : obj->setSlot(JSSLOT_FOUND_FUNCTION, tvr.value());
393 729 : obj->setSlot(JSSLOT_SAVED_ID, idval);
394 729 : vp->setObject(*obj);
395 : }
396 826 : return true;
397 : }
398 :
399 : static JSBool
400 729 : NoSuchMethod(JSContext *cx, unsigned argc, Value *vp)
401 : {
402 1458 : InvokeArgsGuard args;
403 729 : if (!cx->stack.pushInvokeArgs(cx, 2, &args))
404 0 : return JS_FALSE;
405 :
406 729 : JS_ASSERT(vp[0].isObject());
407 729 : JS_ASSERT(vp[1].isObject());
408 729 : JSObject *obj = &vp[0].toObject();
409 729 : JS_ASSERT(obj->getClass() == &js_NoSuchMethodClass);
410 :
411 729 : args.calleev() = obj->getSlot(JSSLOT_FOUND_FUNCTION);
412 729 : args.thisv() = vp[1];
413 729 : args[0] = obj->getSlot(JSSLOT_SAVED_ID);
414 729 : JSObject *argsobj = NewDenseCopiedArray(cx, argc, vp + 2);
415 729 : if (!argsobj)
416 0 : return JS_FALSE;
417 729 : args[1].setObject(*argsobj);
418 729 : JSBool ok = Invoke(cx, args);
419 729 : vp[0] = args.rval();
420 729 : return ok;
421 : }
422 :
423 : #endif /* JS_HAS_NO_SUCH_METHOD */
424 :
425 : bool
426 1547479 : js::RunScript(JSContext *cx, JSScript *script, StackFrame *fp)
427 : {
428 1547479 : JS_ASSERT(script);
429 1547479 : JS_ASSERT(fp == cx->fp());
430 1547479 : JS_ASSERT(fp->script() == script);
431 1547479 : JS_ASSERT_IF(!fp->isGeneratorFrame(), cx->regs().pc == script->code);
432 : #ifdef JS_METHODJIT_SPEW
433 1547479 : JMCheckLogging();
434 : #endif
435 :
436 1547479 : JS_CHECK_RECURSION(cx, return false);
437 :
438 : /* FIXME: Once bug 470510 is fixed, make this an assert. */
439 1547396 : if (script->compileAndGo) {
440 1539520 : if (fp->scopeChain().global().isCleared()) {
441 0 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CLEARED_SCOPE);
442 0 : return false;
443 : }
444 : }
445 :
446 : #ifdef DEBUG
447 : struct CheckStackBalance {
448 : JSContext *cx;
449 : StackFrame *fp;
450 : JSObject *enumerators;
451 1547396 : CheckStackBalance(JSContext *cx)
452 1547396 : : cx(cx), fp(cx->fp()), enumerators(cx->enumerators)
453 1547396 : {}
454 1547396 : ~CheckStackBalance() {
455 1547396 : JS_ASSERT(fp == cx->fp());
456 1547396 : JS_ASSERT_IF(!fp->isGeneratorFrame(), enumerators == cx->enumerators);
457 1547396 : }
458 3094792 : } check(cx);
459 : #endif
460 :
461 : #ifdef JS_METHODJIT
462 : mjit::CompileStatus status;
463 1547396 : status = mjit::CanMethodJIT(cx, script, script->code, fp->isConstructing(),
464 1547396 : mjit::CompileRequest_Interpreter);
465 1547396 : if (status == mjit::Compile_Error)
466 0 : return false;
467 :
468 1547396 : if (status == mjit::Compile_Okay)
469 1063402 : return mjit::JaegerStatusToSuccess(mjit::JaegerShot(cx, false));
470 : #endif
471 :
472 483994 : return Interpret(cx, fp);
473 : }
474 :
475 : /*
476 : * Find a function reference and its 'this' value implicit first parameter
477 : * under argc arguments on cx's stack, and call the function. Push missing
478 : * required arguments, allocate declared local variables, and pop everything
479 : * when done. Then push the return value.
480 : */
481 : bool
482 9022674 : js::InvokeKernel(JSContext *cx, CallArgs args, MaybeConstruct construct)
483 : {
484 9022674 : JS_ASSERT(args.length() <= StackSpace::ARGS_LENGTH_MAX);
485 9022674 : JS_ASSERT(!cx->compartment->activeAnalysis);
486 :
487 : /* MaybeConstruct is a subset of InitialFrameFlags */
488 9022674 : InitialFrameFlags initial = (InitialFrameFlags) construct;
489 :
490 9022674 : if (args.calleev().isPrimitive()) {
491 387 : js_ReportIsNotFunction(cx, &args.calleev(), ToReportFlags(initial));
492 387 : return false;
493 : }
494 :
495 9022287 : JSObject &callee = args.callee();
496 9022287 : Class *clasp = callee.getClass();
497 :
498 : /* Invoke non-functions. */
499 9022287 : if (JS_UNLIKELY(clasp != &FunctionClass)) {
500 : #if JS_HAS_NO_SUCH_METHOD
501 21739 : if (JS_UNLIKELY(clasp == &js_NoSuchMethodClass))
502 729 : return NoSuchMethod(cx, args.length(), args.base());
503 : #endif
504 21010 : JS_ASSERT_IF(construct, !clasp->construct);
505 21010 : if (!clasp->call) {
506 91 : js_ReportIsNotFunction(cx, &args.calleev(), ToReportFlags(initial));
507 91 : return false;
508 : }
509 20919 : return CallJSNative(cx, clasp->call, args);
510 : }
511 :
512 : /* Invoke native functions. */
513 9000548 : JSFunction *fun = callee.toFunction();
514 9000548 : JS_ASSERT_IF(construct, !fun->isNativeConstructor());
515 9000548 : if (fun->isNative())
516 7624791 : return CallJSNative(cx, fun->native(), args);
517 :
518 1375757 : TypeMonitorCall(cx, args, construct);
519 :
520 : /* Get pointer to new frame/slots, prepare arguments. */
521 2751514 : InvokeFrameGuard ifg;
522 1375757 : if (!cx->stack.pushInvokeFrame(cx, args, initial, &ifg))
523 28 : return false;
524 :
525 : /* Now that the new frame is rooted, maybe create a call object. */
526 1375729 : StackFrame *fp = ifg.fp();
527 1375729 : if (!fp->functionPrologue(cx))
528 0 : return false;
529 :
530 : /* Run function until JSOP_STOP, JSOP_RETURN or error. */
531 1375729 : JSBool ok = RunScript(cx, fun->script(), fp);
532 :
533 : /* Propagate the return value out. */
534 1375729 : args.rval() = fp->returnValue();
535 1375729 : JS_ASSERT_IF(ok && construct, !args.rval().isPrimitive());
536 1375729 : return ok;
537 : }
538 :
539 : bool
540 1488650 : js::Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, Value *argv,
541 : Value *rval)
542 : {
543 2977300 : InvokeArgsGuard args;
544 1488650 : if (!cx->stack.pushInvokeArgs(cx, argc, &args))
545 0 : return false;
546 :
547 1488650 : args.calleev() = fval;
548 1488650 : args.thisv() = thisv;
549 1488650 : PodCopy(args.array(), argv, argc);
550 :
551 1488650 : if (args.thisv().isObject()) {
552 : /*
553 : * We must call the thisObject hook in case we are not called from the
554 : * interpreter, where a prior bytecode has computed an appropriate
555 : * |this| already.
556 : */
557 1486671 : JSObject *thisp = args.thisv().toObject().thisObject(cx);
558 1486671 : if (!thisp)
559 0 : return false;
560 1486671 : args.thisv().setObject(*thisp);
561 : }
562 :
563 1488650 : if (!Invoke(cx, args))
564 27445 : return false;
565 :
566 1461205 : *rval = args.rval();
567 1461205 : return true;
568 : }
569 :
570 : bool
571 215471 : js::InvokeConstructorKernel(JSContext *cx, const CallArgs &argsRef)
572 : {
573 215471 : JS_ASSERT(!FunctionClass.construct);
574 215471 : CallArgs args = argsRef;
575 :
576 215471 : args.thisv().setMagic(JS_IS_CONSTRUCTING);
577 :
578 215471 : if (args.calleev().isObject()) {
579 215444 : JSObject *callee = &args.callee();
580 215444 : Class *clasp = callee->getClass();
581 215444 : if (clasp == &FunctionClass) {
582 215227 : JSFunction *fun = callee->toFunction();
583 :
584 215227 : if (fun->isNativeConstructor()) {
585 214660 : Probes::calloutBegin(cx, fun);
586 214660 : bool ok = CallJSNativeConstructor(cx, fun->native(), args);
587 214660 : Probes::calloutEnd(cx, fun);
588 214660 : return ok;
589 : }
590 :
591 567 : if (!fun->isInterpretedConstructor())
592 252 : goto error;
593 :
594 315 : if (!InvokeKernel(cx, args, CONSTRUCT))
595 63 : return false;
596 :
597 252 : JS_ASSERT(args.rval().isObject());
598 252 : return true;
599 : }
600 217 : if (clasp->construct)
601 208 : return CallJSNativeConstructor(cx, clasp->construct, args);
602 : }
603 :
604 : error:
605 288 : js_ReportIsNotFunction(cx, &args.calleev(), JSV2F_CONSTRUCT);
606 288 : return false;
607 : }
608 :
609 : bool
610 12682 : js::InvokeConstructor(JSContext *cx, const Value &fval, unsigned argc, Value *argv, Value *rval)
611 : {
612 25364 : InvokeArgsGuard args;
613 12682 : if (!cx->stack.pushInvokeArgs(cx, argc, &args))
614 0 : return false;
615 :
616 12682 : args.calleev() = fval;
617 12682 : args.thisv().setMagic(JS_THIS_POISON);
618 12682 : PodCopy(args.array(), argv, argc);
619 :
620 12682 : if (!InvokeConstructor(cx, args))
621 72 : return false;
622 :
623 12610 : *rval = args.rval();
624 12610 : return true;
625 : }
626 :
627 : bool
628 346366 : js::InvokeGetterOrSetter(JSContext *cx, JSObject *obj, const Value &fval, unsigned argc, Value *argv,
629 : Value *rval)
630 : {
631 : /*
632 : * Invoke could result in another try to get or set the same id again, see
633 : * bug 355497.
634 : */
635 346366 : JS_CHECK_RECURSION(cx, return false);
636 :
637 346361 : return Invoke(cx, ObjectValue(*obj), fval, argc, argv, rval);
638 : }
639 :
640 : bool
641 153147 : js::ExecuteKernel(JSContext *cx, JSScript *script, JSObject &scopeChain, const Value &thisv,
642 : ExecuteType type, StackFrame *evalInFrame, Value *result)
643 : {
644 153147 : JS_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG);
645 :
646 306294 : Root<JSScript*> scriptRoot(cx, &script);
647 :
648 153147 : if (script->isEmpty()) {
649 500 : if (result)
650 490 : result->setUndefined();
651 500 : return true;
652 : }
653 :
654 305294 : ExecuteFrameGuard efg;
655 152647 : if (!cx->stack.pushExecuteFrame(cx, script, thisv, scopeChain, type, evalInFrame, &efg))
656 0 : return false;
657 :
658 152647 : if (!script->ensureRanAnalysis(cx, &scopeChain))
659 0 : return false;
660 :
661 : /* Give strict mode eval its own fresh lexical environment. */
662 152647 : StackFrame *fp = efg.fp();
663 152647 : if (fp->isStrictEvalFrame() && !CallObject::createForStrictEval(cx, fp))
664 0 : return false;
665 :
666 152647 : Probes::startExecution(cx, script);
667 :
668 152647 : TypeScript::SetThis(cx, script, fp->thisValue());
669 :
670 152647 : bool ok = RunScript(cx, script, fp);
671 :
672 152647 : if (fp->isStrictEvalFrame())
673 1908 : js_PutCallObject(fp);
674 :
675 152647 : Probes::stopExecution(cx, script);
676 :
677 : /* Propgate the return value out. */
678 152647 : if (result)
679 114424 : *result = fp->returnValue();
680 152647 : return ok;
681 : }
682 :
683 : bool
684 57616 : js::Execute(JSContext *cx, JSScript *script, JSObject &scopeChainArg, Value *rval)
685 : {
686 : /* The scope chain could be anything, so innerize just in case. */
687 57616 : JSObject *scopeChain = &scopeChainArg;
688 57616 : OBJ_TO_INNER_OBJECT(cx, scopeChain);
689 57616 : if (!scopeChain)
690 0 : return false;
691 :
692 : /* If we were handed a non-native object, complain bitterly. */
693 57616 : if (!scopeChain->isNative()) {
694 0 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NON_NATIVE_SCOPE);
695 0 : return false;
696 : }
697 57616 : JS_ASSERT(!scopeChain->getOps()->defineProperty);
698 :
699 : /* The VAROBJFIX option makes varObj == globalObj in global code. */
700 57616 : if (!cx->hasRunOption(JSOPTION_VAROBJFIX)) {
701 57384 : if (!scopeChain->setVarObj(cx))
702 0 : return false;
703 : }
704 :
705 : /* Use the scope chain as 'this', modulo outerization. */
706 57616 : JSObject *thisObj = scopeChain->thisObject(cx);
707 57616 : if (!thisObj)
708 0 : return false;
709 57616 : Value thisv = ObjectValue(*thisObj);
710 :
711 : return ExecuteKernel(cx, script, *scopeChain, thisv, EXECUTE_GLOBAL,
712 57616 : NULL /* evalInFrame */, rval);
713 : }
714 :
715 : JSBool
716 1050339 : js::HasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
717 : {
718 1050339 : Class *clasp = obj->getClass();
719 1050339 : if (clasp->hasInstance)
720 1050321 : return clasp->hasInstance(cx, obj, v, bp);
721 18 : js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
722 18 : JSDVG_SEARCH_STACK, ObjectValue(*obj), NULL);
723 18 : return JS_FALSE;
724 : }
725 :
726 : bool
727 4344647 : js::LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *result)
728 : {
729 : #if JS_HAS_XML_SUPPORT
730 8726364 : if (JS_UNLIKELY(lval.isObject() && lval.toObject().isXML()) ||
731 4381717 : (rval.isObject() && rval.toObject().isXML())) {
732 : JSBool res;
733 9 : if (!js_TestXMLEquality(cx, lval, rval, &res))
734 0 : return false;
735 9 : *result = !!res;
736 9 : return true;
737 : }
738 : #endif
739 :
740 4344638 : if (SameType(lval, rval)) {
741 4142675 : if (lval.isString()) {
742 513953 : JSString *l = lval.toString();
743 513953 : JSString *r = rval.toString();
744 513953 : return EqualStrings(cx, l, r, result);
745 : }
746 :
747 3628722 : if (lval.isDouble()) {
748 40057 : double l = lval.toDouble(), r = rval.toDouble();
749 40057 : *result = (l == r);
750 40057 : return true;
751 : }
752 :
753 3588665 : if (lval.isObject()) {
754 34374 : JSObject *l = &lval.toObject();
755 34374 : JSObject *r = &rval.toObject();
756 :
757 34374 : if (JSEqualityOp eq = l->getClass()->ext.equality) {
758 : JSBool res;
759 10 : if (!eq(cx, l, &rval, &res))
760 0 : return false;
761 10 : *result = !!res;
762 10 : return true;
763 : }
764 :
765 34364 : *result = l == r;
766 34364 : return true;
767 : }
768 :
769 3554291 : *result = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
770 3554291 : return true;
771 : }
772 :
773 201963 : if (lval.isNullOrUndefined()) {
774 10063 : *result = rval.isNullOrUndefined();
775 10063 : return true;
776 : }
777 :
778 191900 : if (rval.isNullOrUndefined()) {
779 174565 : *result = false;
780 174565 : return true;
781 : }
782 :
783 17335 : Value lvalue = lval;
784 17335 : Value rvalue = rval;
785 :
786 17335 : if (!ToPrimitive(cx, &lvalue))
787 5 : return false;
788 17330 : if (!ToPrimitive(cx, &rvalue))
789 0 : return false;
790 :
791 17330 : if (lvalue.isString() && rvalue.isString()) {
792 1377 : JSString *l = lvalue.toString();
793 1377 : JSString *r = rvalue.toString();
794 1377 : return EqualStrings(cx, l, r, result);
795 : }
796 :
797 : double l, r;
798 15953 : if (!ToNumber(cx, lvalue, &l) || !ToNumber(cx, rvalue, &r))
799 0 : return false;
800 15953 : *result = (l == r);
801 15953 : return true;
802 : }
803 :
804 : bool
805 10344166 : js::StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, bool *equal)
806 : {
807 10344166 : Value lval = lref, rval = rref;
808 10344166 : if (SameType(lval, rval)) {
809 9135120 : if (lval.isString())
810 1002932 : return EqualStrings(cx, lval.toString(), rval.toString(), equal);
811 8132188 : if (lval.isDouble()) {
812 1048236 : *equal = (lval.toDouble() == rval.toDouble());
813 1048236 : return true;
814 : }
815 7083952 : if (lval.isObject()) {
816 728835 : *equal = lval.toObject() == rval.toObject();
817 728835 : return true;
818 : }
819 6355117 : if (lval.isUndefined()) {
820 1189250 : *equal = true;
821 1189250 : return true;
822 : }
823 5165867 : *equal = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
824 5165867 : return true;
825 : }
826 :
827 1209046 : if (lval.isDouble() && rval.isInt32()) {
828 7518 : double ld = lval.toDouble();
829 7518 : double rd = rval.toInt32();
830 7518 : *equal = (ld == rd);
831 7518 : return true;
832 : }
833 1201528 : if (lval.isInt32() && rval.isDouble()) {
834 6254 : double ld = lval.toInt32();
835 6254 : double rd = rval.toDouble();
836 6254 : *equal = (ld == rd);
837 6254 : return true;
838 : }
839 :
840 1195274 : *equal = false;
841 1195274 : return true;
842 : }
843 :
844 : static inline bool
845 10584212 : IsNegativeZero(const Value &v)
846 : {
847 10584212 : return v.isDouble() && JSDOUBLE_IS_NEGZERO(v.toDouble());
848 : }
849 :
850 : static inline bool
851 5294060 : IsNaN(const Value &v)
852 : {
853 5294060 : return v.isDouble() && JSDOUBLE_IS_NaN(v.toDouble());
854 : }
855 :
856 : bool
857 5292106 : js::SameValue(JSContext *cx, const Value &v1, const Value &v2, bool *same)
858 : {
859 5292106 : if (IsNegativeZero(v1)) {
860 621 : *same = IsNegativeZero(v2);
861 621 : return true;
862 : }
863 5291485 : if (IsNegativeZero(v2)) {
864 1 : *same = false;
865 1 : return true;
866 : }
867 5291484 : if (IsNaN(v1) && IsNaN(v2)) {
868 2576 : *same = true;
869 2576 : return true;
870 : }
871 5288908 : return StrictlyEqual(cx, v1, v2, same);
872 : }
873 :
874 : JSType
875 164799 : js::TypeOfValue(JSContext *cx, const Value &vref)
876 : {
877 164799 : Value v = vref;
878 164799 : if (v.isNumber())
879 36166 : return JSTYPE_NUMBER;
880 128633 : if (v.isString())
881 98180 : return JSTYPE_STRING;
882 30453 : if (v.isNull())
883 54 : return JSTYPE_OBJECT;
884 30399 : if (v.isUndefined())
885 2085 : return JSTYPE_VOID;
886 28314 : if (v.isObject())
887 28137 : return v.toObject().typeOf(cx);
888 177 : JS_ASSERT(v.isBoolean());
889 177 : return JSTYPE_BOOLEAN;
890 : }
891 :
892 : bool
893 12975106 : js::ValueToId(JSContext *cx, const Value &v, jsid *idp)
894 : {
895 : int32_t i;
896 12975106 : if (ValueFitsInInt32(v, &i) && INT_FITS_IN_JSID(i)) {
897 315291 : *idp = INT_TO_JSID(i);
898 315291 : return true;
899 : }
900 :
901 : #if JS_HAS_XML_SUPPORT
902 12659815 : if (v.isObject()) {
903 72 : JSObject *obj = &v.toObject();
904 72 : if (obj->isXMLId()) {
905 36 : *idp = OBJECT_TO_JSID(obj);
906 36 : return JS_TRUE;
907 : }
908 : }
909 : #endif
910 :
911 12659779 : return js_ValueToStringId(cx, v, idp);
912 : }
913 :
914 : /*
915 : * Enter the new with scope using an object at sp[-1] and associate the depth
916 : * of the with block with sp + stackIndex.
917 : */
918 : static bool
919 1836 : EnterWith(JSContext *cx, int stackIndex)
920 : {
921 1836 : StackFrame *fp = cx->fp();
922 1836 : Value *sp = cx->regs().sp;
923 1836 : JS_ASSERT(stackIndex < 0);
924 1836 : JS_ASSERT(fp->base() <= sp + stackIndex);
925 :
926 : JSObject *obj;
927 1836 : if (sp[-1].isObject()) {
928 1809 : obj = &sp[-1].toObject();
929 : } else {
930 27 : obj = js_ValueToNonNullObject(cx, sp[-1]);
931 27 : if (!obj)
932 9 : return JS_FALSE;
933 18 : sp[-1].setObject(*obj);
934 : }
935 :
936 1827 : JSObject *parent = GetScopeChain(cx, fp);
937 1827 : if (!parent)
938 0 : return JS_FALSE;
939 :
940 : JSObject *withobj = WithObject::create(cx, fp, *obj, *parent,
941 1827 : sp + stackIndex - fp->base());
942 1827 : if (!withobj)
943 0 : return JS_FALSE;
944 :
945 1827 : fp->setScopeChainNoCallObj(*withobj);
946 1827 : return JS_TRUE;
947 : }
948 :
949 : static void
950 1827 : LeaveWith(JSContext *cx)
951 : {
952 1827 : WithObject &withobj = cx->fp()->scopeChain().asWith();
953 1827 : JS_ASSERT(withobj.maybeStackFrame() == js_FloatingFrameIfGenerator(cx, cx->fp()));
954 1827 : withobj.setStackFrame(NULL);
955 1827 : cx->fp()->setScopeChainNoCallObj(withobj.enclosingScope());
956 1827 : }
957 :
958 : bool
959 15046374 : js::IsActiveWithOrBlock(JSContext *cx, JSObject &obj, uint32_t stackDepth)
960 : {
961 30092569 : return (obj.isWith() || obj.isBlock()) &&
962 2395 : obj.getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()) &&
963 30094964 : obj.asNestedScope().stackDepth() >= stackDepth;
964 : }
965 :
966 : /* Unwind block and scope chains to match the given depth. */
967 : void
968 3291968 : js::UnwindScope(JSContext *cx, uint32_t stackDepth)
969 : {
970 3291968 : JS_ASSERT(cx->fp()->base() + stackDepth <= cx->regs().sp);
971 :
972 3291968 : StackFrame *fp = cx->fp();
973 3291968 : StaticBlockObject *block = fp->maybeBlockChain();
974 6584143 : while (block) {
975 360 : if (block->stackDepth() < stackDepth)
976 153 : break;
977 207 : block = block->enclosingBlock();
978 : }
979 3291968 : fp->setBlockChain(block);
980 :
981 90 : for (;;) {
982 3292058 : JSObject &scopeChain = fp->scopeChain();
983 3292058 : if (!IsActiveWithOrBlock(cx, scopeChain, stackDepth))
984 : break;
985 90 : if (scopeChain.isClonedBlock())
986 63 : scopeChain.asClonedBlock().put(cx);
987 : else
988 27 : LeaveWith(cx);
989 : }
990 3291968 : }
991 :
992 : void
993 817 : js::UnwindForUncatchableException(JSContext *cx, const FrameRegs ®s)
994 : {
995 :
996 : /* c.f. the regular (catchable) TryNoteIter loop in Interpret. */
997 880 : for (TryNoteIter tni(regs); !tni.done(); ++tni) {
998 63 : JSTryNote *tn = *tni;
999 63 : if (tn->kind == JSTRY_ITER) {
1000 0 : Value *sp = regs.fp()->base() + tn->stackDepth;
1001 0 : UnwindIteratorForUncatchableException(cx, &sp[-1].toObject());
1002 : }
1003 : }
1004 817 : }
1005 :
1006 2018341 : TryNoteIter::TryNoteIter(const FrameRegs ®s)
1007 : : regs(regs),
1008 2018341 : script(regs.fp()->script()),
1009 4036682 : pcOffset(regs.pc - script->main())
1010 : {
1011 2018341 : if (JSScript::isValidOffset(script->trynotesOffset)) {
1012 14664 : tn = script->trynotes()->vector;
1013 14664 : tnEnd = tn + script->trynotes()->length;
1014 : } else {
1015 2003677 : tn = tnEnd = NULL;
1016 : }
1017 2018341 : settle();
1018 2018341 : }
1019 :
1020 : void
1021 2963 : TryNoteIter::operator++()
1022 : {
1023 2963 : ++tn;
1024 2963 : settle();
1025 2963 : }
1026 :
1027 : bool
1028 2021304 : TryNoteIter::done() const
1029 : {
1030 2021304 : return tn == tnEnd;
1031 : }
1032 :
1033 : void
1034 2021304 : TryNoteIter::settle()
1035 : {
1036 2078561 : for (; tn != tnEnd; ++tn) {
1037 : /* If pc is out of range, try the next one. */
1038 72877 : if (pcOffset - tn->start >= tn->length)
1039 57257 : continue;
1040 :
1041 : /*
1042 : * We have a note that covers the exception pc but we must check
1043 : * whether the interpreter has already executed the corresponding
1044 : * handler. This is possible when the executed bytecode implements
1045 : * break or return from inside a for-in loop.
1046 : *
1047 : * In this case the emitter generates additional [enditer] and [gosub]
1048 : * opcodes to close all outstanding iterators and execute the finally
1049 : * blocks. If such an [enditer] throws an exception, its pc can still
1050 : * be inside several nested for-in loops and try-finally statements
1051 : * even if we have already closed the corresponding iterators and
1052 : * invoked the finally blocks.
1053 : *
1054 : * To address this, we make [enditer] always decrease the stack even
1055 : * when its implementation throws an exception. Thus already executed
1056 : * [enditer] and [gosub] opcodes will have try notes with the stack
1057 : * depth exceeding the current one and this condition is what we use to
1058 : * filter them out.
1059 : */
1060 15620 : if (tn->stackDepth <= regs.sp - regs.fp()->base())
1061 15620 : break;
1062 : }
1063 2021304 : }
1064 :
1065 : /*
1066 : * Increment/decrement the value 'v'. The resulting value is stored in *slot.
1067 : * The result of the expression (taking into account prefix/postfix) is stored
1068 : * in *expr.
1069 : */
1070 : static bool
1071 303998787 : DoIncDec(JSContext *cx, JSScript *script, jsbytecode *pc, const Value &v, Value *slot, Value *expr)
1072 : {
1073 303998787 : const JSCodeSpec &cs = js_CodeSpec[*pc];
1074 :
1075 303998787 : if (v.isInt32()) {
1076 303996900 : int32_t i = v.toInt32();
1077 303996900 : if (i > JSVAL_INT_MIN && i < JSVAL_INT_MAX) {
1078 303996880 : int32_t sum = i + (cs.format & JOF_INC ? 1 : -1);
1079 303996880 : *slot = Int32Value(sum);
1080 303996880 : *expr = (cs.format & JOF_POST) ? Int32Value(i) : *slot;
1081 303996880 : return true;
1082 : }
1083 : }
1084 :
1085 : double d;
1086 1907 : if (!ToNumber(cx, *slot, &d))
1087 0 : return false;
1088 :
1089 1907 : double sum = d + (cs.format & JOF_INC ? 1 : -1);
1090 1907 : *slot = NumberValue(sum);
1091 1907 : *expr = (cs.format & JOF_POST) ? NumberValue(d) : *slot;
1092 :
1093 1907 : TypeScript::MonitorOverflow(cx, script, pc);
1094 1907 : return true;
1095 : }
1096 :
1097 : #define PUSH_COPY(v) do { *regs.sp++ = v; assertSameCompartment(cx, regs.sp[-1]); } while (0)
1098 : #define PUSH_COPY_SKIP_CHECK(v) *regs.sp++ = v
1099 : #define PUSH_NULL() regs.sp++->setNull()
1100 : #define PUSH_UNDEFINED() regs.sp++->setUndefined()
1101 : #define PUSH_BOOLEAN(b) regs.sp++->setBoolean(b)
1102 : #define PUSH_DOUBLE(d) regs.sp++->setDouble(d)
1103 : #define PUSH_INT32(i) regs.sp++->setInt32(i)
1104 : #define PUSH_STRING(s) do { regs.sp++->setString(s); assertSameCompartment(cx, regs.sp[-1]); } while (0)
1105 : #define PUSH_OBJECT(obj) do { regs.sp++->setObject(obj); assertSameCompartment(cx, regs.sp[-1]); } while (0)
1106 : #define PUSH_OBJECT_OR_NULL(obj) do { regs.sp++->setObjectOrNull(obj); assertSameCompartment(cx, regs.sp[-1]); } while (0)
1107 : #define PUSH_HOLE() regs.sp++->setMagic(JS_ARRAY_HOLE)
1108 : #define POP_COPY_TO(v) v = *--regs.sp
1109 : #define POP_RETURN_VALUE() regs.fp()->setReturnValue(*--regs.sp)
1110 :
1111 : #define VALUE_TO_BOOLEAN(cx, vp, b) \
1112 : JS_BEGIN_MACRO \
1113 : vp = ®s.sp[-1]; \
1114 : if (vp->isNull()) { \
1115 : b = false; \
1116 : } else if (vp->isBoolean()) { \
1117 : b = vp->toBoolean(); \
1118 : } else { \
1119 : b = !!js_ValueToBoolean(*vp); \
1120 : } \
1121 : JS_END_MACRO
1122 :
1123 : #define POP_BOOLEAN(cx, vp, b) do { VALUE_TO_BOOLEAN(cx, vp, b); regs.sp--; } while(0)
1124 :
1125 : #define FETCH_OBJECT(cx, n, obj) \
1126 : JS_BEGIN_MACRO \
1127 : Value *vp_ = ®s.sp[n]; \
1128 : obj = ToObject(cx, (vp_)); \
1129 : if (!obj) \
1130 : goto error; \
1131 : JS_END_MACRO
1132 :
1133 : /*
1134 : * Threaded interpretation via computed goto appears to be well-supported by
1135 : * GCC 3 and higher. IBM's C compiler when run with the right options (e.g.,
1136 : * -qlanglvl=extended) also supports threading. Ditto the SunPro C compiler.
1137 : * Currently it's broken for JS_VERSION < 160, though this isn't worth fixing.
1138 : * Add your compiler support macros here.
1139 : */
1140 : #ifndef JS_THREADED_INTERP
1141 : # if JS_VERSION >= 160 && ( \
1142 : __GNUC__ >= 3 || \
1143 : (__IBMC__ >= 700 && defined __IBM_COMPUTED_GOTO) || \
1144 : __SUNPRO_C >= 0x570)
1145 : # define JS_THREADED_INTERP 1
1146 : # else
1147 : # define JS_THREADED_INTERP 0
1148 : # endif
1149 : #endif
1150 :
1151 : template<typename T>
1152 : class GenericInterruptEnabler : public InterpreterFrames::InterruptEnablerBase {
1153 : public:
1154 517775 : GenericInterruptEnabler(T *variable, T value) : variable(variable), value(value) { }
1155 1515 : void enableInterrupts() const { *variable = value; }
1156 :
1157 : private:
1158 : T *variable;
1159 : T value;
1160 : };
1161 :
1162 517775 : inline InterpreterFrames::InterpreterFrames(JSContext *cx, FrameRegs *regs,
1163 : const InterruptEnablerBase &enabler)
1164 517775 : : context(cx), regs(regs), enabler(enabler)
1165 : {
1166 517775 : older = cx->runtime->interpreterFrames;
1167 517775 : cx->runtime->interpreterFrames = this;
1168 517775 : }
1169 :
1170 517775 : inline InterpreterFrames::~InterpreterFrames()
1171 : {
1172 517775 : context->runtime->interpreterFrames = older;
1173 517775 : }
1174 :
1175 : #if defined(DEBUG) && !defined(JS_THREADSAFE)
1176 : void
1177 : js::AssertValidPropertyCacheHit(JSContext *cx,
1178 : JSObject *start, JSObject *found,
1179 : PropertyCacheEntry *entry)
1180 : {
1181 : jsbytecode *pc;
1182 : cx->stack.currentScript(&pc);
1183 :
1184 : uint64_t sample = cx->runtime->gcNumber;
1185 : PropertyCacheEntry savedEntry = *entry;
1186 :
1187 : PropertyName *name = GetNameFromBytecode(cx, pc, JSOp(*pc), js_CodeSpec[*pc]);
1188 :
1189 : JSObject *obj, *pobj;
1190 : JSProperty *prop;
1191 : JSBool ok;
1192 :
1193 : if (JOF_OPMODE(*pc) == JOF_NAME)
1194 : ok = FindProperty(cx, name, start, &obj, &pobj, &prop);
1195 : else
1196 : ok = LookupProperty(cx, start, name, &pobj, &prop);
1197 : JS_ASSERT(ok);
1198 :
1199 : if (cx->runtime->gcNumber != sample)
1200 : JS_PROPERTY_CACHE(cx).restore(&savedEntry);
1201 : JS_ASSERT(prop);
1202 : JS_ASSERT(pobj == found);
1203 :
1204 : const Shape *shape = (Shape *) prop;
1205 : JS_ASSERT(entry->prop == shape);
1206 : }
1207 : #endif /* DEBUG && !JS_THREADSAFE */
1208 :
1209 : /*
1210 : * Ensure that the intrepreter switch can close call-bytecode cases in the
1211 : * same way as non-call bytecodes.
1212 : */
1213 : JS_STATIC_ASSERT(JSOP_NAME_LENGTH == JSOP_CALLNAME_LENGTH);
1214 : JS_STATIC_ASSERT(JSOP_GETARG_LENGTH == JSOP_CALLARG_LENGTH);
1215 : JS_STATIC_ASSERT(JSOP_GETLOCAL_LENGTH == JSOP_CALLLOCAL_LENGTH);
1216 : JS_STATIC_ASSERT(JSOP_XMLNAME_LENGTH == JSOP_CALLXMLNAME_LENGTH);
1217 :
1218 : /*
1219 : * Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but
1220 : * remain distinct for the decompiler.
1221 : */
1222 : JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
1223 :
1224 : /* See TRY_BRANCH_AFTER_COND. */
1225 : JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH);
1226 : JS_STATIC_ASSERT(JSOP_IFNE == JSOP_IFEQ + 1);
1227 :
1228 : /* For the fastest case inder JSOP_INCNAME, etc. */
1229 : JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_DECNAME_LENGTH);
1230 : JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEINC_LENGTH);
1231 : JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEDEC_LENGTH);
1232 :
1233 : /*
1234 : * Inline fast paths for iteration. js_IteratorMore and js_IteratorNext handle
1235 : * all cases, but we inline the most frequently taken paths here.
1236 : */
1237 : static inline bool
1238 3273845 : IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, Value *rval)
1239 : {
1240 3273845 : if (iterobj->isIterator()) {
1241 3260121 : NativeIterator *ni = iterobj->getNativeIterator();
1242 3260121 : if (ni->isKeyIter()) {
1243 555984 : *cond = (ni->props_cursor < ni->props_end);
1244 555984 : return true;
1245 : }
1246 : }
1247 2717861 : if (!js_IteratorMore(cx, iterobj, rval))
1248 20 : return false;
1249 2717841 : *cond = rval->isTrue();
1250 2717841 : return true;
1251 : }
1252 :
1253 : static inline bool
1254 3221647 : IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
1255 : {
1256 3221647 : if (iterobj->isIterator()) {
1257 3210231 : NativeIterator *ni = iterobj->getNativeIterator();
1258 3210231 : if (ni->isKeyIter()) {
1259 542627 : JS_ASSERT(ni->props_cursor < ni->props_end);
1260 542627 : rval->setString(*ni->current());
1261 542627 : ni->incCursor();
1262 542627 : return true;
1263 : }
1264 : }
1265 2679020 : return js_IteratorNext(cx, iterobj, rval);
1266 : }
1267 :
1268 : /*
1269 : * For bytecodes which push values and then fall through, make sure the
1270 : * types of the pushed values are consistent with type inference information.
1271 : */
1272 : static inline void
1273 1718061810 : TypeCheckNextBytecode(JSContext *cx, JSScript *script, unsigned n, const FrameRegs ®s)
1274 : {
1275 : #ifdef DEBUG
1276 -1714338827 : if (cx->typeInferenceEnabled() &&
1277 862566659 : n == GetBytecodeLength(regs.pc)) {
1278 859862289 : TypeScript::CheckBytecode(cx, script, regs.pc, regs.sp);
1279 : }
1280 : #endif
1281 1718061810 : }
1282 :
1283 : JS_NEVER_INLINE bool
1284 517775 : js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
1285 : {
1286 1035550 : JSAutoResolveFlags rf(cx, RESOLVE_INFER);
1287 :
1288 517775 : gc::MaybeVerifyBarriers(cx, true);
1289 :
1290 517775 : JS_ASSERT(!cx->compartment->activeAnalysis);
1291 :
1292 : #if JS_THREADED_INTERP
1293 : #define CHECK_PCCOUNT_INTERRUPTS() JS_ASSERT_IF(script->scriptCounts, jumpTable == interruptJumpTable)
1294 : #else
1295 : #define CHECK_PCCOUNT_INTERRUPTS() JS_ASSERT_IF(script->scriptCounts, switchMask == -1)
1296 : #endif
1297 :
1298 : /*
1299 : * Macros for threaded interpreter loop
1300 : */
1301 : #if JS_THREADED_INTERP
1302 : static void *const normalJumpTable[] = {
1303 : # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
1304 : JS_EXTENSION &&L_##op,
1305 : # include "jsopcode.tbl"
1306 : # undef OPDEF
1307 : };
1308 :
1309 : static void *const interruptJumpTable[] = {
1310 : # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
1311 : JS_EXTENSION &&interrupt,
1312 : # include "jsopcode.tbl"
1313 : # undef OPDEF
1314 : };
1315 :
1316 517775 : register void * const *jumpTable = normalJumpTable;
1317 :
1318 : typedef GenericInterruptEnabler<void * const *> InterruptEnabler;
1319 517775 : InterruptEnabler interruptEnabler(&jumpTable, interruptJumpTable);
1320 :
1321 : # define DO_OP() JS_BEGIN_MACRO \
1322 : CHECK_PCCOUNT_INTERRUPTS(); \
1323 : js::gc::MaybeVerifyBarriers(cx); \
1324 : JS_EXTENSION_(goto *jumpTable[op]); \
1325 : JS_END_MACRO
1326 : # define DO_NEXT_OP(n) JS_BEGIN_MACRO \
1327 : TypeCheckNextBytecode(cx, script, n, regs); \
1328 : op = (JSOp) *(regs.pc += (n)); \
1329 : DO_OP(); \
1330 : JS_END_MACRO
1331 :
1332 : # define BEGIN_CASE(OP) L_##OP:
1333 : # define END_CASE(OP) DO_NEXT_OP(OP##_LENGTH);
1334 : # define END_VARLEN_CASE DO_NEXT_OP(len);
1335 : # define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP) \
1336 : JS_ASSERT(js_CodeSpec[OP].length == 1); \
1337 : op = (JSOp) *++regs.pc; \
1338 : DO_OP();
1339 :
1340 : # define END_EMPTY_CASES
1341 :
1342 : #else /* !JS_THREADED_INTERP */
1343 :
1344 : register int switchMask = 0;
1345 : int switchOp;
1346 : typedef GenericInterruptEnabler<int> InterruptEnabler;
1347 : InterruptEnabler interruptEnabler(&switchMask, -1);
1348 :
1349 : # define DO_OP() goto do_op
1350 : # define DO_NEXT_OP(n) JS_BEGIN_MACRO \
1351 : JS_ASSERT((n) == len); \
1352 : goto advance_pc; \
1353 : JS_END_MACRO
1354 :
1355 : # define BEGIN_CASE(OP) case OP:
1356 : # define END_CASE(OP) END_CASE_LEN(OP##_LENGTH)
1357 : # define END_CASE_LEN(n) END_CASE_LENX(n)
1358 : # define END_CASE_LENX(n) END_CASE_LEN##n
1359 :
1360 : /*
1361 : * To share the code for all len == 1 cases we use the specialized label with
1362 : * code that falls through to advance_pc: .
1363 : */
1364 : # define END_CASE_LEN1 goto advance_pc_by_one;
1365 : # define END_CASE_LEN2 len = 2; goto advance_pc;
1366 : # define END_CASE_LEN3 len = 3; goto advance_pc;
1367 : # define END_CASE_LEN4 len = 4; goto advance_pc;
1368 : # define END_CASE_LEN5 len = 5; goto advance_pc;
1369 : # define END_CASE_LEN6 len = 6; goto advance_pc;
1370 : # define END_CASE_LEN7 len = 7; goto advance_pc;
1371 : # define END_VARLEN_CASE goto advance_pc;
1372 : # define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP)
1373 : # define END_EMPTY_CASES goto advance_pc_by_one;
1374 :
1375 : #endif /* !JS_THREADED_INTERP */
1376 :
1377 : #define ENABLE_INTERRUPTS() (interruptEnabler.enableInterrupts())
1378 :
1379 : #define LOAD_ATOM(PCOFF, atom) \
1380 : JS_BEGIN_MACRO \
1381 : JS_ASSERT((size_t)(atoms - script->atoms) < \
1382 : (size_t)(script->natoms - GET_UINT32_INDEX(regs.pc + PCOFF)));\
1383 : atom = atoms[GET_UINT32_INDEX(regs.pc + PCOFF)]; \
1384 : JS_END_MACRO
1385 :
1386 : #define LOAD_NAME(PCOFF, name) \
1387 : JS_BEGIN_MACRO \
1388 : JSAtom *atom; \
1389 : LOAD_ATOM((PCOFF), atom); \
1390 : name = atom->asPropertyName(); \
1391 : JS_END_MACRO
1392 :
1393 : #define LOAD_DOUBLE(PCOFF, dbl) \
1394 : (dbl = script->getConst(GET_UINT32_INDEX(regs.pc + (PCOFF))).toDouble())
1395 :
1396 : #if defined(JS_METHODJIT)
1397 517775 : bool useMethodJIT = false;
1398 : #endif
1399 :
1400 : #ifdef JS_METHODJIT
1401 :
1402 : #define RESET_USE_METHODJIT() \
1403 : JS_BEGIN_MACRO \
1404 : useMethodJIT = cx->methodJitEnabled && \
1405 : (interpMode == JSINTERP_NORMAL || \
1406 : interpMode == JSINTERP_REJOIN || \
1407 : interpMode == JSINTERP_SKIP_TRAP); \
1408 : JS_END_MACRO
1409 :
1410 : #define CHECK_PARTIAL_METHODJIT(status) \
1411 : JS_BEGIN_MACRO \
1412 : switch (status) { \
1413 : case mjit::Jaeger_UnfinishedAtTrap: \
1414 : interpMode = JSINTERP_SKIP_TRAP; \
1415 : /* FALLTHROUGH */ \
1416 : case mjit::Jaeger_Unfinished: \
1417 : op = (JSOp) *regs.pc; \
1418 : RESTORE_INTERP_VARS_CHECK_EXCEPTION(); \
1419 : DO_OP(); \
1420 : default:; \
1421 : } \
1422 : JS_END_MACRO
1423 :
1424 : #else
1425 :
1426 : #define RESET_USE_METHODJIT() ((void) 0)
1427 :
1428 : #endif
1429 :
1430 : #define RESTORE_INTERP_VARS() \
1431 : JS_BEGIN_MACRO \
1432 : SET_SCRIPT(regs.fp()->script()); \
1433 : argv = regs.fp()->maybeFormalArgs(); \
1434 : atoms = FrameAtomBase(cx, regs.fp()); \
1435 : JS_ASSERT(&cx->regs() == ®s); \
1436 : JS_END_MACRO
1437 :
1438 : #define RESTORE_INTERP_VARS_CHECK_EXCEPTION() \
1439 : JS_BEGIN_MACRO \
1440 : RESTORE_INTERP_VARS(); \
1441 : if (cx->isExceptionPending()) \
1442 : goto error; \
1443 : CHECK_INTERRUPT_HANDLER(); \
1444 : JS_END_MACRO
1445 :
1446 : /*
1447 : * Prepare to call a user-supplied branch handler, and abort the script
1448 : * if it returns false.
1449 : */
1450 : #define CHECK_BRANCH() \
1451 : JS_BEGIN_MACRO \
1452 : if (cx->runtime->interrupt && !js_HandleExecutionInterrupt(cx)) \
1453 : goto error; \
1454 : JS_END_MACRO
1455 :
1456 : #define BRANCH(n) \
1457 : JS_BEGIN_MACRO \
1458 : regs.pc += (n); \
1459 : op = (JSOp) *regs.pc; \
1460 : if ((n) <= 0) \
1461 : goto check_backedge; \
1462 : DO_OP(); \
1463 : JS_END_MACRO
1464 :
1465 : #define SET_SCRIPT(s) \
1466 : JS_BEGIN_MACRO \
1467 : script = (s); \
1468 : if (script->hasAnyBreakpointsOrStepMode()) \
1469 : ENABLE_INTERRUPTS(); \
1470 : if (script->scriptCounts) \
1471 : ENABLE_INTERRUPTS(); \
1472 : JS_ASSERT_IF(interpMode == JSINTERP_SKIP_TRAP, \
1473 : script->hasAnyBreakpointsOrStepMode()); \
1474 : JS_END_MACRO
1475 :
1476 : #define CHECK_INTERRUPT_HANDLER() \
1477 : JS_BEGIN_MACRO \
1478 : if (cx->runtime->debugHooks.interruptHook) \
1479 : ENABLE_INTERRUPTS(); \
1480 : JS_END_MACRO
1481 :
1482 : /* Repoint cx->regs to a local variable for faster access. */
1483 517775 : FrameRegs regs = cx->regs();
1484 1035550 : PreserveRegsGuard interpGuard(cx, regs);
1485 :
1486 : /*
1487 : * Help Debugger find frames running scripts that it has put in
1488 : * single-step mode.
1489 : */
1490 1035550 : InterpreterFrames interpreterFrame(cx, ®s, interruptEnabler);
1491 :
1492 : /* Copy in hot values that change infrequently. */
1493 517775 : JSRuntime *const rt = cx->runtime;
1494 : JSScript *script;
1495 517775 : SET_SCRIPT(regs.fp()->script());
1496 517775 : Value *argv = regs.fp()->maybeFormalArgs();
1497 517775 : CHECK_INTERRUPT_HANDLER();
1498 :
1499 517775 : if (rt->profilingScripts)
1500 0 : ENABLE_INTERRUPTS();
1501 :
1502 517775 : if (!entryFrame)
1503 0 : entryFrame = regs.fp();
1504 :
1505 : /*
1506 : * Initialize the index segment register used by LOAD_ATOM and
1507 : * GET_FULL_INDEX macros below. As a register we use a pointer based on
1508 : * the atom map to turn frequently executed LOAD_ATOM into simple array
1509 : * access. For less frequent object loads we have to recover the segment
1510 : * from atoms pointer first.
1511 : */
1512 517775 : JSAtom **atoms = script->atoms;
1513 :
1514 : #if JS_HAS_GENERATORS
1515 517775 : if (JS_UNLIKELY(regs.fp()->isGeneratorFrame())) {
1516 19096 : JS_ASSERT((size_t) (regs.pc - script->code) <= script->length);
1517 19096 : JS_ASSERT((size_t) (regs.sp - regs.fp()->base()) <= StackDepth(script));
1518 :
1519 : /*
1520 : * To support generator_throw and to catch ignored exceptions,
1521 : * fail if cx->isExceptionPending() is true.
1522 : */
1523 19096 : if (cx->isExceptionPending())
1524 1470 : goto error;
1525 : }
1526 : #endif
1527 :
1528 : /* State communicated between non-local jumps: */
1529 : bool interpReturnOK;
1530 :
1531 : /* Don't call the script prologue if executing between Method and Trace JIT. */
1532 516305 : if (interpMode == JSINTERP_NORMAL) {
1533 502134 : StackFrame *fp = regs.fp();
1534 502134 : JS_ASSERT_IF(!fp->isGeneratorFrame(), regs.pc == script->code);
1535 502134 : if (!ScriptPrologueOrGeneratorResume(cx, fp, UseNewTypeAtEntry(cx, fp)))
1536 0 : goto error;
1537 502134 : if (cx->compartment->debugMode()) {
1538 42184 : JSTrapStatus status = ScriptDebugPrologue(cx, fp);
1539 42184 : switch (status) {
1540 : case JSTRAP_CONTINUE:
1541 : break;
1542 : case JSTRAP_RETURN:
1543 10 : interpReturnOK = true;
1544 10 : goto forced_return;
1545 : case JSTRAP_THROW:
1546 : case JSTRAP_ERROR:
1547 402 : goto error;
1548 : default:
1549 0 : JS_NOT_REACHED("bad ScriptDebugPrologue status");
1550 : }
1551 : }
1552 : }
1553 :
1554 : /* The REJOIN mode acts like the normal mode, except the prologue is skipped. */
1555 515893 : if (interpMode == JSINTERP_REJOIN)
1556 14165 : interpMode = JSINTERP_NORMAL;
1557 :
1558 515893 : CHECK_INTERRUPT_HANDLER();
1559 :
1560 515893 : RESET_USE_METHODJIT();
1561 :
1562 : /*
1563 : * It is important that "op" be initialized before calling DO_OP because
1564 : * it is possible for "op" to be specially assigned during the normal
1565 : * processing of an opcode while looping. We rely on DO_NEXT_OP to manage
1566 : * "op" correctly in all other cases.
1567 : */
1568 : JSOp op;
1569 : int32_t len;
1570 515893 : len = 0;
1571 :
1572 515893 : DO_NEXT_OP(len);
1573 :
1574 : #if JS_THREADED_INTERP
1575 : /*
1576 : * This is a loop, but it does not look like a loop. The loop-closing
1577 : * jump is distributed throughout goto *jumpTable[op] inside of DO_OP.
1578 : * When interrupts are enabled, jumpTable is set to interruptJumpTable
1579 : * where all jumps point to the interrupt label. The latter, after
1580 : * calling the interrupt handler, dispatches through normalJumpTable to
1581 : * continue the normal bytecode processing.
1582 : */
1583 :
1584 : #else /* !JS_THREADED_INTERP */
1585 : for (;;) {
1586 : advance_pc_by_one:
1587 : JS_ASSERT(js_CodeSpec[op].length == 1);
1588 : len = 1;
1589 : advance_pc:
1590 : regs.pc += len;
1591 : op = (JSOp) *regs.pc;
1592 :
1593 : do_op:
1594 : CHECK_PCCOUNT_INTERRUPTS();
1595 : js::gc::MaybeVerifyBarriers(cx);
1596 : switchOp = int(op) | switchMask;
1597 : do_switch:
1598 : switch (switchOp) {
1599 : #endif
1600 :
1601 : #if JS_THREADED_INTERP
1602 : interrupt:
1603 : #else /* !JS_THREADED_INTERP */
1604 : case -1:
1605 : JS_ASSERT(switchMask == -1);
1606 : #endif /* !JS_THREADED_INTERP */
1607 : {
1608 18186 : bool moreInterrupts = false;
1609 :
1610 18186 : if (cx->runtime->profilingScripts) {
1611 0 : if (!script->scriptCounts)
1612 0 : script->initScriptCounts(cx);
1613 0 : moreInterrupts = true;
1614 : }
1615 :
1616 18186 : if (script->scriptCounts) {
1617 0 : PCCounts counts = script->getPCCounts(regs.pc);
1618 0 : counts.get(PCCounts::BASE_INTERP)++;
1619 0 : moreInterrupts = true;
1620 : }
1621 :
1622 18186 : JSInterruptHook hook = cx->runtime->debugHooks.interruptHook;
1623 18186 : if (hook || script->stepModeEnabled()) {
1624 : Value rval;
1625 5514 : JSTrapStatus status = JSTRAP_CONTINUE;
1626 5514 : if (hook)
1627 17 : status = hook(cx, script, regs.pc, &rval, cx->runtime->debugHooks.interruptHookData);
1628 5514 : if (status == JSTRAP_CONTINUE && script->stepModeEnabled())
1629 5514 : status = Debugger::onSingleStep(cx, &rval);
1630 5514 : switch (status) {
1631 : case JSTRAP_ERROR:
1632 18 : goto error;
1633 : case JSTRAP_CONTINUE:
1634 5478 : break;
1635 : case JSTRAP_RETURN:
1636 9 : regs.fp()->setReturnValue(rval);
1637 9 : interpReturnOK = true;
1638 9 : goto forced_return;
1639 : case JSTRAP_THROW:
1640 9 : cx->setPendingException(rval);
1641 9 : goto error;
1642 : default:;
1643 : }
1644 5478 : moreInterrupts = true;
1645 : }
1646 :
1647 18150 : if (script->hasAnyBreakpointsOrStepMode())
1648 17725 : moreInterrupts = true;
1649 :
1650 18150 : if (script->hasBreakpointsAt(regs.pc) && interpMode != JSINTERP_SKIP_TRAP) {
1651 : Value rval;
1652 967 : JSTrapStatus status = Debugger::onTrap(cx, &rval);
1653 967 : switch (status) {
1654 : case JSTRAP_ERROR:
1655 5 : goto error;
1656 : case JSTRAP_RETURN:
1657 30 : regs.fp()->setReturnValue(rval);
1658 30 : interpReturnOK = true;
1659 30 : goto forced_return;
1660 : case JSTRAP_THROW:
1661 9 : cx->setPendingException(rval);
1662 9 : goto error;
1663 : default:
1664 : break;
1665 : }
1666 923 : JS_ASSERT(status == JSTRAP_CONTINUE);
1667 923 : CHECK_INTERRUPT_HANDLER();
1668 923 : JS_ASSERT(rval.isInt32() && rval.toInt32() == op);
1669 : }
1670 :
1671 18106 : interpMode = JSINTERP_NORMAL;
1672 :
1673 : #if JS_THREADED_INTERP
1674 18106 : jumpTable = moreInterrupts ? interruptJumpTable : normalJumpTable;
1675 18106 : JS_EXTENSION_(goto *normalJumpTable[op]);
1676 : #else
1677 : switchMask = moreInterrupts ? -1 : 0;
1678 : switchOp = int(op);
1679 : goto do_switch;
1680 : #endif
1681 : }
1682 :
1683 : /* No-ops for ease of decompilation. */
1684 126453 : ADD_EMPTY_CASE(JSOP_NOP)
1685 0 : ADD_EMPTY_CASE(JSOP_UNUSED0)
1686 0 : ADD_EMPTY_CASE(JSOP_UNUSED1)
1687 0 : ADD_EMPTY_CASE(JSOP_UNUSED2)
1688 0 : ADD_EMPTY_CASE(JSOP_UNUSED3)
1689 0 : ADD_EMPTY_CASE(JSOP_UNUSED4)
1690 0 : ADD_EMPTY_CASE(JSOP_UNUSED5)
1691 0 : ADD_EMPTY_CASE(JSOP_UNUSED6)
1692 0 : ADD_EMPTY_CASE(JSOP_UNUSED7)
1693 0 : ADD_EMPTY_CASE(JSOP_UNUSED8)
1694 0 : ADD_EMPTY_CASE(JSOP_UNUSED9)
1695 0 : ADD_EMPTY_CASE(JSOP_UNUSED10)
1696 0 : ADD_EMPTY_CASE(JSOP_UNUSED11)
1697 0 : ADD_EMPTY_CASE(JSOP_UNUSED12)
1698 0 : ADD_EMPTY_CASE(JSOP_UNUSED13)
1699 0 : ADD_EMPTY_CASE(JSOP_UNUSED14)
1700 0 : ADD_EMPTY_CASE(JSOP_UNUSED15)
1701 0 : ADD_EMPTY_CASE(JSOP_UNUSED16)
1702 0 : ADD_EMPTY_CASE(JSOP_UNUSED17)
1703 0 : ADD_EMPTY_CASE(JSOP_UNUSED18)
1704 0 : ADD_EMPTY_CASE(JSOP_UNUSED19)
1705 0 : ADD_EMPTY_CASE(JSOP_UNUSED20)
1706 0 : ADD_EMPTY_CASE(JSOP_UNUSED21)
1707 0 : ADD_EMPTY_CASE(JSOP_UNUSED22)
1708 0 : ADD_EMPTY_CASE(JSOP_UNUSED23)
1709 0 : ADD_EMPTY_CASE(JSOP_UNUSED24)
1710 0 : ADD_EMPTY_CASE(JSOP_UNUSED25)
1711 0 : ADD_EMPTY_CASE(JSOP_UNUSED26)
1712 0 : ADD_EMPTY_CASE(JSOP_UNUSED27)
1713 0 : ADD_EMPTY_CASE(JSOP_UNUSED28)
1714 0 : ADD_EMPTY_CASE(JSOP_UNUSED29)
1715 0 : ADD_EMPTY_CASE(JSOP_UNUSED30)
1716 0 : ADD_EMPTY_CASE(JSOP_UNUSED31)
1717 1000379 : ADD_EMPTY_CASE(JSOP_CONDSWITCH)
1718 311778 : ADD_EMPTY_CASE(JSOP_TRY)
1719 : #if JS_HAS_XML_SUPPORT
1720 622 : ADD_EMPTY_CASE(JSOP_STARTXML)
1721 0 : ADD_EMPTY_CASE(JSOP_STARTXMLEXPR)
1722 : #endif
1723 165503459 : ADD_EMPTY_CASE(JSOP_LOOPHEAD)
1724 167597126 : ADD_EMPTY_CASE(JSOP_LOOPENTRY)
1725 : END_EMPTY_CASES
1726 :
1727 : BEGIN_CASE(JSOP_LABEL)
1728 403 : END_CASE(JSOP_LABEL)
1729 :
1730 : check_backedge:
1731 : {
1732 165506598 : CHECK_BRANCH();
1733 165506598 : if (op != JSOP_LOOPHEAD)
1734 87 : DO_OP();
1735 :
1736 : #ifdef JS_METHODJIT
1737 165506511 : if (!useMethodJIT)
1738 165338202 : DO_OP();
1739 : mjit::CompileStatus status =
1740 168309 : mjit::CanMethodJIT(cx, script, regs.pc, regs.fp()->isConstructing(),
1741 168309 : mjit::CompileRequest_Interpreter);
1742 168309 : if (status == mjit::Compile_Error)
1743 0 : goto error;
1744 168309 : if (status == mjit::Compile_Okay) {
1745 : void *ncode =
1746 24716 : script->nativeCodeForPC(regs.fp()->isConstructing(), regs.pc);
1747 24716 : JS_ASSERT(ncode);
1748 24716 : mjit::JaegerStatus status = mjit::JaegerShotAtSafePoint(cx, ncode, true);
1749 24716 : if (status == mjit::Jaeger_ThrowBeforeEnter)
1750 0 : goto error;
1751 24716 : CHECK_PARTIAL_METHODJIT(status);
1752 4248 : interpReturnOK = (status == mjit::Jaeger_Returned);
1753 4248 : if (entryFrame != regs.fp())
1754 3542 : goto jit_return;
1755 706 : regs.fp()->setFinishedInInterpreter();
1756 706 : goto leave_on_safe_point;
1757 : }
1758 143593 : if (status == mjit::Compile_Abort)
1759 10858 : useMethodJIT = false;
1760 : #endif /* JS_METHODJIT */
1761 :
1762 143593 : DO_OP();
1763 : }
1764 :
1765 : /* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */
1766 : BEGIN_CASE(JSOP_LINENO)
1767 21905 : END_CASE(JSOP_LINENO)
1768 :
1769 : BEGIN_CASE(JSOP_UNDEFINED)
1770 9902520 : PUSH_UNDEFINED();
1771 9902520 : END_CASE(JSOP_UNDEFINED)
1772 :
1773 : BEGIN_CASE(JSOP_POP)
1774 372880092 : regs.sp--;
1775 372880092 : END_CASE(JSOP_POP)
1776 :
1777 : BEGIN_CASE(JSOP_POPN)
1778 : {
1779 2484 : regs.sp -= GET_UINT16(regs.pc);
1780 : #ifdef DEBUG
1781 2484 : JS_ASSERT(regs.fp()->base() <= regs.sp);
1782 2484 : StaticBlockObject *block = regs.fp()->maybeBlockChain();
1783 666 : JS_ASSERT_IF(block,
1784 : block->stackDepth() + block->slotCount()
1785 3150 : <= (size_t) (regs.sp - regs.fp()->base()));
1786 5742 : for (JSObject *obj = ®s.fp()->scopeChain(); obj; obj = obj->enclosingScope()) {
1787 3258 : if (!obj->isBlock() || !obj->isWith())
1788 3258 : continue;
1789 0 : if (obj->getPrivate() != js_FloatingFrameIfGenerator(cx, regs.fp()))
1790 0 : break;
1791 0 : JS_ASSERT(regs.fp()->base() + obj->asBlock().stackDepth()
1792 : + (obj->isBlock() ? obj->asBlock().slotCount() : 1)
1793 0 : <= regs.sp);
1794 : }
1795 : #endif
1796 : }
1797 2484 : END_CASE(JSOP_POPN)
1798 :
1799 : BEGIN_CASE(JSOP_SETRVAL)
1800 : BEGIN_CASE(JSOP_POPV)
1801 62482 : POP_RETURN_VALUE();
1802 62482 : END_CASE(JSOP_POPV)
1803 :
1804 : BEGIN_CASE(JSOP_ENTERWITH)
1805 1773 : if (!EnterWith(cx, -1))
1806 9 : goto error;
1807 :
1808 : /*
1809 : * We must ensure that different "with" blocks have different stack depth
1810 : * associated with them. This allows the try handler search to properly
1811 : * recover the scope chain. Thus we must keep the stack at least at the
1812 : * current level.
1813 : *
1814 : * We set sp[-1] to the current "with" object to help asserting the
1815 : * enter/leave balance in [leavewith].
1816 : */
1817 1764 : regs.sp[-1].setObject(regs.fp()->scopeChain());
1818 1764 : END_CASE(JSOP_ENTERWITH)
1819 :
1820 : BEGIN_CASE(JSOP_LEAVEWITH)
1821 1737 : JS_ASSERT(regs.sp[-1].toObject() == regs.fp()->scopeChain());
1822 1737 : regs.sp--;
1823 1737 : LeaveWith(cx);
1824 1737 : END_CASE(JSOP_LEAVEWITH)
1825 :
1826 : BEGIN_CASE(JSOP_RETURN)
1827 6064878 : POP_RETURN_VALUE();
1828 : /* FALL THROUGH */
1829 :
1830 : BEGIN_CASE(JSOP_RETRVAL) /* fp return value already set */
1831 : BEGIN_CASE(JSOP_STOP)
1832 : {
1833 : /*
1834 : * When the inlined frame exits with an exception or an error, ok will be
1835 : * false after the inline_return label.
1836 : */
1837 8488409 : CHECK_BRANCH();
1838 :
1839 8488409 : interpReturnOK = true;
1840 8488409 : if (entryFrame != regs.fp())
1841 : inline_return:
1842 : {
1843 10000754 : JS_ASSERT(!regs.fp()->hasBlockChain());
1844 10000754 : JS_ASSERT(!IsActiveWithOrBlock(cx, regs.fp()->scopeChain(), 0));
1845 :
1846 10000754 : if (cx->compartment->debugMode())
1847 867842 : interpReturnOK = ScriptDebugEpilogue(cx, regs.fp(), interpReturnOK);
1848 :
1849 10000754 : interpReturnOK = ScriptEpilogue(cx, regs.fp(), interpReturnOK);
1850 :
1851 : /* The JIT inlines ScriptEpilogue. */
1852 : #ifdef JS_METHODJIT
1853 : jit_return:
1854 : #endif
1855 :
1856 : /* The results of lowered call/apply frames need to be shifted. */
1857 10093872 : bool shiftResult = regs.fp()->loweredCallOrApply();
1858 :
1859 10093872 : cx->stack.popInlineFrame(regs);
1860 :
1861 10093872 : RESTORE_INTERP_VARS();
1862 :
1863 0 : JS_ASSERT(*regs.pc == JSOP_NEW || *regs.pc == JSOP_CALL ||
1864 10093872 : *regs.pc == JSOP_FUNCALL || *regs.pc == JSOP_FUNAPPLY);
1865 :
1866 : /* Resume execution in the calling frame. */
1867 10093872 : RESET_USE_METHODJIT();
1868 10093872 : if (JS_LIKELY(interpReturnOK)) {
1869 8096273 : TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
1870 :
1871 8096273 : if (shiftResult) {
1872 39 : regs.sp[-2] = regs.sp[-1];
1873 39 : regs.sp--;
1874 : }
1875 :
1876 8096273 : len = JSOP_CALL_LENGTH;
1877 8096273 : DO_NEXT_OP(len);
1878 : }
1879 :
1880 : /* Increment pc so that |sp - fp->slots == ReconstructStackDepth(pc)|. */
1881 1997599 : regs.pc += JSOP_CALL_LENGTH;
1882 1997599 : goto error;
1883 : } else {
1884 489369 : JS_ASSERT(regs.sp == regs.fp()->base());
1885 : }
1886 489369 : interpReturnOK = true;
1887 489369 : goto exit;
1888 : }
1889 :
1890 : BEGIN_CASE(JSOP_DEFAULT)
1891 162 : regs.sp--;
1892 : /* FALL THROUGH */
1893 : BEGIN_CASE(JSOP_GOTO)
1894 : {
1895 5528659 : len = GET_JUMP_OFFSET(regs.pc);
1896 5528659 : BRANCH(len);
1897 : }
1898 : END_CASE(JSOP_GOTO)
1899 :
1900 : BEGIN_CASE(JSOP_IFEQ)
1901 : {
1902 : bool cond;
1903 : Value *_;
1904 6694869 : POP_BOOLEAN(cx, _, cond);
1905 6694869 : if (cond == false) {
1906 4404471 : len = GET_JUMP_OFFSET(regs.pc);
1907 4404471 : BRANCH(len);
1908 : }
1909 : }
1910 2290398 : END_CASE(JSOP_IFEQ)
1911 :
1912 : BEGIN_CASE(JSOP_IFNE)
1913 : {
1914 : bool cond;
1915 : Value *_;
1916 5100948 : POP_BOOLEAN(cx, _, cond);
1917 5100948 : if (cond != false) {
1918 4891492 : len = GET_JUMP_OFFSET(regs.pc);
1919 4891492 : BRANCH(len);
1920 : }
1921 : }
1922 209456 : END_CASE(JSOP_IFNE)
1923 :
1924 : BEGIN_CASE(JSOP_OR)
1925 : {
1926 : bool cond;
1927 : Value *_;
1928 435506 : VALUE_TO_BOOLEAN(cx, _, cond);
1929 435506 : if (cond == true) {
1930 120464 : len = GET_JUMP_OFFSET(regs.pc);
1931 120464 : DO_NEXT_OP(len);
1932 : }
1933 : }
1934 315042 : END_CASE(JSOP_OR)
1935 :
1936 : BEGIN_CASE(JSOP_AND)
1937 : {
1938 : bool cond;
1939 : Value *_;
1940 147178 : VALUE_TO_BOOLEAN(cx, _, cond);
1941 147178 : if (cond == false) {
1942 67206 : len = GET_JUMP_OFFSET(regs.pc);
1943 67206 : DO_NEXT_OP(len);
1944 : }
1945 : }
1946 79972 : END_CASE(JSOP_AND)
1947 :
1948 : /*
1949 : * If the index value at sp[n] is not an int that fits in a jsval, it could
1950 : * be an object (an XML QName, AttributeName, or AnyName), but only if we are
1951 : * compiling with JS_HAS_XML_SUPPORT. Otherwise convert the index value to a
1952 : * string atom id.
1953 : */
1954 : #define FETCH_ELEMENT_ID(obj, n, id) \
1955 : JS_BEGIN_MACRO \
1956 : const Value &idval_ = regs.sp[n]; \
1957 : int32_t i_; \
1958 : if (ValueFitsInInt32(idval_, &i_) && INT_FITS_IN_JSID(i_)) { \
1959 : id = INT_TO_JSID(i_); \
1960 : } else { \
1961 : if (!js_InternNonIntElementId(cx, obj, idval_, &id, ®s.sp[n])) \
1962 : goto error; \
1963 : } \
1964 : JS_END_MACRO
1965 :
1966 : #define TRY_BRANCH_AFTER_COND(cond,spdec) \
1967 : JS_BEGIN_MACRO \
1968 : JS_ASSERT(js_CodeSpec[op].length == 1); \
1969 : unsigned diff_ = (unsigned) GET_UINT8(regs.pc) - (unsigned) JSOP_IFEQ; \
1970 : if (diff_ <= 1) { \
1971 : regs.sp -= spdec; \
1972 : if (cond == (diff_ != 0)) { \
1973 : ++regs.pc; \
1974 : len = GET_JUMP_OFFSET(regs.pc); \
1975 : BRANCH(len); \
1976 : } \
1977 : len = 1 + JSOP_IFEQ_LENGTH; \
1978 : DO_NEXT_OP(len); \
1979 : } \
1980 : JS_END_MACRO
1981 :
1982 : BEGIN_CASE(JSOP_IN)
1983 : {
1984 151982 : const Value &rref = regs.sp[-1];
1985 151982 : if (!rref.isObject()) {
1986 11 : js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
1987 11 : goto error;
1988 : }
1989 151971 : JSObject *obj = &rref.toObject();
1990 : jsid id;
1991 151971 : FETCH_ELEMENT_ID(obj, -2, id);
1992 : JSObject *obj2;
1993 : JSProperty *prop;
1994 151971 : if (!obj->lookupGeneric(cx, id, &obj2, &prop))
1995 0 : goto error;
1996 151971 : bool cond = prop != NULL;
1997 151971 : TRY_BRANCH_AFTER_COND(cond, 2);
1998 150983 : regs.sp--;
1999 150983 : regs.sp[-1].setBoolean(cond);
2000 : }
2001 150983 : END_CASE(JSOP_IN)
2002 :
2003 : BEGIN_CASE(JSOP_ITER)
2004 : {
2005 164682 : JS_ASSERT(regs.sp > regs.fp()->base());
2006 164682 : uint8_t flags = GET_UINT8(regs.pc);
2007 164682 : if (!ValueToIterator(cx, flags, ®s.sp[-1]))
2008 150 : goto error;
2009 164532 : CHECK_INTERRUPT_HANDLER();
2010 164532 : JS_ASSERT(!regs.sp[-1].isPrimitive());
2011 : }
2012 164532 : END_CASE(JSOP_ITER)
2013 :
2014 : BEGIN_CASE(JSOP_MOREITER)
2015 : {
2016 3273845 : JS_ASSERT(regs.sp - 1 >= regs.fp()->base());
2017 3273845 : JS_ASSERT(regs.sp[-1].isObject());
2018 3273845 : PUSH_NULL();
2019 : bool cond;
2020 3273845 : if (!IteratorMore(cx, ®s.sp[-2].toObject(), &cond, ®s.sp[-1]))
2021 20 : goto error;
2022 3273825 : CHECK_INTERRUPT_HANDLER();
2023 3273825 : regs.sp[-1].setBoolean(cond);
2024 : }
2025 3273825 : END_CASE(JSOP_MOREITER)
2026 :
2027 : BEGIN_CASE(JSOP_ITERNEXT)
2028 : {
2029 3221647 : Value *itervp = regs.sp - GET_INT8(regs.pc);
2030 3221647 : JS_ASSERT(itervp >= regs.fp()->base());
2031 3221647 : JS_ASSERT(itervp->isObject());
2032 3221647 : PUSH_NULL();
2033 3221647 : if (!IteratorNext(cx, &itervp->toObject(), ®s.sp[-1]))
2034 0 : goto error;
2035 : }
2036 3221647 : END_CASE(JSOP_ITERNEXT)
2037 :
2038 : BEGIN_CASE(JSOP_ENDITER)
2039 : {
2040 165285 : JS_ASSERT(regs.sp - 1 >= regs.fp()->base());
2041 165285 : bool ok = CloseIterator(cx, ®s.sp[-1].toObject());
2042 165285 : regs.sp--;
2043 165285 : if (!ok)
2044 0 : goto error;
2045 : }
2046 165285 : END_CASE(JSOP_ENDITER)
2047 :
2048 : BEGIN_CASE(JSOP_DUP)
2049 : {
2050 7853022 : JS_ASSERT(regs.sp > regs.fp()->base());
2051 7853022 : const Value &rref = regs.sp[-1];
2052 7853022 : PUSH_COPY(rref);
2053 : }
2054 7853022 : END_CASE(JSOP_DUP)
2055 :
2056 : BEGIN_CASE(JSOP_DUP2)
2057 : {
2058 1361954 : JS_ASSERT(regs.sp - 2 >= regs.fp()->base());
2059 1361954 : const Value &lref = regs.sp[-2];
2060 1361954 : const Value &rref = regs.sp[-1];
2061 1361954 : PUSH_COPY(lref);
2062 1361954 : PUSH_COPY(rref);
2063 : }
2064 1361954 : END_CASE(JSOP_DUP2)
2065 :
2066 : BEGIN_CASE(JSOP_SWAP)
2067 : {
2068 7035032 : JS_ASSERT(regs.sp - 2 >= regs.fp()->base());
2069 7035032 : Value &lref = regs.sp[-2];
2070 7035032 : Value &rref = regs.sp[-1];
2071 7035032 : lref.swap(rref);
2072 : }
2073 7035032 : END_CASE(JSOP_SWAP)
2074 :
2075 : BEGIN_CASE(JSOP_PICK)
2076 : {
2077 1237665 : unsigned i = GET_UINT8(regs.pc);
2078 1237665 : JS_ASSERT(regs.sp - (i + 1) >= regs.fp()->base());
2079 1237665 : Value lval = regs.sp[-int(i + 1)];
2080 1237665 : memmove(regs.sp - (i + 1), regs.sp - i, sizeof(Value) * i);
2081 1237665 : regs.sp[-1] = lval;
2082 : }
2083 1237665 : END_CASE(JSOP_PICK)
2084 :
2085 : BEGIN_CASE(JSOP_SETCONST)
2086 : {
2087 : PropertyName *name;
2088 31053 : LOAD_NAME(0, name);
2089 31053 : JSObject &obj = regs.fp()->varObj();
2090 31053 : const Value &ref = regs.sp[-1];
2091 31053 : if (!obj.defineProperty(cx, name, ref,
2092 : JS_PropertyStub, JS_StrictPropertyStub,
2093 31053 : JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
2094 0 : goto error;
2095 : }
2096 : }
2097 31053 : END_CASE(JSOP_SETCONST);
2098 :
2099 : #if JS_HAS_DESTRUCTURING
2100 : BEGIN_CASE(JSOP_ENUMCONSTELEM)
2101 : {
2102 0 : const Value &ref = regs.sp[-3];
2103 : JSObject *obj;
2104 0 : FETCH_OBJECT(cx, -2, obj);
2105 : jsid id;
2106 0 : FETCH_ELEMENT_ID(obj, -1, id);
2107 0 : if (!obj->defineGeneric(cx, id, ref,
2108 : JS_PropertyStub, JS_StrictPropertyStub,
2109 0 : JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
2110 0 : goto error;
2111 : }
2112 0 : regs.sp -= 3;
2113 : }
2114 0 : END_CASE(JSOP_ENUMCONSTELEM)
2115 : #endif
2116 :
2117 : BEGIN_CASE(JSOP_BINDGNAME)
2118 11778173 : PUSH_OBJECT(regs.fp()->scopeChain().global());
2119 11778173 : END_CASE(JSOP_BINDGNAME)
2120 :
2121 : BEGIN_CASE(JSOP_BINDNAME)
2122 : {
2123 : JSObject *obj;
2124 : do {
2125 : /*
2126 : * We can skip the property lookup for the global object. If the
2127 : * property does not exist anywhere on the scope chain, JSOP_SETNAME
2128 : * adds the property to the global.
2129 : *
2130 : * As a consequence of this optimization for the global object we run
2131 : * its JSRESOLVE_ASSIGNING-tolerant resolve hooks only in JSOP_SETNAME,
2132 : * after the interpreter evaluates the right- hand-side of the
2133 : * assignment, and not here.
2134 : *
2135 : * This should be transparent to the hooks because the script, instead
2136 : * of name = rhs, could have used global.name = rhs given a global
2137 : * object reference, which also calls the hooks only after evaluating
2138 : * the rhs. We desire such resolve hook equivalence between the two
2139 : * forms.
2140 : */
2141 29387 : obj = ®s.fp()->scopeChain();
2142 29387 : if (obj->isGlobal())
2143 7238 : break;
2144 :
2145 : PropertyName *name;
2146 22149 : LOAD_NAME(0, name);
2147 :
2148 22149 : obj = FindIdentifierBase(cx, ®s.fp()->scopeChain(), name);
2149 22149 : if (!obj)
2150 0 : goto error;
2151 : } while (0);
2152 29387 : PUSH_OBJECT(*obj);
2153 : }
2154 29387 : END_CASE(JSOP_BINDNAME)
2155 :
2156 : #define BITWISE_OP(OP) \
2157 : JS_BEGIN_MACRO \
2158 : int32_t i, j; \
2159 : if (!ToInt32(cx, regs.sp[-2], &i)) \
2160 : goto error; \
2161 : if (!ToInt32(cx, regs.sp[-1], &j)) \
2162 : goto error; \
2163 : i = i OP j; \
2164 : regs.sp--; \
2165 : regs.sp[-1].setInt32(i); \
2166 : JS_END_MACRO
2167 :
2168 : BEGIN_CASE(JSOP_BITOR)
2169 586935 : BITWISE_OP(|);
2170 586929 : END_CASE(JSOP_BITOR)
2171 :
2172 : BEGIN_CASE(JSOP_BITXOR)
2173 603545 : BITWISE_OP(^);
2174 603545 : END_CASE(JSOP_BITXOR)
2175 :
2176 : BEGIN_CASE(JSOP_BITAND)
2177 20918186 : BITWISE_OP(&);
2178 20918186 : END_CASE(JSOP_BITAND)
2179 :
2180 : #undef BITWISE_OP
2181 :
2182 : #define EQUALITY_OP(OP) \
2183 : JS_BEGIN_MACRO \
2184 : Value rval = regs.sp[-1]; \
2185 : Value lval = regs.sp[-2]; \
2186 : bool cond; \
2187 : if (!LooselyEqual(cx, lval, rval, &cond)) \
2188 : goto error; \
2189 : cond = cond OP JS_TRUE; \
2190 : TRY_BRANCH_AFTER_COND(cond, 2); \
2191 : regs.sp--; \
2192 : regs.sp[-1].setBoolean(cond); \
2193 : JS_END_MACRO
2194 :
2195 : BEGIN_CASE(JSOP_EQ)
2196 3855745 : EQUALITY_OP(==);
2197 654590 : END_CASE(JSOP_EQ)
2198 :
2199 : BEGIN_CASE(JSOP_NE)
2200 488826 : EQUALITY_OP(!=);
2201 42247 : END_CASE(JSOP_NE)
2202 :
2203 : #undef EQUALITY_OP
2204 :
2205 : #define STRICT_EQUALITY_OP(OP, COND) \
2206 : JS_BEGIN_MACRO \
2207 : const Value &rref = regs.sp[-1]; \
2208 : const Value &lref = regs.sp[-2]; \
2209 : bool equal; \
2210 : if (!StrictlyEqual(cx, lref, rref, &equal)) \
2211 : goto error; \
2212 : COND = equal OP JS_TRUE; \
2213 : regs.sp--; \
2214 : JS_END_MACRO
2215 :
2216 : BEGIN_CASE(JSOP_STRICTEQ)
2217 : {
2218 : bool cond;
2219 1778962 : STRICT_EQUALITY_OP(==, cond);
2220 1778962 : regs.sp[-1].setBoolean(cond);
2221 : }
2222 1778962 : END_CASE(JSOP_STRICTEQ)
2223 :
2224 : BEGIN_CASE(JSOP_STRICTNE)
2225 : {
2226 : bool cond;
2227 863114 : STRICT_EQUALITY_OP(!=, cond);
2228 863114 : regs.sp[-1].setBoolean(cond);
2229 : }
2230 863114 : END_CASE(JSOP_STRICTNE)
2231 :
2232 : BEGIN_CASE(JSOP_CASE)
2233 : {
2234 : bool cond;
2235 1000977 : STRICT_EQUALITY_OP(==, cond);
2236 1000977 : if (cond) {
2237 1000245 : regs.sp--;
2238 1000245 : len = GET_JUMP_OFFSET(regs.pc);
2239 1000245 : BRANCH(len);
2240 : }
2241 : }
2242 732 : END_CASE(JSOP_CASE)
2243 :
2244 : #undef STRICT_EQUALITY_OP
2245 :
2246 : BEGIN_CASE(JSOP_LT)
2247 : {
2248 : bool cond;
2249 156837398 : const Value &lref = regs.sp[-2];
2250 156837398 : const Value &rref = regs.sp[-1];
2251 156837398 : if (!LessThanOperation(cx, lref, rref, &cond))
2252 0 : goto error;
2253 156837398 : TRY_BRANCH_AFTER_COND(cond, 2);
2254 153859 : regs.sp[-2].setBoolean(cond);
2255 153859 : regs.sp--;
2256 : }
2257 153859 : END_CASE(JSOP_LT)
2258 :
2259 : BEGIN_CASE(JSOP_LE)
2260 : {
2261 : bool cond;
2262 1705631 : const Value &lref = regs.sp[-2];
2263 1705631 : const Value &rref = regs.sp[-1];
2264 1705631 : if (!LessThanOrEqualOperation(cx, lref, rref, &cond))
2265 0 : goto error;
2266 1705631 : TRY_BRANCH_AFTER_COND(cond, 2);
2267 7978 : regs.sp[-2].setBoolean(cond);
2268 7978 : regs.sp--;
2269 : }
2270 7978 : END_CASE(JSOP_LE)
2271 :
2272 : BEGIN_CASE(JSOP_GT)
2273 : {
2274 : bool cond;
2275 1539957 : const Value &lref = regs.sp[-2];
2276 1539957 : const Value &rref = regs.sp[-1];
2277 1539957 : if (!GreaterThanOperation(cx, lref, rref, &cond))
2278 7 : goto error;
2279 1539950 : TRY_BRANCH_AFTER_COND(cond, 2);
2280 52648 : regs.sp[-2].setBoolean(cond);
2281 52648 : regs.sp--;
2282 : }
2283 52648 : END_CASE(JSOP_GT)
2284 :
2285 : BEGIN_CASE(JSOP_GE)
2286 : {
2287 : bool cond;
2288 6143501 : const Value &lref = regs.sp[-2];
2289 6143501 : const Value &rref = regs.sp[-1];
2290 6143501 : if (!GreaterThanOrEqualOperation(cx, lref, rref, &cond))
2291 0 : goto error;
2292 6143501 : TRY_BRANCH_AFTER_COND(cond, 2);
2293 22645 : regs.sp[-2].setBoolean(cond);
2294 22645 : regs.sp--;
2295 : }
2296 22645 : END_CASE(JSOP_GE)
2297 :
2298 : #define SIGNED_SHIFT_OP(OP) \
2299 : JS_BEGIN_MACRO \
2300 : int32_t i, j; \
2301 : if (!ToInt32(cx, regs.sp[-2], &i)) \
2302 : goto error; \
2303 : if (!ToInt32(cx, regs.sp[-1], &j)) \
2304 : goto error; \
2305 : i = i OP (j & 31); \
2306 : regs.sp--; \
2307 : regs.sp[-1].setInt32(i); \
2308 : JS_END_MACRO
2309 :
2310 : BEGIN_CASE(JSOP_LSH)
2311 8255527 : SIGNED_SHIFT_OP(<<);
2312 8255527 : END_CASE(JSOP_LSH)
2313 :
2314 : BEGIN_CASE(JSOP_RSH)
2315 18667328 : SIGNED_SHIFT_OP(>>);
2316 18667328 : END_CASE(JSOP_RSH)
2317 :
2318 : #undef SIGNED_SHIFT_OP
2319 :
2320 : BEGIN_CASE(JSOP_URSH)
2321 : {
2322 : uint32_t u;
2323 140215 : if (!ToUint32(cx, regs.sp[-2], &u))
2324 0 : goto error;
2325 : int32_t j;
2326 140215 : if (!ToInt32(cx, regs.sp[-1], &j))
2327 0 : goto error;
2328 :
2329 140215 : u >>= (j & 31);
2330 :
2331 140215 : regs.sp--;
2332 140215 : if (!regs.sp[-1].setNumber(uint32_t(u)))
2333 384 : TypeScript::MonitorOverflow(cx, script, regs.pc);
2334 : }
2335 140215 : END_CASE(JSOP_URSH)
2336 :
2337 : BEGIN_CASE(JSOP_ADD)
2338 : {
2339 50410500 : Value lval = regs.sp[-2];
2340 50410500 : Value rval = regs.sp[-1];
2341 50410500 : if (!AddOperation(cx, lval, rval, ®s.sp[-2]))
2342 56 : goto error;
2343 50410444 : regs.sp--;
2344 : }
2345 50410444 : END_CASE(JSOP_ADD)
2346 :
2347 : BEGIN_CASE(JSOP_SUB)
2348 : {
2349 6564664 : Value lval = regs.sp[-2];
2350 6564664 : Value rval = regs.sp[-1];
2351 6564664 : if (!SubOperation(cx, lval, rval, ®s.sp[-2]))
2352 0 : goto error;
2353 6564664 : regs.sp--;
2354 : }
2355 6564664 : END_CASE(JSOP_SUB)
2356 :
2357 : BEGIN_CASE(JSOP_MUL)
2358 : {
2359 24958944 : Value lval = regs.sp[-2];
2360 24958944 : Value rval = regs.sp[-1];
2361 24958944 : if (!MulOperation(cx, lval, rval, ®s.sp[-2]))
2362 0 : goto error;
2363 24958944 : regs.sp--;
2364 : }
2365 24958944 : END_CASE(JSOP_MUL)
2366 :
2367 : BEGIN_CASE(JSOP_DIV)
2368 : {
2369 1388305 : Value lval = regs.sp[-2];
2370 1388305 : Value rval = regs.sp[-1];
2371 1388305 : if (!DivOperation(cx, lval, rval, ®s.sp[-2]))
2372 0 : goto error;
2373 1388305 : regs.sp--;
2374 : }
2375 1388305 : END_CASE(JSOP_DIV)
2376 :
2377 : BEGIN_CASE(JSOP_MOD)
2378 : {
2379 457306 : Value lval = regs.sp[-2];
2380 457306 : Value rval = regs.sp[-1];
2381 457306 : if (!ModOperation(cx, lval, rval, ®s.sp[-2]))
2382 0 : goto error;
2383 457306 : regs.sp--;
2384 : }
2385 457306 : END_CASE(JSOP_MOD)
2386 :
2387 : BEGIN_CASE(JSOP_NOT)
2388 : {
2389 : Value *_;
2390 : bool cond;
2391 2223668 : POP_BOOLEAN(cx, _, cond);
2392 2223668 : PUSH_BOOLEAN(!cond);
2393 : }
2394 2223668 : END_CASE(JSOP_NOT)
2395 :
2396 : BEGIN_CASE(JSOP_BITNOT)
2397 : {
2398 : int32_t i;
2399 867829 : if (!ToInt32(cx, regs.sp[-1], &i))
2400 0 : goto error;
2401 867829 : i = ~i;
2402 867829 : regs.sp[-1].setInt32(i);
2403 : }
2404 867829 : END_CASE(JSOP_BITNOT)
2405 :
2406 : BEGIN_CASE(JSOP_NEG)
2407 : {
2408 : /*
2409 : * When the operand is int jsval, INT32_FITS_IN_JSVAL(i) implies
2410 : * INT32_FITS_IN_JSVAL(-i) unless i is 0 or INT32_MIN when the
2411 : * results, -0.0 or INT32_MAX + 1, are double values.
2412 : */
2413 745377 : Value ref = regs.sp[-1];
2414 : int32_t i;
2415 745377 : if (ref.isInt32() && (i = ref.toInt32()) != 0 && i != INT32_MIN) {
2416 268064 : i = -i;
2417 268064 : regs.sp[-1].setInt32(i);
2418 : } else {
2419 : double d;
2420 477313 : if (!ToNumber(cx, regs.sp[-1], &d))
2421 0 : goto error;
2422 477313 : d = -d;
2423 477313 : if (!regs.sp[-1].setNumber(d) && !ref.isDouble())
2424 4129 : TypeScript::MonitorOverflow(cx, script, regs.pc);
2425 : }
2426 : }
2427 745377 : END_CASE(JSOP_NEG)
2428 :
2429 : BEGIN_CASE(JSOP_POS)
2430 4054389 : if (!ToNumber(cx, ®s.sp[-1]))
2431 0 : goto error;
2432 4054389 : if (!regs.sp[-1].isInt32())
2433 2528 : TypeScript::MonitorOverflow(cx, script, regs.pc);
2434 4054389 : END_CASE(JSOP_POS)
2435 :
2436 : BEGIN_CASE(JSOP_DELNAME)
2437 : {
2438 : PropertyName *name;
2439 322 : LOAD_NAME(0, name);
2440 : JSObject *obj, *obj2;
2441 : JSProperty *prop;
2442 322 : if (!FindProperty(cx, name, cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
2443 0 : goto error;
2444 :
2445 : /* Strict mode code should never contain JSOP_DELNAME opcodes. */
2446 322 : JS_ASSERT(!script->strictModeCode);
2447 :
2448 : /* ECMA says to return true if name is undefined or inherited. */
2449 322 : PUSH_BOOLEAN(true);
2450 322 : if (prop) {
2451 239 : if (!obj->deleteProperty(cx, name, ®s.sp[-1], false))
2452 0 : goto error;
2453 : }
2454 : }
2455 322 : END_CASE(JSOP_DELNAME)
2456 :
2457 : BEGIN_CASE(JSOP_DELPROP)
2458 : {
2459 : PropertyName *name;
2460 589 : LOAD_NAME(0, name);
2461 :
2462 : JSObject *obj;
2463 589 : FETCH_OBJECT(cx, -1, obj);
2464 :
2465 : Value rval;
2466 589 : if (!obj->deleteProperty(cx, name, &rval, script->strictModeCode))
2467 0 : goto error;
2468 :
2469 589 : regs.sp[-1] = rval;
2470 : }
2471 589 : END_CASE(JSOP_DELPROP)
2472 :
2473 : BEGIN_CASE(JSOP_DELELEM)
2474 : {
2475 : /* Fetch the left part and resolve it to a non-null object. */
2476 : JSObject *obj;
2477 1160 : FETCH_OBJECT(cx, -2, obj);
2478 :
2479 1160 : const Value &propval = regs.sp[-1];
2480 1160 : Value &rval = regs.sp[-2];
2481 :
2482 1160 : if (!obj->deleteByValue(cx, propval, &rval, script->strictModeCode))
2483 7 : goto error;
2484 :
2485 1153 : regs.sp--;
2486 : }
2487 1153 : END_CASE(JSOP_DELELEM)
2488 :
2489 : BEGIN_CASE(JSOP_TOID)
2490 : {
2491 : /*
2492 : * Increment or decrement requires use to lookup the same property twice, but we need to avoid
2493 : * the oberservable stringification the second time.
2494 : * There must be an object value below the id, which will not be popped
2495 : * but is necessary in interning the id for XML.
2496 : */
2497 83249 : Value objval = regs.sp[-2];
2498 83249 : Value idval = regs.sp[-1];
2499 83249 : if (!ToIdOperation(cx, objval, idval, ®s.sp[-1]))
2500 0 : goto error;
2501 : }
2502 83249 : END_CASE(JSOP_TOID)
2503 :
2504 : BEGIN_CASE(JSOP_TYPEOFEXPR)
2505 : BEGIN_CASE(JSOP_TYPEOF)
2506 : {
2507 98933 : const Value &ref = regs.sp[-1];
2508 98933 : JSType type = JS_TypeOfValue(cx, ref);
2509 98933 : regs.sp[-1].setString(rt->atomState.typeAtoms[type]);
2510 : }
2511 98933 : END_CASE(JSOP_TYPEOF)
2512 :
2513 : BEGIN_CASE(JSOP_VOID)
2514 1222 : regs.sp[-1].setUndefined();
2515 1222 : END_CASE(JSOP_VOID)
2516 :
2517 : BEGIN_CASE(JSOP_INCELEM)
2518 : BEGIN_CASE(JSOP_DECELEM)
2519 : BEGIN_CASE(JSOP_ELEMINC)
2520 : BEGIN_CASE(JSOP_ELEMDEC)
2521 : /* No-op */
2522 83249 : END_CASE(JSOP_INCELEM)
2523 :
2524 : BEGIN_CASE(JSOP_INCPROP)
2525 : BEGIN_CASE(JSOP_DECPROP)
2526 : BEGIN_CASE(JSOP_PROPINC)
2527 : BEGIN_CASE(JSOP_PROPDEC)
2528 : BEGIN_CASE(JSOP_INCNAME)
2529 : BEGIN_CASE(JSOP_DECNAME)
2530 : BEGIN_CASE(JSOP_NAMEINC)
2531 : BEGIN_CASE(JSOP_NAMEDEC)
2532 : BEGIN_CASE(JSOP_INCGNAME)
2533 : BEGIN_CASE(JSOP_DECGNAME)
2534 : BEGIN_CASE(JSOP_GNAMEINC)
2535 : BEGIN_CASE(JSOP_GNAMEDEC)
2536 : /* No-op */
2537 3969902 : END_CASE(JSOP_INCPROP)
2538 :
2539 : BEGIN_CASE(JSOP_DECARG)
2540 : BEGIN_CASE(JSOP_ARGDEC)
2541 : BEGIN_CASE(JSOP_INCARG)
2542 : BEGIN_CASE(JSOP_ARGINC)
2543 : {
2544 13818630 : Value &arg = regs.fp()->formalArg(GET_ARGNO(regs.pc));
2545 13818630 : if (!DoIncDec(cx, script, regs.pc, arg, &arg, ®s.sp[0]))
2546 0 : goto error;
2547 13818630 : regs.sp++;
2548 : }
2549 13818630 : END_CASE(JSOP_ARGINC);
2550 :
2551 : BEGIN_CASE(JSOP_DECLOCAL)
2552 : BEGIN_CASE(JSOP_LOCALDEC)
2553 : BEGIN_CASE(JSOP_INCLOCAL)
2554 : BEGIN_CASE(JSOP_LOCALINC)
2555 : {
2556 290180157 : Value &local = regs.fp()->localSlot(GET_SLOTNO(regs.pc));
2557 290180157 : if (!DoIncDec(cx, script, regs.pc, local, &local, ®s.sp[0]))
2558 0 : goto error;
2559 290180157 : regs.sp++;
2560 : }
2561 290180157 : END_CASE(JSOP_LOCALINC)
2562 :
2563 : BEGIN_CASE(JSOP_THIS)
2564 7519302 : if (!ComputeThis(cx, regs.fp()))
2565 0 : goto error;
2566 7519302 : PUSH_COPY(regs.fp()->thisValue());
2567 7519302 : END_CASE(JSOP_THIS)
2568 :
2569 : BEGIN_CASE(JSOP_GETPROP)
2570 : BEGIN_CASE(JSOP_GETXPROP)
2571 : BEGIN_CASE(JSOP_LENGTH)
2572 : BEGIN_CASE(JSOP_CALLPROP)
2573 : {
2574 : Value rval;
2575 64309689 : if (!GetPropertyOperation(cx, regs.pc, regs.sp[-1], &rval))
2576 192 : goto error;
2577 :
2578 64309497 : TypeScript::Monitor(cx, script, regs.pc, rval);
2579 :
2580 64309497 : regs.sp[-1] = rval;
2581 64309497 : assertSameCompartment(cx, regs.sp[-1]);
2582 : }
2583 64309497 : END_CASE(JSOP_GETPROP)
2584 :
2585 : BEGIN_CASE(JSOP_SETGNAME)
2586 : BEGIN_CASE(JSOP_SETNAME)
2587 : BEGIN_CASE(JSOP_SETPROP)
2588 : {
2589 16138244 : const Value &rval = regs.sp[-1];
2590 16138244 : const Value &lval = regs.sp[-2];
2591 :
2592 16138244 : if (!SetPropertyOperation(cx, regs.pc, lval, rval))
2593 192 : goto error;
2594 :
2595 16138052 : regs.sp[-2] = regs.sp[-1];
2596 16138052 : regs.sp--;
2597 : }
2598 16138052 : END_CASE(JSOP_SETPROP)
2599 :
2600 : BEGIN_CASE(JSOP_GETELEM)
2601 : BEGIN_CASE(JSOP_CALLELEM)
2602 : {
2603 27002084 : Value &lref = regs.sp[-2];
2604 27002084 : Value &rref = regs.sp[-1];
2605 27002084 : if (!GetElementOperation(cx, op, lref, rref, ®s.sp[-2]))
2606 45 : goto error;
2607 27002039 : TypeScript::Monitor(cx, script, regs.pc, regs.sp[-2]);
2608 27002039 : regs.sp--;
2609 : }
2610 27002039 : END_CASE(JSOP_GETELEM)
2611 :
2612 : BEGIN_CASE(JSOP_SETELEM)
2613 : {
2614 : JSObject *obj;
2615 11318797 : FETCH_OBJECT(cx, -3, obj);
2616 : jsid id;
2617 11318786 : FETCH_ELEMENT_ID(obj, -2, id);
2618 11318786 : Value &value = regs.sp[-1];
2619 11318786 : if (!SetObjectElementOperation(cx, obj, id, value, script->strictModeCode))
2620 731 : goto error;
2621 11318055 : regs.sp[-3] = value;
2622 11318055 : regs.sp -= 2;
2623 : }
2624 11318055 : END_CASE(JSOP_SETELEM)
2625 :
2626 : BEGIN_CASE(JSOP_ENUMELEM)
2627 : {
2628 : /* Funky: the value to set is under the [obj, id] pair. */
2629 : JSObject *obj;
2630 4496 : FETCH_OBJECT(cx, -2, obj);
2631 : jsid id;
2632 4496 : FETCH_ELEMENT_ID(obj, -1, id);
2633 4496 : Value rval = regs.sp[-3];
2634 4496 : if (!obj->setGeneric(cx, id, &rval, script->strictModeCode))
2635 0 : goto error;
2636 4496 : regs.sp -= 3;
2637 : }
2638 4496 : END_CASE(JSOP_ENUMELEM)
2639 :
2640 : BEGIN_CASE(JSOP_EVAL)
2641 : {
2642 22161 : CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
2643 22161 : if (IsBuiltinEvalForScope(®s.fp()->scopeChain(), args.calleev())) {
2644 22140 : if (!DirectEval(cx, args))
2645 319 : goto error;
2646 : } else {
2647 21 : if (!InvokeKernel(cx, args))
2648 0 : goto error;
2649 : }
2650 21842 : CHECK_INTERRUPT_HANDLER();
2651 21842 : regs.sp = args.spAfterCall();
2652 21842 : TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
2653 : }
2654 21842 : END_CASE(JSOP_EVAL)
2655 :
2656 : BEGIN_CASE(JSOP_FUNAPPLY)
2657 194748 : if (regs.sp[-1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
2658 144066 : CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
2659 144066 : if (!IsNativeFunction(args.calleev(), js_fun_apply)) {
2660 6 : JS_ASSERT(args.length() == 2);
2661 6 : if (!script->applySpeculationFailed(cx))
2662 0 : goto error;
2663 6 : args[1] = ObjectValue(regs.fp()->argsObj());
2664 : }
2665 : }
2666 : /* FALL THROUGH */
2667 :
2668 : BEGIN_CASE(JSOP_NEW)
2669 : BEGIN_CASE(JSOP_CALL)
2670 : BEGIN_CASE(JSOP_FUNCALL)
2671 : {
2672 15638603 : CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
2673 15638603 : JS_ASSERT(args.base() >= regs.fp()->base());
2674 :
2675 15638603 : bool construct = (*regs.pc == JSOP_NEW);
2676 :
2677 : JSFunction *fun;
2678 :
2679 : /* Don't bother trying to fast-path calls to scripted non-constructors. */
2680 15638603 : if (!IsFunctionObject(args.calleev(), &fun) || !fun->isInterpretedConstructor()) {
2681 6336259 : if (construct) {
2682 125396 : if (!InvokeConstructorKernel(cx, args))
2683 567 : goto error;
2684 : } else {
2685 6210863 : if (!InvokeKernel(cx, args))
2686 9554 : goto error;
2687 : }
2688 6326138 : Value *newsp = args.spAfterCall();
2689 6326138 : TypeScript::Monitor(cx, script, regs.pc, newsp[-1]);
2690 6326138 : regs.sp = newsp;
2691 6326138 : CHECK_INTERRUPT_HANDLER();
2692 6326138 : len = JSOP_CALL_LENGTH;
2693 6326138 : DO_NEXT_OP(len);
2694 : }
2695 :
2696 9302344 : TypeMonitorCall(cx, args, construct);
2697 :
2698 9302344 : InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE;
2699 :
2700 9302344 : JSScript *newScript = fun->script();
2701 :
2702 9302344 : if (newScript->compileAndGo && newScript->hasClearedGlobal()) {
2703 0 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CLEARED_SCOPE);
2704 0 : goto error;
2705 : }
2706 :
2707 9302344 : if (!cx->stack.pushInlineFrame(cx, regs, args, *fun, newScript, initial))
2708 52 : goto error;
2709 :
2710 9302292 : RESTORE_INTERP_VARS();
2711 :
2712 9302292 : if (!regs.fp()->functionPrologue(cx))
2713 0 : goto error;
2714 :
2715 9302292 : RESET_USE_METHODJIT();
2716 :
2717 9302292 : bool newType = cx->typeInferenceEnabled() && UseNewType(cx, script, regs.pc);
2718 :
2719 : #ifdef JS_METHODJIT
2720 9302292 : if (!newType) {
2721 : /* Try to ensure methods are method JIT'd. */
2722 : mjit::CompileRequest request = (interpMode == JSINTERP_NORMAL)
2723 : ? mjit::CompileRequest_Interpreter
2724 9302292 : : mjit::CompileRequest_JIT;
2725 : mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, script->code,
2726 9302292 : construct, request);
2727 9302292 : if (status == mjit::Compile_Error)
2728 0 : goto error;
2729 9302292 : if (status == mjit::Compile_Okay) {
2730 101099 : mjit::JaegerStatus status = mjit::JaegerShot(cx, true);
2731 101099 : CHECK_PARTIAL_METHODJIT(status);
2732 89576 : interpReturnOK = mjit::JaegerStatusToSuccess(status);
2733 89576 : CHECK_INTERRUPT_HANDLER();
2734 89576 : goto jit_return;
2735 : }
2736 : }
2737 : #endif
2738 :
2739 9201193 : if (!ScriptPrologue(cx, regs.fp(), newType))
2740 0 : goto error;
2741 :
2742 9201193 : if (cx->compartment->debugMode()) {
2743 552894 : switch (ScriptDebugPrologue(cx, regs.fp())) {
2744 : case JSTRAP_CONTINUE:
2745 : break;
2746 : case JSTRAP_RETURN:
2747 15 : interpReturnOK = true;
2748 15 : goto forced_return;
2749 : case JSTRAP_THROW:
2750 : case JSTRAP_ERROR:
2751 5 : goto error;
2752 : default:
2753 0 : JS_NOT_REACHED("bad ScriptDebugPrologue status");
2754 : }
2755 : }
2756 :
2757 9201173 : CHECK_INTERRUPT_HANDLER();
2758 :
2759 : /* Load first op and dispatch it (safe since JSOP_STOP). */
2760 9201173 : op = (JSOp) *regs.pc;
2761 9201173 : DO_OP();
2762 : }
2763 :
2764 : BEGIN_CASE(JSOP_SETCALL)
2765 : {
2766 9 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_LEFTSIDE_OF_ASS);
2767 9 : goto error;
2768 : }
2769 : END_CASE(JSOP_SETCALL)
2770 :
2771 : BEGIN_CASE(JSOP_IMPLICITTHIS)
2772 : {
2773 : PropertyName *name;
2774 96449 : LOAD_NAME(0, name);
2775 :
2776 : JSObject *obj, *obj2;
2777 : JSProperty *prop;
2778 96449 : if (!FindPropertyHelper(cx, name, false, cx->stack.currentScriptedScopeChain(), &obj, &obj2, &prop))
2779 0 : goto error;
2780 :
2781 : Value v;
2782 96449 : if (!ComputeImplicitThis(cx, obj, &v))
2783 0 : goto error;
2784 96449 : PUSH_COPY(v);
2785 : }
2786 96449 : END_CASE(JSOP_IMPLICITTHIS)
2787 :
2788 : BEGIN_CASE(JSOP_GETGNAME)
2789 : BEGIN_CASE(JSOP_CALLGNAME)
2790 : BEGIN_CASE(JSOP_NAME)
2791 : BEGIN_CASE(JSOP_CALLNAME)
2792 : {
2793 : Value rval;
2794 37179564 : if (!NameOperation(cx, regs.pc, &rval))
2795 1353 : goto error;
2796 :
2797 37178211 : PUSH_COPY(rval);
2798 37178211 : TypeScript::Monitor(cx, script, regs.pc, rval);
2799 : }
2800 37178211 : END_CASE(JSOP_NAME)
2801 :
2802 : BEGIN_CASE(JSOP_UINT16)
2803 15007573 : PUSH_INT32((int32_t) GET_UINT16(regs.pc));
2804 15007573 : END_CASE(JSOP_UINT16)
2805 :
2806 : BEGIN_CASE(JSOP_UINT24)
2807 2664115 : PUSH_INT32((int32_t) GET_UINT24(regs.pc));
2808 2664115 : END_CASE(JSOP_UINT24)
2809 :
2810 : BEGIN_CASE(JSOP_INT8)
2811 38767849 : PUSH_INT32(GET_INT8(regs.pc));
2812 38767849 : END_CASE(JSOP_INT8)
2813 :
2814 : BEGIN_CASE(JSOP_INT32)
2815 4615743 : PUSH_INT32(GET_INT32(regs.pc));
2816 4615743 : END_CASE(JSOP_INT32)
2817 :
2818 : BEGIN_CASE(JSOP_DOUBLE)
2819 : {
2820 : double dbl;
2821 1376969 : LOAD_DOUBLE(0, dbl);
2822 1376969 : PUSH_DOUBLE(dbl);
2823 : }
2824 1376969 : END_CASE(JSOP_DOUBLE)
2825 :
2826 : BEGIN_CASE(JSOP_STRING)
2827 : {
2828 : JSAtom *atom;
2829 5661363 : LOAD_ATOM(0, atom);
2830 5661363 : PUSH_STRING(atom);
2831 : }
2832 5661363 : END_CASE(JSOP_STRING)
2833 :
2834 : BEGIN_CASE(JSOP_OBJECT)
2835 : {
2836 3699 : PUSH_OBJECT(*script->getObject(GET_UINT32_INDEX(regs.pc)));
2837 : }
2838 3699 : END_CASE(JSOP_OBJECT)
2839 :
2840 : BEGIN_CASE(JSOP_REGEXP)
2841 : {
2842 : /*
2843 : * Push a regexp object cloned from the regexp literal object mapped by the
2844 : * bytecode at pc.
2845 : */
2846 89249 : uint32_t index = GET_UINT32_INDEX(regs.pc);
2847 89249 : JSObject *proto = regs.fp()->scopeChain().global().getOrCreateRegExpPrototype(cx);
2848 89249 : if (!proto)
2849 0 : goto error;
2850 89249 : JSObject *obj = CloneRegExpObject(cx, script->getRegExp(index), proto);
2851 89249 : if (!obj)
2852 0 : goto error;
2853 89249 : PUSH_OBJECT(*obj);
2854 : }
2855 89249 : END_CASE(JSOP_REGEXP)
2856 :
2857 : BEGIN_CASE(JSOP_ZERO)
2858 13163782 : PUSH_INT32(0);
2859 13163782 : END_CASE(JSOP_ZERO)
2860 :
2861 : BEGIN_CASE(JSOP_ONE)
2862 16313937 : PUSH_INT32(1);
2863 16313937 : END_CASE(JSOP_ONE)
2864 :
2865 : BEGIN_CASE(JSOP_NULL)
2866 2427785 : PUSH_NULL();
2867 2427785 : END_CASE(JSOP_NULL)
2868 :
2869 : BEGIN_CASE(JSOP_FALSE)
2870 1806003 : PUSH_BOOLEAN(false);
2871 1806003 : END_CASE(JSOP_FALSE)
2872 :
2873 : BEGIN_CASE(JSOP_TRUE)
2874 1786313 : PUSH_BOOLEAN(true);
2875 1786313 : END_CASE(JSOP_TRUE)
2876 :
2877 : {
2878 : BEGIN_CASE(JSOP_TABLESWITCH)
2879 : {
2880 2081 : jsbytecode *pc2 = regs.pc;
2881 2081 : len = GET_JUMP_OFFSET(pc2);
2882 :
2883 : /*
2884 : * ECMAv2+ forbids conversion of discriminant, so we will skip to the
2885 : * default case if the discriminant isn't already an int jsval. (This
2886 : * opcode is emitted only for dense int-domain switches.)
2887 : */
2888 2081 : const Value &rref = *--regs.sp;
2889 : int32_t i;
2890 2081 : if (rref.isInt32()) {
2891 1564 : i = rref.toInt32();
2892 : } else {
2893 : double d;
2894 : /* Don't use JSDOUBLE_IS_INT32; treat -0 (double) as 0. */
2895 517 : if (!rref.isDouble() || (d = rref.toDouble()) != (i = int32_t(rref.toDouble())))
2896 477 : DO_NEXT_OP(len);
2897 : }
2898 :
2899 1604 : pc2 += JUMP_OFFSET_LEN;
2900 1604 : int32_t low = GET_JUMP_OFFSET(pc2);
2901 1604 : pc2 += JUMP_OFFSET_LEN;
2902 1604 : int32_t high = GET_JUMP_OFFSET(pc2);
2903 :
2904 1604 : i -= low;
2905 1604 : if ((uint32_t)i < (uint32_t)(high - low + 1)) {
2906 1031 : pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i;
2907 1031 : int32_t off = (int32_t) GET_JUMP_OFFSET(pc2);
2908 1031 : if (off)
2909 1021 : len = off;
2910 : }
2911 : }
2912 1604 : END_VARLEN_CASE
2913 : }
2914 :
2915 : {
2916 : BEGIN_CASE(JSOP_LOOKUPSWITCH)
2917 : {
2918 : int32_t off;
2919 980 : off = JUMP_OFFSET_LEN;
2920 :
2921 : /*
2922 : * JSOP_LOOKUPSWITCH are never used if any atom index in it would exceed
2923 : * 64K limit.
2924 : */
2925 980 : JS_ASSERT(atoms == script->atoms);
2926 980 : jsbytecode *pc2 = regs.pc;
2927 :
2928 980 : Value lval = regs.sp[-1];
2929 980 : regs.sp--;
2930 :
2931 : int npairs;
2932 980 : if (!lval.isPrimitive())
2933 0 : goto end_lookup_switch;
2934 :
2935 980 : pc2 += off;
2936 980 : npairs = GET_UINT16(pc2);
2937 980 : pc2 += UINT16_LEN;
2938 980 : JS_ASSERT(npairs); /* empty switch uses JSOP_TABLESWITCH */
2939 :
2940 : bool match;
2941 : #define SEARCH_PAIRS(MATCH_CODE) \
2942 : for (;;) { \
2943 : Value rval = script->getConst(GET_UINT32_INDEX(pc2)); \
2944 : MATCH_CODE \
2945 : pc2 += UINT32_INDEX_LEN; \
2946 : if (match) \
2947 : break; \
2948 : pc2 += off; \
2949 : if (--npairs == 0) { \
2950 : pc2 = regs.pc; \
2951 : break; \
2952 : } \
2953 : }
2954 :
2955 980 : if (lval.isString()) {
2956 741 : JSLinearString *str = lval.toString()->ensureLinear(cx);
2957 741 : if (!str)
2958 0 : goto error;
2959 : JSLinearString *str2;
2960 3453 : SEARCH_PAIRS(
2961 : match = (rval.isString() &&
2962 : ((str2 = &rval.toString()->asLinear()) == str ||
2963 : EqualStrings(str2, str)));
2964 : )
2965 239 : } else if (lval.isNumber()) {
2966 18 : double ldbl = lval.toNumber();
2967 54 : SEARCH_PAIRS(
2968 : match = rval.isNumber() && ldbl == rval.toNumber();
2969 : )
2970 : } else {
2971 221 : SEARCH_PAIRS(
2972 : match = (lval == rval);
2973 : )
2974 : }
2975 : #undef SEARCH_PAIRS
2976 :
2977 : end_lookup_switch:
2978 980 : len = GET_JUMP_OFFSET(pc2);
2979 : }
2980 980 : END_VARLEN_CASE
2981 : }
2982 :
2983 : BEGIN_CASE(JSOP_ARGUMENTS)
2984 229988 : if (script->needsArgsObj())
2985 28505 : PUSH_COPY(ObjectValue(regs.fp()->argsObj()));
2986 : else
2987 201483 : PUSH_COPY(MagicValue(JS_OPTIMIZED_ARGUMENTS));
2988 229988 : END_CASE(JSOP_ARGUMENTS)
2989 :
2990 : BEGIN_CASE(JSOP_GETARG)
2991 : BEGIN_CASE(JSOP_CALLARG)
2992 51247084 : PUSH_COPY(regs.fp()->formalArg(GET_ARGNO(regs.pc)));
2993 51247084 : END_CASE(JSOP_GETARG)
2994 :
2995 : BEGIN_CASE(JSOP_SETARG)
2996 5106320 : regs.fp()->formalArg(GET_ARGNO(regs.pc)) = regs.sp[-1];
2997 5106320 : END_CASE(JSOP_SETARG)
2998 :
2999 : BEGIN_CASE(JSOP_GETLOCAL)
3000 : BEGIN_CASE(JSOP_CALLLOCAL)
3001 444562781 : PUSH_COPY_SKIP_CHECK(regs.fp()->localSlot(GET_SLOTNO(regs.pc)));
3002 :
3003 : /*
3004 : * Skip the same-compartment assertion if the local will be immediately
3005 : * popped. We do not guarantee sync for dead locals when coming in from the
3006 : * method JIT, and a GETLOCAL followed by POP is not considered to be
3007 : * a use of the variable.
3008 : */
3009 444562781 : if (regs.pc[JSOP_GETLOCAL_LENGTH] != JSOP_POP)
3010 440454470 : assertSameCompartment(cx, regs.sp[-1]);
3011 444562781 : END_CASE(JSOP_GETLOCAL)
3012 :
3013 : BEGIN_CASE(JSOP_SETLOCAL)
3014 40921262 : regs.fp()->localSlot(GET_SLOTNO(regs.pc)) = regs.sp[-1];
3015 40921262 : END_CASE(JSOP_SETLOCAL)
3016 :
3017 : BEGIN_CASE(JSOP_DEFCONST)
3018 : BEGIN_CASE(JSOP_DEFVAR)
3019 : {
3020 32687 : PropertyName *dn = atoms[GET_UINT32_INDEX(regs.pc)]->asPropertyName();
3021 :
3022 : /* ES5 10.5 step 8 (with subsequent errata). */
3023 32687 : unsigned attrs = JSPROP_ENUMERATE;
3024 32687 : if (!regs.fp()->isEvalFrame())
3025 31658 : attrs |= JSPROP_PERMANENT;
3026 32687 : if (op == JSOP_DEFCONST)
3027 31048 : attrs |= JSPROP_READONLY;
3028 :
3029 : /* Step 8b. */
3030 32687 : JSObject &obj = regs.fp()->varObj();
3031 :
3032 32687 : if (!DefVarOrConstOperation(cx, obj, dn, attrs))
3033 0 : goto error;
3034 : }
3035 32687 : END_CASE(JSOP_DEFVAR)
3036 :
3037 : BEGIN_CASE(JSOP_DEFFUN)
3038 : {
3039 : /*
3040 : * A top-level function defined in Global or Eval code (see ECMA-262
3041 : * Ed. 3), or else a SpiderMonkey extension: a named function statement in
3042 : * a compound statement (not at the top statement level of global code, or
3043 : * at the top level of a function body).
3044 : */
3045 2247 : JSFunction *fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
3046 2247 : JSObject *obj = fun;
3047 :
3048 : JSObject *obj2;
3049 2247 : if (fun->isNullClosure()) {
3050 : /*
3051 : * Even a null closure needs a parent for principals finding.
3052 : * FIXME: bug 476950, although debugger users may also demand some kind
3053 : * of scope link for debugger-assisted eval-in-frame.
3054 : */
3055 1167 : obj2 = ®s.fp()->scopeChain();
3056 : } else {
3057 1080 : obj2 = GetScopeChain(cx, regs.fp());
3058 1080 : if (!obj2)
3059 0 : goto error;
3060 : }
3061 :
3062 : /*
3063 : * If static link is not current scope, clone fun's object to link to the
3064 : * current scope via parent. We do this to enable sharing of compiled
3065 : * functions among multiple equivalent scopes, amortizing the cost of
3066 : * compilation over a number of executions. Examples include XUL scripts
3067 : * and event handlers shared among Firefox or other Mozilla app chrome
3068 : * windows, and user-defined JS functions precompiled and then shared among
3069 : * requests in server-side JS.
3070 : */
3071 2247 : if (obj->toFunction()->environment() != obj2) {
3072 365 : obj = CloneFunctionObjectIfNotSingleton(cx, fun, obj2);
3073 365 : if (!obj)
3074 0 : goto error;
3075 365 : JS_ASSERT_IF(script->hasGlobal(), obj->getProto() == fun->getProto());
3076 : }
3077 :
3078 : /*
3079 : * ECMA requires functions defined when entering Eval code to be
3080 : * impermanent.
3081 : */
3082 2247 : unsigned attrs = regs.fp()->isEvalFrame()
3083 : ? JSPROP_ENUMERATE
3084 2247 : : JSPROP_ENUMERATE | JSPROP_PERMANENT;
3085 :
3086 : /*
3087 : * We define the function as a property of the variable object and not the
3088 : * current scope chain even for the case of function expression statements
3089 : * and functions defined by eval inside let or with blocks.
3090 : */
3091 2247 : JSObject *parent = ®s.fp()->varObj();
3092 :
3093 : /* ES5 10.5 (NB: with subsequent errata). */
3094 2247 : PropertyName *name = fun->atom->asPropertyName();
3095 2247 : JSProperty *prop = NULL;
3096 : JSObject *pobj;
3097 2247 : if (!parent->lookupProperty(cx, name, &pobj, &prop))
3098 0 : goto error;
3099 :
3100 2247 : Value rval = ObjectValue(*obj);
3101 :
3102 : do {
3103 : /* Steps 5d, 5f. */
3104 2247 : if (!prop || pobj != parent) {
3105 1472 : if (!parent->defineProperty(cx, name, rval,
3106 1472 : JS_PropertyStub, JS_StrictPropertyStub, attrs))
3107 : {
3108 0 : goto error;
3109 : }
3110 1472 : break;
3111 : }
3112 :
3113 : /* Step 5e. */
3114 775 : JS_ASSERT(parent->isNative());
3115 775 : Shape *shape = reinterpret_cast<Shape *>(prop);
3116 775 : if (parent->isGlobal()) {
3117 610 : if (shape->configurable()) {
3118 167 : if (!parent->defineProperty(cx, name, rval,
3119 167 : JS_PropertyStub, JS_StrictPropertyStub, attrs))
3120 : {
3121 0 : goto error;
3122 : }
3123 167 : break;
3124 : }
3125 :
3126 443 : if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
3127 10 : JSAutoByteString bytes;
3128 5 : if (js_AtomToPrintableString(cx, name, &bytes)) {
3129 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3130 5 : JSMSG_CANT_REDEFINE_PROP, bytes.ptr());
3131 : }
3132 : goto error;
3133 : }
3134 : }
3135 :
3136 : /*
3137 : * Non-global properties, and global properties which we aren't simply
3138 : * redefining, must be set. First, this preserves their attributes.
3139 : * Second, this will produce warnings and/or errors as necessary if the
3140 : * specified Call object property is not writable (const).
3141 : */
3142 :
3143 : /* Step 5f. */
3144 603 : if (!parent->setProperty(cx, name, &rval, script->strictModeCode))
3145 0 : goto error;
3146 : } while (false);
3147 : }
3148 2242 : END_CASE(JSOP_DEFFUN)
3149 :
3150 : BEGIN_CASE(JSOP_LAMBDA)
3151 : {
3152 : /* Load the specified function object literal. */
3153 258584 : JSFunction *fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
3154 258584 : JSObject *obj = fun;
3155 :
3156 : /* do-while(0) so we can break instead of using a goto. */
3157 : do {
3158 : JSObject *parent;
3159 258584 : if (fun->isNullClosure()) {
3160 86130 : parent = ®s.fp()->scopeChain();
3161 : } else {
3162 172454 : parent = GetScopeChain(cx, regs.fp());
3163 172454 : if (!parent)
3164 0 : goto error;
3165 : }
3166 :
3167 258584 : obj = CloneFunctionObjectIfNotSingleton(cx, fun, parent);
3168 258584 : if (!obj)
3169 0 : goto error;
3170 : } while (0);
3171 :
3172 258584 : JS_ASSERT(obj->getProto());
3173 258584 : JS_ASSERT_IF(script->hasGlobal(), obj->getProto() == fun->getProto());
3174 :
3175 258584 : PUSH_OBJECT(*obj);
3176 : }
3177 258584 : END_CASE(JSOP_LAMBDA)
3178 :
3179 : BEGIN_CASE(JSOP_CALLEE)
3180 1297382 : JS_ASSERT(regs.fp()->isNonEvalFunctionFrame());
3181 1297382 : PUSH_COPY(argv[-2]);
3182 1297382 : END_CASE(JSOP_CALLEE)
3183 :
3184 : BEGIN_CASE(JSOP_GETTER)
3185 : BEGIN_CASE(JSOP_SETTER)
3186 : {
3187 297 : JSOp op2 = JSOp(*++regs.pc);
3188 : jsid id;
3189 : Value rval;
3190 : int i;
3191 : JSObject *obj;
3192 297 : switch (op2) {
3193 : case JSOP_SETNAME:
3194 : case JSOP_SETPROP:
3195 : {
3196 : PropertyName *name;
3197 0 : LOAD_NAME(0, name);
3198 0 : id = ATOM_TO_JSID(name);
3199 0 : rval = regs.sp[-1];
3200 0 : i = -1;
3201 0 : goto gs_pop_lval;
3202 : }
3203 : case JSOP_SETELEM:
3204 0 : rval = regs.sp[-1];
3205 0 : id = JSID_VOID;
3206 0 : i = -2;
3207 : gs_pop_lval:
3208 0 : FETCH_OBJECT(cx, i - 1, obj);
3209 0 : break;
3210 :
3211 : case JSOP_INITPROP:
3212 : {
3213 297 : JS_ASSERT(regs.sp - regs.fp()->base() >= 2);
3214 297 : rval = regs.sp[-1];
3215 297 : i = -1;
3216 : PropertyName *name;
3217 297 : LOAD_NAME(0, name);
3218 297 : id = ATOM_TO_JSID(name);
3219 297 : goto gs_get_lval;
3220 : }
3221 : default:
3222 0 : JS_ASSERT(op2 == JSOP_INITELEM);
3223 :
3224 0 : JS_ASSERT(regs.sp - regs.fp()->base() >= 3);
3225 0 : rval = regs.sp[-1];
3226 0 : id = JSID_VOID;
3227 0 : i = -2;
3228 : gs_get_lval:
3229 : {
3230 297 : const Value &lref = regs.sp[i-1];
3231 297 : JS_ASSERT(lref.isObject());
3232 297 : obj = &lref.toObject();
3233 297 : break;
3234 : }
3235 : }
3236 :
3237 : /* Ensure that id has a type suitable for use with obj. */
3238 297 : if (JSID_IS_VOID(id))
3239 0 : FETCH_ELEMENT_ID(obj, i, id);
3240 :
3241 297 : if (!js_IsCallable(rval)) {
3242 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GETTER_OR_SETTER,
3243 0 : (op == JSOP_GETTER) ? js_getter_str : js_setter_str);
3244 0 : goto error;
3245 : }
3246 :
3247 : /*
3248 : * Getters and setters are just like watchpoints from an access control
3249 : * point of view.
3250 : */
3251 : Value rtmp;
3252 : unsigned attrs;
3253 297 : if (!CheckAccess(cx, obj, id, JSACC_WATCH, &rtmp, &attrs))
3254 0 : goto error;
3255 :
3256 : PropertyOp getter;
3257 : StrictPropertyOp setter;
3258 297 : if (op == JSOP_GETTER) {
3259 207 : getter = CastAsPropertyOp(&rval.toObject());
3260 207 : setter = JS_StrictPropertyStub;
3261 207 : attrs = JSPROP_GETTER;
3262 : } else {
3263 90 : getter = JS_PropertyStub;
3264 90 : setter = CastAsStrictPropertyOp(&rval.toObject());
3265 90 : attrs = JSPROP_SETTER;
3266 : }
3267 297 : attrs |= JSPROP_ENUMERATE | JSPROP_SHARED;
3268 :
3269 297 : if (!obj->defineGeneric(cx, id, UndefinedValue(), getter, setter, attrs))
3270 0 : goto error;
3271 :
3272 297 : regs.sp += i;
3273 297 : if (js_CodeSpec[op2].ndefs > js_CodeSpec[op2].nuses) {
3274 0 : JS_ASSERT(js_CodeSpec[op2].ndefs == js_CodeSpec[op2].nuses + 1);
3275 0 : regs.sp[-1] = rval;
3276 0 : assertSameCompartment(cx, regs.sp[-1]);
3277 : }
3278 297 : len = js_CodeSpec[op2].length;
3279 297 : DO_NEXT_OP(len);
3280 : }
3281 :
3282 : BEGIN_CASE(JSOP_HOLE)
3283 4764 : PUSH_HOLE();
3284 4764 : END_CASE(JSOP_HOLE)
3285 :
3286 : BEGIN_CASE(JSOP_NEWINIT)
3287 : {
3288 1626 : uint8_t i = GET_UINT8(regs.pc);
3289 1626 : JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
3290 :
3291 : JSObject *obj;
3292 1626 : if (i == JSProto_Array) {
3293 324 : obj = NewDenseEmptyArray(cx);
3294 : } else {
3295 1302 : gc::AllocKind kind = GuessObjectGCKind(0);
3296 1302 : obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
3297 : }
3298 1626 : if (!obj || !SetInitializerObjectType(cx, script, regs.pc, obj))
3299 0 : goto error;
3300 :
3301 1626 : PUSH_OBJECT(*obj);
3302 1626 : CHECK_INTERRUPT_HANDLER();
3303 : }
3304 1626 : END_CASE(JSOP_NEWINIT)
3305 :
3306 : BEGIN_CASE(JSOP_NEWARRAY)
3307 : {
3308 809319 : unsigned count = GET_UINT24(regs.pc);
3309 809319 : JSObject *obj = NewDenseAllocatedArray(cx, count);
3310 809319 : if (!obj || !SetInitializerObjectType(cx, script, regs.pc, obj))
3311 0 : goto error;
3312 :
3313 809319 : PUSH_OBJECT(*obj);
3314 809319 : CHECK_INTERRUPT_HANDLER();
3315 : }
3316 809319 : END_CASE(JSOP_NEWARRAY)
3317 :
3318 : BEGIN_CASE(JSOP_NEWOBJECT)
3319 : {
3320 1059353 : JSObject *baseobj = script->getObject(GET_UINT32_INDEX(regs.pc));
3321 :
3322 1059353 : JSObject *obj = CopyInitializerObject(cx, baseobj);
3323 1059353 : if (!obj || !SetInitializerObjectType(cx, script, regs.pc, obj))
3324 1 : goto error;
3325 :
3326 1059352 : PUSH_OBJECT(*obj);
3327 1059352 : CHECK_INTERRUPT_HANDLER();
3328 : }
3329 1059352 : END_CASE(JSOP_NEWOBJECT)
3330 :
3331 : BEGIN_CASE(JSOP_ENDINIT)
3332 : {
3333 : /* FIXME remove JSOP_ENDINIT bug 588522 */
3334 1807081 : JS_ASSERT(regs.sp - regs.fp()->base() >= 1);
3335 1807081 : JS_ASSERT(regs.sp[-1].isObject());
3336 : }
3337 1807081 : END_CASE(JSOP_ENDINIT)
3338 :
3339 : BEGIN_CASE(JSOP_INITPROP)
3340 : {
3341 : /* Load the property's initial value into rval. */
3342 2075074 : JS_ASSERT(regs.sp - regs.fp()->base() >= 2);
3343 2075074 : Value rval = regs.sp[-1];
3344 :
3345 : /* Load the object being initialized into lval/obj. */
3346 2075074 : JSObject *obj = ®s.sp[-2].toObject();
3347 2075074 : JS_ASSERT(obj->isObject());
3348 :
3349 : JSAtom *atom;
3350 2075074 : LOAD_ATOM(0, atom);
3351 2075074 : jsid id = ATOM_TO_JSID(atom);
3352 :
3353 4150148 : if (JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom)
3354 74 : ? !js_SetPropertyHelper(cx, obj, id, 0, &rval, script->strictModeCode)
3355 : : !DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
3356 2075000 : JSPROP_ENUMERATE, 0, 0, 0)) {
3357 0 : goto error;
3358 : }
3359 :
3360 2075074 : regs.sp--;
3361 : }
3362 2075074 : END_CASE(JSOP_INITPROP);
3363 :
3364 : BEGIN_CASE(JSOP_INITELEM)
3365 : {
3366 : /* Pop the element's value into rval. */
3367 5794866 : JS_ASSERT(regs.sp - regs.fp()->base() >= 3);
3368 5794866 : const Value &rref = regs.sp[-1];
3369 :
3370 : /* Find the object being initialized at top of stack. */
3371 5794866 : const Value &lref = regs.sp[-3];
3372 5794866 : JS_ASSERT(lref.isObject());
3373 5794866 : JSObject *obj = &lref.toObject();
3374 :
3375 : /* Fetch id now that we have obj. */
3376 : jsid id;
3377 5794866 : FETCH_ELEMENT_ID(obj, -2, id);
3378 :
3379 : /*
3380 : * If rref is a hole, do not call JSObject::defineProperty. In this case,
3381 : * obj must be an array, so if the current op is the last element
3382 : * initialiser, set the array length to one greater than id.
3383 : */
3384 5794866 : if (rref.isMagic(JS_ARRAY_HOLE)) {
3385 4764 : JS_ASSERT(obj->isArray());
3386 4764 : JS_ASSERT(JSID_IS_INT(id));
3387 4764 : JS_ASSERT(uint32_t(JSID_TO_INT(id)) < StackSpace::ARGS_LENGTH_MAX);
3388 5162 : if (JSOp(regs.pc[JSOP_INITELEM_LENGTH]) == JSOP_ENDINIT &&
3389 398 : !js_SetLengthProperty(cx, obj, (uint32_t) (JSID_TO_INT(id) + 1))) {
3390 0 : goto error;
3391 : }
3392 : } else {
3393 5790102 : if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
3394 0 : goto error;
3395 : }
3396 5794866 : regs.sp -= 2;
3397 : }
3398 5794866 : END_CASE(JSOP_INITELEM)
3399 :
3400 : {
3401 : BEGIN_CASE(JSOP_GOSUB)
3402 54 : PUSH_BOOLEAN(false);
3403 54 : int32_t i = (regs.pc - script->code) + JSOP_GOSUB_LENGTH;
3404 54 : len = GET_JUMP_OFFSET(regs.pc);
3405 54 : PUSH_INT32(i);
3406 54 : END_VARLEN_CASE
3407 : }
3408 :
3409 : {
3410 : BEGIN_CASE(JSOP_RETSUB)
3411 : /* Pop [exception or hole, retsub pc-index]. */
3412 : Value rval, lval;
3413 1443 : POP_COPY_TO(rval);
3414 1443 : POP_COPY_TO(lval);
3415 1443 : JS_ASSERT(lval.isBoolean());
3416 1443 : if (lval.toBoolean()) {
3417 : /*
3418 : * Exception was pending during finally, throw it *before* we adjust
3419 : * pc, because pc indexes into script->trynotes. This turns out not to
3420 : * be necessary, but it seems clearer. And it points out a FIXME:
3421 : * 350509, due to Igor Bukanov.
3422 : */
3423 1407 : cx->setPendingException(rval);
3424 1407 : goto error;
3425 : }
3426 36 : JS_ASSERT(rval.isInt32());
3427 36 : len = rval.toInt32();
3428 36 : regs.pc = script->code;
3429 36 : END_VARLEN_CASE
3430 : }
3431 :
3432 : BEGIN_CASE(JSOP_EXCEPTION)
3433 8316 : PUSH_COPY(cx->getPendingException());
3434 8316 : cx->clearPendingException();
3435 8316 : CHECK_BRANCH();
3436 8316 : END_CASE(JSOP_EXCEPTION)
3437 :
3438 : BEGIN_CASE(JSOP_FINALLY)
3439 1479 : CHECK_BRANCH();
3440 1479 : END_CASE(JSOP_FINALLY)
3441 :
3442 : BEGIN_CASE(JSOP_THROWING)
3443 : {
3444 0 : JS_ASSERT(!cx->isExceptionPending());
3445 : Value v;
3446 0 : POP_COPY_TO(v);
3447 0 : cx->setPendingException(v);
3448 : }
3449 0 : END_CASE(JSOP_THROWING)
3450 :
3451 : BEGIN_CASE(JSOP_THROW)
3452 : {
3453 820 : JS_ASSERT(!cx->isExceptionPending());
3454 820 : CHECK_BRANCH();
3455 : Value v;
3456 820 : POP_COPY_TO(v);
3457 820 : cx->setPendingException(v);
3458 : /* let the code at error try to catch the exception. */
3459 820 : goto error;
3460 : }
3461 :
3462 : BEGIN_CASE(JSOP_INSTANCEOF)
3463 : {
3464 1009919 : const Value &rref = regs.sp[-1];
3465 1009919 : if (rref.isPrimitive()) {
3466 0 : js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, NULL);
3467 0 : goto error;
3468 : }
3469 1009919 : JSObject *obj = &rref.toObject();
3470 1009919 : const Value &lref = regs.sp[-2];
3471 1009919 : JSBool cond = JS_FALSE;
3472 1009919 : if (!HasInstance(cx, obj, &lref, &cond))
3473 19 : goto error;
3474 1009900 : regs.sp--;
3475 1009900 : regs.sp[-1].setBoolean(cond);
3476 : }
3477 1009900 : END_CASE(JSOP_INSTANCEOF)
3478 :
3479 : BEGIN_CASE(JSOP_DEBUGGER)
3480 : {
3481 4830 : JSTrapStatus st = JSTRAP_CONTINUE;
3482 : Value rval;
3483 4830 : if (JSDebuggerHandler handler = cx->runtime->debugHooks.debuggerHandler)
3484 10 : st = handler(cx, script, regs.pc, &rval, cx->runtime->debugHooks.debuggerHandlerData);
3485 4830 : if (st == JSTRAP_CONTINUE)
3486 4825 : st = Debugger::onDebuggerStatement(cx, &rval);
3487 4830 : switch (st) {
3488 : case JSTRAP_ERROR:
3489 118 : goto error;
3490 : case JSTRAP_CONTINUE:
3491 4488 : break;
3492 : case JSTRAP_RETURN:
3493 149 : regs.fp()->setReturnValue(rval);
3494 149 : interpReturnOK = true;
3495 149 : goto forced_return;
3496 : case JSTRAP_THROW:
3497 75 : cx->setPendingException(rval);
3498 75 : goto error;
3499 : default:;
3500 : }
3501 4488 : CHECK_INTERRUPT_HANDLER();
3502 : }
3503 4488 : END_CASE(JSOP_DEBUGGER)
3504 :
3505 : #if JS_HAS_XML_SUPPORT
3506 : BEGIN_CASE(JSOP_DEFXMLNS)
3507 : {
3508 9 : JS_ASSERT(!script->strictModeCode);
3509 :
3510 9 : if (!js_SetDefaultXMLNamespace(cx, regs.sp[-1]))
3511 0 : goto error;
3512 9 : regs.sp--;
3513 : }
3514 9 : END_CASE(JSOP_DEFXMLNS)
3515 :
3516 : BEGIN_CASE(JSOP_ANYNAME)
3517 : {
3518 18 : JS_ASSERT(!script->strictModeCode);
3519 :
3520 : jsid id;
3521 18 : if (!js_GetAnyName(cx, &id))
3522 0 : goto error;
3523 18 : PUSH_COPY(IdToValue(id));
3524 : }
3525 18 : END_CASE(JSOP_ANYNAME)
3526 :
3527 : BEGIN_CASE(JSOP_QNAMEPART)
3528 : {
3529 : /*
3530 : * We do not JS_ASSERT(!script->strictModeCode) here because JSOP_QNAMEPART
3531 : * is used for __proto__ and (in contexts where we favor JSOP_*ELEM instead
3532 : * of JSOP_*PROP) obj.prop compiled as obj['prop'].
3533 : */
3534 :
3535 : JSAtom *atom;
3536 5585 : LOAD_ATOM(0, atom);
3537 5585 : PUSH_STRING(atom);
3538 : }
3539 5585 : END_CASE(JSOP_QNAMEPART)
3540 :
3541 : BEGIN_CASE(JSOP_QNAMECONST)
3542 : {
3543 45 : JS_ASSERT(!script->strictModeCode);
3544 :
3545 : JSAtom *atom;
3546 45 : LOAD_ATOM(0, atom);
3547 45 : Value rval = StringValue(atom);
3548 45 : Value lval = regs.sp[-1];
3549 45 : JSObject *obj = js_ConstructXMLQNameObject(cx, lval, rval);
3550 45 : if (!obj)
3551 0 : goto error;
3552 45 : regs.sp[-1].setObject(*obj);
3553 : }
3554 45 : END_CASE(JSOP_QNAMECONST)
3555 :
3556 : BEGIN_CASE(JSOP_QNAME)
3557 : {
3558 0 : JS_ASSERT(!script->strictModeCode);
3559 :
3560 0 : Value rval = regs.sp[-1];
3561 0 : Value lval = regs.sp[-2];
3562 0 : JSObject *obj = js_ConstructXMLQNameObject(cx, lval, rval);
3563 0 : if (!obj)
3564 0 : goto error;
3565 0 : regs.sp--;
3566 0 : regs.sp[-1].setObject(*obj);
3567 : }
3568 0 : END_CASE(JSOP_QNAME)
3569 :
3570 : BEGIN_CASE(JSOP_TOATTRNAME)
3571 : {
3572 0 : JS_ASSERT(!script->strictModeCode);
3573 :
3574 : Value rval;
3575 0 : rval = regs.sp[-1];
3576 0 : if (!js_ToAttributeName(cx, &rval))
3577 0 : goto error;
3578 0 : regs.sp[-1] = rval;
3579 : }
3580 0 : END_CASE(JSOP_TOATTRNAME)
3581 :
3582 : BEGIN_CASE(JSOP_TOATTRVAL)
3583 : {
3584 0 : JS_ASSERT(!script->strictModeCode);
3585 :
3586 : Value rval;
3587 0 : rval = regs.sp[-1];
3588 0 : JS_ASSERT(rval.isString());
3589 0 : JSString *str = js_EscapeAttributeValue(cx, rval.toString(), JS_FALSE);
3590 0 : if (!str)
3591 0 : goto error;
3592 0 : regs.sp[-1].setString(str);
3593 : }
3594 0 : END_CASE(JSOP_TOATTRVAL)
3595 :
3596 : BEGIN_CASE(JSOP_ADDATTRNAME)
3597 : BEGIN_CASE(JSOP_ADDATTRVAL)
3598 : {
3599 0 : JS_ASSERT(!script->strictModeCode);
3600 :
3601 0 : Value rval = regs.sp[-1];
3602 0 : Value lval = regs.sp[-2];
3603 0 : JSString *str = lval.toString();
3604 0 : JSString *str2 = rval.toString();
3605 0 : str = js_AddAttributePart(cx, op == JSOP_ADDATTRNAME, str, str2);
3606 0 : if (!str)
3607 0 : goto error;
3608 0 : regs.sp--;
3609 0 : regs.sp[-1].setString(str);
3610 : }
3611 0 : END_CASE(JSOP_ADDATTRNAME)
3612 :
3613 : BEGIN_CASE(JSOP_BINDXMLNAME)
3614 : {
3615 18 : JS_ASSERT(!script->strictModeCode);
3616 :
3617 : Value lval;
3618 18 : lval = regs.sp[-1];
3619 : JSObject *obj;
3620 : jsid id;
3621 18 : if (!js_FindXMLProperty(cx, lval, &obj, &id))
3622 0 : goto error;
3623 18 : regs.sp[-1].setObjectOrNull(obj);
3624 18 : PUSH_COPY(IdToValue(id));
3625 : }
3626 18 : END_CASE(JSOP_BINDXMLNAME)
3627 :
3628 : BEGIN_CASE(JSOP_SETXMLNAME)
3629 : {
3630 18 : JS_ASSERT(!script->strictModeCode);
3631 :
3632 18 : JSObject *obj = ®s.sp[-3].toObject();
3633 18 : Value rval = regs.sp[-1];
3634 : jsid id;
3635 18 : FETCH_ELEMENT_ID(obj, -2, id);
3636 18 : if (!obj->setGeneric(cx, id, &rval, script->strictModeCode))
3637 0 : goto error;
3638 18 : rval = regs.sp[-1];
3639 18 : regs.sp -= 2;
3640 18 : regs.sp[-1] = rval;
3641 : }
3642 18 : END_CASE(JSOP_SETXMLNAME)
3643 :
3644 : BEGIN_CASE(JSOP_CALLXMLNAME)
3645 : BEGIN_CASE(JSOP_XMLNAME)
3646 : {
3647 36 : JS_ASSERT(!script->strictModeCode);
3648 :
3649 36 : Value lval = regs.sp[-1];
3650 : JSObject *obj;
3651 : jsid id;
3652 36 : if (!js_FindXMLProperty(cx, lval, &obj, &id))
3653 27 : goto error;
3654 : Value rval;
3655 9 : if (!obj->getGeneric(cx, id, &rval))
3656 0 : goto error;
3657 9 : regs.sp[-1] = rval;
3658 9 : if (op == JSOP_CALLXMLNAME) {
3659 : Value v;
3660 0 : if (!ComputeImplicitThis(cx, obj, &v))
3661 0 : goto error;
3662 0 : PUSH_COPY(v);
3663 : }
3664 : }
3665 9 : END_CASE(JSOP_XMLNAME)
3666 :
3667 : BEGIN_CASE(JSOP_DESCENDANTS)
3668 : BEGIN_CASE(JSOP_DELDESC)
3669 : {
3670 9 : JS_ASSERT(!script->strictModeCode);
3671 :
3672 : JSObject *obj;
3673 9 : FETCH_OBJECT(cx, -2, obj);
3674 9 : jsval rval = regs.sp[-1];
3675 9 : if (!js_GetXMLDescendants(cx, obj, rval, &rval))
3676 0 : goto error;
3677 :
3678 9 : if (op == JSOP_DELDESC) {
3679 0 : regs.sp[-1] = rval; /* set local root */
3680 0 : if (!js_DeleteXMLListElements(cx, JSVAL_TO_OBJECT(rval)))
3681 0 : goto error;
3682 0 : rval = JSVAL_TRUE; /* always succeed */
3683 : }
3684 :
3685 9 : regs.sp--;
3686 9 : regs.sp[-1] = rval;
3687 : }
3688 9 : END_CASE(JSOP_DESCENDANTS)
3689 :
3690 : BEGIN_CASE(JSOP_FILTER)
3691 : {
3692 63 : JS_ASSERT(!script->strictModeCode);
3693 :
3694 : /*
3695 : * We push the hole value before jumping to [enditer] so we can detect the
3696 : * first iteration and direct js_StepXMLListFilter to initialize filter's
3697 : * state.
3698 : */
3699 63 : PUSH_HOLE();
3700 63 : len = GET_JUMP_OFFSET(regs.pc);
3701 63 : JS_ASSERT(len > 0);
3702 : }
3703 63 : END_VARLEN_CASE
3704 :
3705 : BEGIN_CASE(JSOP_ENDFILTER)
3706 : {
3707 126 : JS_ASSERT(!script->strictModeCode);
3708 :
3709 126 : bool cond = !regs.sp[-1].isMagic();
3710 126 : if (cond) {
3711 : /* Exit the "with" block left from the previous iteration. */
3712 63 : LeaveWith(cx);
3713 : }
3714 126 : if (!js_StepXMLListFilter(cx, cond))
3715 9 : goto error;
3716 117 : if (!regs.sp[-1].isNull()) {
3717 : /*
3718 : * Decrease sp after EnterWith returns as we use sp[-1] there to root
3719 : * temporaries.
3720 : */
3721 63 : JS_ASSERT(IsXML(regs.sp[-1]));
3722 63 : if (!EnterWith(cx, -2))
3723 0 : goto error;
3724 63 : regs.sp--;
3725 63 : len = GET_JUMP_OFFSET(regs.pc);
3726 63 : JS_ASSERT(len < 0);
3727 63 : BRANCH(len);
3728 : }
3729 54 : regs.sp--;
3730 : }
3731 54 : END_CASE(JSOP_ENDFILTER);
3732 :
3733 : BEGIN_CASE(JSOP_TOXML)
3734 : {
3735 595 : JS_ASSERT(!script->strictModeCode);
3736 :
3737 595 : Value rval = regs.sp[-1];
3738 595 : JSObject *obj = js_ValueToXMLObject(cx, rval);
3739 595 : if (!obj)
3740 0 : goto error;
3741 595 : regs.sp[-1].setObject(*obj);
3742 : }
3743 595 : END_CASE(JSOP_TOXML)
3744 :
3745 : BEGIN_CASE(JSOP_TOXMLLIST)
3746 : {
3747 18 : JS_ASSERT(!script->strictModeCode);
3748 :
3749 18 : Value rval = regs.sp[-1];
3750 18 : JSObject *obj = js_ValueToXMLListObject(cx, rval);
3751 18 : if (!obj)
3752 0 : goto error;
3753 18 : regs.sp[-1].setObject(*obj);
3754 : }
3755 18 : END_CASE(JSOP_TOXMLLIST)
3756 :
3757 : BEGIN_CASE(JSOP_XMLTAGEXPR)
3758 : {
3759 0 : JS_ASSERT(!script->strictModeCode);
3760 :
3761 0 : Value rval = regs.sp[-1];
3762 0 : JSString *str = ToString(cx, rval);
3763 0 : if (!str)
3764 0 : goto error;
3765 0 : regs.sp[-1].setString(str);
3766 : }
3767 0 : END_CASE(JSOP_XMLTAGEXPR)
3768 :
3769 : BEGIN_CASE(JSOP_XMLELTEXPR)
3770 : {
3771 0 : JS_ASSERT(!script->strictModeCode);
3772 :
3773 0 : Value rval = regs.sp[-1];
3774 : JSString *str;
3775 0 : if (IsXML(rval)) {
3776 0 : str = js_ValueToXMLString(cx, rval);
3777 : } else {
3778 0 : str = ToString(cx, rval);
3779 0 : if (str)
3780 0 : str = js_EscapeElementValue(cx, str);
3781 : }
3782 0 : if (!str)
3783 0 : goto error;
3784 0 : regs.sp[-1].setString(str);
3785 : }
3786 0 : END_CASE(JSOP_XMLELTEXPR)
3787 :
3788 : BEGIN_CASE(JSOP_XMLCDATA)
3789 : {
3790 0 : JS_ASSERT(!script->strictModeCode);
3791 :
3792 0 : JSAtom *atom = script->getAtom(GET_UINT32_INDEX(regs.pc));
3793 0 : JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, atom);
3794 0 : if (!obj)
3795 0 : goto error;
3796 0 : PUSH_OBJECT(*obj);
3797 : }
3798 0 : END_CASE(JSOP_XMLCDATA)
3799 :
3800 : BEGIN_CASE(JSOP_XMLCOMMENT)
3801 : {
3802 0 : JS_ASSERT(!script->strictModeCode);
3803 :
3804 0 : JSAtom *atom = script->getAtom(GET_UINT32_INDEX(regs.pc));
3805 0 : JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, atom);
3806 0 : if (!obj)
3807 0 : goto error;
3808 0 : PUSH_OBJECT(*obj);
3809 : }
3810 0 : END_CASE(JSOP_XMLCOMMENT)
3811 :
3812 : BEGIN_CASE(JSOP_XMLPI)
3813 : {
3814 0 : JS_ASSERT(!script->strictModeCode);
3815 :
3816 0 : JSAtom *atom = script->getAtom(GET_UINT32_INDEX(regs.pc));
3817 0 : Value rval = regs.sp[-1];
3818 0 : JSString *str2 = rval.toString();
3819 0 : JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_PROCESSING_INSTRUCTION, atom, str2);
3820 0 : if (!obj)
3821 0 : goto error;
3822 0 : regs.sp[-1].setObject(*obj);
3823 : }
3824 0 : END_CASE(JSOP_XMLPI)
3825 :
3826 : BEGIN_CASE(JSOP_GETFUNNS)
3827 : {
3828 36 : JS_ASSERT(!script->strictModeCode);
3829 :
3830 : Value rval;
3831 36 : if (!cx->fp()->scopeChain().global().getFunctionNamespace(cx, &rval))
3832 0 : goto error;
3833 36 : PUSH_COPY(rval);
3834 : }
3835 36 : END_CASE(JSOP_GETFUNNS)
3836 : #endif /* JS_HAS_XML_SUPPORT */
3837 :
3838 : BEGIN_CASE(JSOP_ENTERBLOCK)
3839 : BEGIN_CASE(JSOP_ENTERLET0)
3840 : BEGIN_CASE(JSOP_ENTERLET1)
3841 : {
3842 25078 : StaticBlockObject &blockObj = script->getObject(GET_UINT32_INDEX(regs.pc))->asStaticBlock();
3843 25078 : JS_ASSERT(regs.fp()->maybeBlockChain() == blockObj.enclosingBlock());
3844 :
3845 25078 : if (op == JSOP_ENTERBLOCK) {
3846 17929 : JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() == regs.sp);
3847 17929 : Value *vp = regs.sp + blockObj.slotCount();
3848 17929 : JS_ASSERT(regs.sp < vp);
3849 17929 : JS_ASSERT(vp <= regs.fp()->slots() + script->nslots);
3850 17929 : SetValueRangeToUndefined(regs.sp, vp);
3851 17929 : regs.sp = vp;
3852 7149 : } else if (op == JSOP_ENTERLET0) {
3853 5074 : JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() + blockObj.slotCount()
3854 5074 : == regs.sp);
3855 2075 : } else if (op == JSOP_ENTERLET1) {
3856 2075 : JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() + blockObj.slotCount()
3857 2075 : == regs.sp - 1);
3858 : }
3859 :
3860 : #ifdef DEBUG
3861 25078 : JS_ASSERT(regs.fp()->maybeBlockChain() == blockObj.enclosingBlock());
3862 :
3863 : /*
3864 : * The young end of fp->scopeChain may omit blocks if we haven't closed
3865 : * over them, but if there are any closure blocks on fp->scopeChain, they'd
3866 : * better be (clones of) ancestors of the block we're entering now;
3867 : * anything else we should have popped off fp->scopeChain when we left its
3868 : * static scope.
3869 : */
3870 25078 : JSObject *obj2 = ®s.fp()->scopeChain();
3871 50318 : while (obj2->isWith())
3872 162 : obj2 = &obj2->asWith().enclosingScope();
3873 25948 : if (obj2->isBlock() &&
3874 870 : obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, regs.fp()))
3875 : {
3876 270 : StaticBlockObject &youngestProto = obj2->asClonedBlock().staticBlock();
3877 270 : StaticBlockObject *parent = &blockObj;
3878 540 : while ((parent = parent->enclosingBlock()) != &youngestProto)
3879 0 : JS_ASSERT(parent);
3880 : }
3881 : #endif
3882 :
3883 25078 : regs.fp()->setBlockChain(&blockObj);
3884 : }
3885 25078 : END_CASE(JSOP_ENTERBLOCK)
3886 :
3887 : BEGIN_CASE(JSOP_LEAVEBLOCK)
3888 : BEGIN_CASE(JSOP_LEAVEFORLETIN)
3889 : BEGIN_CASE(JSOP_LEAVEBLOCKEXPR)
3890 : {
3891 28182 : StaticBlockObject &blockObj = regs.fp()->blockChain();
3892 28182 : JS_ASSERT(blockObj.stackDepth() <= StackDepth(script));
3893 :
3894 : /*
3895 : * If we're about to leave the dynamic scope of a block that has been
3896 : * cloned onto fp->scopeChain, clear its private data, move its locals from
3897 : * the stack into the clone, and pop it off the chain.
3898 : */
3899 28182 : JSObject &scope = regs.fp()->scopeChain();
3900 28182 : if (scope.getProto() == &blockObj)
3901 1594 : scope.asClonedBlock().put(cx);
3902 :
3903 28182 : regs.fp()->setBlockChain(blockObj.enclosingBlock());
3904 :
3905 28182 : if (op == JSOP_LEAVEBLOCK) {
3906 : /* Pop the block's slots. */
3907 25364 : regs.sp -= GET_UINT16(regs.pc);
3908 25364 : JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() == regs.sp);
3909 2818 : } else if (op == JSOP_LEAVEBLOCKEXPR) {
3910 : /* Pop the block's slots maintaining the topmost expr. */
3911 829 : Value *vp = ®s.sp[-1];
3912 829 : regs.sp -= GET_UINT16(regs.pc);
3913 829 : JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() == regs.sp - 1);
3914 829 : regs.sp[-1] = *vp;
3915 : } else {
3916 : /* Another op will pop; nothing to do here. */
3917 1989 : len = JSOP_LEAVEFORLETIN_LENGTH;
3918 1989 : DO_NEXT_OP(len);
3919 : }
3920 : }
3921 26193 : END_CASE(JSOP_LEAVEBLOCK)
3922 :
3923 : #if JS_HAS_GENERATORS
3924 : BEGIN_CASE(JSOP_GENERATOR)
3925 : {
3926 8222 : JS_ASSERT(!cx->isExceptionPending());
3927 8222 : regs.pc += JSOP_GENERATOR_LENGTH;
3928 8222 : JSObject *obj = js_NewGenerator(cx);
3929 8222 : if (!obj)
3930 0 : goto error;
3931 8222 : regs.fp()->setReturnValue(ObjectValue(*obj));
3932 8222 : interpReturnOK = true;
3933 8222 : if (entryFrame != regs.fp())
3934 6044 : goto inline_return;
3935 2178 : goto exit;
3936 : }
3937 :
3938 : BEGIN_CASE(JSOP_YIELD)
3939 15426 : JS_ASSERT(!cx->isExceptionPending());
3940 15426 : JS_ASSERT(regs.fp()->isNonEvalFunctionFrame());
3941 15426 : if (cx->generatorFor(regs.fp())->state == JSGEN_CLOSING) {
3942 0 : js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD,
3943 0 : JSDVG_SEARCH_STACK, argv[-2], NULL);
3944 0 : goto error;
3945 : }
3946 15426 : regs.fp()->setReturnValue(regs.sp[-1]);
3947 15426 : regs.fp()->setYielding();
3948 15426 : regs.pc += JSOP_YIELD_LENGTH;
3949 15426 : interpReturnOK = true;
3950 15426 : goto exit;
3951 :
3952 : BEGIN_CASE(JSOP_ARRAYPUSH)
3953 : {
3954 4680 : uint32_t slot = GET_UINT16(regs.pc);
3955 4680 : JS_ASSERT(script->nfixed <= slot);
3956 4680 : JS_ASSERT(slot < script->nslots);
3957 4680 : JSObject *obj = ®s.fp()->slots()[slot].toObject();
3958 4680 : if (!js_NewbornArrayPush(cx, obj, regs.sp[-1]))
3959 0 : goto error;
3960 4680 : regs.sp--;
3961 : }
3962 4680 : END_CASE(JSOP_ARRAYPUSH)
3963 : #endif /* JS_HAS_GENERATORS */
3964 :
3965 : #if JS_THREADED_INTERP
3966 : L_JSOP_BACKPATCH:
3967 : L_JSOP_BACKPATCH_POP:
3968 :
3969 : # if !JS_HAS_GENERATORS
3970 : L_JSOP_GENERATOR:
3971 : L_JSOP_YIELD:
3972 : L_JSOP_ARRAYPUSH:
3973 : # endif
3974 :
3975 : # if !JS_HAS_DESTRUCTURING
3976 : L_JSOP_ENUMCONSTELEM:
3977 : # endif
3978 :
3979 : # if !JS_HAS_XML_SUPPORT
3980 : L_JSOP_CALLXMLNAME:
3981 : L_JSOP_STARTXMLEXPR:
3982 : L_JSOP_STARTXML:
3983 : L_JSOP_DELDESC:
3984 : L_JSOP_GETFUNNS:
3985 : L_JSOP_XMLPI:
3986 : L_JSOP_XMLCOMMENT:
3987 : L_JSOP_XMLCDATA:
3988 : L_JSOP_XMLELTEXPR:
3989 : L_JSOP_XMLTAGEXPR:
3990 : L_JSOP_TOXMLLIST:
3991 : L_JSOP_TOXML:
3992 : L_JSOP_ENDFILTER:
3993 : L_JSOP_FILTER:
3994 : L_JSOP_DESCENDANTS:
3995 : L_JSOP_XMLNAME:
3996 : L_JSOP_SETXMLNAME:
3997 : L_JSOP_BINDXMLNAME:
3998 : L_JSOP_ADDATTRVAL:
3999 : L_JSOP_ADDATTRNAME:
4000 : L_JSOP_TOATTRVAL:
4001 : L_JSOP_TOATTRNAME:
4002 : L_JSOP_QNAME:
4003 : L_JSOP_QNAMECONST:
4004 : L_JSOP_QNAMEPART:
4005 : L_JSOP_ANYNAME:
4006 : L_JSOP_DEFXMLNS:
4007 : # endif
4008 :
4009 : #endif /* !JS_THREADED_INTERP */
4010 : #if !JS_THREADED_INTERP
4011 : default:
4012 : #endif
4013 : {
4014 : char numBuf[12];
4015 0 : JS_snprintf(numBuf, sizeof numBuf, "%d", op);
4016 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4017 0 : JSMSG_BAD_BYTECODE, numBuf);
4018 0 : goto error;
4019 : }
4020 :
4021 : #if !JS_THREADED_INTERP
4022 : } /* switch (op) */
4023 : } /* for (;;) */
4024 : #endif /* !JS_THREADED_INTERP */
4025 :
4026 : error:
4027 2015322 : JS_ASSERT(&cx->regs() == ®s);
4028 2015322 : JS_ASSERT(uint32_t(regs.pc - script->code) < script->length);
4029 :
4030 : /* When rejoining, we must not err before finishing Interpret's prologue. */
4031 2015322 : JS_ASSERT(interpMode != JSINTERP_REJOIN);
4032 :
4033 2015322 : if (cx->isExceptionPending()) {
4034 : /* Restore atoms local in case we will resume. */
4035 2014512 : atoms = script->atoms;
4036 :
4037 : /* Call debugger throw hook if set. */
4038 2014512 : if (cx->runtime->debugHooks.throwHook || !cx->compartment->getDebuggees().empty()) {
4039 : Value rval;
4040 718 : JSTrapStatus st = Debugger::onExceptionUnwind(cx, &rval);
4041 718 : if (st == JSTRAP_CONTINUE) {
4042 683 : if (JSThrowHook handler = cx->runtime->debugHooks.throwHook)
4043 20 : st = handler(cx, script, regs.pc, &rval, cx->runtime->debugHooks.throwHookData);
4044 : }
4045 :
4046 718 : switch (st) {
4047 : case JSTRAP_ERROR:
4048 20 : cx->clearPendingException();
4049 20 : goto error;
4050 : case JSTRAP_RETURN:
4051 15 : cx->clearPendingException();
4052 15 : regs.fp()->setReturnValue(rval);
4053 15 : interpReturnOK = true;
4054 15 : goto forced_return;
4055 : case JSTRAP_THROW:
4056 5 : cx->setPendingException(rval);
4057 : case JSTRAP_CONTINUE:
4058 : default:;
4059 : }
4060 683 : CHECK_INTERRUPT_HANDLER();
4061 : }
4062 :
4063 2017343 : for (TryNoteIter tni(regs); !tni.done(); ++tni) {
4064 12615 : JSTryNote *tn = *tni;
4065 :
4066 12615 : UnwindScope(cx, tn->stackDepth);
4067 :
4068 : /*
4069 : * Set pc to the first bytecode after the the try note to point
4070 : * to the beginning of catch or finally or to [enditer] closing
4071 : * the for-in loop.
4072 : */
4073 12615 : regs.pc = (script)->main() + tn->start + tn->length;
4074 12615 : regs.sp = regs.fp()->base() + tn->stackDepth;
4075 :
4076 12615 : switch (tn->kind) {
4077 : case JSTRY_CATCH:
4078 11076 : JS_ASSERT(*regs.pc == JSOP_ENTERBLOCK);
4079 :
4080 : #if JS_HAS_GENERATORS
4081 : /* Catch cannot intercept the closing of a generator. */
4082 11076 : if (JS_UNLIKELY(cx->getPendingException().isMagic(JS_GENERATOR_CLOSING)))
4083 2760 : break;
4084 : #endif
4085 :
4086 : /*
4087 : * Don't clear exceptions to save cx->exception from GC
4088 : * until it is pushed to the stack via [exception] in the
4089 : * catch block.
4090 : */
4091 8316 : len = 0;
4092 8316 : DO_NEXT_OP(len);
4093 :
4094 : case JSTRY_FINALLY:
4095 : /*
4096 : * Push (true, exception) pair for finally to indicate that
4097 : * [retsub] should rethrow the exception.
4098 : */
4099 1425 : PUSH_BOOLEAN(true);
4100 1425 : PUSH_COPY(cx->getPendingException());
4101 1425 : cx->clearPendingException();
4102 1425 : len = 0;
4103 1425 : DO_NEXT_OP(len);
4104 :
4105 : case JSTRY_ITER: {
4106 : /* This is similar to JSOP_ENDITER in the interpreter loop. */
4107 114 : JS_ASSERT(JSOp(*regs.pc) == JSOP_ENDITER);
4108 114 : bool ok = UnwindIteratorForException(cx, ®s.sp[-1].toObject());
4109 114 : regs.sp -= 1;
4110 114 : if (!ok)
4111 8 : goto error;
4112 : }
4113 : }
4114 : }
4115 :
4116 : /*
4117 : * Propagate the exception or error to the caller unless the exception
4118 : * is an asynchronous return from a generator.
4119 : */
4120 2004728 : interpReturnOK = false;
4121 : #if JS_HAS_GENERATORS
4122 2004728 : if (JS_UNLIKELY(cx->isExceptionPending() &&
4123 : cx->getPendingException().isMagic(JS_GENERATOR_CLOSING))) {
4124 1452 : cx->clearPendingException();
4125 1452 : interpReturnOK = true;
4126 1452 : regs.fp()->clearReturnValue();
4127 : }
4128 : #endif
4129 : } else {
4130 810 : UnwindForUncatchableException(cx, regs);
4131 810 : interpReturnOK = false;
4132 : }
4133 :
4134 : forced_return:
4135 2005766 : UnwindScope(cx, 0);
4136 2005766 : regs.sp = regs.fp()->base();
4137 :
4138 2005766 : if (entryFrame != regs.fp())
4139 1995670 : goto inline_return;
4140 :
4141 : exit:
4142 517069 : if (cx->compartment->debugMode())
4143 50912 : interpReturnOK = ScriptDebugEpilogue(cx, regs.fp(), interpReturnOK);
4144 517069 : interpReturnOK = ScriptEpilogueOrGeneratorYield(cx, regs.fp(), interpReturnOK);
4145 517069 : regs.fp()->setFinishedInInterpreter();
4146 :
4147 : /*
4148 : * At this point we are inevitably leaving an interpreted function or a
4149 : * top-level script, and returning to one of:
4150 : * (a) an "out of line" call made through Invoke;
4151 : * (b) a js_Execute activation;
4152 : * (c) a generator (SendToGenerator, jsiter.c).
4153 : *
4154 : * We must not be in an inline frame. The check above ensures that for the
4155 : * error case and for a normal return, the code jumps directly to parent's
4156 : * frame pc.
4157 : */
4158 517069 : JS_ASSERT(entryFrame == regs.fp());
4159 517069 : if (!regs.fp()->isGeneratorFrame()) {
4160 497973 : JS_ASSERT(!IsActiveWithOrBlock(cx, regs.fp()->scopeChain(), 0));
4161 497973 : JS_ASSERT(!regs.fp()->hasBlockChain());
4162 : }
4163 :
4164 : #ifdef JS_METHODJIT
4165 : /*
4166 : * This path is used when it's guaranteed the method can be finished
4167 : * inside the JIT.
4168 : */
4169 : leave_on_safe_point:
4170 : #endif
4171 :
4172 517775 : gc::MaybeVerifyBarriers(cx, true);
4173 517775 : return interpReturnOK;
4174 : }
|