}
+Node* InterpreterAssembler::ContextTaggedPointer() {
+ return raw_assembler_->Parameter(Linkage::kInterpreterContextParameter);
+}
+
+
Node* InterpreterAssembler::RegisterFileRawPointer() {
return raw_assembler_->Parameter(Linkage::kInterpreterRegisterFileParameter);
}
Node* InterpreterAssembler::LoadRegister(Node* reg_index) {
- return raw_assembler_->Load(kMachPtr, RegisterFileRawPointer(),
+ return raw_assembler_->Load(kMachAnyTagged, RegisterFileRawPointer(),
RegisterFrameOffset(reg_index));
}
Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) {
- return raw_assembler_->Store(kMachPtr, RegisterFileRawPointer(),
+ return raw_assembler_->Store(kMachAnyTagged, RegisterFileRawPointer(),
RegisterFrameOffset(reg_index), value);
}
}
+Node* InterpreterAssembler::IntPtrConstant(intptr_t value) {
+ return raw_assembler_->IntPtrConstant(value);
+}
+
+
Node* InterpreterAssembler::NumberConstant(double value) {
return raw_assembler_->NumberConstant(value);
}
}
+Node* InterpreterAssembler::LoadContextSlot(int slot_index) {
+ return raw_assembler_->Load(kMachAnyTagged, ContextTaggedPointer(),
+ IntPtrConstant(Context::SlotOffset(slot_index)));
+}
+
+
void InterpreterAssembler::Return() {
Node* exit_trampoline_code_object =
HeapConstant(Unique<HeapObject>::CreateImmovable(
STATIC_ASSERT(2 == Linkage::kInterpreterBytecodeOffsetParameter);
STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
+ STATIC_ASSERT(5 == Linkage::kInterpreterContextParameter);
Node* tail_call = raw_assembler_->TailCallInterpreterDispatch(
call_descriptor(), exit_trampoline_code_object, GetAccumulator(),
RegisterFileRawPointer(), BytecodeOffset(), BytecodeArrayTaggedPointer(),
- DispatchTableRawPointer());
+ DispatchTableRawPointer(), ContextTaggedPointer());
// This should always be the end node.
SetEndInput(tail_call);
}
STATIC_ASSERT(2 == Linkage::kInterpreterBytecodeOffsetParameter);
STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
+ STATIC_ASSERT(5 == Linkage::kInterpreterContextParameter);
Node* tail_call = raw_assembler_->TailCallInterpreterDispatch(
call_descriptor(), target_code_object, GetAccumulator(),
RegisterFileRawPointer(), new_bytecode_offset,
- BytecodeArrayTaggedPointer(), DispatchTableRawPointer());
+ BytecodeArrayTaggedPointer(), DispatchTableRawPointer(),
+ ContextTaggedPointer());
// This should always be the end node.
SetEndInput(tail_call);
}
// Constants.
Node* Int32Constant(int value);
+ Node* IntPtrConstant(intptr_t value);
Node* NumberConstant(double value);
Node* HeapConstant(Unique<HeapObject> object);
Node* SmiTag(Node* value);
Node* SmiUntag(Node* value);
+ // Load |slot_index| from the current context.
+ Node* LoadContextSlot(int slot_index);
+
// Returns from the function.
void Return();
Node* BytecodeArrayTaggedPointer();
// Returns the offset from the BytecodeArrayPointer of the current bytecode.
Node* BytecodeOffset();
- // Returns a pointer to first entry in the interpreter dispatch table.
+ // Returns a raw pointer to first entry in the interpreter dispatch table.
Node* DispatchTableRawPointer();
+ // Returns a tagged pointer to the current context.
+ Node* ContextTaggedPointer();
// Returns the offset of register |index| relative to RegisterFilePointer().
Node* RegisterFrameOffset(Node* index);
CallDescriptor* Linkage::GetInterpreterDispatchDescriptor(Zone* zone) {
- MachineSignature::Builder types(zone, 0, 5);
- LocationSignature::Builder locations(zone, 0, 5);
+ MachineSignature::Builder types(zone, 0, 6);
+ LocationSignature::Builder locations(zone, 0, 6);
// Add registers for fixed parameters passed via interpreter dispatch.
STATIC_ASSERT(0 == Linkage::kInterpreterAccumulatorParameter);
types.AddParam(kMachPtr);
locations.AddParam(regloc(kInterpreterDispatchTableRegister));
+ STATIC_ASSERT(5 == Linkage::kInterpreterContextParameter);
+ types.AddParam(kMachAnyTagged);
+#if defined(V8_TARGET_ARCH_IA32)
+ locations.AddParam(
+ LinkageLocation::ForCallerFrameSlot(kInterpreterContextSpillSlot));
+#else
+ locations.AddParam(regloc(kContextRegister));
+#endif
+
LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
return new (zone) CallDescriptor( // --
CallDescriptor::kCallCodeObject, // kind
static const int kInterpreterBytecodeOffsetParameter = 2;
static const int kInterpreterBytecodeArrayParameter = 3;
static const int kInterpreterDispatchTableParameter = 4;
+ static const int kInterpreterContextParameter = 5;
private:
CallDescriptor* const incoming_;
Node* RawMachineAssembler::TailCallInterpreterDispatch(
const CallDescriptor* call_descriptor, Node* target, Node* arg1, Node* arg2,
- Node* arg3, Node* arg4, Node* arg5) {
- Node* tail_call =
- graph()->NewNode(common()->TailCall(call_descriptor), target, arg1, arg2,
- arg3, arg4, arg5, graph()->start(), graph()->start());
+ Node* arg3, Node* arg4, Node* arg5, Node* arg6) {
+ Node* tail_call = graph()->NewNode(common()->TailCall(call_descriptor),
+ target, arg1, arg2, arg3, arg4, arg5, arg6,
+ graph()->start(), graph()->start());
schedule()->AddTailCall(CurrentBlock(), tail_call);
return tail_call;
}
Node* arg5, Node* arg6, Node* arg7);
Node* TailCallInterpreterDispatch(const CallDescriptor* call_descriptor,
Node* target, Node* arg1, Node* arg2,
- Node* arg3, Node* arg4, Node* arg5);
+ Node* arg3, Node* arg4, Node* arg5,
+ Node* arg6);
// ===========================================================================
// The following utility methods deal with control flow, hence might switch
__ add(kInterpreterDispatchTableRegister,
Immediate(FixedArray::kHeaderSize - kHeapObjectTag));
- // TODO(rmcilroy) Push our context as a stack located parameter of the
- // bytecode handler.
+ // Push context as a stack located parameter to the bytecode handler.
+ DCHECK_EQ(-1, kInterpreterContextSpillSlot);
+ __ push(esi);
// Dispatch to the first bytecode handler for the function.
__ movzx_b(esi, Operand(kInterpreterBytecodeArrayRegister,
const Register kRuntimeCallFunctionRegister = {kRegister_ebx_Code};
const Register kRuntimeCallArgCountRegister = {kRegister_eax_Code};
+// Spill slots used by interpreter dispatch calling convention.
+const int kInterpreterContextSpillSlot = -1;
+
// Convenience for platform-independent signatures. We do not normally
// distinguish memory operands from other operands on ia32.
typedef Operand MemOperand;
};
+Matcher<Node*> IsIntPtrConstant(const intptr_t value) {
+ return kPointerSize == 8 ? IsInt64Constant(static_cast<int64_t>(value))
+ : IsInt32Constant(static_cast<int32_t>(value));
+}
+
+
Matcher<Node*> IsIntPtrAdd(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher) {
return kPointerSize == 8 ? IsInt64Add(lhs_matcher, rhs_matcher)
next_bytecode_offset_matcher,
IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsParameter(Linkage::kInterpreterDispatchTableParameter),
+ IsParameter(Linkage::kInterpreterContextParameter),
graph->start(), graph->start()));
}
}
IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsParameter(Linkage::kInterpreterDispatchTableParameter),
+ IsParameter(Linkage::kInterpreterContextParameter),
graph->start(), graph->start()));
}
}
Node* load_reg_node = m.LoadRegister(reg_index_node);
EXPECT_THAT(
load_reg_node,
- m.IsLoad(kMachPtr,
+ m.IsLoad(kMachAnyTagged,
IsParameter(Linkage::kInterpreterRegisterFileParameter),
IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2))));
}
Node* store_reg_node = m.StoreRegister(store_value, reg_index_node);
EXPECT_THAT(
store_reg_node,
- m.IsStore(StoreRepresentation(kMachPtr, kNoWriteBarrier),
+ m.IsStore(StoreRepresentation(kMachAnyTagged, kNoWriteBarrier),
IsParameter(Linkage::kInterpreterRegisterFileParameter),
IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)),
store_value));
}
}
+
+TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) {
+ TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
+ InterpreterAssemblerForTest m(this, bytecode);
+ Node* load_context = m.LoadContextSlot(22);
+ EXPECT_THAT(load_context,
+ m.IsLoad(kMachAnyTagged,
+ IsParameter(Linkage::kInterpreterContextParameter),
+ IsIntPtrConstant(Context::SlotOffset(22))));
+ }
+}
+
} // namespace compiler
} // namespace internal
} // namespace v8
}
+Matcher<Node*> IsTailCall(
+ const Matcher<CallDescriptor const*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& value4_matcher, const Matcher<Node*>& value5_matcher,
+ const Matcher<Node*>& value6_matcher, const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher) {
+ std::vector<Matcher<Node*>> value_matchers;
+ value_matchers.push_back(value0_matcher);
+ value_matchers.push_back(value1_matcher);
+ value_matchers.push_back(value2_matcher);
+ value_matchers.push_back(value3_matcher);
+ value_matchers.push_back(value4_matcher);
+ value_matchers.push_back(value5_matcher);
+ value_matchers.push_back(value6_matcher);
+ return MakeMatcher(new IsTailCallMatcher(descriptor_matcher, value_matchers,
+ effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsTailCall(
+ const Matcher<CallDescriptor const*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& value4_matcher, const Matcher<Node*>& value5_matcher,
+ const Matcher<Node*>& value6_matcher, const Matcher<Node*>& value7_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher) {
+ std::vector<Matcher<Node*>> value_matchers;
+ value_matchers.push_back(value0_matcher);
+ value_matchers.push_back(value1_matcher);
+ value_matchers.push_back(value2_matcher);
+ value_matchers.push_back(value3_matcher);
+ value_matchers.push_back(value4_matcher);
+ value_matchers.push_back(value5_matcher);
+ value_matchers.push_back(value6_matcher);
+ value_matchers.push_back(value7_matcher);
+ return MakeMatcher(new IsTailCallMatcher(descriptor_matcher, value_matchers,
+ effect_matcher, control_matcher));
+}
+
+
Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,
const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher) {
const Matcher<Node*>& value4_matcher, const Matcher<Node*>& value5_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsTailCall(
+ const Matcher<CallDescriptor const*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& value4_matcher, const Matcher<Node*>& value5_matcher,
+ const Matcher<Node*>& value6_matcher, const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsTailCall(
+ const Matcher<CallDescriptor const*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& value4_matcher, const Matcher<Node*>& value5_matcher,
+ const Matcher<Node*>& value6_matcher, const Matcher<Node*>& value7_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher);
Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher);