#ifndef vm_Interpreter_h
#define vm_Interpreter_h
#include "jspubtd.h"
#include "vm/Iteration.h"
#include "vm/Stack.h"
namespace js {
class EnvironmentIter;
extern bool BoxNonStrictThis(JSContext* cx, HandleValue thisv,
MutableHandleValue vp);
extern bool GetFunctionThis(JSContext* cx, AbstractFramePtr frame,
MutableHandleValue res);
extern void GetNonSyntacticGlobalThis(JSContext* cx, HandleObject envChain,
MutableHandleValue res);
extern bool ReportIsNotFunction(JSContext* cx, HandleValue v, int numToSkip,
MaybeConstruct construct = NO_CONSTRUCT);
extern JSObject* ValueToCallable(JSContext* cx, HandleValue v,
int numToSkip = -1,
MaybeConstruct construct = NO_CONSTRUCT);
extern bool InternalCallOrConstruct(JSContext* cx, const CallArgs& args,
MaybeConstruct construct);
extern bool CallGetter(JSContext* cx, HandleValue thisv, HandleValue getter,
MutableHandleValue rval);
extern bool CallSetter(JSContext* cx, HandleValue thisv, HandleValue setter,
HandleValue rval);
extern bool Call(JSContext* cx, HandleValue fval, HandleValue thisv,
const AnyInvokeArgs& args, MutableHandleValue rval);
inline bool Call(JSContext* cx, HandleValue fval, HandleValue thisv,
MutableHandleValue rval) {
FixedInvokeArgs<0> args(cx);
return Call(cx, fval, thisv, args, rval);
}
inline bool Call(JSContext* cx, HandleValue fval, JSObject* thisObj,
MutableHandleValue rval) {
RootedValue thisv(cx, ObjectOrNullValue(thisObj));
FixedInvokeArgs<0> args(cx);
return Call(cx, fval, thisv, args, rval);
}
inline bool Call(JSContext* cx, HandleValue fval, HandleValue thisv,
HandleValue arg0, MutableHandleValue rval) {
FixedInvokeArgs<1> args(cx);
args[0].set(arg0);
return Call(cx, fval, thisv, args, rval);
}
inline bool Call(JSContext* cx, HandleValue fval, JSObject* thisObj,
HandleValue arg0, MutableHandleValue rval) {
RootedValue thisv(cx, ObjectOrNullValue(thisObj));
FixedInvokeArgs<1> args(cx);
args[0].set(arg0);
return Call(cx, fval, thisv, args, rval);
}
inline bool Call(JSContext* cx, HandleValue fval, HandleValue thisv,
HandleValue arg0, HandleValue arg1, MutableHandleValue rval) {
FixedInvokeArgs<2> args(cx);
args[0].set(arg0);
args[1].set(arg1);
return Call(cx, fval, thisv, args, rval);
}
inline bool Call(JSContext* cx, HandleValue fval, JSObject* thisObj,
HandleValue arg0, HandleValue arg1, MutableHandleValue rval) {
RootedValue thisv(cx, ObjectOrNullValue(thisObj));
FixedInvokeArgs<2> args(cx);
args[0].set(arg0);
args[1].set(arg1);
return Call(cx, fval, thisv, args, rval);
}
extern bool CallFromStack(JSContext* cx, const CallArgs& args);
extern bool Construct(JSContext* cx, HandleValue fval,
const AnyConstructArgs& args, HandleValue newTarget,
MutableHandleObject objp);
extern bool ConstructFromStack(JSContext* cx, const CallArgs& args);
extern bool InternalConstructWithProvidedThis(JSContext* cx, HandleValue fval,
HandleValue thisv,
const AnyConstructArgs& args,
HandleValue newTarget,
MutableHandleValue rval);
extern bool ExecuteKernel(JSContext* cx, HandleScript script,
JSObject& scopeChain, const Value& newTargetVal,
AbstractFramePtr evalInFrame, Value* result);
extern bool Execute(JSContext* cx, HandleScript script, JSObject& scopeChain,
Value* rval);
class ExecuteState;
class InvokeState;
class RunState {
protected:
enum Kind { Execute, Invoke };
Kind kind_;
RootedScript script_;
explicit RunState(JSContext* cx, Kind kind, JSScript* script)
: kind_(kind), script_(cx, script) {}
public:
bool isExecute() const { return kind_ == Execute; }
bool isInvoke() const { return kind_ == Invoke; }
ExecuteState* asExecute() const {
MOZ_ASSERT(isExecute());
return (ExecuteState*)this;
}
InvokeState* asInvoke() const {
MOZ_ASSERT(isInvoke());
return (InvokeState*)this;
}
JS::HandleScript script() const { return script_; }
InterpreterFrame* pushInterpreterFrame(JSContext* cx);
inline void setReturnValue(const Value& v);
private:
RunState(const RunState& other) = delete;
RunState(const ExecuteState& other) = delete;
RunState(const InvokeState& other) = delete;
void operator=(const RunState& other) = delete;
};
class ExecuteState : public RunState {
RootedValue newTargetValue_;
RootedObject envChain_;
AbstractFramePtr evalInFrame_;
Value* result_;
public:
ExecuteState(JSContext* cx, JSScript* script, const Value& newTargetValue,
JSObject& envChain, AbstractFramePtr evalInFrame, Value* result)
: RunState(cx, Execute, script),
newTargetValue_(cx, newTargetValue),
envChain_(cx, &envChain),
evalInFrame_(evalInFrame),
result_(result) {}
Value newTarget() const { return newTargetValue_; }
void setNewTarget(const Value& v) { newTargetValue_ = v; }
Value* addressOfNewTarget() { return newTargetValue_.address(); }
JSObject* environmentChain() const { return envChain_; }
bool isDebuggerEval() const { return !!evalInFrame_; }
InterpreterFrame* pushInterpreterFrame(JSContext* cx);
void setReturnValue(const Value& v) {
if (result_) {
*result_ = v;
}
}
};
class InvokeState final : public RunState {
const CallArgs& args_;
MaybeConstruct construct_;
public:
InvokeState(JSContext* cx, const CallArgs& args, MaybeConstruct construct)
: RunState(cx, Invoke, args.callee().as<JSFunction>().nonLazyScript()),
args_(args),
construct_(construct) {}
bool constructing() const { return construct_; }
const CallArgs& args() const { return args_; }
InterpreterFrame* pushInterpreterFrame(JSContext* cx);
void setReturnValue(const Value& v) { args_.rval().set(v); }
};
inline void RunState::setReturnValue(const Value& v) {
if (isInvoke()) {
asInvoke()->setReturnValue(v);
} else {
asExecute()->setReturnValue(v);
}
}
extern bool RunScript(JSContext* cx, RunState& state);
extern JSType TypeOfObject(JSObject* obj);
extern JSType TypeOfValue(const Value& v);
extern bool HasInstance(JSContext* cx, HandleObject obj, HandleValue v,
bool* bp);
extern void UnwindEnvironment(JSContext* cx, EnvironmentIter& ei,
jsbytecode* pc);
extern void UnwindAllEnvironmentsInFrame(JSContext* cx, EnvironmentIter& ei);
extern jsbytecode* UnwindEnvironmentToTryPc(JSScript* script,
const JSTryNote* tn);
template <class TryNoteFilter>
class MOZ_STACK_CLASS TryNoteIter {
RootedScript script_;
uint32_t pcOffset_;
TryNoteFilter isTryNoteValid_;
const JSTryNote* tn_;
const JSTryNote* tnEnd_;
void settle() {
for (; tn_ != tnEnd_; ++tn_) {
if (!pcInRange()) {
continue;
}
if (tn_->kind == JSTRY_FOR_OF_ITERCLOSE) {
do {
++tn_;
MOZ_ASSERT(tn_ != tnEnd_);
MOZ_ASSERT_IF(pcInRange(), tn_->kind != JSTRY_FOR_OF_ITERCLOSE);
} while (!(pcInRange() && tn_->kind == JSTRY_FOR_OF));
continue;
}
if (tn_ == tnEnd_ || isTryNoteValid_(tn_)) {
return;
}
}
}
public:
TryNoteIter(JSContext* cx, JSScript* script, jsbytecode* pc,
TryNoteFilter isTryNoteValid)
: script_(cx, script),
pcOffset_(script->pcToOffset(pc)),
isTryNoteValid_(isTryNoteValid) {
if (script->hasTrynotes()) {
auto trynotes = script->trynotes();
tn_ = trynotes.data();
tnEnd_ = tn_ + trynotes.size();
} else {
tn_ = tnEnd_ = nullptr;
}
settle();
}
void operator++() {
++tn_;
settle();
}
bool pcInRange() const {
uint32_t offset = pcOffset_;
uint32_t start = tn_->start;
uint32_t length = tn_->length;
return offset - start < length;
}
bool done() const { return tn_ == tnEnd_; }
const JSTryNote* operator*() const { return tn_; }
};
bool HandleClosingGeneratorReturn(JSContext* cx, AbstractFramePtr frame,
bool ok);
bool ThrowOperation(JSContext* cx, HandleValue v);
bool GetProperty(JSContext* cx, HandleValue value, HandlePropertyName name,
MutableHandleValue vp);
bool GetValueProperty(JSContext* cx, HandleValue value, HandlePropertyName name,
MutableHandleValue vp);
JSObject* Lambda(JSContext* cx, HandleFunction fun, HandleObject parent);
JSObject* LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent,
HandleValue newTargetv);
bool SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
HandleValue value, bool strict);
bool SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
HandleValue value, bool strict, HandleScript script,
jsbytecode* pc);
bool SetObjectElementWithReceiver(JSContext* cx, HandleObject obj,
HandleValue index, HandleValue value,
HandleValue receiver, bool strict);
bool SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
HandleValue value, HandleValue receiver, bool strict,
HandleScript script, jsbytecode* pc);
bool InitElementArray(JSContext* cx, jsbytecode* pc, HandleObject obj,
uint32_t index, HandleValue value);
bool AddValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
MutableHandleValue res);
bool SubValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
MutableHandleValue res);
bool MulValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
MutableHandleValue res);
bool DivValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
MutableHandleValue res);
bool ModValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
MutableHandleValue res);
bool PowValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
MutableHandleValue res);
bool UrshValues(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
MutableHandleValue res);
bool AtomicIsLockFree(JSContext* cx, HandleValue in, int* out);
template <bool strict>
bool DeletePropertyJit(JSContext* ctx, HandleValue val, HandlePropertyName name,
bool* bv);
template <bool strict>
bool DeleteElementJit(JSContext* cx, HandleValue val, HandleValue index,
bool* bv);
JSObject* BindVarOperation(JSContext* cx, JSObject* envChain);
bool DefVarOperation(JSContext* cx, HandleObject envChain, HandleScript script,
jsbytecode* pc);
bool DefLexicalOperation(JSContext* cx, HandleObject envChain,
HandleScript script, jsbytecode* pc);
bool DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain,
HandleFunction funArg);
JSObject* SingletonObjectLiteralOperation(JSContext* cx, HandleScript script,
jsbytecode* pc);
JSObject* ImportMetaOperation(JSContext* cx, HandleScript script);
JSObject* BuiltinProtoOperation(JSContext* cx, jsbytecode* pc);
bool ThrowMsgOperation(JSContext* cx, const unsigned errorNum);
bool GetAndClearException(JSContext* cx, MutableHandleValue res);
bool DeleteNameOperation(JSContext* cx, HandlePropertyName name,
HandleObject scopeObj, MutableHandleValue res);
bool ImplicitThisOperation(JSContext* cx, HandleObject scopeObj,
HandlePropertyName name, MutableHandleValue res);
bool InitPropGetterSetterOperation(JSContext* cx, jsbytecode* pc,
HandleObject obj, HandlePropertyName name,
HandleObject val);
unsigned GetInitDataPropAttrs(JSOp op);
bool EnterWithOperation(JSContext* cx, AbstractFramePtr frame, HandleValue val,
Handle<WithScope*> scope);
bool InitElemGetterSetterOperation(JSContext* cx, jsbytecode* pc,
HandleObject obj, HandleValue idval,
HandleObject val);
bool SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
HandleValue thisv, HandleValue callee, HandleValue arr,
HandleValue newTarget, MutableHandleValue res);
bool OptimizeSpreadCall(JSContext* cx, HandleValue arg, bool* optimized);
JSObject* NewObjectOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
NewObjectKind newKind = GenericObject);
JSObject* NewObjectOperationWithTemplate(JSContext* cx,
HandleObject templateObject);
JSObject* CreateThisWithTemplate(JSContext* cx, HandleObject templateObject);
JSObject* NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
uint32_t length,
NewObjectKind newKind = GenericObject);
JSObject* NewArrayOperationWithTemplate(JSContext* cx,
HandleObject templateObject);
ArrayObject* NewArrayCopyOnWriteOperation(JSContext* cx, HandleScript script,
jsbytecode* pc);
MOZ_MUST_USE bool GetImportOperation(JSContext* cx, HandleObject envChain,
HandleScript script, jsbytecode* pc,
MutableHandleValue vp);
void ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
HandleId id);
void ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
HandlePropertyName name);
void ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
HandleScript script, jsbytecode* pc);
void ReportInNotObjectError(JSContext* cx, HandleValue lref, int lindex,
HandleValue rref, int rindex);
void ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name,
const char* redeclKind);
enum class CheckIsObjectKind : uint8_t {
IteratorNext,
IteratorReturn,
IteratorThrow,
GetIterator,
GetAsyncIterator
};
bool ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind);
enum class CheckIsCallableKind : uint8_t { IteratorReturn };
bool ThrowCheckIsCallable(JSContext* cx, CheckIsCallableKind kind);
bool ThrowUninitializedThis(JSContext* cx, AbstractFramePtr frame);
bool ThrowInitializedThis(JSContext* cx);
bool DefaultClassConstructor(JSContext* cx, unsigned argc, Value* vp);
bool Debug_CheckSelfHosted(JSContext* cx, HandleValue v);
bool CheckClassHeritageOperation(JSContext* cx, HandleValue heritage);
JSObject* ObjectWithProtoOperation(JSContext* cx, HandleValue proto);
JSObject* FunWithProtoOperation(JSContext* cx, HandleFunction fun,
HandleObject parent, HandleObject proto);
JSFunction* MakeDefaultConstructor(JSContext* cx, HandleScript script,
jsbytecode* pc, HandleObject proto);
JSObject* HomeObjectSuperBase(JSContext* cx, HandleObject homeObj);
JSObject* SuperFunOperation(JSContext* cx, HandleObject callee);
bool SetPropertySuper(JSContext* cx, HandleObject obj, HandleValue receiver,
HandlePropertyName id, HandleValue rval, bool strict);
}
#endif