1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/Interpreter.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,475 @@ 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 +#ifndef vm_Interpreter_h 1.11 +#define vm_Interpreter_h 1.12 + 1.13 +/* 1.14 + * JS interpreter interface. 1.15 + */ 1.16 + 1.17 +#include "jsiter.h" 1.18 +#include "jspubtd.h" 1.19 + 1.20 +#include "vm/Stack.h" 1.21 + 1.22 +namespace js { 1.23 + 1.24 +class ScopeIter; 1.25 + 1.26 +/* 1.27 + * Announce to the debugger that the thread has entered a new JavaScript frame, 1.28 + * |frame|. Call whatever hooks have been registered to observe new frames, and 1.29 + * return a JSTrapStatus code indication how execution should proceed: 1.30 + * 1.31 + * - JSTRAP_CONTINUE: Continue execution normally. 1.32 + * 1.33 + * - JSTRAP_THROW: Throw an exception. ScriptDebugPrologue has set |cx|'s 1.34 + * pending exception to the value to be thrown. 1.35 + * 1.36 + * - JSTRAP_ERROR: Terminate execution (as is done when a script is terminated 1.37 + * for running too long). ScriptDebugPrologue has cleared |cx|'s pending 1.38 + * exception. 1.39 + * 1.40 + * - JSTRAP_RETURN: Return from the new frame immediately. ScriptDebugPrologue 1.41 + * has set |frame|'s return value appropriately. 1.42 + */ 1.43 +extern JSTrapStatus 1.44 +ScriptDebugPrologue(JSContext *cx, AbstractFramePtr frame, jsbytecode *pc); 1.45 + 1.46 +/* 1.47 + * Announce to the debugger that the thread has exited a JavaScript frame, |frame|. 1.48 + * If |ok| is true, the frame is returning normally; if |ok| is false, the frame 1.49 + * is throwing an exception or terminating. 1.50 + * 1.51 + * Call whatever hooks have been registered to observe frame exits. Change cx's 1.52 + * current exception and |frame|'s return value to reflect the changes in behavior 1.53 + * the hooks request, if any. Return the new error/success value. 1.54 + * 1.55 + * This function may be called twice for the same outgoing frame; only the 1.56 + * first call has any effect. (Permitting double calls simplifies some 1.57 + * cases where an onPop handler's resumption value changes a return to a 1.58 + * throw, or vice versa: we can redirect to a complete copy of the 1.59 + * alternative path, containing its own call to ScriptDebugEpilogue.) 1.60 + */ 1.61 +extern bool 1.62 +ScriptDebugEpilogue(JSContext *cx, AbstractFramePtr frame, jsbytecode *pc, bool ok); 1.63 + 1.64 +/* 1.65 + * Announce to the debugger that an exception has been thrown and propagated 1.66 + * to |frame|. Call whatever hooks have been registered to observe this and 1.67 + * return a JSTrapStatus code indication how execution should proceed: 1.68 + * 1.69 + * - JSTRAP_CONTINUE: Continue throwing the current exception. 1.70 + * 1.71 + * - JSTRAP_THROW: Throw another value. DebugExceptionUnwind has set |cx|'s 1.72 + * pending exception to the new value. 1.73 + * 1.74 + * - JSTRAP_ERROR: Terminate execution. DebugExceptionUnwind has cleared |cx|'s 1.75 + * pending exception. 1.76 + * 1.77 + * - JSTRAP_RETURN: Return from |frame|. DebugExceptionUnwind has cleared 1.78 + * |cx|'s pending exception and set |frame|'s return value. 1.79 + */ 1.80 +extern JSTrapStatus 1.81 +DebugExceptionUnwind(JSContext *cx, AbstractFramePtr frame, jsbytecode *pc); 1.82 + 1.83 +/* 1.84 + * For a given |call|, convert null/undefined |this| into the global object for 1.85 + * the callee and replace other primitives with boxed versions. This assumes 1.86 + * that call.callee() is not strict mode code. This is the special/slow case of 1.87 + * ComputeThis. 1.88 + */ 1.89 +extern bool 1.90 +BoxNonStrictThis(JSContext *cx, const CallReceiver &call); 1.91 + 1.92 +extern JSObject * 1.93 +BoxNonStrictThis(JSContext *cx, HandleValue thisv); 1.94 + 1.95 +/* 1.96 + * Ensure that fp->thisValue() is the correct value of |this| for the scripted 1.97 + * call represented by |fp|. ComputeThis is necessary because fp->thisValue() 1.98 + * may be set to 'undefined' when 'this' should really be the global object (as 1.99 + * an optimization to avoid global-this computation). 1.100 + */ 1.101 +inline bool 1.102 +ComputeThis(JSContext *cx, AbstractFramePtr frame); 1.103 + 1.104 +enum MaybeConstruct { 1.105 + NO_CONSTRUCT = INITIAL_NONE, 1.106 + CONSTRUCT = INITIAL_CONSTRUCT 1.107 +}; 1.108 + 1.109 +/* 1.110 + * numToSkip is the number of stack values the expression decompiler should skip 1.111 + * before it reaches |v|. If it's -1, the decompiler will search the stack. 1.112 + */ 1.113 +extern bool 1.114 +ReportIsNotFunction(JSContext *cx, HandleValue v, int numToSkip = -1, 1.115 + MaybeConstruct construct = NO_CONSTRUCT); 1.116 + 1.117 +/* See ReportIsNotFunction comment for the meaning of numToSkip. */ 1.118 +extern JSObject * 1.119 +ValueToCallable(JSContext *cx, HandleValue v, int numToSkip = -1, 1.120 + MaybeConstruct construct = NO_CONSTRUCT); 1.121 + 1.122 +/* 1.123 + * Invoke assumes that the given args have been pushed on the top of the 1.124 + * VM stack. 1.125 + */ 1.126 +extern bool 1.127 +Invoke(JSContext *cx, CallArgs args, MaybeConstruct construct = NO_CONSTRUCT); 1.128 + 1.129 +/* 1.130 + * This Invoke overload places the least requirements on the caller: it may be 1.131 + * called at any time and it takes care of copying the given callee, this, and 1.132 + * arguments onto the stack. 1.133 + */ 1.134 +extern bool 1.135 +Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, const Value *argv, 1.136 + MutableHandleValue rval); 1.137 + 1.138 +/* 1.139 + * This helper takes care of the infinite-recursion check necessary for 1.140 + * getter/setter calls. 1.141 + */ 1.142 +extern bool 1.143 +InvokeGetterOrSetter(JSContext *cx, JSObject *obj, Value fval, unsigned argc, Value *argv, 1.144 + MutableHandleValue rval); 1.145 + 1.146 +/* 1.147 + * InvokeConstructor implement a function call from a constructor context 1.148 + * (e.g. 'new') handling the the creation of the new 'this' object. 1.149 + */ 1.150 +extern bool 1.151 +InvokeConstructor(JSContext *cx, CallArgs args); 1.152 + 1.153 +/* See the fval overload of Invoke. */ 1.154 +extern bool 1.155 +InvokeConstructor(JSContext *cx, Value fval, unsigned argc, Value *argv, Value *rval); 1.156 + 1.157 +/* 1.158 + * Executes a script with the given scopeChain/this. The 'type' indicates 1.159 + * whether this is eval code or global code. To support debugging, the 1.160 + * evalFrame parameter can point to an arbitrary frame in the context's call 1.161 + * stack to simulate executing an eval in that frame. 1.162 + */ 1.163 +extern bool 1.164 +ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChain, const Value &thisv, 1.165 + ExecuteType type, AbstractFramePtr evalInFrame, Value *result); 1.166 + 1.167 +/* Execute a script with the given scopeChain as global code. */ 1.168 +extern bool 1.169 +Execute(JSContext *cx, HandleScript script, JSObject &scopeChain, Value *rval); 1.170 + 1.171 +class ExecuteState; 1.172 +class InvokeState; 1.173 +class GeneratorState; 1.174 + 1.175 +// RunState is passed to RunScript and RunScript then eiter passes it to the 1.176 +// interpreter or to the JITs. RunState contains all information we need to 1.177 +// construct an interpreter or JIT frame. 1.178 +class RunState 1.179 +{ 1.180 + protected: 1.181 + enum Kind { Execute, Invoke, Generator }; 1.182 + Kind kind_; 1.183 + 1.184 + RootedScript script_; 1.185 + 1.186 + explicit RunState(JSContext *cx, Kind kind, JSScript *script) 1.187 + : kind_(kind), 1.188 + script_(cx, script) 1.189 + { } 1.190 + 1.191 + public: 1.192 + bool isExecute() const { return kind_ == Execute; } 1.193 + bool isInvoke() const { return kind_ == Invoke; } 1.194 + bool isGenerator() const { return kind_ == Generator; } 1.195 + 1.196 + ExecuteState *asExecute() const { 1.197 + JS_ASSERT(isExecute()); 1.198 + return (ExecuteState *)this; 1.199 + } 1.200 + InvokeState *asInvoke() const { 1.201 + JS_ASSERT(isInvoke()); 1.202 + return (InvokeState *)this; 1.203 + } 1.204 + GeneratorState *asGenerator() const { 1.205 + JS_ASSERT(isGenerator()); 1.206 + return (GeneratorState *)this; 1.207 + } 1.208 + 1.209 + JSScript *script() const { return script_; } 1.210 + 1.211 + virtual InterpreterFrame *pushInterpreterFrame(JSContext *cx) = 0; 1.212 + virtual void setReturnValue(Value v) = 0; 1.213 + 1.214 + private: 1.215 + RunState(const RunState &other) MOZ_DELETE; 1.216 + RunState(const ExecuteState &other) MOZ_DELETE; 1.217 + RunState(const InvokeState &other) MOZ_DELETE; 1.218 + RunState(const GeneratorState &other) MOZ_DELETE; 1.219 + void operator=(const RunState &other) MOZ_DELETE; 1.220 +}; 1.221 + 1.222 +// Eval or global script. 1.223 +class ExecuteState : public RunState 1.224 +{ 1.225 + ExecuteType type_; 1.226 + 1.227 + RootedValue thisv_; 1.228 + RootedObject scopeChain_; 1.229 + 1.230 + AbstractFramePtr evalInFrame_; 1.231 + Value *result_; 1.232 + 1.233 + public: 1.234 + ExecuteState(JSContext *cx, JSScript *script, const Value &thisv, JSObject &scopeChain, 1.235 + ExecuteType type, AbstractFramePtr evalInFrame, Value *result) 1.236 + : RunState(cx, Execute, script), 1.237 + type_(type), 1.238 + thisv_(cx, thisv), 1.239 + scopeChain_(cx, &scopeChain), 1.240 + evalInFrame_(evalInFrame), 1.241 + result_(result) 1.242 + { } 1.243 + 1.244 + Value *addressOfThisv() { return thisv_.address(); } 1.245 + JSObject *scopeChain() const { return scopeChain_; } 1.246 + ExecuteType type() const { return type_; } 1.247 + 1.248 + virtual InterpreterFrame *pushInterpreterFrame(JSContext *cx); 1.249 + 1.250 + virtual void setReturnValue(Value v) { 1.251 + if (result_) 1.252 + *result_ = v; 1.253 + } 1.254 +}; 1.255 + 1.256 +// Data to invoke a function. 1.257 +class InvokeState : public RunState 1.258 +{ 1.259 + CallArgs &args_; 1.260 + InitialFrameFlags initial_; 1.261 + bool useNewType_; 1.262 + 1.263 + public: 1.264 + InvokeState(JSContext *cx, CallArgs &args, InitialFrameFlags initial) 1.265 + : RunState(cx, Invoke, args.callee().as<JSFunction>().nonLazyScript()), 1.266 + args_(args), 1.267 + initial_(initial), 1.268 + useNewType_(false) 1.269 + { } 1.270 + 1.271 + bool useNewType() const { return useNewType_; } 1.272 + void setUseNewType() { useNewType_ = true; } 1.273 + 1.274 + bool constructing() const { return InitialFrameFlagsAreConstructing(initial_); } 1.275 + CallArgs &args() const { return args_; } 1.276 + 1.277 + virtual InterpreterFrame *pushInterpreterFrame(JSContext *cx); 1.278 + 1.279 + virtual void setReturnValue(Value v) { 1.280 + args_.rval().set(v); 1.281 + } 1.282 +}; 1.283 + 1.284 +// Generator script. 1.285 +class GeneratorState : public RunState 1.286 +{ 1.287 + JSContext *cx_; 1.288 + JSGenerator *gen_; 1.289 + JSGeneratorState futureState_; 1.290 + bool entered_; 1.291 + 1.292 + public: 1.293 + GeneratorState(JSContext *cx, JSGenerator *gen, JSGeneratorState futureState); 1.294 + ~GeneratorState(); 1.295 + 1.296 + virtual InterpreterFrame *pushInterpreterFrame(JSContext *cx); 1.297 + virtual void setReturnValue(Value) { } 1.298 + 1.299 + JSGenerator *gen() const { return gen_; } 1.300 +}; 1.301 + 1.302 +extern bool 1.303 +RunScript(JSContext *cx, RunState &state); 1.304 + 1.305 +extern bool 1.306 +StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *equal); 1.307 + 1.308 +extern bool 1.309 +LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *equal); 1.310 + 1.311 +/* === except that NaN is the same as NaN and -0 is not the same as +0. */ 1.312 +extern bool 1.313 +SameValue(JSContext *cx, const Value &v1, const Value &v2, bool *same); 1.314 + 1.315 +extern JSType 1.316 +TypeOfObject(JSObject *obj); 1.317 + 1.318 +extern JSType 1.319 +TypeOfValue(const Value &v); 1.320 + 1.321 +extern bool 1.322 +HasInstance(JSContext *cx, HandleObject obj, HandleValue v, bool *bp); 1.323 + 1.324 +// Unwind scope chain and iterator to match the static scope corresponding to 1.325 +// the given bytecode position. 1.326 +extern void 1.327 +UnwindScope(JSContext *cx, ScopeIter &si, jsbytecode *pc); 1.328 + 1.329 +/* 1.330 + * Unwind for an uncatchable exception. This means not running finalizers, etc; 1.331 + * just preserving the basic engine stack invariants. 1.332 + */ 1.333 +extern void 1.334 +UnwindForUncatchableException(JSContext *cx, const InterpreterRegs ®s); 1.335 + 1.336 +extern bool 1.337 +OnUnknownMethod(JSContext *cx, HandleObject obj, Value idval, MutableHandleValue vp); 1.338 + 1.339 +class TryNoteIter 1.340 +{ 1.341 + const InterpreterRegs ®s; 1.342 + RootedScript script; /* TryNotIter is always stack allocated. */ 1.343 + uint32_t pcOffset; 1.344 + JSTryNote *tn, *tnEnd; 1.345 + 1.346 + void settle(); 1.347 + 1.348 + public: 1.349 + explicit TryNoteIter(JSContext *cx, const InterpreterRegs ®s); 1.350 + bool done() const; 1.351 + void operator++(); 1.352 + JSTryNote *operator*() const { return tn; } 1.353 +}; 1.354 + 1.355 +/************************************************************************/ 1.356 + 1.357 +bool 1.358 +Throw(JSContext *cx, HandleValue v); 1.359 + 1.360 +bool 1.361 +GetProperty(JSContext *cx, HandleValue value, HandlePropertyName name, MutableHandleValue vp); 1.362 + 1.363 +bool 1.364 +CallProperty(JSContext *cx, HandleValue value, HandlePropertyName name, MutableHandleValue vp); 1.365 + 1.366 +bool 1.367 +GetScopeName(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleValue vp); 1.368 + 1.369 +bool 1.370 +GetScopeNameForTypeOf(JSContext *cx, HandleObject obj, HandlePropertyName name, 1.371 + MutableHandleValue vp); 1.372 + 1.373 +JSObject * 1.374 +Lambda(JSContext *cx, HandleFunction fun, HandleObject parent); 1.375 + 1.376 +JSObject * 1.377 +LambdaArrow(JSContext *cx, HandleFunction fun, HandleObject parent, HandleValue thisv); 1.378 + 1.379 +bool 1.380 +GetElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res); 1.381 + 1.382 +bool 1.383 +CallElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res); 1.384 + 1.385 +bool 1.386 +SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value, 1.387 + bool strict); 1.388 +bool 1.389 +SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value, 1.390 + bool strict, HandleScript script, jsbytecode *pc); 1.391 + 1.392 +bool 1.393 +InitElementArray(JSContext *cx, jsbytecode *pc, 1.394 + HandleObject obj, uint32_t index, HandleValue value); 1.395 + 1.396 +bool 1.397 +AddValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res); 1.398 + 1.399 +bool 1.400 +SubValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res); 1.401 + 1.402 +bool 1.403 +MulValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res); 1.404 + 1.405 +bool 1.406 +DivValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res); 1.407 + 1.408 +bool 1.409 +ModValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res); 1.410 + 1.411 +bool 1.412 +UrshValues(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, MutableHandleValue res); 1.413 + 1.414 +template <bool strict> 1.415 +bool 1.416 +SetProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &value); 1.417 + 1.418 +template <bool strict> 1.419 +bool 1.420 +DeleteProperty(JSContext *ctx, HandleValue val, HandlePropertyName name, bool *bv); 1.421 + 1.422 +template <bool strict> 1.423 +bool 1.424 +DeleteElement(JSContext *cx, HandleValue val, HandleValue index, bool *bv); 1.425 + 1.426 +bool 1.427 +DefFunOperation(JSContext *cx, HandleScript script, HandleObject scopeChain, HandleFunction funArg); 1.428 + 1.429 +bool 1.430 +SetCallOperation(JSContext *cx); 1.431 + 1.432 +bool 1.433 +GetAndClearException(JSContext *cx, MutableHandleValue res); 1.434 + 1.435 +bool 1.436 +DeleteNameOperation(JSContext *cx, HandlePropertyName name, HandleObject scopeObj, 1.437 + MutableHandleValue res); 1.438 + 1.439 +bool 1.440 +ImplicitThisOperation(JSContext *cx, HandleObject scopeObj, HandlePropertyName name, 1.441 + MutableHandleValue res); 1.442 + 1.443 +bool 1.444 +IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, MutableHandleValue rval); 1.445 + 1.446 +bool 1.447 +IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval); 1.448 + 1.449 +bool 1.450 +RunOnceScriptPrologue(JSContext *cx, HandleScript script); 1.451 + 1.452 +bool 1.453 +InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleId id, 1.454 + HandleObject val); 1.455 + 1.456 +bool 1.457 +InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandlePropertyName name, 1.458 + HandleObject val); 1.459 + 1.460 +bool 1.461 +EnterWithOperation(JSContext *cx, AbstractFramePtr frame, HandleValue val, HandleObject staticWith); 1.462 + 1.463 + 1.464 +bool 1.465 +InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleValue idval, 1.466 + HandleObject val); 1.467 + 1.468 +inline bool 1.469 +SetConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName name, HandleValue rval) 1.470 +{ 1.471 + return JSObject::defineProperty(cx, varobj, name, rval, 1.472 + JS_PropertyStub, JS_StrictPropertyStub, 1.473 + JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); 1.474 +} 1.475 + 1.476 +} /* namespace js */ 1.477 + 1.478 +#endif /* vm_Interpreter_h */