summaryrefslogtreecommitdiffstats
path: root/js/src/jit/BaselineFrameInfo.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/BaselineFrameInfo.h')
-rw-r--r--js/src/jit/BaselineFrameInfo.h315
1 files changed, 315 insertions, 0 deletions
diff --git a/js/src/jit/BaselineFrameInfo.h b/js/src/jit/BaselineFrameInfo.h
new file mode 100644
index 000000000..13bf0358d
--- /dev/null
+++ b/js/src/jit/BaselineFrameInfo.h
@@ -0,0 +1,315 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_BaselineFrameInfo_h
+#define jit_BaselineFrameInfo_h
+
+#include "mozilla/Alignment.h"
+
+#include "jit/BaselineFrame.h"
+#include "jit/FixedList.h"
+#include "jit/MacroAssembler.h"
+#include "jit/SharedICRegisters.h"
+
+namespace js {
+namespace jit {
+
+struct BytecodeInfo;
+
+// FrameInfo overview.
+//
+// FrameInfo is used by the compiler to track values stored in the frame. This
+// includes locals, arguments and stack values. Locals and arguments are always
+// fully synced. Stack values can either be synced, stored as constant, stored in
+// a Value register or refer to a local slot. Syncing a StackValue ensures it's
+// stored on the stack, e.g. kind == Stack.
+//
+// To see how this works, consider the following statement:
+//
+// var y = x + 9;
+//
+// Here two values are pushed: StackValue(LocalSlot(0)) and StackValue(Int32Value(9)).
+// Only when we reach the ADD op, code is generated to load the operands directly
+// into the right operand registers and sync all other stack values.
+//
+// For stack values, the following invariants hold (and are checked between ops):
+//
+// (1) If a value is synced (kind == Stack), all values below it must also be synced.
+// In other words, values with kind other than Stack can only appear on top of the
+// abstract stack.
+//
+// (2) When we call a stub or IC, all values still on the stack must be synced.
+
+// Represents a value pushed on the stack. Note that StackValue is not used for
+// locals or arguments since these are always fully synced.
+class StackValue
+{
+ public:
+ enum Kind {
+ Constant,
+ Register,
+ Stack,
+ LocalSlot,
+ ArgSlot,
+ ThisSlot,
+ EvalNewTargetSlot
+#ifdef DEBUG
+ // In debug builds, assert Kind is initialized.
+ , Uninitialized
+#endif
+ };
+
+ private:
+ Kind kind_;
+
+ union {
+ struct {
+ Value v;
+ } constant;
+ struct {
+ mozilla::AlignedStorage2<ValueOperand> reg;
+ } reg;
+ struct {
+ uint32_t slot;
+ } local;
+ struct {
+ uint32_t slot;
+ } arg;
+ } data;
+
+ JSValueType knownType_;
+
+ public:
+ StackValue() {
+ reset();
+ }
+
+ Kind kind() const {
+ return kind_;
+ }
+ bool hasKnownType() const {
+ return knownType_ != JSVAL_TYPE_UNKNOWN;
+ }
+ bool hasKnownType(JSValueType type) const {
+ MOZ_ASSERT(type != JSVAL_TYPE_UNKNOWN);
+ return knownType_ == type;
+ }
+ bool isKnownBoolean() const {
+ return hasKnownType(JSVAL_TYPE_BOOLEAN);
+ }
+ JSValueType knownType() const {
+ MOZ_ASSERT(hasKnownType());
+ return knownType_;
+ }
+ void reset() {
+#ifdef DEBUG
+ kind_ = Uninitialized;
+ knownType_ = JSVAL_TYPE_UNKNOWN;
+#endif
+ }
+ Value constant() const {
+ MOZ_ASSERT(kind_ == Constant);
+ return data.constant.v;
+ }
+ ValueOperand reg() const {
+ MOZ_ASSERT(kind_ == Register);
+ return *data.reg.reg.addr();
+ }
+ uint32_t localSlot() const {
+ MOZ_ASSERT(kind_ == LocalSlot);
+ return data.local.slot;
+ }
+ uint32_t argSlot() const {
+ MOZ_ASSERT(kind_ == ArgSlot);
+ return data.arg.slot;
+ }
+
+ void setConstant(const Value& v) {
+ kind_ = Constant;
+ data.constant.v = v;
+ knownType_ = v.isDouble() ? JSVAL_TYPE_DOUBLE : v.extractNonDoubleType();
+ }
+ void setRegister(const ValueOperand& val, JSValueType knownType = JSVAL_TYPE_UNKNOWN) {
+ kind_ = Register;
+ *data.reg.reg.addr() = val;
+ knownType_ = knownType;
+ }
+ void setLocalSlot(uint32_t slot) {
+ kind_ = LocalSlot;
+ data.local.slot = slot;
+ knownType_ = JSVAL_TYPE_UNKNOWN;
+ }
+ void setArgSlot(uint32_t slot) {
+ kind_ = ArgSlot;
+ data.arg.slot = slot;
+ knownType_ = JSVAL_TYPE_UNKNOWN;
+ }
+ void setThis() {
+ kind_ = ThisSlot;
+ knownType_ = JSVAL_TYPE_UNKNOWN;
+ }
+ void setEvalNewTarget() {
+ kind_ = EvalNewTargetSlot;
+ knownType_ = JSVAL_TYPE_UNKNOWN;
+ }
+ void setStack() {
+ kind_ = Stack;
+ knownType_ = JSVAL_TYPE_UNKNOWN;
+ }
+};
+
+enum StackAdjustment { AdjustStack, DontAdjustStack };
+
+class FrameInfo
+{
+ JSScript* script;
+ MacroAssembler& masm;
+
+ FixedList<StackValue> stack;
+ size_t spIndex;
+
+ public:
+ FrameInfo(JSScript* script, MacroAssembler& masm)
+ : script(script),
+ masm(masm),
+ stack(),
+ spIndex(0)
+ { }
+
+ MOZ_MUST_USE bool init(TempAllocator& alloc);
+
+ size_t nlocals() const {
+ return script->nfixed();
+ }
+ size_t nargs() const {
+ return script->functionNonDelazifying()->nargs();
+ }
+
+ private:
+ inline StackValue* rawPush() {
+ StackValue* val = &stack[spIndex++];
+ val->reset();
+ return val;
+ }
+
+ public:
+ inline size_t stackDepth() const {
+ return spIndex;
+ }
+ inline void setStackDepth(uint32_t newDepth) {
+ if (newDepth <= stackDepth()) {
+ spIndex = newDepth;
+ } else {
+ uint32_t diff = newDepth - stackDepth();
+ for (uint32_t i = 0; i < diff; i++) {
+ StackValue* val = rawPush();
+ val->setStack();
+ }
+
+ MOZ_ASSERT(spIndex == newDepth);
+ }
+ }
+ inline StackValue* peek(int32_t index) const {
+ MOZ_ASSERT(index < 0);
+ return const_cast<StackValue*>(&stack[spIndex + index]);
+ }
+
+ inline void pop(StackAdjustment adjust = AdjustStack);
+ inline void popn(uint32_t n, StackAdjustment adjust = AdjustStack);
+ inline void push(const Value& val) {
+ StackValue* sv = rawPush();
+ sv->setConstant(val);
+ }
+ inline void push(const ValueOperand& val, JSValueType knownType=JSVAL_TYPE_UNKNOWN) {
+ StackValue* sv = rawPush();
+ sv->setRegister(val, knownType);
+ }
+ inline void pushLocal(uint32_t local) {
+ MOZ_ASSERT(local < nlocals());
+ StackValue* sv = rawPush();
+ sv->setLocalSlot(local);
+ }
+ inline void pushArg(uint32_t arg) {
+ StackValue* sv = rawPush();
+ sv->setArgSlot(arg);
+ }
+ inline void pushThis() {
+ StackValue* sv = rawPush();
+ sv->setThis();
+ }
+ inline void pushEvalNewTarget() {
+ MOZ_ASSERT(script->isForEval());
+ StackValue* sv = rawPush();
+ sv->setEvalNewTarget();
+ }
+
+ inline void pushScratchValue() {
+ masm.pushValue(addressOfScratchValue());
+ StackValue* sv = rawPush();
+ sv->setStack();
+ }
+ inline Address addressOfLocal(size_t local) const {
+ MOZ_ASSERT(local < nlocals());
+ return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfLocal(local));
+ }
+ Address addressOfArg(size_t arg) const {
+ MOZ_ASSERT(arg < nargs());
+ return Address(BaselineFrameReg, BaselineFrame::offsetOfArg(arg));
+ }
+ Address addressOfThis() const {
+ return Address(BaselineFrameReg, BaselineFrame::offsetOfThis());
+ }
+ Address addressOfEvalNewTarget() const {
+ return Address(BaselineFrameReg, BaselineFrame::offsetOfEvalNewTarget());
+ }
+ Address addressOfCalleeToken() const {
+ return Address(BaselineFrameReg, BaselineFrame::offsetOfCalleeToken());
+ }
+ Address addressOfEnvironmentChain() const {
+ return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfEnvironmentChain());
+ }
+ Address addressOfFlags() const {
+ return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags());
+ }
+ Address addressOfReturnValue() const {
+ return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfReturnValue());
+ }
+ Address addressOfArgsObj() const {
+ return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfArgsObj());
+ }
+ Address addressOfStackValue(const StackValue* value) const {
+ MOZ_ASSERT(value->kind() == StackValue::Stack);
+ size_t slot = value - &stack[0];
+ MOZ_ASSERT(slot < stackDepth());
+ return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfLocal(nlocals() + slot));
+ }
+ Address addressOfScratchValue() const {
+ return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfScratchValue());
+ }
+
+ void popValue(ValueOperand dest);
+
+ void sync(StackValue* val);
+ void syncStack(uint32_t uses);
+ uint32_t numUnsyncedSlots();
+ void popRegsAndSync(uint32_t uses);
+
+ inline void assertSyncedStack() const {
+ MOZ_ASSERT_IF(stackDepth() > 0, peek(-1)->kind() == StackValue::Stack);
+ }
+
+#ifdef DEBUG
+ // Assert the state is valid before excuting "pc".
+ void assertValidState(const BytecodeInfo& info);
+#else
+ inline void assertValidState(const BytecodeInfo& info) {}
+#endif
+};
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_BaselineFrameInfo_h */