1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/Interpreter.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,3965 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * JavaScript bytecode interpreter. 1.12 + */ 1.13 + 1.14 +#include "vm/Interpreter-inl.h" 1.15 + 1.16 +#include "mozilla/DebugOnly.h" 1.17 +#include "mozilla/FloatingPoint.h" 1.18 +#include "mozilla/PodOperations.h" 1.19 + 1.20 +#include <string.h> 1.21 + 1.22 +#include "jsarray.h" 1.23 +#include "jsatom.h" 1.24 +#include "jscntxt.h" 1.25 +#include "jsfun.h" 1.26 +#include "jsgc.h" 1.27 +#include "jsiter.h" 1.28 +#include "jslibmath.h" 1.29 +#include "jsnum.h" 1.30 +#include "jsobj.h" 1.31 +#include "jsopcode.h" 1.32 +#include "jsprf.h" 1.33 +#include "jsscript.h" 1.34 +#include "jsstr.h" 1.35 + 1.36 +#include "builtin/Eval.h" 1.37 +#include "jit/BaselineJIT.h" 1.38 +#include "jit/Ion.h" 1.39 +#include "jit/IonAnalysis.h" 1.40 +#include "js/OldDebugAPI.h" 1.41 +#include "vm/Debugger.h" 1.42 +#include "vm/Opcodes.h" 1.43 +#include "vm/Shape.h" 1.44 +#include "vm/TraceLogging.h" 1.45 + 1.46 +#include "jsatominlines.h" 1.47 +#include "jsboolinlines.h" 1.48 +#include "jsfuninlines.h" 1.49 +#include "jsinferinlines.h" 1.50 +#include "jsscriptinlines.h" 1.51 + 1.52 +#include "jit/IonFrames-inl.h" 1.53 +#include "vm/Probes-inl.h" 1.54 +#include "vm/ScopeObject-inl.h" 1.55 +#include "vm/Stack-inl.h" 1.56 + 1.57 +using namespace js; 1.58 +using namespace js::gc; 1.59 +using namespace js::types; 1.60 + 1.61 +using mozilla::DebugOnly; 1.62 +using mozilla::NumberEqualsInt32; 1.63 +using mozilla::PodCopy; 1.64 +using JS::ForOfIterator; 1.65 + 1.66 +/* 1.67 + * Note: when Clang 3.2 (32-bit) inlines the two functions below in Interpret, 1.68 + * the conservative stack scanner leaks a ton of memory and this negatively 1.69 + * influences performance. The MOZ_NEVER_INLINE is a temporary workaround until 1.70 + * we can remove the conservative scanner. See bug 849526 for more info. 1.71 + */ 1.72 +#if defined(__clang__) && defined(JS_CPU_X86) 1.73 +static MOZ_NEVER_INLINE bool 1.74 +#else 1.75 +static bool 1.76 +#endif 1.77 +ToBooleanOp(const InterpreterRegs ®s) 1.78 +{ 1.79 + return ToBoolean(regs.stackHandleAt(-1)); 1.80 +} 1.81 + 1.82 +template <bool Eq> 1.83 +#if defined(__clang__) && defined(JS_CPU_X86) 1.84 +static MOZ_NEVER_INLINE bool 1.85 +#else 1.86 +static bool 1.87 +#endif 1.88 +LooseEqualityOp(JSContext *cx, InterpreterRegs ®s) 1.89 +{ 1.90 + HandleValue rval = regs.stackHandleAt(-1); 1.91 + HandleValue lval = regs.stackHandleAt(-2); 1.92 + bool cond; 1.93 + if (!LooselyEqual(cx, lval, rval, &cond)) 1.94 + return false; 1.95 + cond = (cond == Eq); 1.96 + regs.sp--; 1.97 + regs.sp[-1].setBoolean(cond); 1.98 + return true; 1.99 +} 1.100 + 1.101 +JSObject * 1.102 +js::BoxNonStrictThis(JSContext *cx, HandleValue thisv) 1.103 +{ 1.104 + /* 1.105 + * Check for SynthesizeFrame poisoning and fast constructors which 1.106 + * didn't check their callee properly. 1.107 + */ 1.108 + JS_ASSERT(!thisv.isMagic()); 1.109 + 1.110 + if (thisv.isNullOrUndefined()) { 1.111 + Rooted<GlobalObject*> global(cx, cx->global()); 1.112 + return JSObject::thisObject(cx, global); 1.113 + } 1.114 + 1.115 + if (thisv.isObject()) 1.116 + return &thisv.toObject(); 1.117 + 1.118 + return PrimitiveToObject(cx, thisv); 1.119 +} 1.120 + 1.121 +/* 1.122 + * ECMA requires "the global object", but in embeddings such as the browser, 1.123 + * which have multiple top-level objects (windows, frames, etc. in the DOM), 1.124 + * we prefer fun's parent. An example that causes this code to run: 1.125 + * 1.126 + * // in window w1 1.127 + * function f() { return this } 1.128 + * function g() { return f } 1.129 + * 1.130 + * // in window w2 1.131 + * var h = w1.g() 1.132 + * alert(h() == w1) 1.133 + * 1.134 + * The alert should display "true". 1.135 + */ 1.136 +bool 1.137 +js::BoxNonStrictThis(JSContext *cx, const CallReceiver &call) 1.138 +{ 1.139 + /* 1.140 + * Check for SynthesizeFrame poisoning and fast constructors which 1.141 + * didn't check their callee properly. 1.142 + */ 1.143 + JS_ASSERT(!call.thisv().isMagic()); 1.144 + 1.145 +#ifdef DEBUG 1.146 + JSFunction *fun = call.callee().is<JSFunction>() ? &call.callee().as<JSFunction>() : nullptr; 1.147 + JS_ASSERT_IF(fun && fun->isInterpreted(), !fun->strict()); 1.148 +#endif 1.149 + 1.150 + JSObject *thisObj = BoxNonStrictThis(cx, call.thisv()); 1.151 + if (!thisObj) 1.152 + return false; 1.153 + 1.154 + call.setThis(ObjectValue(*thisObj)); 1.155 + return true; 1.156 +} 1.157 + 1.158 +#if JS_HAS_NO_SUCH_METHOD 1.159 + 1.160 +static const uint32_t JSSLOT_FOUND_FUNCTION = 0; 1.161 +static const uint32_t JSSLOT_SAVED_ID = 1; 1.162 + 1.163 +static const Class js_NoSuchMethodClass = { 1.164 + "NoSuchMethod", 1.165 + JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS, 1.166 + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, 1.167 + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, 1.168 +}; 1.169 + 1.170 +/* 1.171 + * When JSOP_CALLPROP or JSOP_CALLELEM does not find the method property of 1.172 + * the base object, we search for the __noSuchMethod__ method in the base. 1.173 + * If it exists, we store the method and the property's id into an object of 1.174 + * NoSuchMethod class and store this object into the callee's stack slot. 1.175 + * Later, Invoke will recognise such an object and transfer control to 1.176 + * NoSuchMethod that invokes the method like: 1.177 + * 1.178 + * this.__noSuchMethod__(id, args) 1.179 + * 1.180 + * where id is the name of the method that this invocation attempted to 1.181 + * call by name, and args is an Array containing this invocation's actual 1.182 + * parameters. 1.183 + */ 1.184 +bool 1.185 +js::OnUnknownMethod(JSContext *cx, HandleObject obj, Value idval_, MutableHandleValue vp) 1.186 +{ 1.187 + RootedValue idval(cx, idval_); 1.188 + 1.189 + RootedValue value(cx); 1.190 + if (!JSObject::getProperty(cx, obj, obj, cx->names().noSuchMethod, &value)) 1.191 + return false; 1.192 + 1.193 + if (value.isObject()) { 1.194 + JSObject *obj = NewObjectWithClassProto(cx, &js_NoSuchMethodClass, nullptr, nullptr); 1.195 + if (!obj) 1.196 + return false; 1.197 + 1.198 + obj->setSlot(JSSLOT_FOUND_FUNCTION, value); 1.199 + obj->setSlot(JSSLOT_SAVED_ID, idval); 1.200 + vp.setObject(*obj); 1.201 + } 1.202 + return true; 1.203 +} 1.204 + 1.205 +static bool 1.206 +NoSuchMethod(JSContext *cx, unsigned argc, Value *vp) 1.207 +{ 1.208 + InvokeArgs args(cx); 1.209 + if (!args.init(2)) 1.210 + return false; 1.211 + 1.212 + JS_ASSERT(vp[0].isObject()); 1.213 + JS_ASSERT(vp[1].isObject()); 1.214 + JSObject *obj = &vp[0].toObject(); 1.215 + JS_ASSERT(obj->getClass() == &js_NoSuchMethodClass); 1.216 + 1.217 + args.setCallee(obj->getReservedSlot(JSSLOT_FOUND_FUNCTION)); 1.218 + args.setThis(vp[1]); 1.219 + args[0].set(obj->getReservedSlot(JSSLOT_SAVED_ID)); 1.220 + JSObject *argsobj = NewDenseCopiedArray(cx, argc, vp + 2); 1.221 + if (!argsobj) 1.222 + return false; 1.223 + args[1].setObject(*argsobj); 1.224 + bool ok = Invoke(cx, args); 1.225 + vp[0] = args.rval(); 1.226 + return ok; 1.227 +} 1.228 + 1.229 +#endif /* JS_HAS_NO_SUCH_METHOD */ 1.230 + 1.231 +static inline bool 1.232 +GetPropertyOperation(JSContext *cx, InterpreterFrame *fp, HandleScript script, jsbytecode *pc, 1.233 + MutableHandleValue lval, MutableHandleValue vp) 1.234 +{ 1.235 + JSOp op = JSOp(*pc); 1.236 + 1.237 + if (op == JSOP_LENGTH) { 1.238 + if (IsOptimizedArguments(fp, lval.address())) { 1.239 + vp.setInt32(fp->numActualArgs()); 1.240 + return true; 1.241 + } 1.242 + 1.243 + if (GetLengthProperty(lval, vp)) 1.244 + return true; 1.245 + } 1.246 + 1.247 + Rooted<GlobalObject*> global(cx, &fp->global()); 1.248 + RootedId id(cx, NameToId(script->getName(pc))); 1.249 + RootedObject obj(cx); 1.250 + 1.251 + /* Optimize (.1).toString(). */ 1.252 + if (lval.isNumber() && id == NameToId(cx->names().toString)) { 1.253 + JSObject *proto = GlobalObject::getOrCreateNumberPrototype(cx, global); 1.254 + if (!proto) 1.255 + return false; 1.256 + if (ClassMethodIsNative(cx, proto, &NumberObject::class_, id, js_num_toString)) 1.257 + obj = proto; 1.258 + } 1.259 + 1.260 + if (!obj) { 1.261 + obj = ToObjectFromStack(cx, lval); 1.262 + if (!obj) 1.263 + return false; 1.264 + } 1.265 + 1.266 + bool wasObject = lval.isObject(); 1.267 + 1.268 + if (!JSObject::getGeneric(cx, obj, obj, id, vp)) 1.269 + return false; 1.270 + 1.271 +#if JS_HAS_NO_SUCH_METHOD 1.272 + if (op == JSOP_CALLPROP && 1.273 + MOZ_UNLIKELY(vp.isUndefined()) && 1.274 + wasObject) 1.275 + { 1.276 + if (!OnUnknownMethod(cx, obj, IdToValue(id), vp)) 1.277 + return false; 1.278 + } 1.279 +#endif 1.280 + 1.281 + return true; 1.282 +} 1.283 + 1.284 +static inline bool 1.285 +NameOperation(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc, MutableHandleValue vp) 1.286 +{ 1.287 + JSObject *obj = fp->scopeChain(); 1.288 + PropertyName *name = fp->script()->getName(pc); 1.289 + 1.290 + /* 1.291 + * Skip along the scope chain to the enclosing global object. This is 1.292 + * used for GNAME opcodes where the bytecode emitter has determined a 1.293 + * name access must be on the global. It also insulates us from bugs 1.294 + * in the emitter: type inference will assume that GNAME opcodes are 1.295 + * accessing the global object, and the inferred behavior should match 1.296 + * the actual behavior even if the id could be found on the scope chain 1.297 + * before the global object. 1.298 + */ 1.299 + if (IsGlobalOp(JSOp(*pc))) 1.300 + obj = &obj->global(); 1.301 + 1.302 + Shape *shape = nullptr; 1.303 + JSObject *scope = nullptr, *pobj = nullptr; 1.304 + if (LookupNameNoGC(cx, name, obj, &scope, &pobj, &shape)) { 1.305 + if (FetchNameNoGC(pobj, shape, vp)) 1.306 + return true; 1.307 + } 1.308 + 1.309 + RootedObject objRoot(cx, obj), scopeRoot(cx), pobjRoot(cx); 1.310 + RootedPropertyName nameRoot(cx, name); 1.311 + RootedShape shapeRoot(cx); 1.312 + 1.313 + if (!LookupName(cx, nameRoot, objRoot, &scopeRoot, &pobjRoot, &shapeRoot)) 1.314 + return false; 1.315 + 1.316 + /* Kludge to allow (typeof foo == "undefined") tests. */ 1.317 + JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]); 1.318 + if (op2 == JSOP_TYPEOF) 1.319 + return FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp); 1.320 + return FetchName<false>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp); 1.321 +} 1.322 + 1.323 +static inline bool 1.324 +SetPropertyOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lval, 1.325 + HandleValue rval) 1.326 +{ 1.327 + JS_ASSERT(*pc == JSOP_SETPROP); 1.328 + 1.329 + RootedObject obj(cx, ToObjectFromStack(cx, lval)); 1.330 + if (!obj) 1.331 + return false; 1.332 + 1.333 + RootedValue rref(cx, rval); 1.334 + 1.335 + RootedId id(cx, NameToId(script->getName(pc))); 1.336 + if (MOZ_LIKELY(!obj->getOps()->setProperty)) { 1.337 + if (!baseops::SetPropertyHelper<SequentialExecution>(cx, obj, obj, id, baseops::Qualified, 1.338 + &rref, script->strict())) 1.339 + { 1.340 + return false; 1.341 + } 1.342 + } else { 1.343 + if (!JSObject::setGeneric(cx, obj, obj, id, &rref, script->strict())) 1.344 + return false; 1.345 + } 1.346 + 1.347 + return true; 1.348 +} 1.349 + 1.350 +bool 1.351 +js::ReportIsNotFunction(JSContext *cx, HandleValue v, int numToSkip, MaybeConstruct construct) 1.352 +{ 1.353 + unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION; 1.354 + int spIndex = numToSkip >= 0 ? -(numToSkip + 1) : JSDVG_SEARCH_STACK; 1.355 + 1.356 + js_ReportValueError3(cx, error, spIndex, v, NullPtr(), nullptr, nullptr); 1.357 + return false; 1.358 +} 1.359 + 1.360 +JSObject * 1.361 +js::ValueToCallable(JSContext *cx, HandleValue v, int numToSkip, MaybeConstruct construct) 1.362 +{ 1.363 + if (v.isObject()) { 1.364 + JSObject *callable = &v.toObject(); 1.365 + if (callable->isCallable()) 1.366 + return callable; 1.367 + } 1.368 + 1.369 + ReportIsNotFunction(cx, v, numToSkip, construct); 1.370 + return nullptr; 1.371 +} 1.372 + 1.373 +static MOZ_NEVER_INLINE bool 1.374 +Interpret(JSContext *cx, RunState &state); 1.375 + 1.376 +InterpreterFrame * 1.377 +InvokeState::pushInterpreterFrame(JSContext *cx) 1.378 +{ 1.379 + return cx->runtime()->interpreterStack().pushInvokeFrame(cx, args_, initial_); 1.380 +} 1.381 + 1.382 +InterpreterFrame * 1.383 +ExecuteState::pushInterpreterFrame(JSContext *cx) 1.384 +{ 1.385 + return cx->runtime()->interpreterStack().pushExecuteFrame(cx, script_, thisv_, scopeChain_, 1.386 + type_, evalInFrame_); 1.387 +} 1.388 + 1.389 +bool 1.390 +js::RunScript(JSContext *cx, RunState &state) 1.391 +{ 1.392 + JS_CHECK_RECURSION(cx, return false); 1.393 + 1.394 + SPSEntryMarker marker(cx->runtime()); 1.395 + 1.396 + state.script()->ensureNonLazyCanonicalFunction(cx); 1.397 + 1.398 +#ifdef JS_ION 1.399 + if (jit::IsIonEnabled(cx)) { 1.400 + jit::MethodStatus status = jit::CanEnter(cx, state); 1.401 + if (status == jit::Method_Error) 1.402 + return false; 1.403 + if (status == jit::Method_Compiled) { 1.404 + jit::IonExecStatus status = jit::IonCannon(cx, state); 1.405 + return !IsErrorStatus(status); 1.406 + } 1.407 + } 1.408 + 1.409 + if (jit::IsBaselineEnabled(cx)) { 1.410 + jit::MethodStatus status = jit::CanEnterBaselineMethod(cx, state); 1.411 + if (status == jit::Method_Error) 1.412 + return false; 1.413 + if (status == jit::Method_Compiled) { 1.414 + jit::IonExecStatus status = jit::EnterBaselineMethod(cx, state); 1.415 + return !IsErrorStatus(status); 1.416 + } 1.417 + } 1.418 +#endif 1.419 + 1.420 + if (state.isInvoke()) { 1.421 + InvokeState &invoke = *state.asInvoke(); 1.422 + TypeMonitorCall(cx, invoke.args(), invoke.constructing()); 1.423 + } 1.424 + 1.425 + return Interpret(cx, state); 1.426 +} 1.427 + 1.428 +struct AutoGCIfNeeded 1.429 +{ 1.430 + JSContext *cx_; 1.431 + AutoGCIfNeeded(JSContext *cx) : cx_(cx) {} 1.432 + ~AutoGCIfNeeded() { js::gc::GCIfNeeded(cx_); } 1.433 +}; 1.434 + 1.435 +/* 1.436 + * Find a function reference and its 'this' value implicit first parameter 1.437 + * under argc arguments on cx's stack, and call the function. Push missing 1.438 + * required arguments, allocate declared local variables, and pop everything 1.439 + * when done. Then push the return value. 1.440 + */ 1.441 +bool 1.442 +js::Invoke(JSContext *cx, CallArgs args, MaybeConstruct construct) 1.443 +{ 1.444 + JS_ASSERT(args.length() <= ARGS_LENGTH_MAX); 1.445 + JS_ASSERT(!cx->compartment()->activeAnalysis); 1.446 + 1.447 + /* We should never enter a new script while cx->iterValue is live. */ 1.448 + JS_ASSERT(cx->iterValue.isMagic(JS_NO_ITER_VALUE)); 1.449 + 1.450 + /* Perform GC if necessary on exit from the function. */ 1.451 + AutoGCIfNeeded gcIfNeeded(cx); 1.452 + 1.453 + /* MaybeConstruct is a subset of InitialFrameFlags */ 1.454 + InitialFrameFlags initial = (InitialFrameFlags) construct; 1.455 + 1.456 + if (args.calleev().isPrimitive()) 1.457 + return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, construct); 1.458 + 1.459 + JSObject &callee = args.callee(); 1.460 + const Class *clasp = callee.getClass(); 1.461 + 1.462 + /* Invoke non-functions. */ 1.463 + if (MOZ_UNLIKELY(clasp != &JSFunction::class_)) { 1.464 +#if JS_HAS_NO_SUCH_METHOD 1.465 + if (MOZ_UNLIKELY(clasp == &js_NoSuchMethodClass)) 1.466 + return NoSuchMethod(cx, args.length(), args.base()); 1.467 +#endif 1.468 + JS_ASSERT_IF(construct, !clasp->construct); 1.469 + if (!clasp->call) 1.470 + return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, construct); 1.471 + return CallJSNative(cx, clasp->call, args); 1.472 + } 1.473 + 1.474 + /* Invoke native functions. */ 1.475 + JSFunction *fun = &callee.as<JSFunction>(); 1.476 + JS_ASSERT_IF(construct, !fun->isNativeConstructor()); 1.477 + if (fun->isNative()) 1.478 + return CallJSNative(cx, fun->native(), args); 1.479 + 1.480 + if (!fun->getOrCreateScript(cx)) 1.481 + return false; 1.482 + 1.483 + /* Run function until JSOP_RETRVAL, JSOP_RETURN or error. */ 1.484 + InvokeState state(cx, args, initial); 1.485 + 1.486 + // Check to see if useNewType flag should be set for this frame. 1.487 + if (construct) { 1.488 + FrameIter iter(cx); 1.489 + if (!iter.done() && iter.hasScript()) { 1.490 + JSScript *script = iter.script(); 1.491 + jsbytecode *pc = iter.pc(); 1.492 + if (UseNewType(cx, script, pc)) 1.493 + state.setUseNewType(); 1.494 + } 1.495 + } 1.496 + 1.497 + bool ok = RunScript(cx, state); 1.498 + 1.499 + JS_ASSERT_IF(ok && construct, !args.rval().isPrimitive()); 1.500 + return ok; 1.501 +} 1.502 + 1.503 +bool 1.504 +js::Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, const Value *argv, 1.505 + MutableHandleValue rval) 1.506 +{ 1.507 + InvokeArgs args(cx); 1.508 + if (!args.init(argc)) 1.509 + return false; 1.510 + 1.511 + args.setCallee(fval); 1.512 + args.setThis(thisv); 1.513 + PodCopy(args.array(), argv, argc); 1.514 + 1.515 + if (args.thisv().isObject()) { 1.516 + /* 1.517 + * We must call the thisObject hook in case we are not called from the 1.518 + * interpreter, where a prior bytecode has computed an appropriate 1.519 + * |this| already. But don't do that if fval is a DOM function. 1.520 + */ 1.521 + if (!fval.isObject() || !fval.toObject().is<JSFunction>() || 1.522 + !fval.toObject().as<JSFunction>().isNative() || 1.523 + !fval.toObject().as<JSFunction>().jitInfo() || 1.524 + fval.toObject().as<JSFunction>().jitInfo()->needsOuterizedThisObject()) 1.525 + { 1.526 + RootedObject thisObj(cx, &args.thisv().toObject()); 1.527 + JSObject *thisp = JSObject::thisObject(cx, thisObj); 1.528 + if (!thisp) 1.529 + return false; 1.530 + args.setThis(ObjectValue(*thisp)); 1.531 + } 1.532 + } 1.533 + 1.534 + if (!Invoke(cx, args)) 1.535 + return false; 1.536 + 1.537 + rval.set(args.rval()); 1.538 + return true; 1.539 +} 1.540 + 1.541 +bool 1.542 +js::InvokeConstructor(JSContext *cx, CallArgs args) 1.543 +{ 1.544 + JS_ASSERT(!JSFunction::class_.construct); 1.545 + 1.546 + args.setThis(MagicValue(JS_IS_CONSTRUCTING)); 1.547 + 1.548 + if (!args.calleev().isObject()) 1.549 + return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT); 1.550 + 1.551 + JSObject &callee = args.callee(); 1.552 + if (callee.is<JSFunction>()) { 1.553 + RootedFunction fun(cx, &callee.as<JSFunction>()); 1.554 + 1.555 + if (fun->isNativeConstructor()) { 1.556 + bool ok = CallJSNativeConstructor(cx, fun->native(), args); 1.557 + return ok; 1.558 + } 1.559 + 1.560 + if (!fun->isInterpretedConstructor()) { 1.561 + RootedValue orig(cx, ObjectValue(*fun->originalFunction())); 1.562 + return ReportIsNotFunction(cx, orig, args.length() + 1, CONSTRUCT); 1.563 + } 1.564 + if (!Invoke(cx, args, CONSTRUCT)) 1.565 + return false; 1.566 + 1.567 + JS_ASSERT(args.rval().isObject()); 1.568 + return true; 1.569 + } 1.570 + 1.571 + const Class *clasp = callee.getClass(); 1.572 + if (!clasp->construct) 1.573 + return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT); 1.574 + 1.575 + return CallJSNativeConstructor(cx, clasp->construct, args); 1.576 +} 1.577 + 1.578 +bool 1.579 +js::InvokeConstructor(JSContext *cx, Value fval, unsigned argc, Value *argv, Value *rval) 1.580 +{ 1.581 + InvokeArgs args(cx); 1.582 + if (!args.init(argc)) 1.583 + return false; 1.584 + 1.585 + args.setCallee(fval); 1.586 + args.setThis(MagicValue(JS_THIS_POISON)); 1.587 + PodCopy(args.array(), argv, argc); 1.588 + 1.589 + if (!InvokeConstructor(cx, args)) 1.590 + return false; 1.591 + 1.592 + *rval = args.rval(); 1.593 + return true; 1.594 +} 1.595 + 1.596 +bool 1.597 +js::InvokeGetterOrSetter(JSContext *cx, JSObject *obj, Value fval, unsigned argc, 1.598 + Value *argv, MutableHandleValue rval) 1.599 +{ 1.600 + /* 1.601 + * Invoke could result in another try to get or set the same id again, see 1.602 + * bug 355497. 1.603 + */ 1.604 + JS_CHECK_RECURSION(cx, return false); 1.605 + 1.606 + return Invoke(cx, ObjectValue(*obj), fval, argc, argv, rval); 1.607 +} 1.608 + 1.609 +bool 1.610 +js::ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChainArg, const Value &thisv, 1.611 + ExecuteType type, AbstractFramePtr evalInFrame, Value *result) 1.612 +{ 1.613 + JS_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG); 1.614 + JS_ASSERT_IF(type == EXECUTE_GLOBAL, !scopeChainArg.is<ScopeObject>()); 1.615 +#ifdef DEBUG 1.616 + if (thisv.isObject()) { 1.617 + RootedObject thisObj(cx, &thisv.toObject()); 1.618 + AutoSuppressGC nogc(cx); 1.619 + JS_ASSERT(GetOuterObject(cx, thisObj) == thisObj); 1.620 + } 1.621 +#endif 1.622 + 1.623 + if (script->isEmpty()) { 1.624 + if (result) 1.625 + result->setUndefined(); 1.626 + return true; 1.627 + } 1.628 + 1.629 + TypeScript::SetThis(cx, script, thisv); 1.630 + 1.631 + probes::StartExecution(script); 1.632 + ExecuteState state(cx, script, thisv, scopeChainArg, type, evalInFrame, result); 1.633 + bool ok = RunScript(cx, state); 1.634 + probes::StopExecution(script); 1.635 + 1.636 + return ok; 1.637 +} 1.638 + 1.639 +bool 1.640 +js::Execute(JSContext *cx, HandleScript script, JSObject &scopeChainArg, Value *rval) 1.641 +{ 1.642 + /* The scope chain could be anything, so innerize just in case. */ 1.643 + RootedObject scopeChain(cx, &scopeChainArg); 1.644 + scopeChain = GetInnerObject(cx, scopeChain); 1.645 + if (!scopeChain) 1.646 + return false; 1.647 + 1.648 + /* Ensure the scope chain is all same-compartment and terminates in a global. */ 1.649 +#ifdef DEBUG 1.650 + JSObject *s = scopeChain; 1.651 + do { 1.652 + assertSameCompartment(cx, s); 1.653 + JS_ASSERT_IF(!s->enclosingScope(), s->is<GlobalObject>()); 1.654 + } while ((s = s->enclosingScope())); 1.655 +#endif 1.656 + 1.657 + /* The VAROBJFIX option makes varObj == globalObj in global code. */ 1.658 + if (!cx->options().varObjFix()) { 1.659 + if (!scopeChain->setVarObj(cx)) 1.660 + return false; 1.661 + } 1.662 + 1.663 + /* Use the scope chain as 'this', modulo outerization. */ 1.664 + JSObject *thisObj = JSObject::thisObject(cx, scopeChain); 1.665 + if (!thisObj) 1.666 + return false; 1.667 + Value thisv = ObjectValue(*thisObj); 1.668 + 1.669 + return ExecuteKernel(cx, script, *scopeChain, thisv, EXECUTE_GLOBAL, 1.670 + NullFramePtr() /* evalInFrame */, rval); 1.671 +} 1.672 + 1.673 +bool 1.674 +js::HasInstance(JSContext *cx, HandleObject obj, HandleValue v, bool *bp) 1.675 +{ 1.676 + const Class *clasp = obj->getClass(); 1.677 + RootedValue local(cx, v); 1.678 + if (clasp->hasInstance) 1.679 + return clasp->hasInstance(cx, obj, &local, bp); 1.680 + 1.681 + RootedValue val(cx, ObjectValue(*obj)); 1.682 + js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, 1.683 + JSDVG_SEARCH_STACK, val, NullPtr()); 1.684 + return false; 1.685 +} 1.686 + 1.687 +bool 1.688 +js::LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *result) 1.689 +{ 1.690 + if (SameType(lval, rval)) { 1.691 + if (lval.isString()) { 1.692 + JSString *l = lval.toString(); 1.693 + JSString *r = rval.toString(); 1.694 + return EqualStrings(cx, l, r, result); 1.695 + } 1.696 + 1.697 + if (lval.isDouble()) { 1.698 + double l = lval.toDouble(), r = rval.toDouble(); 1.699 + *result = (l == r); 1.700 + return true; 1.701 + } 1.702 + 1.703 + if (lval.isObject()) { 1.704 + JSObject *l = &lval.toObject(); 1.705 + JSObject *r = &rval.toObject(); 1.706 + *result = l == r; 1.707 + return true; 1.708 + } 1.709 + 1.710 + *result = lval.payloadAsRawUint32() == rval.payloadAsRawUint32(); 1.711 + return true; 1.712 + } 1.713 + 1.714 + if (lval.isNullOrUndefined()) { 1.715 + *result = rval.isNullOrUndefined() || 1.716 + (rval.isObject() && EmulatesUndefined(&rval.toObject())); 1.717 + return true; 1.718 + } 1.719 + 1.720 + if (rval.isNullOrUndefined()) { 1.721 + *result = (lval.isObject() && EmulatesUndefined(&lval.toObject())); 1.722 + return true; 1.723 + } 1.724 + 1.725 + RootedValue lvalue(cx, lval); 1.726 + RootedValue rvalue(cx, rval); 1.727 + 1.728 + if (!ToPrimitive(cx, &lvalue)) 1.729 + return false; 1.730 + if (!ToPrimitive(cx, &rvalue)) 1.731 + return false; 1.732 + 1.733 + if (lvalue.get().isString() && rvalue.get().isString()) { 1.734 + JSString *l = lvalue.get().toString(); 1.735 + JSString *r = rvalue.get().toString(); 1.736 + return EqualStrings(cx, l, r, result); 1.737 + } 1.738 + 1.739 + double l, r; 1.740 + if (!ToNumber(cx, lvalue, &l) || !ToNumber(cx, rvalue, &r)) 1.741 + return false; 1.742 + *result = (l == r); 1.743 + return true; 1.744 +} 1.745 + 1.746 +bool 1.747 +js::StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, bool *equal) 1.748 +{ 1.749 + Value lval = lref, rval = rref; 1.750 + if (SameType(lval, rval)) { 1.751 + if (lval.isString()) 1.752 + return EqualStrings(cx, lval.toString(), rval.toString(), equal); 1.753 + if (lval.isDouble()) { 1.754 + *equal = (lval.toDouble() == rval.toDouble()); 1.755 + return true; 1.756 + } 1.757 + if (lval.isObject()) { 1.758 + *equal = lval.toObject() == rval.toObject(); 1.759 + return true; 1.760 + } 1.761 + if (lval.isUndefined()) { 1.762 + *equal = true; 1.763 + return true; 1.764 + } 1.765 + *equal = lval.payloadAsRawUint32() == rval.payloadAsRawUint32(); 1.766 + return true; 1.767 + } 1.768 + 1.769 + if (lval.isDouble() && rval.isInt32()) { 1.770 + double ld = lval.toDouble(); 1.771 + double rd = rval.toInt32(); 1.772 + *equal = (ld == rd); 1.773 + return true; 1.774 + } 1.775 + if (lval.isInt32() && rval.isDouble()) { 1.776 + double ld = lval.toInt32(); 1.777 + double rd = rval.toDouble(); 1.778 + *equal = (ld == rd); 1.779 + return true; 1.780 + } 1.781 + 1.782 + *equal = false; 1.783 + return true; 1.784 +} 1.785 + 1.786 +static inline bool 1.787 +IsNegativeZero(const Value &v) 1.788 +{ 1.789 + return v.isDouble() && mozilla::IsNegativeZero(v.toDouble()); 1.790 +} 1.791 + 1.792 +static inline bool 1.793 +IsNaN(const Value &v) 1.794 +{ 1.795 + return v.isDouble() && mozilla::IsNaN(v.toDouble()); 1.796 +} 1.797 + 1.798 +bool 1.799 +js::SameValue(JSContext *cx, const Value &v1, const Value &v2, bool *same) 1.800 +{ 1.801 + if (IsNegativeZero(v1)) { 1.802 + *same = IsNegativeZero(v2); 1.803 + return true; 1.804 + } 1.805 + if (IsNegativeZero(v2)) { 1.806 + *same = false; 1.807 + return true; 1.808 + } 1.809 + if (IsNaN(v1) && IsNaN(v2)) { 1.810 + *same = true; 1.811 + return true; 1.812 + } 1.813 + return StrictlyEqual(cx, v1, v2, same); 1.814 +} 1.815 + 1.816 +JSType 1.817 +js::TypeOfObject(JSObject *obj) 1.818 +{ 1.819 + if (EmulatesUndefined(obj)) 1.820 + return JSTYPE_VOID; 1.821 + if (obj->isCallable()) 1.822 + return JSTYPE_FUNCTION; 1.823 + return JSTYPE_OBJECT; 1.824 +} 1.825 + 1.826 +JSType 1.827 +js::TypeOfValue(const Value &v) 1.828 +{ 1.829 + if (v.isNumber()) 1.830 + return JSTYPE_NUMBER; 1.831 + if (v.isString()) 1.832 + return JSTYPE_STRING; 1.833 + if (v.isNull()) 1.834 + return JSTYPE_OBJECT; 1.835 + if (v.isUndefined()) 1.836 + return JSTYPE_VOID; 1.837 + if (v.isObject()) 1.838 + return TypeOfObject(&v.toObject()); 1.839 + JS_ASSERT(v.isBoolean()); 1.840 + return JSTYPE_BOOLEAN; 1.841 +} 1.842 + 1.843 +/* 1.844 + * Enter the new with scope using an object at sp[-1] and associate the depth 1.845 + * of the with block with sp + stackIndex. 1.846 + */ 1.847 +bool 1.848 +js::EnterWithOperation(JSContext *cx, AbstractFramePtr frame, HandleValue val, 1.849 + HandleObject staticWith) 1.850 +{ 1.851 + JS_ASSERT(staticWith->is<StaticWithObject>()); 1.852 + RootedObject obj(cx); 1.853 + if (val.isObject()) { 1.854 + obj = &val.toObject(); 1.855 + } else { 1.856 + obj = ToObject(cx, val); 1.857 + if (!obj) 1.858 + return false; 1.859 + } 1.860 + 1.861 + RootedObject scopeChain(cx, frame.scopeChain()); 1.862 + DynamicWithObject *withobj = DynamicWithObject::create(cx, obj, scopeChain, staticWith); 1.863 + if (!withobj) 1.864 + return false; 1.865 + 1.866 + frame.pushOnScopeChain(*withobj); 1.867 + return true; 1.868 +} 1.869 + 1.870 +// Unwind scope chain and iterator to match the static scope corresponding to 1.871 +// the given bytecode position. 1.872 +void 1.873 +js::UnwindScope(JSContext *cx, ScopeIter &si, jsbytecode *pc) 1.874 +{ 1.875 + if (si.done()) 1.876 + return; 1.877 + 1.878 + Rooted<NestedScopeObject *> staticScope(cx, si.frame().script()->getStaticScope(pc)); 1.879 + 1.880 + for (; si.staticScope() != staticScope; ++si) { 1.881 + switch (si.type()) { 1.882 + case ScopeIter::Block: 1.883 + if (cx->compartment()->debugMode()) 1.884 + DebugScopes::onPopBlock(cx, si); 1.885 + if (si.staticBlock().needsClone()) 1.886 + si.frame().popBlock(cx); 1.887 + break; 1.888 + case ScopeIter::With: 1.889 + si.frame().popWith(cx); 1.890 + break; 1.891 + case ScopeIter::Call: 1.892 + case ScopeIter::StrictEvalScope: 1.893 + break; 1.894 + } 1.895 + } 1.896 +} 1.897 + 1.898 +static void 1.899 +ForcedReturn(JSContext *cx, ScopeIter &si, InterpreterRegs ®s) 1.900 +{ 1.901 + UnwindScope(cx, si, regs.fp()->script()->main()); 1.902 + regs.setToEndOfScript(); 1.903 +} 1.904 + 1.905 +static void 1.906 +ForcedReturn(JSContext *cx, InterpreterRegs ®s) 1.907 +{ 1.908 + ScopeIter si(regs.fp(), regs.pc, cx); 1.909 + ForcedReturn(cx, si, regs); 1.910 +} 1.911 + 1.912 +void 1.913 +js::UnwindForUncatchableException(JSContext *cx, const InterpreterRegs ®s) 1.914 +{ 1.915 + /* c.f. the regular (catchable) TryNoteIter loop in HandleError. */ 1.916 + for (TryNoteIter tni(cx, regs); !tni.done(); ++tni) { 1.917 + JSTryNote *tn = *tni; 1.918 + if (tn->kind == JSTRY_ITER) { 1.919 + Value *sp = regs.spForStackDepth(tn->stackDepth); 1.920 + UnwindIteratorForUncatchableException(cx, &sp[-1].toObject()); 1.921 + } 1.922 + } 1.923 +} 1.924 + 1.925 +TryNoteIter::TryNoteIter(JSContext *cx, const InterpreterRegs ®s) 1.926 + : regs(regs), 1.927 + script(cx, regs.fp()->script()), 1.928 + pcOffset(regs.pc - script->main()) 1.929 +{ 1.930 + if (script->hasTrynotes()) { 1.931 + tn = script->trynotes()->vector; 1.932 + tnEnd = tn + script->trynotes()->length; 1.933 + } else { 1.934 + tn = tnEnd = nullptr; 1.935 + } 1.936 + settle(); 1.937 +} 1.938 + 1.939 +void 1.940 +TryNoteIter::operator++() 1.941 +{ 1.942 + ++tn; 1.943 + settle(); 1.944 +} 1.945 + 1.946 +bool 1.947 +TryNoteIter::done() const 1.948 +{ 1.949 + return tn == tnEnd; 1.950 +} 1.951 + 1.952 +void 1.953 +TryNoteIter::settle() 1.954 +{ 1.955 + for (; tn != tnEnd; ++tn) { 1.956 + /* If pc is out of range, try the next one. */ 1.957 + if (pcOffset - tn->start >= tn->length) 1.958 + continue; 1.959 + 1.960 + /* 1.961 + * We have a note that covers the exception pc but we must check 1.962 + * whether the interpreter has already executed the corresponding 1.963 + * handler. This is possible when the executed bytecode implements 1.964 + * break or return from inside a for-in loop. 1.965 + * 1.966 + * In this case the emitter generates additional [enditer] and [gosub] 1.967 + * opcodes to close all outstanding iterators and execute the finally 1.968 + * blocks. If such an [enditer] throws an exception, its pc can still 1.969 + * be inside several nested for-in loops and try-finally statements 1.970 + * even if we have already closed the corresponding iterators and 1.971 + * invoked the finally blocks. 1.972 + * 1.973 + * To address this, we make [enditer] always decrease the stack even 1.974 + * when its implementation throws an exception. Thus already executed 1.975 + * [enditer] and [gosub] opcodes will have try notes with the stack 1.976 + * depth exceeding the current one and this condition is what we use to 1.977 + * filter them out. 1.978 + */ 1.979 + if (tn->stackDepth <= regs.stackDepth()) 1.980 + break; 1.981 + } 1.982 +} 1.983 + 1.984 +enum HandleErrorContinuation 1.985 +{ 1.986 + SuccessfulReturnContinuation, 1.987 + ErrorReturnContinuation, 1.988 + CatchContinuation, 1.989 + FinallyContinuation 1.990 +}; 1.991 + 1.992 +static HandleErrorContinuation 1.993 +HandleError(JSContext *cx, InterpreterRegs ®s) 1.994 +{ 1.995 + JS_ASSERT(regs.fp()->script()->containsPC(regs.pc)); 1.996 + 1.997 + ScopeIter si(regs.fp(), regs.pc, cx); 1.998 + bool ok = false; 1.999 + 1.1000 + again: 1.1001 + if (cx->isExceptionPending()) { 1.1002 + /* Call debugger throw hooks. */ 1.1003 + if (MOZ_UNLIKELY(cx->compartment()->debugMode())) { 1.1004 + JSTrapStatus status = DebugExceptionUnwind(cx, regs.fp(), regs.pc); 1.1005 + switch (status) { 1.1006 + case JSTRAP_ERROR: 1.1007 + goto again; 1.1008 + 1.1009 + case JSTRAP_CONTINUE: 1.1010 + case JSTRAP_THROW: 1.1011 + break; 1.1012 + 1.1013 + case JSTRAP_RETURN: 1.1014 + ForcedReturn(cx, si, regs); 1.1015 + return SuccessfulReturnContinuation; 1.1016 + 1.1017 + default: 1.1018 + MOZ_ASSUME_UNREACHABLE("Invalid trap status"); 1.1019 + } 1.1020 + } 1.1021 + 1.1022 + RootedValue exception(cx); 1.1023 + for (TryNoteIter tni(cx, regs); !tni.done(); ++tni) { 1.1024 + JSTryNote *tn = *tni; 1.1025 + 1.1026 + UnwindScope(cx, si, regs.fp()->script()->main() + tn->start); 1.1027 + 1.1028 + /* 1.1029 + * Set pc to the first bytecode after the the try note to point 1.1030 + * to the beginning of catch or finally or to [enditer] closing 1.1031 + * the for-in loop. 1.1032 + */ 1.1033 + regs.pc = regs.fp()->script()->main() + tn->start + tn->length; 1.1034 + regs.sp = regs.spForStackDepth(tn->stackDepth); 1.1035 + 1.1036 + switch (tn->kind) { 1.1037 + case JSTRY_CATCH: 1.1038 + /* Catch cannot intercept the closing of a generator. */ 1.1039 + if (!cx->getPendingException(&exception)) 1.1040 + return ErrorReturnContinuation; 1.1041 + if (exception.isMagic(JS_GENERATOR_CLOSING)) 1.1042 + break; 1.1043 + return CatchContinuation; 1.1044 + 1.1045 + case JSTRY_FINALLY: 1.1046 + return FinallyContinuation; 1.1047 + 1.1048 + case JSTRY_ITER: { 1.1049 + /* This is similar to JSOP_ENDITER in the interpreter loop. */ 1.1050 + JS_ASSERT(JSOp(*regs.pc) == JSOP_ENDITER); 1.1051 + RootedObject obj(cx, ®s.sp[-1].toObject()); 1.1052 + bool ok = UnwindIteratorForException(cx, obj); 1.1053 + regs.sp -= 1; 1.1054 + if (!ok) 1.1055 + goto again; 1.1056 + break; 1.1057 + } 1.1058 + 1.1059 + case JSTRY_LOOP: 1.1060 + break; 1.1061 + } 1.1062 + } 1.1063 + 1.1064 + /* 1.1065 + * Propagate the exception or error to the caller unless the exception 1.1066 + * is an asynchronous return from a generator. 1.1067 + */ 1.1068 + if (cx->isExceptionPending()) { 1.1069 + RootedValue exception(cx); 1.1070 + if (!cx->getPendingException(&exception)) 1.1071 + return ErrorReturnContinuation; 1.1072 + 1.1073 + if (exception.isMagic(JS_GENERATOR_CLOSING)) { 1.1074 + cx->clearPendingException(); 1.1075 + ok = true; 1.1076 + regs.fp()->clearReturnValue(); 1.1077 + } 1.1078 + } 1.1079 + } else { 1.1080 + UnwindForUncatchableException(cx, regs); 1.1081 + } 1.1082 + 1.1083 + ForcedReturn(cx, si, regs); 1.1084 + return ok ? SuccessfulReturnContinuation : ErrorReturnContinuation; 1.1085 +} 1.1086 + 1.1087 +#define REGS (activation.regs()) 1.1088 +#define PUSH_COPY(v) do { *REGS.sp++ = (v); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0) 1.1089 +#define PUSH_COPY_SKIP_CHECK(v) *REGS.sp++ = (v) 1.1090 +#define PUSH_NULL() REGS.sp++->setNull() 1.1091 +#define PUSH_UNDEFINED() REGS.sp++->setUndefined() 1.1092 +#define PUSH_BOOLEAN(b) REGS.sp++->setBoolean(b) 1.1093 +#define PUSH_DOUBLE(d) REGS.sp++->setDouble(d) 1.1094 +#define PUSH_INT32(i) REGS.sp++->setInt32(i) 1.1095 +#define PUSH_STRING(s) do { REGS.sp++->setString(s); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0) 1.1096 +#define PUSH_OBJECT(obj) do { REGS.sp++->setObject(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0) 1.1097 +#define PUSH_OBJECT_OR_NULL(obj) do { REGS.sp++->setObjectOrNull(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0) 1.1098 +#define PUSH_HOLE() REGS.sp++->setMagic(JS_ELEMENTS_HOLE) 1.1099 +#define POP_COPY_TO(v) (v) = *--REGS.sp 1.1100 +#define POP_RETURN_VALUE() REGS.fp()->setReturnValue(*--REGS.sp) 1.1101 + 1.1102 +#define FETCH_OBJECT(cx, n, obj) \ 1.1103 + JS_BEGIN_MACRO \ 1.1104 + HandleValue val = REGS.stackHandleAt(n); \ 1.1105 + obj = ToObjectFromStack((cx), (val)); \ 1.1106 + if (!obj) \ 1.1107 + goto error; \ 1.1108 + JS_END_MACRO 1.1109 + 1.1110 +/* 1.1111 + * Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but 1.1112 + * remain distinct for the decompiler. 1.1113 + */ 1.1114 +JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH); 1.1115 + 1.1116 +/* See TRY_BRANCH_AFTER_COND. */ 1.1117 +JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH); 1.1118 +JS_STATIC_ASSERT(JSOP_IFNE == JSOP_IFEQ + 1); 1.1119 + 1.1120 +/* 1.1121 + * Inline fast paths for iteration. js_IteratorMore and js_IteratorNext handle 1.1122 + * all cases, but we inline the most frequently taken paths here. 1.1123 + */ 1.1124 +bool 1.1125 +js::IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, MutableHandleValue rval) 1.1126 +{ 1.1127 + if (iterobj->is<PropertyIteratorObject>()) { 1.1128 + NativeIterator *ni = iterobj->as<PropertyIteratorObject>().getNativeIterator(); 1.1129 + if (ni->isKeyIter()) { 1.1130 + *cond = (ni->props_cursor < ni->props_end); 1.1131 + return true; 1.1132 + } 1.1133 + } 1.1134 + Rooted<JSObject*> iobj(cx, iterobj); 1.1135 + if (!js_IteratorMore(cx, iobj, rval)) 1.1136 + return false; 1.1137 + *cond = rval.isTrue(); 1.1138 + return true; 1.1139 +} 1.1140 + 1.1141 +bool 1.1142 +js::IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval) 1.1143 +{ 1.1144 + if (iterobj->is<PropertyIteratorObject>()) { 1.1145 + NativeIterator *ni = iterobj->as<PropertyIteratorObject>().getNativeIterator(); 1.1146 + if (ni->isKeyIter()) { 1.1147 + JS_ASSERT(ni->props_cursor < ni->props_end); 1.1148 + rval.setString(*ni->current()); 1.1149 + ni->incCursor(); 1.1150 + return true; 1.1151 + } 1.1152 + } 1.1153 + return js_IteratorNext(cx, iterobj, rval); 1.1154 +} 1.1155 + 1.1156 +/* 1.1157 + * Compute the implicit |this| parameter for a call expression where the callee 1.1158 + * funval was resolved from an unqualified name reference to a property on obj 1.1159 + * (an object on the scope chain). 1.1160 + * 1.1161 + * We can avoid computing |this| eagerly and push the implicit callee-coerced 1.1162 + * |this| value, undefined, if any of these conditions hold: 1.1163 + * 1.1164 + * 1. The nominal |this|, obj, is a global object. 1.1165 + * 1.1166 + * 2. The nominal |this|, obj, has one of Block, Call, or DeclEnv class (this 1.1167 + * is what IsCacheableNonGlobalScope tests). Such objects-as-scopes must be 1.1168 + * censored with undefined. 1.1169 + * 1.1170 + * Otherwise, we bind |this| to obj->thisObject(). Only names inside |with| 1.1171 + * statements and embedding-specific scope objects fall into this category. 1.1172 + * 1.1173 + * If the callee is a strict mode function, then code implementing JSOP_THIS 1.1174 + * in the interpreter and JITs will leave undefined as |this|. If funval is a 1.1175 + * function not in strict mode, JSOP_THIS code replaces undefined with funval's 1.1176 + * global. 1.1177 + * 1.1178 + * We set *vp to undefined early to reduce code size and bias this code for the 1.1179 + * common and future-friendly cases. 1.1180 + */ 1.1181 +static inline bool 1.1182 +ComputeImplicitThis(JSContext *cx, HandleObject obj, MutableHandleValue vp) 1.1183 +{ 1.1184 + vp.setUndefined(); 1.1185 + 1.1186 + if (obj->is<GlobalObject>()) 1.1187 + return true; 1.1188 + 1.1189 + if (IsCacheableNonGlobalScope(obj)) 1.1190 + return true; 1.1191 + 1.1192 + JSObject *nobj = JSObject::thisObject(cx, obj); 1.1193 + if (!nobj) 1.1194 + return false; 1.1195 + 1.1196 + vp.setObject(*nobj); 1.1197 + return true; 1.1198 +} 1.1199 + 1.1200 +static MOZ_ALWAYS_INLINE bool 1.1201 +AddOperation(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res) 1.1202 +{ 1.1203 + if (lhs.isInt32() && rhs.isInt32()) { 1.1204 + int32_t l = lhs.toInt32(), r = rhs.toInt32(); 1.1205 + int32_t t; 1.1206 + if (MOZ_LIKELY(SafeAdd(l, r, &t))) { 1.1207 + res.setInt32(t); 1.1208 + return true; 1.1209 + } 1.1210 + } 1.1211 + 1.1212 + if (!ToPrimitive(cx, lhs)) 1.1213 + return false; 1.1214 + if (!ToPrimitive(cx, rhs)) 1.1215 + return false; 1.1216 + 1.1217 + bool lIsString, rIsString; 1.1218 + if ((lIsString = lhs.isString()) | (rIsString = rhs.isString())) { 1.1219 + JSString *lstr, *rstr; 1.1220 + if (lIsString) { 1.1221 + lstr = lhs.toString(); 1.1222 + } else { 1.1223 + lstr = ToString<CanGC>(cx, lhs); 1.1224 + if (!lstr) 1.1225 + return false; 1.1226 + } 1.1227 + if (rIsString) { 1.1228 + rstr = rhs.toString(); 1.1229 + } else { 1.1230 + // Save/restore lstr in case of GC activity under ToString. 1.1231 + lhs.setString(lstr); 1.1232 + rstr = ToString<CanGC>(cx, rhs); 1.1233 + if (!rstr) 1.1234 + return false; 1.1235 + lstr = lhs.toString(); 1.1236 + } 1.1237 + JSString *str = ConcatStrings<NoGC>(cx, lstr, rstr); 1.1238 + if (!str) { 1.1239 + RootedString nlstr(cx, lstr), nrstr(cx, rstr); 1.1240 + str = ConcatStrings<CanGC>(cx, nlstr, nrstr); 1.1241 + if (!str) 1.1242 + return false; 1.1243 + } 1.1244 + res.setString(str); 1.1245 + } else { 1.1246 + double l, r; 1.1247 + if (!ToNumber(cx, lhs, &l) || !ToNumber(cx, rhs, &r)) 1.1248 + return false; 1.1249 + res.setNumber(l + r); 1.1250 + } 1.1251 + 1.1252 + return true; 1.1253 +} 1.1254 + 1.1255 +static MOZ_ALWAYS_INLINE bool 1.1256 +SubOperation(JSContext *cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res) 1.1257 +{ 1.1258 + double d1, d2; 1.1259 + if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2)) 1.1260 + return false; 1.1261 + res.setNumber(d1 - d2); 1.1262 + return true; 1.1263 +} 1.1264 + 1.1265 +static MOZ_ALWAYS_INLINE bool 1.1266 +MulOperation(JSContext *cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res) 1.1267 +{ 1.1268 + double d1, d2; 1.1269 + if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2)) 1.1270 + return false; 1.1271 + res.setNumber(d1 * d2); 1.1272 + return true; 1.1273 +} 1.1274 + 1.1275 +static MOZ_ALWAYS_INLINE bool 1.1276 +DivOperation(JSContext *cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res) 1.1277 +{ 1.1278 + double d1, d2; 1.1279 + if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2)) 1.1280 + return false; 1.1281 + res.setNumber(NumberDiv(d1, d2)); 1.1282 + return true; 1.1283 +} 1.1284 + 1.1285 +static MOZ_ALWAYS_INLINE bool 1.1286 +ModOperation(JSContext *cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res) 1.1287 +{ 1.1288 + int32_t l, r; 1.1289 + if (lhs.isInt32() && rhs.isInt32() && 1.1290 + (l = lhs.toInt32()) >= 0 && (r = rhs.toInt32()) > 0) { 1.1291 + int32_t mod = l % r; 1.1292 + res.setInt32(mod); 1.1293 + return true; 1.1294 + } 1.1295 + 1.1296 + double d1, d2; 1.1297 + if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2)) 1.1298 + return false; 1.1299 + 1.1300 + res.setNumber(NumberMod(d1, d2)); 1.1301 + return true; 1.1302 +} 1.1303 + 1.1304 +static MOZ_ALWAYS_INLINE bool 1.1305 +SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, const Value &value, 1.1306 + bool strict, JSScript *script = nullptr, jsbytecode *pc = nullptr) 1.1307 +{ 1.1308 + types::TypeScript::MonitorAssign(cx, obj, id); 1.1309 + 1.1310 +#ifdef JS_ION 1.1311 + if (obj->isNative() && JSID_IS_INT(id)) { 1.1312 + uint32_t length = obj->getDenseInitializedLength(); 1.1313 + int32_t i = JSID_TO_INT(id); 1.1314 + if ((uint32_t)i >= length) { 1.1315 + // Annotate script if provided with information (e.g. baseline) 1.1316 + if (script && script->hasBaselineScript() && *pc == JSOP_SETELEM) 1.1317 + script->baselineScript()->noteArrayWriteHole(script->pcToOffset(pc)); 1.1318 + } 1.1319 + } 1.1320 +#endif 1.1321 + 1.1322 + if (obj->isNative() && !JSID_IS_INT(id) && !obj->setHadElementsAccess(cx)) 1.1323 + return false; 1.1324 + 1.1325 + RootedValue tmp(cx, value); 1.1326 + return JSObject::setGeneric(cx, obj, obj, id, &tmp, strict); 1.1327 +} 1.1328 + 1.1329 +static MOZ_NEVER_INLINE bool 1.1330 +Interpret(JSContext *cx, RunState &state) 1.1331 +{ 1.1332 +/* 1.1333 + * Define macros for an interpreter loop. Opcode dispatch may be either by a 1.1334 + * switch statement or by indirect goto (aka a threaded interpreter), depending 1.1335 + * on compiler support. 1.1336 + * 1.1337 + * Threaded interpretation appears to be well-supported by GCC 3 and higher. 1.1338 + * IBM's C compiler when run with the right options (e.g., -qlanglvl=extended) 1.1339 + * also supports threading. Ditto the SunPro C compiler. 1.1340 + */ 1.1341 +#if (__GNUC__ >= 3 || \ 1.1342 + (__IBMC__ >= 700 && defined __IBM_COMPUTED_GOTO) || \ 1.1343 + __SUNPRO_C >= 0x570) 1.1344 +// Non-standard but faster indirect-goto-based dispatch. 1.1345 +# define INTERPRETER_LOOP() 1.1346 +# define CASE(OP) label_##OP: 1.1347 +# define DEFAULT() label_default: 1.1348 +# define DISPATCH_TO(OP) goto *addresses[(OP)] 1.1349 + 1.1350 +# define LABEL(X) (&&label_##X) 1.1351 + 1.1352 + // Use addresses instead of offsets to optimize for runtime speed over 1.1353 + // load-time relocation overhead. 1.1354 + static const void *const addresses[EnableInterruptsPseudoOpcode + 1] = { 1.1355 +# define OPCODE_LABEL(op, ...) LABEL(op), 1.1356 + FOR_EACH_OPCODE(OPCODE_LABEL) 1.1357 +# undef OPCODE_LABEL 1.1358 +# define TRAILING_LABEL(v) \ 1.1359 + ((v) == EnableInterruptsPseudoOpcode \ 1.1360 + ? LABEL(EnableInterruptsPseudoOpcode) \ 1.1361 + : LABEL(default)), 1.1362 + FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_LABEL) 1.1363 +# undef TRAILING_LABEL 1.1364 + }; 1.1365 +#else 1.1366 +// Portable switch-based dispatch. 1.1367 +# define INTERPRETER_LOOP() the_switch: switch (switchOp) 1.1368 +# define CASE(OP) case OP: 1.1369 +# define DEFAULT() default: 1.1370 +# define DISPATCH_TO(OP) \ 1.1371 + JS_BEGIN_MACRO \ 1.1372 + switchOp = (OP); \ 1.1373 + goto the_switch; \ 1.1374 + JS_END_MACRO 1.1375 + 1.1376 + // This variable is effectively a parameter to the_switch. 1.1377 + jsbytecode switchOp; 1.1378 +#endif 1.1379 + 1.1380 + /* 1.1381 + * Increment REGS.pc by N, load the opcode at that position, 1.1382 + * and jump to the code to execute it. 1.1383 + * 1.1384 + * When Debugger puts a script in single-step mode, all js::Interpret 1.1385 + * invocations that might be presently running that script must have 1.1386 + * interrupts enabled. It's not practical to simply check 1.1387 + * script->stepModeEnabled() at each point some callee could have changed 1.1388 + * it, because there are so many places js::Interpret could possibly cause 1.1389 + * JavaScript to run: each place an object might be coerced to a primitive 1.1390 + * or a number, for example. So instead, we expose a simple mechanism to 1.1391 + * let Debugger tweak the affected js::Interpret frames when an onStep 1.1392 + * handler is added: calling activation.enableInterruptsUnconditionally() 1.1393 + * will enable interrupts, and activation.opMask() is or'd with the opcode 1.1394 + * to implement a simple alternate dispatch. 1.1395 + */ 1.1396 +#define ADVANCE_AND_DISPATCH(N) \ 1.1397 + JS_BEGIN_MACRO \ 1.1398 + REGS.pc += (N); \ 1.1399 + SANITY_CHECKS(); \ 1.1400 + DISPATCH_TO(*REGS.pc | activation.opMask()); \ 1.1401 + JS_END_MACRO 1.1402 + 1.1403 + /* 1.1404 + * Shorthand for the common sequence at the end of a fixed-size opcode. 1.1405 + */ 1.1406 +#define END_CASE(OP) ADVANCE_AND_DISPATCH(OP##_LENGTH); 1.1407 + 1.1408 + /* 1.1409 + * Prepare to call a user-supplied branch handler, and abort the script 1.1410 + * if it returns false. 1.1411 + */ 1.1412 +#define CHECK_BRANCH() \ 1.1413 + JS_BEGIN_MACRO \ 1.1414 + if (!CheckForInterrupt(cx)) \ 1.1415 + goto error; \ 1.1416 + JS_END_MACRO 1.1417 + 1.1418 + /* 1.1419 + * This is a simple wrapper around ADVANCE_AND_DISPATCH which also does 1.1420 + * a CHECK_BRANCH() if n is not positive, which possibly indicates that it 1.1421 + * is the backedge of a loop. 1.1422 + */ 1.1423 +#define BRANCH(n) \ 1.1424 + JS_BEGIN_MACRO \ 1.1425 + int32_t nlen = (n); \ 1.1426 + if (nlen <= 0) \ 1.1427 + CHECK_BRANCH(); \ 1.1428 + ADVANCE_AND_DISPATCH(nlen); \ 1.1429 + JS_END_MACRO 1.1430 + 1.1431 +#define LOAD_DOUBLE(PCOFF, dbl) \ 1.1432 + ((dbl) = script->getConst(GET_UINT32_INDEX(REGS.pc + (PCOFF))).toDouble()) 1.1433 + 1.1434 +#define SET_SCRIPT(s) \ 1.1435 + JS_BEGIN_MACRO \ 1.1436 + script = (s); \ 1.1437 + if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts()) \ 1.1438 + activation.enableInterruptsUnconditionally(); \ 1.1439 + JS_END_MACRO 1.1440 + 1.1441 +#define SANITY_CHECKS() \ 1.1442 + JS_BEGIN_MACRO \ 1.1443 + js::gc::MaybeVerifyBarriers(cx); \ 1.1444 + JS_ASSERT_IF(script->hasScriptCounts(), \ 1.1445 + activation.opMask() == EnableInterruptsPseudoOpcode); \ 1.1446 + JS_END_MACRO 1.1447 + 1.1448 + gc::MaybeVerifyBarriers(cx, true); 1.1449 + JS_ASSERT(!cx->compartment()->activeAnalysis); 1.1450 + 1.1451 + InterpreterFrame *entryFrame = state.pushInterpreterFrame(cx); 1.1452 + if (!entryFrame) 1.1453 + return false; 1.1454 + 1.1455 + InterpreterActivation activation(state, cx, entryFrame); 1.1456 + 1.1457 + /* The script is used frequently, so keep a local copy. */ 1.1458 + RootedScript script(cx); 1.1459 + SET_SCRIPT(REGS.fp()->script()); 1.1460 + 1.1461 + TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); 1.1462 + uint32_t scriptLogId = TraceLogCreateTextId(logger, script); 1.1463 + TraceLogStartEvent(logger, scriptLogId); 1.1464 + TraceLogStartEvent(logger, TraceLogger::Interpreter); 1.1465 + 1.1466 + /* 1.1467 + * Pool of rooters for use in this interpreter frame. References to these 1.1468 + * are used for local variables within interpreter cases. This avoids 1.1469 + * creating new rooters each time an interpreter case is entered, and also 1.1470 + * correctness pitfalls due to incorrect compilation of destructor calls 1.1471 + * around computed gotos. 1.1472 + */ 1.1473 + RootedValue rootValue0(cx), rootValue1(cx); 1.1474 + RootedString rootString0(cx), rootString1(cx); 1.1475 + RootedObject rootObject0(cx), rootObject1(cx), rootObject2(cx); 1.1476 + RootedFunction rootFunction0(cx); 1.1477 + RootedTypeObject rootType0(cx); 1.1478 + RootedPropertyName rootName0(cx); 1.1479 + RootedId rootId0(cx); 1.1480 + RootedShape rootShape0(cx); 1.1481 + RootedScript rootScript0(cx); 1.1482 + DebugOnly<uint32_t> blockDepth; 1.1483 + 1.1484 + if (MOZ_UNLIKELY(REGS.fp()->isGeneratorFrame())) { 1.1485 + JS_ASSERT(script->containsPC(REGS.pc)); 1.1486 + JS_ASSERT(REGS.stackDepth() <= script->nslots()); 1.1487 + 1.1488 + /* 1.1489 + * To support generator_throw and to catch ignored exceptions, 1.1490 + * fail if cx->isExceptionPending() is true. 1.1491 + */ 1.1492 + if (cx->isExceptionPending()) { 1.1493 + probes::EnterScript(cx, script, script->functionNonDelazifying(), REGS.fp()); 1.1494 + goto error; 1.1495 + } 1.1496 + } 1.1497 + 1.1498 + /* State communicated between non-local jumps: */ 1.1499 + bool interpReturnOK; 1.1500 + 1.1501 + if (!activation.entryFrame()->isGeneratorFrame()) { 1.1502 + if (!activation.entryFrame()->prologue(cx)) 1.1503 + goto error; 1.1504 + } else { 1.1505 + if (!probes::EnterScript(cx, script, script->functionNonDelazifying(), 1.1506 + activation.entryFrame())) 1.1507 + { 1.1508 + goto error; 1.1509 + } 1.1510 + } 1.1511 + if (MOZ_UNLIKELY(cx->compartment()->debugMode())) { 1.1512 + JSTrapStatus status = ScriptDebugPrologue(cx, activation.entryFrame(), REGS.pc); 1.1513 + switch (status) { 1.1514 + case JSTRAP_CONTINUE: 1.1515 + break; 1.1516 + case JSTRAP_RETURN: 1.1517 + ForcedReturn(cx, REGS); 1.1518 + goto successful_return_continuation; 1.1519 + case JSTRAP_THROW: 1.1520 + case JSTRAP_ERROR: 1.1521 + goto error; 1.1522 + default: 1.1523 + MOZ_ASSUME_UNREACHABLE("bad ScriptDebugPrologue status"); 1.1524 + } 1.1525 + } 1.1526 + 1.1527 + if (cx->runtime()->profilingScripts || cx->runtime()->debugHooks.interruptHook) 1.1528 + activation.enableInterruptsUnconditionally(); 1.1529 + 1.1530 + // Enter the interpreter loop starting at the current pc. 1.1531 + ADVANCE_AND_DISPATCH(0); 1.1532 + 1.1533 +INTERPRETER_LOOP() { 1.1534 + 1.1535 +CASE(EnableInterruptsPseudoOpcode) 1.1536 +{ 1.1537 + bool moreInterrupts = false; 1.1538 + jsbytecode op = *REGS.pc; 1.1539 + 1.1540 + if (cx->runtime()->profilingScripts) { 1.1541 + if (!script->hasScriptCounts()) 1.1542 + script->initScriptCounts(cx); 1.1543 + moreInterrupts = true; 1.1544 + } 1.1545 + 1.1546 + if (script->hasScriptCounts()) { 1.1547 + PCCounts counts = script->getPCCounts(REGS.pc); 1.1548 + counts.get(PCCounts::BASE_INTERP)++; 1.1549 + moreInterrupts = true; 1.1550 + } 1.1551 + 1.1552 + if (cx->compartment()->debugMode()) { 1.1553 + JSInterruptHook hook = cx->runtime()->debugHooks.interruptHook; 1.1554 + if (hook || script->stepModeEnabled()) { 1.1555 + RootedValue rval(cx); 1.1556 + JSTrapStatus status = JSTRAP_CONTINUE; 1.1557 + if (hook) 1.1558 + status = hook(cx, script, REGS.pc, rval.address(), 1.1559 + cx->runtime()->debugHooks.interruptHookData); 1.1560 + if (status == JSTRAP_CONTINUE && script->stepModeEnabled()) 1.1561 + status = Debugger::onSingleStep(cx, &rval); 1.1562 + switch (status) { 1.1563 + case JSTRAP_ERROR: 1.1564 + goto error; 1.1565 + case JSTRAP_CONTINUE: 1.1566 + break; 1.1567 + case JSTRAP_RETURN: 1.1568 + REGS.fp()->setReturnValue(rval); 1.1569 + ForcedReturn(cx, REGS); 1.1570 + goto successful_return_continuation; 1.1571 + case JSTRAP_THROW: 1.1572 + cx->setPendingException(rval); 1.1573 + goto error; 1.1574 + default:; 1.1575 + } 1.1576 + moreInterrupts = true; 1.1577 + } 1.1578 + 1.1579 + if (script->hasAnyBreakpointsOrStepMode()) 1.1580 + moreInterrupts = true; 1.1581 + 1.1582 + if (script->hasBreakpointsAt(REGS.pc)) { 1.1583 + RootedValue rval(cx); 1.1584 + JSTrapStatus status = Debugger::onTrap(cx, &rval); 1.1585 + switch (status) { 1.1586 + case JSTRAP_ERROR: 1.1587 + goto error; 1.1588 + case JSTRAP_RETURN: 1.1589 + REGS.fp()->setReturnValue(rval); 1.1590 + ForcedReturn(cx, REGS); 1.1591 + goto successful_return_continuation; 1.1592 + case JSTRAP_THROW: 1.1593 + cx->setPendingException(rval); 1.1594 + goto error; 1.1595 + default: 1.1596 + break; 1.1597 + } 1.1598 + JS_ASSERT(status == JSTRAP_CONTINUE); 1.1599 + JS_ASSERT(rval.isInt32() && rval.toInt32() == op); 1.1600 + } 1.1601 + } 1.1602 + 1.1603 + JS_ASSERT(activation.opMask() == EnableInterruptsPseudoOpcode); 1.1604 + if (!moreInterrupts) 1.1605 + activation.clearInterruptsMask(); 1.1606 + 1.1607 + /* Commence executing the actual opcode. */ 1.1608 + SANITY_CHECKS(); 1.1609 + DISPATCH_TO(op); 1.1610 +} 1.1611 + 1.1612 +/* Various 1-byte no-ops. */ 1.1613 +CASE(JSOP_NOP) 1.1614 +CASE(JSOP_UNUSED2) 1.1615 +CASE(JSOP_UNUSED45) 1.1616 +CASE(JSOP_UNUSED46) 1.1617 +CASE(JSOP_UNUSED47) 1.1618 +CASE(JSOP_UNUSED48) 1.1619 +CASE(JSOP_UNUSED49) 1.1620 +CASE(JSOP_UNUSED50) 1.1621 +CASE(JSOP_UNUSED51) 1.1622 +CASE(JSOP_UNUSED52) 1.1623 +CASE(JSOP_UNUSED57) 1.1624 +CASE(JSOP_UNUSED101) 1.1625 +CASE(JSOP_UNUSED102) 1.1626 +CASE(JSOP_UNUSED103) 1.1627 +CASE(JSOP_UNUSED104) 1.1628 +CASE(JSOP_UNUSED105) 1.1629 +CASE(JSOP_UNUSED107) 1.1630 +CASE(JSOP_UNUSED124) 1.1631 +CASE(JSOP_UNUSED125) 1.1632 +CASE(JSOP_UNUSED126) 1.1633 +CASE(JSOP_UNUSED138) 1.1634 +CASE(JSOP_UNUSED139) 1.1635 +CASE(JSOP_UNUSED140) 1.1636 +CASE(JSOP_UNUSED141) 1.1637 +CASE(JSOP_UNUSED142) 1.1638 +CASE(JSOP_UNUSED146) 1.1639 +CASE(JSOP_UNUSED147) 1.1640 +CASE(JSOP_UNUSED148) 1.1641 +CASE(JSOP_BACKPATCH) 1.1642 +CASE(JSOP_UNUSED150) 1.1643 +CASE(JSOP_UNUSED156) 1.1644 +CASE(JSOP_UNUSED157) 1.1645 +CASE(JSOP_UNUSED158) 1.1646 +CASE(JSOP_UNUSED159) 1.1647 +CASE(JSOP_UNUSED161) 1.1648 +CASE(JSOP_UNUSED162) 1.1649 +CASE(JSOP_UNUSED163) 1.1650 +CASE(JSOP_UNUSED164) 1.1651 +CASE(JSOP_UNUSED165) 1.1652 +CASE(JSOP_UNUSED166) 1.1653 +CASE(JSOP_UNUSED167) 1.1654 +CASE(JSOP_UNUSED168) 1.1655 +CASE(JSOP_UNUSED169) 1.1656 +CASE(JSOP_UNUSED170) 1.1657 +CASE(JSOP_UNUSED171) 1.1658 +CASE(JSOP_UNUSED172) 1.1659 +CASE(JSOP_UNUSED173) 1.1660 +CASE(JSOP_UNUSED174) 1.1661 +CASE(JSOP_UNUSED175) 1.1662 +CASE(JSOP_UNUSED176) 1.1663 +CASE(JSOP_UNUSED177) 1.1664 +CASE(JSOP_UNUSED178) 1.1665 +CASE(JSOP_UNUSED179) 1.1666 +CASE(JSOP_UNUSED180) 1.1667 +CASE(JSOP_UNUSED181) 1.1668 +CASE(JSOP_UNUSED182) 1.1669 +CASE(JSOP_UNUSED183) 1.1670 +CASE(JSOP_UNUSED185) 1.1671 +CASE(JSOP_UNUSED186) 1.1672 +CASE(JSOP_UNUSED187) 1.1673 +CASE(JSOP_UNUSED189) 1.1674 +CASE(JSOP_UNUSED190) 1.1675 +CASE(JSOP_UNUSED191) 1.1676 +CASE(JSOP_UNUSED192) 1.1677 +CASE(JSOP_UNUSED196) 1.1678 +CASE(JSOP_UNUSED201) 1.1679 +CASE(JSOP_UNUSED205) 1.1680 +CASE(JSOP_UNUSED206) 1.1681 +CASE(JSOP_UNUSED207) 1.1682 +CASE(JSOP_UNUSED208) 1.1683 +CASE(JSOP_UNUSED209) 1.1684 +CASE(JSOP_UNUSED210) 1.1685 +CASE(JSOP_UNUSED211) 1.1686 +CASE(JSOP_UNUSED212) 1.1687 +CASE(JSOP_UNUSED213) 1.1688 +CASE(JSOP_UNUSED219) 1.1689 +CASE(JSOP_UNUSED220) 1.1690 +CASE(JSOP_UNUSED221) 1.1691 +CASE(JSOP_UNUSED222) 1.1692 +CASE(JSOP_UNUSED223) 1.1693 +CASE(JSOP_CONDSWITCH) 1.1694 +CASE(JSOP_TRY) 1.1695 +{ 1.1696 + JS_ASSERT(js_CodeSpec[*REGS.pc].length == 1); 1.1697 + ADVANCE_AND_DISPATCH(1); 1.1698 +} 1.1699 + 1.1700 +CASE(JSOP_LOOPHEAD) 1.1701 +END_CASE(JSOP_LOOPHEAD) 1.1702 + 1.1703 +CASE(JSOP_LABEL) 1.1704 +END_CASE(JSOP_LABEL) 1.1705 + 1.1706 +CASE(JSOP_LOOPENTRY) 1.1707 + 1.1708 +#ifdef JS_ION 1.1709 + // Attempt on-stack replacement with Baseline code. 1.1710 + if (jit::IsBaselineEnabled(cx)) { 1.1711 + jit::MethodStatus status = jit::CanEnterBaselineAtBranch(cx, REGS.fp(), false); 1.1712 + if (status == jit::Method_Error) 1.1713 + goto error; 1.1714 + if (status == jit::Method_Compiled) { 1.1715 + bool wasSPS = REGS.fp()->hasPushedSPSFrame(); 1.1716 + jit::IonExecStatus maybeOsr = jit::EnterBaselineAtBranch(cx, REGS.fp(), REGS.pc); 1.1717 + 1.1718 + // We failed to call into baseline at all, so treat as an error. 1.1719 + if (maybeOsr == jit::IonExec_Aborted) 1.1720 + goto error; 1.1721 + 1.1722 + interpReturnOK = (maybeOsr == jit::IonExec_Ok); 1.1723 + 1.1724 + // Pop the SPS frame pushed by the interpreter. (The compiled version of the 1.1725 + // function popped a copy of the frame pushed by the OSR trampoline.) 1.1726 + if (wasSPS) 1.1727 + cx->runtime()->spsProfiler.exit(script, script->functionNonDelazifying()); 1.1728 + 1.1729 + if (activation.entryFrame() != REGS.fp()) 1.1730 + goto jit_return_pop_frame; 1.1731 + goto leave_on_safe_point; 1.1732 + } 1.1733 + } 1.1734 +#endif /* JS_ION */ 1.1735 + 1.1736 +END_CASE(JSOP_LOOPENTRY) 1.1737 + 1.1738 +CASE(JSOP_LINENO) 1.1739 +END_CASE(JSOP_LINENO) 1.1740 + 1.1741 +CASE(JSOP_UNDEFINED) 1.1742 + PUSH_UNDEFINED(); 1.1743 +END_CASE(JSOP_UNDEFINED) 1.1744 + 1.1745 +CASE(JSOP_POP) 1.1746 + REGS.sp--; 1.1747 +END_CASE(JSOP_POP) 1.1748 + 1.1749 +CASE(JSOP_POPN) 1.1750 + JS_ASSERT(GET_UINT16(REGS.pc) <= REGS.stackDepth()); 1.1751 + REGS.sp -= GET_UINT16(REGS.pc); 1.1752 +END_CASE(JSOP_POPN) 1.1753 + 1.1754 +CASE(JSOP_DUPAT) 1.1755 +{ 1.1756 + JS_ASSERT(GET_UINT24(REGS.pc) < REGS.stackDepth()); 1.1757 + unsigned i = GET_UINT24(REGS.pc); 1.1758 + const Value &rref = REGS.sp[-int(i + 1)]; 1.1759 + PUSH_COPY(rref); 1.1760 +} 1.1761 +END_CASE(JSOP_DUPAT) 1.1762 + 1.1763 +CASE(JSOP_SETRVAL) 1.1764 + POP_RETURN_VALUE(); 1.1765 +END_CASE(JSOP_SETRVAL) 1.1766 + 1.1767 +CASE(JSOP_ENTERWITH) 1.1768 +{ 1.1769 + RootedValue &val = rootValue0; 1.1770 + RootedObject &staticWith = rootObject0; 1.1771 + val = REGS.sp[-1]; 1.1772 + REGS.sp--; 1.1773 + staticWith = script->getObject(REGS.pc); 1.1774 + 1.1775 + if (!EnterWithOperation(cx, REGS.fp(), val, staticWith)) 1.1776 + goto error; 1.1777 +} 1.1778 +END_CASE(JSOP_ENTERWITH) 1.1779 + 1.1780 +CASE(JSOP_LEAVEWITH) 1.1781 + REGS.fp()->popWith(cx); 1.1782 +END_CASE(JSOP_LEAVEWITH) 1.1783 + 1.1784 +CASE(JSOP_RETURN) 1.1785 + POP_RETURN_VALUE(); 1.1786 + /* FALL THROUGH */ 1.1787 + 1.1788 +CASE(JSOP_RETRVAL) 1.1789 +{ 1.1790 + /* 1.1791 + * When the inlined frame exits with an exception or an error, ok will be 1.1792 + * false after the inline_return label. 1.1793 + */ 1.1794 + CHECK_BRANCH(); 1.1795 + 1.1796 + successful_return_continuation: 1.1797 + interpReturnOK = true; 1.1798 + return_continuation: 1.1799 + if (activation.entryFrame() != REGS.fp()) 1.1800 + inline_return: 1.1801 + { 1.1802 + // Stop the engine. (No details about which engine exactly, could be 1.1803 + // interpreter, Baseline or IonMonkey.) 1.1804 + TraceLogStopEvent(logger); 1.1805 + // Stop the script. (Again no details about which script exactly.) 1.1806 + TraceLogStopEvent(logger); 1.1807 + 1.1808 + if (MOZ_UNLIKELY(cx->compartment()->debugMode())) 1.1809 + interpReturnOK = ScriptDebugEpilogue(cx, REGS.fp(), REGS.pc, interpReturnOK); 1.1810 + 1.1811 + if (!REGS.fp()->isYielding()) 1.1812 + REGS.fp()->epilogue(cx); 1.1813 + else 1.1814 + probes::ExitScript(cx, script, script->functionNonDelazifying(), 1.1815 + REGS.fp()->hasPushedSPSFrame()); 1.1816 + 1.1817 +#if defined(JS_ION) 1.1818 + jit_return_pop_frame: 1.1819 +#endif 1.1820 + 1.1821 + activation.popInlineFrame(REGS.fp()); 1.1822 + SET_SCRIPT(REGS.fp()->script()); 1.1823 + 1.1824 +#if defined(JS_ION) 1.1825 + jit_return: 1.1826 +#endif 1.1827 + 1.1828 + JS_ASSERT(js_CodeSpec[*REGS.pc].format & JOF_INVOKE); 1.1829 + 1.1830 + /* Resume execution in the calling frame. */ 1.1831 + if (MOZ_LIKELY(interpReturnOK)) { 1.1832 + TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]); 1.1833 + 1.1834 + ADVANCE_AND_DISPATCH(JSOP_CALL_LENGTH); 1.1835 + } 1.1836 + 1.1837 + /* Increment pc so that |sp - fp->slots == ReconstructStackDepth(pc)|. */ 1.1838 + REGS.pc += JSOP_CALL_LENGTH; 1.1839 + goto error; 1.1840 + } else { 1.1841 + JS_ASSERT(REGS.stackDepth() == 0); 1.1842 + } 1.1843 + goto exit; 1.1844 +} 1.1845 + 1.1846 +CASE(JSOP_DEFAULT) 1.1847 + REGS.sp--; 1.1848 + /* FALL THROUGH */ 1.1849 +CASE(JSOP_GOTO) 1.1850 +{ 1.1851 + BRANCH(GET_JUMP_OFFSET(REGS.pc)); 1.1852 +} 1.1853 + 1.1854 +CASE(JSOP_IFEQ) 1.1855 +{ 1.1856 + bool cond = ToBooleanOp(REGS); 1.1857 + REGS.sp--; 1.1858 + if (!cond) 1.1859 + BRANCH(GET_JUMP_OFFSET(REGS.pc)); 1.1860 +} 1.1861 +END_CASE(JSOP_IFEQ) 1.1862 + 1.1863 +CASE(JSOP_IFNE) 1.1864 +{ 1.1865 + bool cond = ToBooleanOp(REGS); 1.1866 + REGS.sp--; 1.1867 + if (cond) 1.1868 + BRANCH(GET_JUMP_OFFSET(REGS.pc)); 1.1869 +} 1.1870 +END_CASE(JSOP_IFNE) 1.1871 + 1.1872 +CASE(JSOP_OR) 1.1873 +{ 1.1874 + bool cond = ToBooleanOp(REGS); 1.1875 + if (cond) 1.1876 + ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc)); 1.1877 +} 1.1878 +END_CASE(JSOP_OR) 1.1879 + 1.1880 +CASE(JSOP_AND) 1.1881 +{ 1.1882 + bool cond = ToBooleanOp(REGS); 1.1883 + if (!cond) 1.1884 + ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc)); 1.1885 +} 1.1886 +END_CASE(JSOP_AND) 1.1887 + 1.1888 +#define FETCH_ELEMENT_ID(n, id) \ 1.1889 + JS_BEGIN_MACRO \ 1.1890 + if (!ValueToId<CanGC>(cx, REGS.stackHandleAt(n), &(id))) \ 1.1891 + goto error; \ 1.1892 + JS_END_MACRO 1.1893 + 1.1894 +#define TRY_BRANCH_AFTER_COND(cond,spdec) \ 1.1895 + JS_BEGIN_MACRO \ 1.1896 + JS_ASSERT(js_CodeSpec[*REGS.pc].length == 1); \ 1.1897 + unsigned diff_ = (unsigned) GET_UINT8(REGS.pc) - (unsigned) JSOP_IFEQ; \ 1.1898 + if (diff_ <= 1) { \ 1.1899 + REGS.sp -= (spdec); \ 1.1900 + if ((cond) == (diff_ != 0)) { \ 1.1901 + ++REGS.pc; \ 1.1902 + BRANCH(GET_JUMP_OFFSET(REGS.pc)); \ 1.1903 + } \ 1.1904 + ADVANCE_AND_DISPATCH(1 + JSOP_IFEQ_LENGTH); \ 1.1905 + } \ 1.1906 + JS_END_MACRO 1.1907 + 1.1908 +CASE(JSOP_IN) 1.1909 +{ 1.1910 + HandleValue rref = REGS.stackHandleAt(-1); 1.1911 + if (!rref.isObject()) { 1.1912 + js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, js::NullPtr()); 1.1913 + goto error; 1.1914 + } 1.1915 + RootedObject &obj = rootObject0; 1.1916 + obj = &rref.toObject(); 1.1917 + RootedId &id = rootId0; 1.1918 + FETCH_ELEMENT_ID(-2, id); 1.1919 + RootedObject &obj2 = rootObject1; 1.1920 + RootedShape &prop = rootShape0; 1.1921 + if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &prop)) 1.1922 + goto error; 1.1923 + bool cond = prop != nullptr; 1.1924 + prop = nullptr; 1.1925 + TRY_BRANCH_AFTER_COND(cond, 2); 1.1926 + REGS.sp--; 1.1927 + REGS.sp[-1].setBoolean(cond); 1.1928 +} 1.1929 +END_CASE(JSOP_IN) 1.1930 + 1.1931 +CASE(JSOP_ITER) 1.1932 +{ 1.1933 + JS_ASSERT(REGS.stackDepth() >= 1); 1.1934 + uint8_t flags = GET_UINT8(REGS.pc); 1.1935 + MutableHandleValue res = REGS.stackHandleAt(-1); 1.1936 + if (!ValueToIterator(cx, flags, res)) 1.1937 + goto error; 1.1938 + JS_ASSERT(!res.isPrimitive()); 1.1939 +} 1.1940 +END_CASE(JSOP_ITER) 1.1941 + 1.1942 +CASE(JSOP_MOREITER) 1.1943 +{ 1.1944 + JS_ASSERT(REGS.stackDepth() >= 1); 1.1945 + JS_ASSERT(REGS.sp[-1].isObject()); 1.1946 + PUSH_NULL(); 1.1947 + bool cond; 1.1948 + MutableHandleValue res = REGS.stackHandleAt(-1); 1.1949 + if (!IteratorMore(cx, ®S.sp[-2].toObject(), &cond, res)) 1.1950 + goto error; 1.1951 + REGS.sp[-1].setBoolean(cond); 1.1952 +} 1.1953 +END_CASE(JSOP_MOREITER) 1.1954 + 1.1955 +CASE(JSOP_ITERNEXT) 1.1956 +{ 1.1957 + JS_ASSERT(REGS.sp[-1].isObject()); 1.1958 + PUSH_NULL(); 1.1959 + MutableHandleValue res = REGS.stackHandleAt(-1); 1.1960 + RootedObject &obj = rootObject0; 1.1961 + obj = ®S.sp[-2].toObject(); 1.1962 + if (!IteratorNext(cx, obj, res)) 1.1963 + goto error; 1.1964 +} 1.1965 +END_CASE(JSOP_ITERNEXT) 1.1966 + 1.1967 +CASE(JSOP_ENDITER) 1.1968 +{ 1.1969 + JS_ASSERT(REGS.stackDepth() >= 1); 1.1970 + RootedObject &obj = rootObject0; 1.1971 + obj = ®S.sp[-1].toObject(); 1.1972 + bool ok = CloseIterator(cx, obj); 1.1973 + REGS.sp--; 1.1974 + if (!ok) 1.1975 + goto error; 1.1976 +} 1.1977 +END_CASE(JSOP_ENDITER) 1.1978 + 1.1979 +CASE(JSOP_DUP) 1.1980 +{ 1.1981 + JS_ASSERT(REGS.stackDepth() >= 1); 1.1982 + const Value &rref = REGS.sp[-1]; 1.1983 + PUSH_COPY(rref); 1.1984 +} 1.1985 +END_CASE(JSOP_DUP) 1.1986 + 1.1987 +CASE(JSOP_DUP2) 1.1988 +{ 1.1989 + JS_ASSERT(REGS.stackDepth() >= 2); 1.1990 + const Value &lref = REGS.sp[-2]; 1.1991 + const Value &rref = REGS.sp[-1]; 1.1992 + PUSH_COPY(lref); 1.1993 + PUSH_COPY(rref); 1.1994 +} 1.1995 +END_CASE(JSOP_DUP2) 1.1996 + 1.1997 +CASE(JSOP_SWAP) 1.1998 +{ 1.1999 + JS_ASSERT(REGS.stackDepth() >= 2); 1.2000 + Value &lref = REGS.sp[-2]; 1.2001 + Value &rref = REGS.sp[-1]; 1.2002 + lref.swap(rref); 1.2003 +} 1.2004 +END_CASE(JSOP_SWAP) 1.2005 + 1.2006 +CASE(JSOP_PICK) 1.2007 +{ 1.2008 + unsigned i = GET_UINT8(REGS.pc); 1.2009 + JS_ASSERT(REGS.stackDepth() >= i + 1); 1.2010 + Value lval = REGS.sp[-int(i + 1)]; 1.2011 + memmove(REGS.sp - (i + 1), REGS.sp - i, sizeof(Value) * i); 1.2012 + REGS.sp[-1] = lval; 1.2013 +} 1.2014 +END_CASE(JSOP_PICK) 1.2015 + 1.2016 +CASE(JSOP_SETCONST) 1.2017 +{ 1.2018 + RootedPropertyName &name = rootName0; 1.2019 + name = script->getName(REGS.pc); 1.2020 + 1.2021 + RootedValue &rval = rootValue0; 1.2022 + rval = REGS.sp[-1]; 1.2023 + 1.2024 + RootedObject &obj = rootObject0; 1.2025 + obj = ®S.fp()->varObj(); 1.2026 + 1.2027 + if (!SetConstOperation(cx, obj, name, rval)) 1.2028 + goto error; 1.2029 +} 1.2030 +END_CASE(JSOP_SETCONST); 1.2031 + 1.2032 +CASE(JSOP_BINDGNAME) 1.2033 + PUSH_OBJECT(REGS.fp()->global()); 1.2034 +END_CASE(JSOP_BINDGNAME) 1.2035 + 1.2036 +CASE(JSOP_BINDINTRINSIC) 1.2037 + PUSH_OBJECT(*cx->global()->intrinsicsHolder()); 1.2038 +END_CASE(JSOP_BINDINTRINSIC) 1.2039 + 1.2040 +CASE(JSOP_BINDNAME) 1.2041 +{ 1.2042 + RootedObject &scopeChain = rootObject0; 1.2043 + scopeChain = REGS.fp()->scopeChain(); 1.2044 + 1.2045 + RootedPropertyName &name = rootName0; 1.2046 + name = script->getName(REGS.pc); 1.2047 + 1.2048 + /* Assigning to an undeclared name adds a property to the global object. */ 1.2049 + RootedObject &scope = rootObject1; 1.2050 + if (!LookupNameWithGlobalDefault(cx, name, scopeChain, &scope)) 1.2051 + goto error; 1.2052 + 1.2053 + PUSH_OBJECT(*scope); 1.2054 +} 1.2055 +END_CASE(JSOP_BINDNAME) 1.2056 + 1.2057 +#define BITWISE_OP(OP) \ 1.2058 + JS_BEGIN_MACRO \ 1.2059 + int32_t i, j; \ 1.2060 + if (!ToInt32(cx, REGS.stackHandleAt(-2), &i)) \ 1.2061 + goto error; \ 1.2062 + if (!ToInt32(cx, REGS.stackHandleAt(-1), &j)) \ 1.2063 + goto error; \ 1.2064 + i = i OP j; \ 1.2065 + REGS.sp--; \ 1.2066 + REGS.sp[-1].setInt32(i); \ 1.2067 + JS_END_MACRO 1.2068 + 1.2069 +CASE(JSOP_BITOR) 1.2070 + BITWISE_OP(|); 1.2071 +END_CASE(JSOP_BITOR) 1.2072 + 1.2073 +CASE(JSOP_BITXOR) 1.2074 + BITWISE_OP(^); 1.2075 +END_CASE(JSOP_BITXOR) 1.2076 + 1.2077 +CASE(JSOP_BITAND) 1.2078 + BITWISE_OP(&); 1.2079 +END_CASE(JSOP_BITAND) 1.2080 + 1.2081 +#undef BITWISE_OP 1.2082 + 1.2083 +CASE(JSOP_EQ) 1.2084 + if (!LooseEqualityOp<true>(cx, REGS)) 1.2085 + goto error; 1.2086 +END_CASE(JSOP_EQ) 1.2087 + 1.2088 +CASE(JSOP_NE) 1.2089 + if (!LooseEqualityOp<false>(cx, REGS)) 1.2090 + goto error; 1.2091 +END_CASE(JSOP_NE) 1.2092 + 1.2093 +#define STRICT_EQUALITY_OP(OP, COND) \ 1.2094 + JS_BEGIN_MACRO \ 1.2095 + const Value &rref = REGS.sp[-1]; \ 1.2096 + const Value &lref = REGS.sp[-2]; \ 1.2097 + bool equal; \ 1.2098 + if (!StrictlyEqual(cx, lref, rref, &equal)) \ 1.2099 + goto error; \ 1.2100 + (COND) = equal OP true; \ 1.2101 + REGS.sp--; \ 1.2102 + JS_END_MACRO 1.2103 + 1.2104 +CASE(JSOP_STRICTEQ) 1.2105 +{ 1.2106 + bool cond; 1.2107 + STRICT_EQUALITY_OP(==, cond); 1.2108 + REGS.sp[-1].setBoolean(cond); 1.2109 +} 1.2110 +END_CASE(JSOP_STRICTEQ) 1.2111 + 1.2112 +CASE(JSOP_STRICTNE) 1.2113 +{ 1.2114 + bool cond; 1.2115 + STRICT_EQUALITY_OP(!=, cond); 1.2116 + REGS.sp[-1].setBoolean(cond); 1.2117 +} 1.2118 +END_CASE(JSOP_STRICTNE) 1.2119 + 1.2120 +CASE(JSOP_CASE) 1.2121 +{ 1.2122 + bool cond; 1.2123 + STRICT_EQUALITY_OP(==, cond); 1.2124 + if (cond) { 1.2125 + REGS.sp--; 1.2126 + BRANCH(GET_JUMP_OFFSET(REGS.pc)); 1.2127 + } 1.2128 +} 1.2129 +END_CASE(JSOP_CASE) 1.2130 + 1.2131 +#undef STRICT_EQUALITY_OP 1.2132 + 1.2133 +CASE(JSOP_LT) 1.2134 +{ 1.2135 + bool cond; 1.2136 + MutableHandleValue lval = REGS.stackHandleAt(-2); 1.2137 + MutableHandleValue rval = REGS.stackHandleAt(-1); 1.2138 + if (!LessThanOperation(cx, lval, rval, &cond)) 1.2139 + goto error; 1.2140 + TRY_BRANCH_AFTER_COND(cond, 2); 1.2141 + REGS.sp[-2].setBoolean(cond); 1.2142 + REGS.sp--; 1.2143 +} 1.2144 +END_CASE(JSOP_LT) 1.2145 + 1.2146 +CASE(JSOP_LE) 1.2147 +{ 1.2148 + bool cond; 1.2149 + MutableHandleValue lval = REGS.stackHandleAt(-2); 1.2150 + MutableHandleValue rval = REGS.stackHandleAt(-1); 1.2151 + if (!LessThanOrEqualOperation(cx, lval, rval, &cond)) 1.2152 + goto error; 1.2153 + TRY_BRANCH_AFTER_COND(cond, 2); 1.2154 + REGS.sp[-2].setBoolean(cond); 1.2155 + REGS.sp--; 1.2156 +} 1.2157 +END_CASE(JSOP_LE) 1.2158 + 1.2159 +CASE(JSOP_GT) 1.2160 +{ 1.2161 + bool cond; 1.2162 + MutableHandleValue lval = REGS.stackHandleAt(-2); 1.2163 + MutableHandleValue rval = REGS.stackHandleAt(-1); 1.2164 + if (!GreaterThanOperation(cx, lval, rval, &cond)) 1.2165 + goto error; 1.2166 + TRY_BRANCH_AFTER_COND(cond, 2); 1.2167 + REGS.sp[-2].setBoolean(cond); 1.2168 + REGS.sp--; 1.2169 +} 1.2170 +END_CASE(JSOP_GT) 1.2171 + 1.2172 +CASE(JSOP_GE) 1.2173 +{ 1.2174 + bool cond; 1.2175 + MutableHandleValue lval = REGS.stackHandleAt(-2); 1.2176 + MutableHandleValue rval = REGS.stackHandleAt(-1); 1.2177 + if (!GreaterThanOrEqualOperation(cx, lval, rval, &cond)) 1.2178 + goto error; 1.2179 + TRY_BRANCH_AFTER_COND(cond, 2); 1.2180 + REGS.sp[-2].setBoolean(cond); 1.2181 + REGS.sp--; 1.2182 +} 1.2183 +END_CASE(JSOP_GE) 1.2184 + 1.2185 +#define SIGNED_SHIFT_OP(OP) \ 1.2186 + JS_BEGIN_MACRO \ 1.2187 + int32_t i, j; \ 1.2188 + if (!ToInt32(cx, REGS.stackHandleAt(-2), &i)) \ 1.2189 + goto error; \ 1.2190 + if (!ToInt32(cx, REGS.stackHandleAt(-1), &j)) \ 1.2191 + goto error; \ 1.2192 + i = i OP (j & 31); \ 1.2193 + REGS.sp--; \ 1.2194 + REGS.sp[-1].setInt32(i); \ 1.2195 + JS_END_MACRO 1.2196 + 1.2197 +CASE(JSOP_LSH) 1.2198 + SIGNED_SHIFT_OP(<<); 1.2199 +END_CASE(JSOP_LSH) 1.2200 + 1.2201 +CASE(JSOP_RSH) 1.2202 + SIGNED_SHIFT_OP(>>); 1.2203 +END_CASE(JSOP_RSH) 1.2204 + 1.2205 +#undef SIGNED_SHIFT_OP 1.2206 + 1.2207 +CASE(JSOP_URSH) 1.2208 +{ 1.2209 + HandleValue lval = REGS.stackHandleAt(-2); 1.2210 + HandleValue rval = REGS.stackHandleAt(-1); 1.2211 + MutableHandleValue res = REGS.stackHandleAt(-2); 1.2212 + if (!UrshOperation(cx, lval, rval, res)) 1.2213 + goto error; 1.2214 + REGS.sp--; 1.2215 +} 1.2216 +END_CASE(JSOP_URSH) 1.2217 + 1.2218 +CASE(JSOP_ADD) 1.2219 +{ 1.2220 + MutableHandleValue lval = REGS.stackHandleAt(-2); 1.2221 + MutableHandleValue rval = REGS.stackHandleAt(-1); 1.2222 + MutableHandleValue res = REGS.stackHandleAt(-2); 1.2223 + if (!AddOperation(cx, lval, rval, res)) 1.2224 + goto error; 1.2225 + REGS.sp--; 1.2226 +} 1.2227 +END_CASE(JSOP_ADD) 1.2228 + 1.2229 +CASE(JSOP_SUB) 1.2230 +{ 1.2231 + RootedValue &lval = rootValue0, &rval = rootValue1; 1.2232 + lval = REGS.sp[-2]; 1.2233 + rval = REGS.sp[-1]; 1.2234 + MutableHandleValue res = REGS.stackHandleAt(-2); 1.2235 + if (!SubOperation(cx, lval, rval, res)) 1.2236 + goto error; 1.2237 + REGS.sp--; 1.2238 +} 1.2239 +END_CASE(JSOP_SUB) 1.2240 + 1.2241 +CASE(JSOP_MUL) 1.2242 +{ 1.2243 + RootedValue &lval = rootValue0, &rval = rootValue1; 1.2244 + lval = REGS.sp[-2]; 1.2245 + rval = REGS.sp[-1]; 1.2246 + MutableHandleValue res = REGS.stackHandleAt(-2); 1.2247 + if (!MulOperation(cx, lval, rval, res)) 1.2248 + goto error; 1.2249 + REGS.sp--; 1.2250 +} 1.2251 +END_CASE(JSOP_MUL) 1.2252 + 1.2253 +CASE(JSOP_DIV) 1.2254 +{ 1.2255 + RootedValue &lval = rootValue0, &rval = rootValue1; 1.2256 + lval = REGS.sp[-2]; 1.2257 + rval = REGS.sp[-1]; 1.2258 + MutableHandleValue res = REGS.stackHandleAt(-2); 1.2259 + if (!DivOperation(cx, lval, rval, res)) 1.2260 + goto error; 1.2261 + REGS.sp--; 1.2262 +} 1.2263 +END_CASE(JSOP_DIV) 1.2264 + 1.2265 +CASE(JSOP_MOD) 1.2266 +{ 1.2267 + RootedValue &lval = rootValue0, &rval = rootValue1; 1.2268 + lval = REGS.sp[-2]; 1.2269 + rval = REGS.sp[-1]; 1.2270 + MutableHandleValue res = REGS.stackHandleAt(-2); 1.2271 + if (!ModOperation(cx, lval, rval, res)) 1.2272 + goto error; 1.2273 + REGS.sp--; 1.2274 +} 1.2275 +END_CASE(JSOP_MOD) 1.2276 + 1.2277 +CASE(JSOP_NOT) 1.2278 +{ 1.2279 + bool cond = ToBooleanOp(REGS); 1.2280 + REGS.sp--; 1.2281 + PUSH_BOOLEAN(!cond); 1.2282 +} 1.2283 +END_CASE(JSOP_NOT) 1.2284 + 1.2285 +CASE(JSOP_BITNOT) 1.2286 +{ 1.2287 + int32_t i; 1.2288 + HandleValue value = REGS.stackHandleAt(-1); 1.2289 + if (!BitNot(cx, value, &i)) 1.2290 + goto error; 1.2291 + REGS.sp[-1].setInt32(i); 1.2292 +} 1.2293 +END_CASE(JSOP_BITNOT) 1.2294 + 1.2295 +CASE(JSOP_NEG) 1.2296 +{ 1.2297 + RootedValue &val = rootValue0; 1.2298 + val = REGS.sp[-1]; 1.2299 + MutableHandleValue res = REGS.stackHandleAt(-1); 1.2300 + if (!NegOperation(cx, script, REGS.pc, val, res)) 1.2301 + goto error; 1.2302 +} 1.2303 +END_CASE(JSOP_NEG) 1.2304 + 1.2305 +CASE(JSOP_POS) 1.2306 + if (!ToNumber(cx, REGS.stackHandleAt(-1))) 1.2307 + goto error; 1.2308 +END_CASE(JSOP_POS) 1.2309 + 1.2310 +CASE(JSOP_DELNAME) 1.2311 +{ 1.2312 + /* Strict mode code should never contain JSOP_DELNAME opcodes. */ 1.2313 + JS_ASSERT(!script->strict()); 1.2314 + 1.2315 + RootedPropertyName &name = rootName0; 1.2316 + name = script->getName(REGS.pc); 1.2317 + 1.2318 + RootedObject &scopeObj = rootObject0; 1.2319 + scopeObj = REGS.fp()->scopeChain(); 1.2320 + 1.2321 + PUSH_BOOLEAN(true); 1.2322 + MutableHandleValue res = REGS.stackHandleAt(-1); 1.2323 + if (!DeleteNameOperation(cx, name, scopeObj, res)) 1.2324 + goto error; 1.2325 +} 1.2326 +END_CASE(JSOP_DELNAME) 1.2327 + 1.2328 +CASE(JSOP_DELPROP) 1.2329 +{ 1.2330 + RootedPropertyName &name = rootName0; 1.2331 + name = script->getName(REGS.pc); 1.2332 + 1.2333 + RootedObject &obj = rootObject0; 1.2334 + FETCH_OBJECT(cx, -1, obj); 1.2335 + 1.2336 + bool succeeded; 1.2337 + if (!JSObject::deleteProperty(cx, obj, name, &succeeded)) 1.2338 + goto error; 1.2339 + if (!succeeded && script->strict()) { 1.2340 + obj->reportNotConfigurable(cx, NameToId(name)); 1.2341 + goto error; 1.2342 + } 1.2343 + MutableHandleValue res = REGS.stackHandleAt(-1); 1.2344 + res.setBoolean(succeeded); 1.2345 +} 1.2346 +END_CASE(JSOP_DELPROP) 1.2347 + 1.2348 +CASE(JSOP_DELELEM) 1.2349 +{ 1.2350 + /* Fetch the left part and resolve it to a non-null object. */ 1.2351 + RootedObject &obj = rootObject0; 1.2352 + FETCH_OBJECT(cx, -2, obj); 1.2353 + 1.2354 + RootedValue &propval = rootValue0; 1.2355 + propval = REGS.sp[-1]; 1.2356 + 1.2357 + bool succeeded; 1.2358 + if (!JSObject::deleteByValue(cx, obj, propval, &succeeded)) 1.2359 + goto error; 1.2360 + if (!succeeded && script->strict()) { 1.2361 + // XXX This observably calls ToString(propval). We should convert to 1.2362 + // PropertyKey and use that to delete, and to report an error if 1.2363 + // necessary! 1.2364 + RootedId id(cx); 1.2365 + if (!ValueToId<CanGC>(cx, propval, &id)) 1.2366 + goto error; 1.2367 + obj->reportNotConfigurable(cx, id); 1.2368 + goto error; 1.2369 + } 1.2370 + 1.2371 + MutableHandleValue res = REGS.stackHandleAt(-2); 1.2372 + res.setBoolean(succeeded); 1.2373 + REGS.sp--; 1.2374 +} 1.2375 +END_CASE(JSOP_DELELEM) 1.2376 + 1.2377 +CASE(JSOP_TOID) 1.2378 +{ 1.2379 + /* 1.2380 + * Increment or decrement requires use to lookup the same property twice, 1.2381 + * but we need to avoid the observable stringification the second time. 1.2382 + * There must be an object value below the id, which will not be popped. 1.2383 + */ 1.2384 + RootedValue &objval = rootValue0, &idval = rootValue1; 1.2385 + objval = REGS.sp[-2]; 1.2386 + idval = REGS.sp[-1]; 1.2387 + 1.2388 + MutableHandleValue res = REGS.stackHandleAt(-1); 1.2389 + if (!ToIdOperation(cx, script, REGS.pc, objval, idval, res)) 1.2390 + goto error; 1.2391 +} 1.2392 +END_CASE(JSOP_TOID) 1.2393 + 1.2394 +CASE(JSOP_TYPEOFEXPR) 1.2395 +CASE(JSOP_TYPEOF) 1.2396 +{ 1.2397 + REGS.sp[-1].setString(TypeOfOperation(REGS.sp[-1], cx->runtime())); 1.2398 +} 1.2399 +END_CASE(JSOP_TYPEOF) 1.2400 + 1.2401 +CASE(JSOP_VOID) 1.2402 + REGS.sp[-1].setUndefined(); 1.2403 +END_CASE(JSOP_VOID) 1.2404 + 1.2405 +CASE(JSOP_THIS) 1.2406 + if (!ComputeThis(cx, REGS.fp())) 1.2407 + goto error; 1.2408 + PUSH_COPY(REGS.fp()->thisValue()); 1.2409 +END_CASE(JSOP_THIS) 1.2410 + 1.2411 +CASE(JSOP_GETPROP) 1.2412 +CASE(JSOP_GETXPROP) 1.2413 +CASE(JSOP_LENGTH) 1.2414 +CASE(JSOP_CALLPROP) 1.2415 +{ 1.2416 + 1.2417 + MutableHandleValue lval = REGS.stackHandleAt(-1); 1.2418 + if (!GetPropertyOperation(cx, REGS.fp(), script, REGS.pc, lval, lval)) 1.2419 + goto error; 1.2420 + 1.2421 + TypeScript::Monitor(cx, script, REGS.pc, lval); 1.2422 + assertSameCompartmentDebugOnly(cx, lval); 1.2423 +} 1.2424 +END_CASE(JSOP_GETPROP) 1.2425 + 1.2426 +CASE(JSOP_SETINTRINSIC) 1.2427 +{ 1.2428 + HandleValue value = REGS.stackHandleAt(-1); 1.2429 + 1.2430 + if (!SetIntrinsicOperation(cx, script, REGS.pc, value)) 1.2431 + goto error; 1.2432 + 1.2433 + REGS.sp[-2] = REGS.sp[-1]; 1.2434 + REGS.sp--; 1.2435 +} 1.2436 +END_CASE(JSOP_SETINTRINSIC) 1.2437 + 1.2438 +CASE(JSOP_SETGNAME) 1.2439 +CASE(JSOP_SETNAME) 1.2440 +{ 1.2441 + RootedObject &scope = rootObject0; 1.2442 + scope = ®S.sp[-2].toObject(); 1.2443 + 1.2444 + HandleValue value = REGS.stackHandleAt(-1); 1.2445 + 1.2446 + if (!SetNameOperation(cx, script, REGS.pc, scope, value)) 1.2447 + goto error; 1.2448 + 1.2449 + REGS.sp[-2] = REGS.sp[-1]; 1.2450 + REGS.sp--; 1.2451 +} 1.2452 +END_CASE(JSOP_SETNAME) 1.2453 + 1.2454 +CASE(JSOP_SETPROP) 1.2455 +{ 1.2456 + HandleValue lval = REGS.stackHandleAt(-2); 1.2457 + HandleValue rval = REGS.stackHandleAt(-1); 1.2458 + 1.2459 + if (!SetPropertyOperation(cx, script, REGS.pc, lval, rval)) 1.2460 + goto error; 1.2461 + 1.2462 + REGS.sp[-2] = REGS.sp[-1]; 1.2463 + REGS.sp--; 1.2464 +} 1.2465 +END_CASE(JSOP_SETPROP) 1.2466 + 1.2467 +CASE(JSOP_GETELEM) 1.2468 +CASE(JSOP_CALLELEM) 1.2469 +{ 1.2470 + MutableHandleValue lval = REGS.stackHandleAt(-2); 1.2471 + HandleValue rval = REGS.stackHandleAt(-1); 1.2472 + MutableHandleValue res = REGS.stackHandleAt(-2); 1.2473 + 1.2474 + bool done = false; 1.2475 + if (!GetElemOptimizedArguments(cx, REGS.fp(), lval, rval, res, &done)) 1.2476 + goto error; 1.2477 + 1.2478 + if (!done) { 1.2479 + if (!GetElementOperation(cx, JSOp(*REGS.pc), lval, rval, res)) 1.2480 + goto error; 1.2481 + } 1.2482 + 1.2483 + TypeScript::Monitor(cx, script, REGS.pc, res); 1.2484 + REGS.sp--; 1.2485 +} 1.2486 +END_CASE(JSOP_GETELEM) 1.2487 + 1.2488 +CASE(JSOP_SETELEM) 1.2489 +{ 1.2490 + RootedObject &obj = rootObject0; 1.2491 + FETCH_OBJECT(cx, -3, obj); 1.2492 + RootedId &id = rootId0; 1.2493 + FETCH_ELEMENT_ID(-2, id); 1.2494 + Value &value = REGS.sp[-1]; 1.2495 + if (!SetObjectElementOperation(cx, obj, id, value, script->strict())) 1.2496 + goto error; 1.2497 + REGS.sp[-3] = value; 1.2498 + REGS.sp -= 2; 1.2499 +} 1.2500 +END_CASE(JSOP_SETELEM) 1.2501 + 1.2502 +CASE(JSOP_EVAL) 1.2503 +{ 1.2504 + CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp); 1.2505 + if (REGS.fp()->scopeChain()->global().valueIsEval(args.calleev())) { 1.2506 + if (!DirectEval(cx, args)) 1.2507 + goto error; 1.2508 + } else { 1.2509 + if (!Invoke(cx, args)) 1.2510 + goto error; 1.2511 + } 1.2512 + REGS.sp = args.spAfterCall(); 1.2513 + TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]); 1.2514 +} 1.2515 +END_CASE(JSOP_EVAL) 1.2516 + 1.2517 +CASE(JSOP_SPREADNEW) 1.2518 +CASE(JSOP_SPREADCALL) 1.2519 + if (REGS.fp()->hasPushedSPSFrame()) 1.2520 + cx->runtime()->spsProfiler.updatePC(script, REGS.pc); 1.2521 + /* FALL THROUGH */ 1.2522 + 1.2523 +CASE(JSOP_SPREADEVAL) 1.2524 +{ 1.2525 + JS_ASSERT(REGS.stackDepth() >= 3); 1.2526 + RootedObject &aobj = rootObject0; 1.2527 + aobj = ®S.sp[-1].toObject(); 1.2528 + 1.2529 + uint32_t length = aobj->as<ArrayObject>().length(); 1.2530 + 1.2531 + if (length > ARGS_LENGTH_MAX) { 1.2532 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, 1.2533 + *REGS.pc == JSOP_SPREADNEW ? JSMSG_TOO_MANY_CON_SPREADARGS 1.2534 + : JSMSG_TOO_MANY_FUN_SPREADARGS); 1.2535 + goto error; 1.2536 + } 1.2537 + 1.2538 + InvokeArgs args(cx); 1.2539 + 1.2540 + if (!args.init(length)) 1.2541 + return false; 1.2542 + 1.2543 + args.setCallee(REGS.sp[-3]); 1.2544 + args.setThis(REGS.sp[-2]); 1.2545 + 1.2546 + if (!GetElements(cx, aobj, length, args.array())) 1.2547 + goto error; 1.2548 + 1.2549 + switch (*REGS.pc) { 1.2550 + case JSOP_SPREADNEW: 1.2551 + if (!InvokeConstructor(cx, args)) 1.2552 + goto error; 1.2553 + break; 1.2554 + case JSOP_SPREADCALL: 1.2555 + if (!Invoke(cx, args)) 1.2556 + goto error; 1.2557 + break; 1.2558 + case JSOP_SPREADEVAL: 1.2559 + if (REGS.fp()->scopeChain()->global().valueIsEval(args.calleev())) { 1.2560 + if (!DirectEval(cx, args)) 1.2561 + goto error; 1.2562 + } else { 1.2563 + if (!Invoke(cx, args)) 1.2564 + goto error; 1.2565 + } 1.2566 + break; 1.2567 + default: 1.2568 + MOZ_ASSUME_UNREACHABLE("bad spread opcode"); 1.2569 + } 1.2570 + 1.2571 + REGS.sp -= 2; 1.2572 + REGS.sp[-1] = args.rval(); 1.2573 + TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]); 1.2574 +} 1.2575 +END_CASE(JSOP_SPREADCALL) 1.2576 + 1.2577 +CASE(JSOP_FUNAPPLY) 1.2578 +{ 1.2579 + CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp); 1.2580 + if (!GuardFunApplyArgumentsOptimization(cx, REGS.fp(), args.calleev(), args.array(), 1.2581 + args.length())) 1.2582 + goto error; 1.2583 + /* FALL THROUGH */ 1.2584 +} 1.2585 + 1.2586 +CASE(JSOP_NEW) 1.2587 +CASE(JSOP_CALL) 1.2588 +CASE(JSOP_FUNCALL) 1.2589 +{ 1.2590 + if (REGS.fp()->hasPushedSPSFrame()) 1.2591 + cx->runtime()->spsProfiler.updatePC(script, REGS.pc); 1.2592 + JS_ASSERT(REGS.stackDepth() >= 2 + GET_ARGC(REGS.pc)); 1.2593 + CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp); 1.2594 + 1.2595 + bool construct = (*REGS.pc == JSOP_NEW); 1.2596 + 1.2597 + RootedFunction &fun = rootFunction0; 1.2598 + RootedScript &funScript = rootScript0; 1.2599 + bool isFunction = IsFunctionObject(args.calleev(), fun.address()); 1.2600 + 1.2601 + /* 1.2602 + * Some builtins are marked as clone-at-callsite to increase precision of 1.2603 + * TI and JITs. 1.2604 + */ 1.2605 + if (isFunction && fun->isInterpreted()) { 1.2606 + funScript = fun->getOrCreateScript(cx); 1.2607 + if (!funScript) 1.2608 + goto error; 1.2609 + if (funScript->shouldCloneAtCallsite()) { 1.2610 + fun = CloneFunctionAtCallsite(cx, fun, script, REGS.pc); 1.2611 + if (!fun) 1.2612 + goto error; 1.2613 + args.setCallee(ObjectValue(*fun)); 1.2614 + } 1.2615 + } 1.2616 + 1.2617 + /* Don't bother trying to fast-path calls to scripted non-constructors. */ 1.2618 + if (!isFunction || !fun->isInterpretedConstructor()) { 1.2619 + if (construct) { 1.2620 + if (!InvokeConstructor(cx, args)) 1.2621 + goto error; 1.2622 + } else { 1.2623 + if (!Invoke(cx, args)) 1.2624 + goto error; 1.2625 + } 1.2626 + Value *newsp = args.spAfterCall(); 1.2627 + TypeScript::Monitor(cx, script, REGS.pc, newsp[-1]); 1.2628 + REGS.sp = newsp; 1.2629 + ADVANCE_AND_DISPATCH(JSOP_CALL_LENGTH); 1.2630 + } 1.2631 + 1.2632 + InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE; 1.2633 + bool newType = UseNewType(cx, script, REGS.pc); 1.2634 + 1.2635 + TypeMonitorCall(cx, args, construct); 1.2636 + 1.2637 +#ifdef JS_ION 1.2638 + { 1.2639 + InvokeState state(cx, args, initial); 1.2640 + if (newType) 1.2641 + state.setUseNewType(); 1.2642 + 1.2643 + if (!newType && jit::IsIonEnabled(cx)) { 1.2644 + jit::MethodStatus status = jit::CanEnter(cx, state); 1.2645 + if (status == jit::Method_Error) 1.2646 + goto error; 1.2647 + if (status == jit::Method_Compiled) { 1.2648 + jit::IonExecStatus exec = jit::IonCannon(cx, state); 1.2649 + CHECK_BRANCH(); 1.2650 + REGS.sp = args.spAfterCall(); 1.2651 + interpReturnOK = !IsErrorStatus(exec); 1.2652 + goto jit_return; 1.2653 + } 1.2654 + } 1.2655 + 1.2656 + if (jit::IsBaselineEnabled(cx)) { 1.2657 + jit::MethodStatus status = jit::CanEnterBaselineMethod(cx, state); 1.2658 + if (status == jit::Method_Error) 1.2659 + goto error; 1.2660 + if (status == jit::Method_Compiled) { 1.2661 + jit::IonExecStatus exec = jit::EnterBaselineMethod(cx, state); 1.2662 + CHECK_BRANCH(); 1.2663 + REGS.sp = args.spAfterCall(); 1.2664 + interpReturnOK = !IsErrorStatus(exec); 1.2665 + goto jit_return; 1.2666 + } 1.2667 + } 1.2668 + } 1.2669 +#endif 1.2670 + 1.2671 + funScript = fun->nonLazyScript(); 1.2672 + if (!activation.pushInlineFrame(args, funScript, initial)) 1.2673 + goto error; 1.2674 + 1.2675 + if (newType) 1.2676 + REGS.fp()->setUseNewType(); 1.2677 + 1.2678 + SET_SCRIPT(REGS.fp()->script()); 1.2679 + 1.2680 + uint32_t scriptLogId = TraceLogCreateTextId(logger, script); 1.2681 + TraceLogStartEvent(logger, scriptLogId); 1.2682 + TraceLogStartEvent(logger, TraceLogger::Interpreter); 1.2683 + 1.2684 + if (!REGS.fp()->prologue(cx)) 1.2685 + goto error; 1.2686 + if (MOZ_UNLIKELY(cx->compartment()->debugMode())) { 1.2687 + switch (ScriptDebugPrologue(cx, REGS.fp(), REGS.pc)) { 1.2688 + case JSTRAP_CONTINUE: 1.2689 + break; 1.2690 + case JSTRAP_RETURN: 1.2691 + ForcedReturn(cx, REGS); 1.2692 + goto successful_return_continuation; 1.2693 + case JSTRAP_THROW: 1.2694 + case JSTRAP_ERROR: 1.2695 + goto error; 1.2696 + default: 1.2697 + MOZ_ASSUME_UNREACHABLE("bad ScriptDebugPrologue status"); 1.2698 + } 1.2699 + } 1.2700 + 1.2701 + /* Load first op and dispatch it (safe since JSOP_RETRVAL). */ 1.2702 + ADVANCE_AND_DISPATCH(0); 1.2703 +} 1.2704 + 1.2705 +CASE(JSOP_SETCALL) 1.2706 +{ 1.2707 + JS_ALWAYS_FALSE(SetCallOperation(cx)); 1.2708 + goto error; 1.2709 +} 1.2710 +END_CASE(JSOP_SETCALL) 1.2711 + 1.2712 +CASE(JSOP_IMPLICITTHIS) 1.2713 +{ 1.2714 + RootedPropertyName &name = rootName0; 1.2715 + name = script->getName(REGS.pc); 1.2716 + 1.2717 + RootedObject &scopeObj = rootObject0; 1.2718 + scopeObj = REGS.fp()->scopeChain(); 1.2719 + 1.2720 + RootedObject &scope = rootObject1; 1.2721 + if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &scope)) 1.2722 + goto error; 1.2723 + 1.2724 + RootedValue &v = rootValue0; 1.2725 + if (!ComputeImplicitThis(cx, scope, &v)) 1.2726 + goto error; 1.2727 + PUSH_COPY(v); 1.2728 +} 1.2729 +END_CASE(JSOP_IMPLICITTHIS) 1.2730 + 1.2731 +CASE(JSOP_GETGNAME) 1.2732 +CASE(JSOP_NAME) 1.2733 +{ 1.2734 + RootedValue &rval = rootValue0; 1.2735 + 1.2736 + if (!NameOperation(cx, REGS.fp(), REGS.pc, &rval)) 1.2737 + goto error; 1.2738 + 1.2739 + PUSH_COPY(rval); 1.2740 + TypeScript::Monitor(cx, script, REGS.pc, rval); 1.2741 +} 1.2742 +END_CASE(JSOP_NAME) 1.2743 + 1.2744 +CASE(JSOP_GETINTRINSIC) 1.2745 +{ 1.2746 + RootedValue &rval = rootValue0; 1.2747 + 1.2748 + if (!GetIntrinsicOperation(cx, REGS.pc, &rval)) 1.2749 + goto error; 1.2750 + 1.2751 + PUSH_COPY(rval); 1.2752 + TypeScript::Monitor(cx, script, REGS.pc, rval); 1.2753 +} 1.2754 +END_CASE(JSOP_GETINTRINSIC) 1.2755 + 1.2756 +CASE(JSOP_UINT16) 1.2757 + PUSH_INT32((int32_t) GET_UINT16(REGS.pc)); 1.2758 +END_CASE(JSOP_UINT16) 1.2759 + 1.2760 +CASE(JSOP_UINT24) 1.2761 + PUSH_INT32((int32_t) GET_UINT24(REGS.pc)); 1.2762 +END_CASE(JSOP_UINT24) 1.2763 + 1.2764 +CASE(JSOP_INT8) 1.2765 + PUSH_INT32(GET_INT8(REGS.pc)); 1.2766 +END_CASE(JSOP_INT8) 1.2767 + 1.2768 +CASE(JSOP_INT32) 1.2769 + PUSH_INT32(GET_INT32(REGS.pc)); 1.2770 +END_CASE(JSOP_INT32) 1.2771 + 1.2772 +CASE(JSOP_DOUBLE) 1.2773 +{ 1.2774 + double dbl; 1.2775 + LOAD_DOUBLE(0, dbl); 1.2776 + PUSH_DOUBLE(dbl); 1.2777 +} 1.2778 +END_CASE(JSOP_DOUBLE) 1.2779 + 1.2780 +CASE(JSOP_STRING) 1.2781 + PUSH_STRING(script->getAtom(REGS.pc)); 1.2782 +END_CASE(JSOP_STRING) 1.2783 + 1.2784 +CASE(JSOP_OBJECT) 1.2785 +{ 1.2786 + RootedObject &ref = rootObject0; 1.2787 + ref = script->getObject(REGS.pc); 1.2788 + if (JS::CompartmentOptionsRef(cx).cloneSingletons(cx)) { 1.2789 + JSObject *obj = js::DeepCloneObjectLiteral(cx, ref, js::MaybeSingletonObject); 1.2790 + if (!obj) 1.2791 + goto error; 1.2792 + PUSH_OBJECT(*obj); 1.2793 + } else { 1.2794 + JS::CompartmentOptionsRef(cx).setSingletonsAsValues(); 1.2795 + PUSH_OBJECT(*ref); 1.2796 + } 1.2797 +} 1.2798 +END_CASE(JSOP_OBJECT) 1.2799 + 1.2800 +CASE(JSOP_REGEXP) 1.2801 +{ 1.2802 + /* 1.2803 + * Push a regexp object cloned from the regexp literal object mapped by the 1.2804 + * bytecode at pc. 1.2805 + */ 1.2806 + JSObject *obj = CloneRegExpObject(cx, script->getRegExp(REGS.pc)); 1.2807 + if (!obj) 1.2808 + goto error; 1.2809 + PUSH_OBJECT(*obj); 1.2810 +} 1.2811 +END_CASE(JSOP_REGEXP) 1.2812 + 1.2813 +CASE(JSOP_ZERO) 1.2814 + PUSH_INT32(0); 1.2815 +END_CASE(JSOP_ZERO) 1.2816 + 1.2817 +CASE(JSOP_ONE) 1.2818 + PUSH_INT32(1); 1.2819 +END_CASE(JSOP_ONE) 1.2820 + 1.2821 +CASE(JSOP_NULL) 1.2822 + PUSH_NULL(); 1.2823 +END_CASE(JSOP_NULL) 1.2824 + 1.2825 +CASE(JSOP_FALSE) 1.2826 + PUSH_BOOLEAN(false); 1.2827 +END_CASE(JSOP_FALSE) 1.2828 + 1.2829 +CASE(JSOP_TRUE) 1.2830 + PUSH_BOOLEAN(true); 1.2831 +END_CASE(JSOP_TRUE) 1.2832 + 1.2833 +CASE(JSOP_TABLESWITCH) 1.2834 +{ 1.2835 + jsbytecode *pc2 = REGS.pc; 1.2836 + int32_t len = GET_JUMP_OFFSET(pc2); 1.2837 + 1.2838 + /* 1.2839 + * ECMAv2+ forbids conversion of discriminant, so we will skip to the 1.2840 + * default case if the discriminant isn't already an int jsval. (This 1.2841 + * opcode is emitted only for dense int-domain switches.) 1.2842 + */ 1.2843 + const Value &rref = *--REGS.sp; 1.2844 + int32_t i; 1.2845 + if (rref.isInt32()) { 1.2846 + i = rref.toInt32(); 1.2847 + } else { 1.2848 + /* Use mozilla::NumberEqualsInt32 to treat -0 (double) as 0. */ 1.2849 + if (!rref.isDouble() || !NumberEqualsInt32(rref.toDouble(), &i)) 1.2850 + ADVANCE_AND_DISPATCH(len); 1.2851 + } 1.2852 + 1.2853 + pc2 += JUMP_OFFSET_LEN; 1.2854 + int32_t low = GET_JUMP_OFFSET(pc2); 1.2855 + pc2 += JUMP_OFFSET_LEN; 1.2856 + int32_t high = GET_JUMP_OFFSET(pc2); 1.2857 + 1.2858 + i -= low; 1.2859 + if ((uint32_t)i < (uint32_t)(high - low + 1)) { 1.2860 + pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i; 1.2861 + int32_t off = (int32_t) GET_JUMP_OFFSET(pc2); 1.2862 + if (off) 1.2863 + len = off; 1.2864 + } 1.2865 + ADVANCE_AND_DISPATCH(len); 1.2866 +} 1.2867 + 1.2868 +CASE(JSOP_ARGUMENTS) 1.2869 + JS_ASSERT(!REGS.fp()->fun()->hasRest()); 1.2870 + if (!script->ensureHasAnalyzedArgsUsage(cx)) 1.2871 + goto error; 1.2872 + if (script->needsArgsObj()) { 1.2873 + ArgumentsObject *obj = ArgumentsObject::createExpected(cx, REGS.fp()); 1.2874 + if (!obj) 1.2875 + goto error; 1.2876 + PUSH_COPY(ObjectValue(*obj)); 1.2877 + } else { 1.2878 + PUSH_COPY(MagicValue(JS_OPTIMIZED_ARGUMENTS)); 1.2879 + } 1.2880 +END_CASE(JSOP_ARGUMENTS) 1.2881 + 1.2882 +CASE(JSOP_RUNONCE) 1.2883 +{ 1.2884 + if (!RunOnceScriptPrologue(cx, script)) 1.2885 + goto error; 1.2886 +} 1.2887 +END_CASE(JSOP_RUNONCE) 1.2888 + 1.2889 +CASE(JSOP_REST) 1.2890 +{ 1.2891 + RootedObject &rest = rootObject0; 1.2892 + rest = REGS.fp()->createRestParameter(cx); 1.2893 + if (!rest) 1.2894 + goto error; 1.2895 + PUSH_COPY(ObjectValue(*rest)); 1.2896 +} 1.2897 +END_CASE(JSOP_REST) 1.2898 + 1.2899 +CASE(JSOP_GETALIASEDVAR) 1.2900 +{ 1.2901 + ScopeCoordinate sc = ScopeCoordinate(REGS.pc); 1.2902 + PUSH_COPY(REGS.fp()->aliasedVarScope(sc).aliasedVar(sc)); 1.2903 + TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]); 1.2904 +} 1.2905 +END_CASE(JSOP_GETALIASEDVAR) 1.2906 + 1.2907 +CASE(JSOP_SETALIASEDVAR) 1.2908 +{ 1.2909 + ScopeCoordinate sc = ScopeCoordinate(REGS.pc); 1.2910 + ScopeObject &obj = REGS.fp()->aliasedVarScope(sc); 1.2911 + 1.2912 + // Avoid computing the name if no type updates are needed, as this may be 1.2913 + // expensive on scopes with large numbers of variables. 1.2914 + PropertyName *name = (obj.hasSingletonType() && !obj.hasLazyType()) 1.2915 + ? ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, REGS.pc) 1.2916 + : nullptr; 1.2917 + 1.2918 + obj.setAliasedVar(cx, sc, name, REGS.sp[-1]); 1.2919 +} 1.2920 +END_CASE(JSOP_SETALIASEDVAR) 1.2921 + 1.2922 +CASE(JSOP_GETARG) 1.2923 +{ 1.2924 + unsigned i = GET_ARGNO(REGS.pc); 1.2925 + if (script->argsObjAliasesFormals()) 1.2926 + PUSH_COPY(REGS.fp()->argsObj().arg(i)); 1.2927 + else 1.2928 + PUSH_COPY(REGS.fp()->unaliasedFormal(i)); 1.2929 +} 1.2930 +END_CASE(JSOP_GETARG) 1.2931 + 1.2932 +CASE(JSOP_SETARG) 1.2933 +{ 1.2934 + unsigned i = GET_ARGNO(REGS.pc); 1.2935 + if (script->argsObjAliasesFormals()) 1.2936 + REGS.fp()->argsObj().setArg(i, REGS.sp[-1]); 1.2937 + else 1.2938 + REGS.fp()->unaliasedFormal(i) = REGS.sp[-1]; 1.2939 +} 1.2940 +END_CASE(JSOP_SETARG) 1.2941 + 1.2942 +CASE(JSOP_GETLOCAL) 1.2943 +{ 1.2944 + uint32_t i = GET_LOCALNO(REGS.pc); 1.2945 + PUSH_COPY_SKIP_CHECK(REGS.fp()->unaliasedLocal(i)); 1.2946 + 1.2947 + /* 1.2948 + * Skip the same-compartment assertion if the local will be immediately 1.2949 + * popped. We do not guarantee sync for dead locals when coming in from the 1.2950 + * method JIT, and a GETLOCAL followed by POP is not considered to be 1.2951 + * a use of the variable. 1.2952 + */ 1.2953 + if (REGS.pc[JSOP_GETLOCAL_LENGTH] != JSOP_POP) 1.2954 + assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); 1.2955 +} 1.2956 +END_CASE(JSOP_GETLOCAL) 1.2957 + 1.2958 +CASE(JSOP_SETLOCAL) 1.2959 +{ 1.2960 + uint32_t i = GET_LOCALNO(REGS.pc); 1.2961 + REGS.fp()->unaliasedLocal(i) = REGS.sp[-1]; 1.2962 +} 1.2963 +END_CASE(JSOP_SETLOCAL) 1.2964 + 1.2965 +CASE(JSOP_DEFCONST) 1.2966 +CASE(JSOP_DEFVAR) 1.2967 +{ 1.2968 + /* ES5 10.5 step 8 (with subsequent errata). */ 1.2969 + unsigned attrs = JSPROP_ENUMERATE; 1.2970 + if (!REGS.fp()->isEvalFrame()) 1.2971 + attrs |= JSPROP_PERMANENT; 1.2972 + if (*REGS.pc == JSOP_DEFCONST) 1.2973 + attrs |= JSPROP_READONLY; 1.2974 + 1.2975 + /* Step 8b. */ 1.2976 + RootedObject &obj = rootObject0; 1.2977 + obj = ®S.fp()->varObj(); 1.2978 + 1.2979 + RootedPropertyName &name = rootName0; 1.2980 + name = script->getName(REGS.pc); 1.2981 + 1.2982 + if (!DefVarOrConstOperation(cx, obj, name, attrs)) 1.2983 + goto error; 1.2984 +} 1.2985 +END_CASE(JSOP_DEFVAR) 1.2986 + 1.2987 +CASE(JSOP_DEFFUN) 1.2988 +{ 1.2989 + /* 1.2990 + * A top-level function defined in Global or Eval code (see ECMA-262 1.2991 + * Ed. 3), or else a SpiderMonkey extension: a named function statement in 1.2992 + * a compound statement (not at the top statement level of global code, or 1.2993 + * at the top level of a function body). 1.2994 + */ 1.2995 + RootedFunction &fun = rootFunction0; 1.2996 + fun = script->getFunction(GET_UINT32_INDEX(REGS.pc)); 1.2997 + 1.2998 + if (!DefFunOperation(cx, script, REGS.fp()->scopeChain(), fun)) 1.2999 + goto error; 1.3000 +} 1.3001 +END_CASE(JSOP_DEFFUN) 1.3002 + 1.3003 +CASE(JSOP_LAMBDA) 1.3004 +{ 1.3005 + /* Load the specified function object literal. */ 1.3006 + RootedFunction &fun = rootFunction0; 1.3007 + fun = script->getFunction(GET_UINT32_INDEX(REGS.pc)); 1.3008 + 1.3009 + JSObject *obj = Lambda(cx, fun, REGS.fp()->scopeChain()); 1.3010 + if (!obj) 1.3011 + goto error; 1.3012 + JS_ASSERT(obj->getProto()); 1.3013 + PUSH_OBJECT(*obj); 1.3014 +} 1.3015 +END_CASE(JSOP_LAMBDA) 1.3016 + 1.3017 +CASE(JSOP_LAMBDA_ARROW) 1.3018 +{ 1.3019 + /* Load the specified function object literal. */ 1.3020 + RootedFunction &fun = rootFunction0; 1.3021 + fun = script->getFunction(GET_UINT32_INDEX(REGS.pc)); 1.3022 + RootedValue &thisv = rootValue0; 1.3023 + thisv = REGS.sp[-1]; 1.3024 + JSObject *obj = LambdaArrow(cx, fun, REGS.fp()->scopeChain(), thisv); 1.3025 + if (!obj) 1.3026 + goto error; 1.3027 + JS_ASSERT(obj->getProto()); 1.3028 + REGS.sp[-1].setObject(*obj); 1.3029 +} 1.3030 +END_CASE(JSOP_LAMBDA_ARROW) 1.3031 + 1.3032 +CASE(JSOP_CALLEE) 1.3033 + JS_ASSERT(REGS.fp()->isNonEvalFunctionFrame()); 1.3034 + PUSH_COPY(REGS.fp()->calleev()); 1.3035 +END_CASE(JSOP_CALLEE) 1.3036 + 1.3037 +CASE(JSOP_INITPROP_GETTER) 1.3038 +CASE(JSOP_INITPROP_SETTER) 1.3039 +{ 1.3040 + RootedObject &obj = rootObject0; 1.3041 + RootedPropertyName &name = rootName0; 1.3042 + RootedObject &val = rootObject1; 1.3043 + 1.3044 + JS_ASSERT(REGS.stackDepth() >= 2); 1.3045 + obj = ®S.sp[-2].toObject(); 1.3046 + name = script->getName(REGS.pc); 1.3047 + val = ®S.sp[-1].toObject(); 1.3048 + 1.3049 + if (!InitGetterSetterOperation(cx, REGS.pc, obj, name, val)) 1.3050 + goto error; 1.3051 + 1.3052 + REGS.sp--; 1.3053 +} 1.3054 +END_CASE(JSOP_INITPROP_GETTER) 1.3055 + 1.3056 +CASE(JSOP_INITELEM_GETTER) 1.3057 +CASE(JSOP_INITELEM_SETTER) 1.3058 +{ 1.3059 + RootedObject &obj = rootObject0; 1.3060 + RootedValue &idval = rootValue0; 1.3061 + RootedObject &val = rootObject1; 1.3062 + 1.3063 + JS_ASSERT(REGS.stackDepth() >= 3); 1.3064 + obj = ®S.sp[-3].toObject(); 1.3065 + idval = REGS.sp[-2]; 1.3066 + val = ®S.sp[-1].toObject(); 1.3067 + 1.3068 + if (!InitGetterSetterOperation(cx, REGS.pc, obj, idval, val)) 1.3069 + goto error; 1.3070 + 1.3071 + REGS.sp -= 2; 1.3072 +} 1.3073 +END_CASE(JSOP_INITELEM_GETTER) 1.3074 + 1.3075 +CASE(JSOP_HOLE) 1.3076 + PUSH_HOLE(); 1.3077 +END_CASE(JSOP_HOLE) 1.3078 + 1.3079 +CASE(JSOP_NEWINIT) 1.3080 +{ 1.3081 + uint8_t i = GET_UINT8(REGS.pc); 1.3082 + JS_ASSERT(i == JSProto_Array || i == JSProto_Object); 1.3083 + 1.3084 + RootedObject &obj = rootObject0; 1.3085 + NewObjectKind newKind; 1.3086 + if (i == JSProto_Array) { 1.3087 + newKind = UseNewTypeForInitializer(script, REGS.pc, &ArrayObject::class_); 1.3088 + obj = NewDenseEmptyArray(cx, nullptr, newKind); 1.3089 + } else { 1.3090 + gc::AllocKind allocKind = GuessObjectGCKind(0); 1.3091 + newKind = UseNewTypeForInitializer(script, REGS.pc, &JSObject::class_); 1.3092 + obj = NewBuiltinClassInstance(cx, &JSObject::class_, allocKind, newKind); 1.3093 + } 1.3094 + if (!obj || !SetInitializerObjectType(cx, script, REGS.pc, obj, newKind)) 1.3095 + goto error; 1.3096 + 1.3097 + PUSH_OBJECT(*obj); 1.3098 +} 1.3099 +END_CASE(JSOP_NEWINIT) 1.3100 + 1.3101 +CASE(JSOP_NEWARRAY) 1.3102 +{ 1.3103 + unsigned count = GET_UINT24(REGS.pc); 1.3104 + RootedObject &obj = rootObject0; 1.3105 + NewObjectKind newKind = UseNewTypeForInitializer(script, REGS.pc, &ArrayObject::class_); 1.3106 + obj = NewDenseAllocatedArray(cx, count, nullptr, newKind); 1.3107 + if (!obj || !SetInitializerObjectType(cx, script, REGS.pc, obj, newKind)) 1.3108 + goto error; 1.3109 + 1.3110 + PUSH_OBJECT(*obj); 1.3111 +} 1.3112 +END_CASE(JSOP_NEWARRAY) 1.3113 + 1.3114 +CASE(JSOP_NEWOBJECT) 1.3115 +{ 1.3116 + RootedObject &baseobj = rootObject0; 1.3117 + baseobj = script->getObject(REGS.pc); 1.3118 + 1.3119 + RootedObject &obj = rootObject1; 1.3120 + NewObjectKind newKind = UseNewTypeForInitializer(script, REGS.pc, baseobj->getClass()); 1.3121 + obj = CopyInitializerObject(cx, baseobj, newKind); 1.3122 + if (!obj || !SetInitializerObjectType(cx, script, REGS.pc, obj, newKind)) 1.3123 + goto error; 1.3124 + 1.3125 + PUSH_OBJECT(*obj); 1.3126 +} 1.3127 +END_CASE(JSOP_NEWOBJECT) 1.3128 + 1.3129 +CASE(JSOP_ENDINIT) 1.3130 +{ 1.3131 + /* FIXME remove JSOP_ENDINIT bug 588522 */ 1.3132 + JS_ASSERT(REGS.stackDepth() >= 1); 1.3133 + JS_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined()); 1.3134 +} 1.3135 +END_CASE(JSOP_ENDINIT) 1.3136 + 1.3137 +CASE(JSOP_MUTATEPROTO) 1.3138 +{ 1.3139 + MOZ_ASSERT(REGS.stackDepth() >= 2); 1.3140 + 1.3141 + if (REGS.sp[-1].isObjectOrNull()) { 1.3142 + RootedObject &newProto = rootObject1; 1.3143 + rootObject1 = REGS.sp[-1].toObjectOrNull(); 1.3144 + 1.3145 + RootedObject &obj = rootObject0; 1.3146 + obj = ®S.sp[-2].toObject(); 1.3147 + MOZ_ASSERT(obj->is<JSObject>()); 1.3148 + 1.3149 + bool succeeded; 1.3150 + if (!JSObject::setProto(cx, obj, newProto, &succeeded)) 1.3151 + goto error; 1.3152 + MOZ_ASSERT(succeeded); 1.3153 + } 1.3154 + 1.3155 + REGS.sp--; 1.3156 +} 1.3157 +END_CASE(JSOP_MUTATEPROTO); 1.3158 + 1.3159 +CASE(JSOP_INITPROP) 1.3160 +{ 1.3161 + /* Load the property's initial value into rval. */ 1.3162 + JS_ASSERT(REGS.stackDepth() >= 2); 1.3163 + RootedValue &rval = rootValue0; 1.3164 + rval = REGS.sp[-1]; 1.3165 + 1.3166 + /* Load the object being initialized into lval/obj. */ 1.3167 + RootedObject &obj = rootObject0; 1.3168 + obj = ®S.sp[-2].toObject(); 1.3169 + JS_ASSERT(obj->is<JSObject>()); 1.3170 + 1.3171 + PropertyName *name = script->getName(REGS.pc); 1.3172 + 1.3173 + RootedId &id = rootId0; 1.3174 + id = NameToId(name); 1.3175 + 1.3176 + if (!DefineNativeProperty(cx, obj, id, rval, nullptr, nullptr, JSPROP_ENUMERATE)) 1.3177 + goto error; 1.3178 + 1.3179 + REGS.sp--; 1.3180 +} 1.3181 +END_CASE(JSOP_INITPROP); 1.3182 + 1.3183 +CASE(JSOP_INITELEM) 1.3184 +{ 1.3185 + JS_ASSERT(REGS.stackDepth() >= 3); 1.3186 + HandleValue val = REGS.stackHandleAt(-1); 1.3187 + HandleValue id = REGS.stackHandleAt(-2); 1.3188 + 1.3189 + RootedObject &obj = rootObject0; 1.3190 + obj = ®S.sp[-3].toObject(); 1.3191 + 1.3192 + if (!InitElemOperation(cx, obj, id, val)) 1.3193 + goto error; 1.3194 + 1.3195 + REGS.sp -= 2; 1.3196 +} 1.3197 +END_CASE(JSOP_INITELEM) 1.3198 + 1.3199 +CASE(JSOP_INITELEM_ARRAY) 1.3200 +{ 1.3201 + JS_ASSERT(REGS.stackDepth() >= 2); 1.3202 + HandleValue val = REGS.stackHandleAt(-1); 1.3203 + 1.3204 + RootedObject &obj = rootObject0; 1.3205 + obj = ®S.sp[-2].toObject(); 1.3206 + 1.3207 + JS_ASSERT(obj->is<ArrayObject>()); 1.3208 + 1.3209 + uint32_t index = GET_UINT24(REGS.pc); 1.3210 + if (!InitArrayElemOperation(cx, REGS.pc, obj, index, val)) 1.3211 + goto error; 1.3212 + 1.3213 + REGS.sp--; 1.3214 +} 1.3215 +END_CASE(JSOP_INITELEM_ARRAY) 1.3216 + 1.3217 +CASE(JSOP_INITELEM_INC) 1.3218 +{ 1.3219 + JS_ASSERT(REGS.stackDepth() >= 3); 1.3220 + HandleValue val = REGS.stackHandleAt(-1); 1.3221 + 1.3222 + RootedObject &obj = rootObject0; 1.3223 + obj = ®S.sp[-3].toObject(); 1.3224 + 1.3225 + uint32_t index = REGS.sp[-2].toInt32(); 1.3226 + if (!InitArrayElemOperation(cx, REGS.pc, obj, index, val)) 1.3227 + goto error; 1.3228 + 1.3229 + REGS.sp[-2].setInt32(index + 1); 1.3230 + REGS.sp--; 1.3231 +} 1.3232 +END_CASE(JSOP_INITELEM_INC) 1.3233 + 1.3234 +CASE(JSOP_SPREAD) 1.3235 +{ 1.3236 + int32_t count = REGS.sp[-2].toInt32(); 1.3237 + RootedObject &arr = rootObject0; 1.3238 + arr = ®S.sp[-3].toObject(); 1.3239 + const Value iterable = REGS.sp[-1]; 1.3240 + ForOfIterator iter(cx); 1.3241 + RootedValue &iterVal = rootValue0; 1.3242 + iterVal.set(iterable); 1.3243 + if (!iter.init(iterVal)) 1.3244 + goto error; 1.3245 + while (true) { 1.3246 + bool done; 1.3247 + if (!iter.next(&iterVal, &done)) 1.3248 + goto error; 1.3249 + if (done) 1.3250 + break; 1.3251 + if (count == INT32_MAX) { 1.3252 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, 1.3253 + JSMSG_SPREAD_TOO_LARGE); 1.3254 + goto error; 1.3255 + } 1.3256 + if (!JSObject::defineElement(cx, arr, count++, iterVal, nullptr, nullptr, 1.3257 + JSPROP_ENUMERATE)) 1.3258 + goto error; 1.3259 + } 1.3260 + REGS.sp[-2].setInt32(count); 1.3261 + REGS.sp--; 1.3262 +} 1.3263 +END_CASE(JSOP_SPREAD) 1.3264 + 1.3265 +CASE(JSOP_GOSUB) 1.3266 +{ 1.3267 + PUSH_BOOLEAN(false); 1.3268 + int32_t i = script->pcToOffset(REGS.pc) + JSOP_GOSUB_LENGTH; 1.3269 + int32_t len = GET_JUMP_OFFSET(REGS.pc); 1.3270 + PUSH_INT32(i); 1.3271 + ADVANCE_AND_DISPATCH(len); 1.3272 +} 1.3273 + 1.3274 +CASE(JSOP_RETSUB) 1.3275 +{ 1.3276 + /* Pop [exception or hole, retsub pc-index]. */ 1.3277 + Value rval, lval; 1.3278 + POP_COPY_TO(rval); 1.3279 + POP_COPY_TO(lval); 1.3280 + JS_ASSERT(lval.isBoolean()); 1.3281 + if (lval.toBoolean()) { 1.3282 + /* 1.3283 + * Exception was pending during finally, throw it *before* we adjust 1.3284 + * pc, because pc indexes into script->trynotes. This turns out not to 1.3285 + * be necessary, but it seems clearer. And it points out a FIXME: 1.3286 + * 350509, due to Igor Bukanov. 1.3287 + */ 1.3288 + cx->setPendingException(rval); 1.3289 + goto error; 1.3290 + } 1.3291 + JS_ASSERT(rval.isInt32()); 1.3292 + 1.3293 + /* Increment the PC by this much. */ 1.3294 + int32_t len = rval.toInt32() - int32_t(script->pcToOffset(REGS.pc)); 1.3295 + ADVANCE_AND_DISPATCH(len); 1.3296 +} 1.3297 + 1.3298 +CASE(JSOP_EXCEPTION) 1.3299 +{ 1.3300 + PUSH_NULL(); 1.3301 + MutableHandleValue res = REGS.stackHandleAt(-1); 1.3302 + if (!GetAndClearException(cx, res)) 1.3303 + goto error; 1.3304 +} 1.3305 +END_CASE(JSOP_EXCEPTION) 1.3306 + 1.3307 +CASE(JSOP_FINALLY) 1.3308 + CHECK_BRANCH(); 1.3309 +END_CASE(JSOP_FINALLY) 1.3310 + 1.3311 +CASE(JSOP_THROWING) 1.3312 +{ 1.3313 + JS_ASSERT(!cx->isExceptionPending()); 1.3314 + Value v; 1.3315 + POP_COPY_TO(v); 1.3316 + cx->setPendingException(v); 1.3317 +} 1.3318 +END_CASE(JSOP_THROWING) 1.3319 + 1.3320 +CASE(JSOP_THROW) 1.3321 +{ 1.3322 + CHECK_BRANCH(); 1.3323 + RootedValue &v = rootValue0; 1.3324 + POP_COPY_TO(v); 1.3325 + JS_ALWAYS_FALSE(Throw(cx, v)); 1.3326 + /* let the code at error try to catch the exception. */ 1.3327 + goto error; 1.3328 +} 1.3329 + 1.3330 +CASE(JSOP_INSTANCEOF) 1.3331 +{ 1.3332 + RootedValue &rref = rootValue0; 1.3333 + rref = REGS.sp[-1]; 1.3334 + if (rref.isPrimitive()) { 1.3335 + js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, js::NullPtr()); 1.3336 + goto error; 1.3337 + } 1.3338 + RootedObject &obj = rootObject0; 1.3339 + obj = &rref.toObject(); 1.3340 + bool cond = false; 1.3341 + if (!HasInstance(cx, obj, REGS.stackHandleAt(-2), &cond)) 1.3342 + goto error; 1.3343 + REGS.sp--; 1.3344 + REGS.sp[-1].setBoolean(cond); 1.3345 +} 1.3346 +END_CASE(JSOP_INSTANCEOF) 1.3347 + 1.3348 +CASE(JSOP_DEBUGGER) 1.3349 +{ 1.3350 + JSTrapStatus st = JSTRAP_CONTINUE; 1.3351 + RootedValue rval(cx); 1.3352 + if (JSDebuggerHandler handler = cx->runtime()->debugHooks.debuggerHandler) 1.3353 + st = handler(cx, script, REGS.pc, rval.address(), cx->runtime()->debugHooks.debuggerHandlerData); 1.3354 + if (st == JSTRAP_CONTINUE) 1.3355 + st = Debugger::onDebuggerStatement(cx, &rval); 1.3356 + switch (st) { 1.3357 + case JSTRAP_ERROR: 1.3358 + goto error; 1.3359 + case JSTRAP_CONTINUE: 1.3360 + break; 1.3361 + case JSTRAP_RETURN: 1.3362 + REGS.fp()->setReturnValue(rval); 1.3363 + ForcedReturn(cx, REGS); 1.3364 + goto successful_return_continuation; 1.3365 + case JSTRAP_THROW: 1.3366 + cx->setPendingException(rval); 1.3367 + goto error; 1.3368 + default:; 1.3369 + } 1.3370 +} 1.3371 +END_CASE(JSOP_DEBUGGER) 1.3372 + 1.3373 +CASE(JSOP_PUSHBLOCKSCOPE) 1.3374 +{ 1.3375 + StaticBlockObject &blockObj = script->getObject(REGS.pc)->as<StaticBlockObject>(); 1.3376 + 1.3377 + JS_ASSERT(blockObj.needsClone()); 1.3378 + // Clone block and push on scope chain. 1.3379 + if (!REGS.fp()->pushBlock(cx, blockObj)) 1.3380 + goto error; 1.3381 +} 1.3382 +END_CASE(JSOP_PUSHBLOCKSCOPE) 1.3383 + 1.3384 +CASE(JSOP_POPBLOCKSCOPE) 1.3385 +{ 1.3386 +#ifdef DEBUG 1.3387 + // Pop block from scope chain. 1.3388 + JS_ASSERT(*(REGS.pc - JSOP_DEBUGLEAVEBLOCK_LENGTH) == JSOP_DEBUGLEAVEBLOCK); 1.3389 + NestedScopeObject *scope = script->getStaticScope(REGS.pc - JSOP_DEBUGLEAVEBLOCK_LENGTH); 1.3390 + JS_ASSERT(scope && scope->is<StaticBlockObject>()); 1.3391 + StaticBlockObject &blockObj = scope->as<StaticBlockObject>(); 1.3392 + JS_ASSERT(blockObj.needsClone()); 1.3393 +#endif 1.3394 + 1.3395 + // Pop block from scope chain. 1.3396 + REGS.fp()->popBlock(cx); 1.3397 +} 1.3398 +END_CASE(JSOP_POPBLOCKSCOPE) 1.3399 + 1.3400 +CASE(JSOP_DEBUGLEAVEBLOCK) 1.3401 +{ 1.3402 + JS_ASSERT(script->getStaticScope(REGS.pc)); 1.3403 + JS_ASSERT(script->getStaticScope(REGS.pc)->is<StaticBlockObject>()); 1.3404 + 1.3405 + // FIXME: This opcode should not be necessary. The debugger shouldn't need 1.3406 + // help from bytecode to do its job. See bug 927782. 1.3407 + 1.3408 + if (MOZ_UNLIKELY(cx->compartment()->debugMode())) 1.3409 + DebugScopes::onPopBlock(cx, REGS.fp(), REGS.pc); 1.3410 +} 1.3411 +END_CASE(JSOP_DEBUGLEAVEBLOCK) 1.3412 + 1.3413 +CASE(JSOP_GENERATOR) 1.3414 +{ 1.3415 + JS_ASSERT(!cx->isExceptionPending()); 1.3416 + REGS.fp()->initGeneratorFrame(); 1.3417 + REGS.pc += JSOP_GENERATOR_LENGTH; 1.3418 + JSObject *obj = js_NewGenerator(cx, REGS); 1.3419 + if (!obj) 1.3420 + goto error; 1.3421 + REGS.fp()->setReturnValue(ObjectValue(*obj)); 1.3422 + REGS.fp()->setYielding(); 1.3423 + interpReturnOK = true; 1.3424 + if (activation.entryFrame() != REGS.fp()) 1.3425 + goto inline_return; 1.3426 + goto exit; 1.3427 +} 1.3428 + 1.3429 +CASE(JSOP_YIELD) 1.3430 + JS_ASSERT(!cx->isExceptionPending()); 1.3431 + JS_ASSERT(REGS.fp()->isNonEvalFunctionFrame()); 1.3432 + if (cx->innermostGenerator()->state == JSGEN_CLOSING) { 1.3433 + RootedValue &val = rootValue0; 1.3434 + val.setObject(REGS.fp()->callee()); 1.3435 + js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK, val, js::NullPtr()); 1.3436 + goto error; 1.3437 + } 1.3438 + REGS.fp()->setReturnValue(REGS.sp[-1]); 1.3439 + REGS.fp()->setYielding(); 1.3440 + REGS.pc += JSOP_YIELD_LENGTH; 1.3441 + interpReturnOK = true; 1.3442 + goto exit; 1.3443 + 1.3444 +CASE(JSOP_ARRAYPUSH) 1.3445 +{ 1.3446 + RootedObject &obj = rootObject0; 1.3447 + obj = ®S.sp[-1].toObject(); 1.3448 + if (!NewbornArrayPush(cx, obj, REGS.sp[-2])) 1.3449 + goto error; 1.3450 + REGS.sp -= 2; 1.3451 +} 1.3452 +END_CASE(JSOP_ARRAYPUSH) 1.3453 + 1.3454 +DEFAULT() 1.3455 +{ 1.3456 + char numBuf[12]; 1.3457 + JS_snprintf(numBuf, sizeof numBuf, "%d", *REGS.pc); 1.3458 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, 1.3459 + JSMSG_BAD_BYTECODE, numBuf); 1.3460 + goto error; 1.3461 +} 1.3462 + 1.3463 +} /* interpreter loop */ 1.3464 + 1.3465 + MOZ_ASSUME_UNREACHABLE("Interpreter loop exited via fallthrough"); 1.3466 + 1.3467 + error: 1.3468 + switch (HandleError(cx, REGS)) { 1.3469 + case SuccessfulReturnContinuation: 1.3470 + goto successful_return_continuation; 1.3471 + 1.3472 + case ErrorReturnContinuation: 1.3473 + interpReturnOK = false; 1.3474 + goto return_continuation; 1.3475 + 1.3476 + case CatchContinuation: 1.3477 + ADVANCE_AND_DISPATCH(0); 1.3478 + 1.3479 + case FinallyContinuation: 1.3480 + /* 1.3481 + * Push (true, exception) pair for finally to indicate that [retsub] 1.3482 + * should rethrow the exception. 1.3483 + */ 1.3484 + RootedValue &exception = rootValue0; 1.3485 + if (!cx->getPendingException(&exception)) { 1.3486 + interpReturnOK = false; 1.3487 + goto return_continuation; 1.3488 + } 1.3489 + PUSH_BOOLEAN(true); 1.3490 + PUSH_COPY(exception); 1.3491 + cx->clearPendingException(); 1.3492 + ADVANCE_AND_DISPATCH(0); 1.3493 + } 1.3494 + MOZ_ASSUME_UNREACHABLE("Invalid HandleError continuation"); 1.3495 + 1.3496 + exit: 1.3497 + if (MOZ_UNLIKELY(cx->compartment()->debugMode())) 1.3498 + interpReturnOK = ScriptDebugEpilogue(cx, REGS.fp(), REGS.pc, interpReturnOK); 1.3499 + if (!REGS.fp()->isYielding()) 1.3500 + REGS.fp()->epilogue(cx); 1.3501 + else 1.3502 + probes::ExitScript(cx, script, script->functionNonDelazifying(), 1.3503 + REGS.fp()->hasPushedSPSFrame()); 1.3504 + 1.3505 + gc::MaybeVerifyBarriers(cx, true); 1.3506 + 1.3507 + TraceLogStopEvent(logger); 1.3508 + TraceLogStopEvent(logger, scriptLogId); 1.3509 + 1.3510 +#ifdef JS_ION 1.3511 + /* 1.3512 + * This path is used when it's guaranteed the method can be finished 1.3513 + * inside the JIT. 1.3514 + */ 1.3515 + leave_on_safe_point: 1.3516 +#endif 1.3517 + 1.3518 + if (interpReturnOK) 1.3519 + state.setReturnValue(activation.entryFrame()->returnValue()); 1.3520 + 1.3521 + return interpReturnOK; 1.3522 +} 1.3523 + 1.3524 +bool 1.3525 +js::Throw(JSContext *cx, HandleValue v) 1.3526 +{ 1.3527 + JS_ASSERT(!cx->isExceptionPending()); 1.3528 + cx->setPendingException(v); 1.3529 + return false; 1.3530 +} 1.3531 + 1.3532 +bool 1.3533 +js::GetProperty(JSContext *cx, HandleValue v, HandlePropertyName name, MutableHandleValue vp) 1.3534 +{ 1.3535 + if (name == cx->names().length) { 1.3536 + // Fast path for strings, arrays and arguments. 1.3537 + if (GetLengthProperty(v, vp)) 1.3538 + return true; 1.3539 + } 1.3540 + 1.3541 + RootedObject obj(cx, ToObjectFromStack(cx, v)); 1.3542 + if (!obj) 1.3543 + return false; 1.3544 + return JSObject::getProperty(cx, obj, obj, name, vp); 1.3545 +} 1.3546 + 1.3547 +bool 1.3548 +js::CallProperty(JSContext *cx, HandleValue v, HandlePropertyName name, MutableHandleValue vp) 1.3549 +{ 1.3550 + if (!GetProperty(cx, v, name, vp)) 1.3551 + return false; 1.3552 + 1.3553 +#if JS_HAS_NO_SUCH_METHOD 1.3554 + if (MOZ_UNLIKELY(vp.isUndefined()) && v.isObject()) 1.3555 + { 1.3556 + RootedObject obj(cx, &v.toObject()); 1.3557 + if (!OnUnknownMethod(cx, obj, StringValue(name), vp)) 1.3558 + return false; 1.3559 + } 1.3560 +#endif 1.3561 + 1.3562 + return true; 1.3563 +} 1.3564 + 1.3565 +bool 1.3566 +js::GetScopeName(JSContext *cx, HandleObject scopeChain, HandlePropertyName name, MutableHandleValue vp) 1.3567 +{ 1.3568 + RootedShape shape(cx); 1.3569 + RootedObject obj(cx), pobj(cx); 1.3570 + if (!LookupName(cx, name, scopeChain, &obj, &pobj, &shape)) 1.3571 + return false; 1.3572 + 1.3573 + if (!shape) { 1.3574 + JSAutoByteString printable; 1.3575 + if (AtomToPrintableString(cx, name, &printable)) 1.3576 + js_ReportIsNotDefined(cx, printable.ptr()); 1.3577 + return false; 1.3578 + } 1.3579 + 1.3580 + return JSObject::getProperty(cx, obj, obj, name, vp); 1.3581 +} 1.3582 + 1.3583 +/* 1.3584 + * Alternate form for NAME opcodes followed immediately by a TYPEOF, 1.3585 + * which do not report an exception on (typeof foo == "undefined") tests. 1.3586 + */ 1.3587 +bool 1.3588 +js::GetScopeNameForTypeOf(JSContext *cx, HandleObject scopeChain, HandlePropertyName name, 1.3589 + MutableHandleValue vp) 1.3590 +{ 1.3591 + RootedShape shape(cx); 1.3592 + RootedObject obj(cx), pobj(cx); 1.3593 + if (!LookupName(cx, name, scopeChain, &obj, &pobj, &shape)) 1.3594 + return false; 1.3595 + 1.3596 + if (!shape) { 1.3597 + vp.set(UndefinedValue()); 1.3598 + return true; 1.3599 + } 1.3600 + 1.3601 + return JSObject::getProperty(cx, obj, obj, name, vp); 1.3602 +} 1.3603 + 1.3604 +JSObject * 1.3605 +js::Lambda(JSContext *cx, HandleFunction fun, HandleObject parent) 1.3606 +{ 1.3607 + MOZ_ASSERT(!fun->isArrow()); 1.3608 + 1.3609 + RootedObject clone(cx, CloneFunctionObjectIfNotSingleton(cx, fun, parent, TenuredObject)); 1.3610 + if (!clone) 1.3611 + return nullptr; 1.3612 + 1.3613 + MOZ_ASSERT(clone->global() == clone->global()); 1.3614 + return clone; 1.3615 +} 1.3616 + 1.3617 +JSObject * 1.3618 +js::LambdaArrow(JSContext *cx, HandleFunction fun, HandleObject parent, HandleValue thisv) 1.3619 +{ 1.3620 + MOZ_ASSERT(fun->isArrow()); 1.3621 + 1.3622 + RootedObject clone(cx, CloneFunctionObjectIfNotSingleton(cx, fun, parent, TenuredObject)); 1.3623 + if (!clone) 1.3624 + return nullptr; 1.3625 + 1.3626 + MOZ_ASSERT(clone->as<JSFunction>().isArrow()); 1.3627 + clone->as<JSFunction>().setExtendedSlot(0, thisv); 1.3628 + 1.3629 + MOZ_ASSERT(clone->global() == clone->global()); 1.3630 + return clone; 1.3631 +} 1.3632 + 1.3633 +bool 1.3634 +js::DefFunOperation(JSContext *cx, HandleScript script, HandleObject scopeChain, 1.3635 + HandleFunction funArg) 1.3636 +{ 1.3637 + /* 1.3638 + * If static link is not current scope, clone fun's object to link to the 1.3639 + * current scope via parent. We do this to enable sharing of compiled 1.3640 + * functions among multiple equivalent scopes, amortizing the cost of 1.3641 + * compilation over a number of executions. Examples include XUL scripts 1.3642 + * and event handlers shared among Firefox or other Mozilla app chrome 1.3643 + * windows, and user-defined JS functions precompiled and then shared among 1.3644 + * requests in server-side JS. 1.3645 + */ 1.3646 + RootedFunction fun(cx, funArg); 1.3647 + if (fun->isNative() || fun->environment() != scopeChain) { 1.3648 + fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain, TenuredObject); 1.3649 + if (!fun) 1.3650 + return false; 1.3651 + } else { 1.3652 + JS_ASSERT(script->compileAndGo()); 1.3653 + JS_ASSERT(!script->functionNonDelazifying()); 1.3654 + } 1.3655 + 1.3656 + /* 1.3657 + * We define the function as a property of the variable object and not the 1.3658 + * current scope chain even for the case of function expression statements 1.3659 + * and functions defined by eval inside let or with blocks. 1.3660 + */ 1.3661 + RootedObject parent(cx, scopeChain); 1.3662 + while (!parent->isVarObj()) 1.3663 + parent = parent->enclosingScope(); 1.3664 + 1.3665 + /* ES5 10.5 (NB: with subsequent errata). */ 1.3666 + RootedPropertyName name(cx, fun->atom()->asPropertyName()); 1.3667 + 1.3668 + RootedShape shape(cx); 1.3669 + RootedObject pobj(cx); 1.3670 + if (!JSObject::lookupProperty(cx, parent, name, &pobj, &shape)) 1.3671 + return false; 1.3672 + 1.3673 + RootedValue rval(cx, ObjectValue(*fun)); 1.3674 + 1.3675 + /* 1.3676 + * ECMA requires functions defined when entering Eval code to be 1.3677 + * impermanent. 1.3678 + */ 1.3679 + unsigned attrs = script->isActiveEval() 1.3680 + ? JSPROP_ENUMERATE 1.3681 + : JSPROP_ENUMERATE | JSPROP_PERMANENT; 1.3682 + 1.3683 + /* Steps 5d, 5f. */ 1.3684 + if (!shape || pobj != parent) { 1.3685 + return JSObject::defineProperty(cx, parent, name, rval, JS_PropertyStub, 1.3686 + JS_StrictPropertyStub, attrs); 1.3687 + } 1.3688 + 1.3689 + /* Step 5e. */ 1.3690 + JS_ASSERT(parent->isNative()); 1.3691 + if (parent->is<GlobalObject>()) { 1.3692 + if (shape->configurable()) { 1.3693 + return JSObject::defineProperty(cx, parent, name, rval, JS_PropertyStub, 1.3694 + JS_StrictPropertyStub, attrs); 1.3695 + } 1.3696 + 1.3697 + if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) { 1.3698 + JSAutoByteString bytes; 1.3699 + if (AtomToPrintableString(cx, name, &bytes)) { 1.3700 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_REDEFINE_PROP, 1.3701 + bytes.ptr()); 1.3702 + } 1.3703 + 1.3704 + return false; 1.3705 + } 1.3706 + } 1.3707 + 1.3708 + /* 1.3709 + * Non-global properties, and global properties which we aren't simply 1.3710 + * redefining, must be set. First, this preserves their attributes. 1.3711 + * Second, this will produce warnings and/or errors as necessary if the 1.3712 + * specified Call object property is not writable (const). 1.3713 + */ 1.3714 + 1.3715 + /* Step 5f. */ 1.3716 + return JSObject::setProperty(cx, parent, parent, name, &rval, script->strict()); 1.3717 +} 1.3718 + 1.3719 +bool 1.3720 +js::SetCallOperation(JSContext *cx) 1.3721 +{ 1.3722 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_LEFTSIDE_OF_ASS); 1.3723 + return false; 1.3724 +} 1.3725 + 1.3726 +bool 1.3727 +js::GetAndClearException(JSContext *cx, MutableHandleValue res) 1.3728 +{ 1.3729 + bool status = cx->getPendingException(res); 1.3730 + cx->clearPendingException(); 1.3731 + if (!status) 1.3732 + return false; 1.3733 + 1.3734 + // Allow interrupting deeply nested exception handling. 1.3735 + return CheckForInterrupt(cx); 1.3736 +} 1.3737 + 1.3738 +template <bool strict> 1.3739 +bool 1.3740 +js::SetProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &value) 1.3741 +{ 1.3742 + RootedValue v(cx, value); 1.3743 + return JSObject::setGeneric(cx, obj, obj, id, &v, strict); 1.3744 +} 1.3745 + 1.3746 +template bool js::SetProperty<true> (JSContext *cx, HandleObject obj, HandleId id, const Value &value); 1.3747 +template bool js::SetProperty<false>(JSContext *cx, HandleObject obj, HandleId id, const Value &value); 1.3748 + 1.3749 +template <bool strict> 1.3750 +bool 1.3751 +js::DeleteProperty(JSContext *cx, HandleValue v, HandlePropertyName name, bool *bp) 1.3752 +{ 1.3753 + RootedObject obj(cx, ToObjectFromStack(cx, v)); 1.3754 + if (!obj) 1.3755 + return false; 1.3756 + 1.3757 + if (!JSObject::deleteProperty(cx, obj, name, bp)) 1.3758 + return false; 1.3759 + 1.3760 + if (strict && !*bp) { 1.3761 + obj->reportNotConfigurable(cx, NameToId(name)); 1.3762 + return false; 1.3763 + } 1.3764 + return true; 1.3765 +} 1.3766 + 1.3767 +template bool js::DeleteProperty<true> (JSContext *cx, HandleValue val, HandlePropertyName name, bool *bp); 1.3768 +template bool js::DeleteProperty<false>(JSContext *cx, HandleValue val, HandlePropertyName name, bool *bp); 1.3769 + 1.3770 +template <bool strict> 1.3771 +bool 1.3772 +js::DeleteElement(JSContext *cx, HandleValue val, HandleValue index, bool *bp) 1.3773 +{ 1.3774 + RootedObject obj(cx, ToObjectFromStack(cx, val)); 1.3775 + if (!obj) 1.3776 + return false; 1.3777 + 1.3778 + if (!JSObject::deleteByValue(cx, obj, index, bp)) 1.3779 + return false; 1.3780 + 1.3781 + if (strict && !*bp) { 1.3782 + // XXX This observably calls ToString(propval). We should convert to 1.3783 + // PropertyKey and use that to delete, and to report an error if 1.3784 + // necessary! 1.3785 + RootedId id(cx); 1.3786 + if (!ValueToId<CanGC>(cx, index, &id)) 1.3787 + return false; 1.3788 + obj->reportNotConfigurable(cx, id); 1.3789 + return false; 1.3790 + } 1.3791 + return true; 1.3792 +} 1.3793 + 1.3794 +template bool js::DeleteElement<true> (JSContext *, HandleValue, HandleValue, bool *succeeded); 1.3795 +template bool js::DeleteElement<false>(JSContext *, HandleValue, HandleValue, bool *succeeded); 1.3796 + 1.3797 +bool 1.3798 +js::GetElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue vp) 1.3799 +{ 1.3800 + return GetElementOperation(cx, JSOP_GETELEM, lref, rref, vp); 1.3801 +} 1.3802 + 1.3803 +bool 1.3804 +js::CallElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res) 1.3805 +{ 1.3806 + return GetElementOperation(cx, JSOP_CALLELEM, lref, rref, res); 1.3807 +} 1.3808 + 1.3809 +bool 1.3810 +js::SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value, 1.3811 + bool strict) 1.3812 +{ 1.3813 + RootedId id(cx); 1.3814 + if (!ValueToId<CanGC>(cx, index, &id)) 1.3815 + return false; 1.3816 + return SetObjectElementOperation(cx, obj, id, value, strict); 1.3817 +} 1.3818 + 1.3819 +bool 1.3820 +js::SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value, 1.3821 + bool strict, HandleScript script, jsbytecode *pc) 1.3822 +{ 1.3823 + JS_ASSERT(pc); 1.3824 + RootedId id(cx); 1.3825 + if (!ValueToId<CanGC>(cx, index, &id)) 1.3826 + return false; 1.3827 + return SetObjectElementOperation(cx, obj, id, value, strict, script, pc); 1.3828 +} 1.3829 + 1.3830 +bool 1.3831 +js::InitElementArray(JSContext *cx, jsbytecode *pc, HandleObject obj, uint32_t index, HandleValue value) 1.3832 +{ 1.3833 + return InitArrayElemOperation(cx, pc, obj, index, value); 1.3834 +} 1.3835 + 1.3836 +bool 1.3837 +js::AddValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res) 1.3838 +{ 1.3839 + return AddOperation(cx, lhs, rhs, res); 1.3840 +} 1.3841 + 1.3842 +bool 1.3843 +js::SubValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res) 1.3844 +{ 1.3845 + return SubOperation(cx, lhs, rhs, res); 1.3846 +} 1.3847 + 1.3848 +bool 1.3849 +js::MulValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res) 1.3850 +{ 1.3851 + return MulOperation(cx, lhs, rhs, res); 1.3852 +} 1.3853 + 1.3854 +bool 1.3855 +js::DivValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res) 1.3856 +{ 1.3857 + return DivOperation(cx, lhs, rhs, res); 1.3858 +} 1.3859 + 1.3860 +bool 1.3861 +js::ModValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res) 1.3862 +{ 1.3863 + return ModOperation(cx, lhs, rhs, res); 1.3864 +} 1.3865 + 1.3866 +bool 1.3867 +js::UrshValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res) 1.3868 +{ 1.3869 + return UrshOperation(cx, lhs, rhs, res); 1.3870 +} 1.3871 + 1.3872 +bool 1.3873 +js::DeleteNameOperation(JSContext *cx, HandlePropertyName name, HandleObject scopeObj, 1.3874 + MutableHandleValue res) 1.3875 +{ 1.3876 + RootedObject scope(cx), pobj(cx); 1.3877 + RootedShape shape(cx); 1.3878 + if (!LookupName(cx, name, scopeObj, &scope, &pobj, &shape)) 1.3879 + return false; 1.3880 + 1.3881 + if (!scope) { 1.3882 + // Return true for non-existent names. 1.3883 + res.setBoolean(true); 1.3884 + return true; 1.3885 + } 1.3886 + 1.3887 + bool succeeded; 1.3888 + if (!JSObject::deleteProperty(cx, scope, name, &succeeded)) 1.3889 + return false; 1.3890 + res.setBoolean(succeeded); 1.3891 + return true; 1.3892 +} 1.3893 + 1.3894 +bool 1.3895 +js::ImplicitThisOperation(JSContext *cx, HandleObject scopeObj, HandlePropertyName name, 1.3896 + MutableHandleValue res) 1.3897 +{ 1.3898 + RootedObject obj(cx); 1.3899 + if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &obj)) 1.3900 + return false; 1.3901 + 1.3902 + return ComputeImplicitThis(cx, obj, res); 1.3903 +} 1.3904 + 1.3905 +bool 1.3906 +js::RunOnceScriptPrologue(JSContext *cx, HandleScript script) 1.3907 +{ 1.3908 + JS_ASSERT(script->treatAsRunOnce()); 1.3909 + 1.3910 + if (!script->hasRunOnce()) { 1.3911 + script->setHasRunOnce(); 1.3912 + return true; 1.3913 + } 1.3914 + 1.3915 + // Force instantiation of the script's function's type to ensure the flag 1.3916 + // is preserved in type information. 1.3917 + if (!script->functionNonDelazifying()->getType(cx)) 1.3918 + return false; 1.3919 + 1.3920 + types::MarkTypeObjectFlags(cx, script->functionNonDelazifying(), 1.3921 + types::OBJECT_FLAG_RUNONCE_INVALIDATED); 1.3922 + return true; 1.3923 +} 1.3924 + 1.3925 +bool 1.3926 +js::InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleId id, 1.3927 + HandleObject val) 1.3928 +{ 1.3929 + JS_ASSERT(val->isCallable()); 1.3930 + PropertyOp getter; 1.3931 + StrictPropertyOp setter; 1.3932 + unsigned attrs = JSPROP_ENUMERATE | JSPROP_SHARED; 1.3933 + 1.3934 + JSOp op = JSOp(*pc); 1.3935 + 1.3936 + if (op == JSOP_INITPROP_GETTER || op == JSOP_INITELEM_GETTER) { 1.3937 + getter = CastAsPropertyOp(val); 1.3938 + setter = JS_StrictPropertyStub; 1.3939 + attrs |= JSPROP_GETTER; 1.3940 + } else { 1.3941 + JS_ASSERT(op == JSOP_INITPROP_SETTER || op == JSOP_INITELEM_SETTER); 1.3942 + getter = JS_PropertyStub; 1.3943 + setter = CastAsStrictPropertyOp(val); 1.3944 + attrs |= JSPROP_SETTER; 1.3945 + } 1.3946 + 1.3947 + RootedValue scratch(cx); 1.3948 + return JSObject::defineGeneric(cx, obj, id, scratch, getter, setter, attrs); 1.3949 +} 1.3950 + 1.3951 +bool 1.3952 +js::InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, 1.3953 + HandlePropertyName name, HandleObject val) 1.3954 +{ 1.3955 + RootedId id(cx, NameToId(name)); 1.3956 + return InitGetterSetterOperation(cx, pc, obj, id, val); 1.3957 +} 1.3958 + 1.3959 +bool 1.3960 +js::InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleValue idval, 1.3961 + HandleObject val) 1.3962 +{ 1.3963 + RootedId id(cx); 1.3964 + if (!ValueToId<CanGC>(cx, idval, &id)) 1.3965 + return false; 1.3966 + 1.3967 + return InitGetterSetterOperation(cx, pc, obj, id, val); 1.3968 +}