1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "src/compiler/interpreter-assembler.h"
9 #include "src/code-factory.h"
10 #include "src/compiler/graph.h"
11 #include "src/compiler/instruction-selector.h"
12 #include "src/compiler/linkage.h"
13 #include "src/compiler/machine-type.h"
14 #include "src/compiler/pipeline.h"
15 #include "src/compiler/raw-machine-assembler.h"
16 #include "src/compiler/schedule.h"
17 #include "src/frames.h"
18 #include "src/interface-descriptors.h"
19 #include "src/interpreter/bytecodes.h"
20 #include "src/macro-assembler.h"
28 InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone,
29 interpreter::Bytecode bytecode)
30 : bytecode_(bytecode),
31 raw_assembler_(new RawMachineAssembler(
32 isolate, new (zone) Graph(zone),
33 Linkage::GetInterpreterDispatchDescriptor(zone), kMachPtr,
34 InstructionSelector::SupportedMachineOperatorFlags())),
37 raw_assembler_->Parameter(Linkage::kInterpreterAccumulatorParameter)),
38 code_generated_(false) {}
41 InterpreterAssembler::~InterpreterAssembler() {}
44 Handle<Code> InterpreterAssembler::GenerateCode() {
45 DCHECK(!code_generated_);
49 const char* bytecode_name = interpreter::Bytecodes::ToString(bytecode_);
50 Schedule* schedule = raw_assembler_->Export();
51 // TODO(rmcilroy): use a non-testing code generator.
52 Handle<Code> code = Pipeline::GenerateCodeForInterpreter(
53 isolate(), raw_assembler_->call_descriptor(), graph(), schedule,
56 #ifdef ENABLE_DISASSEMBLER
57 if (FLAG_trace_ignition_codegen) {
59 code->Disassemble(bytecode_name, os);
64 code_generated_ = true;
69 Node* InterpreterAssembler::GetAccumulator() {
74 void InterpreterAssembler::SetAccumulator(Node* value) {
79 Node* InterpreterAssembler::ContextTaggedPointer() {
80 return raw_assembler_->Parameter(Linkage::kInterpreterContextParameter);
84 Node* InterpreterAssembler::RegisterFileRawPointer() {
85 return raw_assembler_->Parameter(Linkage::kInterpreterRegisterFileParameter);
89 Node* InterpreterAssembler::BytecodeArrayTaggedPointer() {
90 return raw_assembler_->Parameter(Linkage::kInterpreterBytecodeArrayParameter);
94 Node* InterpreterAssembler::BytecodeOffset() {
95 return raw_assembler_->Parameter(
96 Linkage::kInterpreterBytecodeOffsetParameter);
100 Node* InterpreterAssembler::DispatchTableRawPointer() {
101 return raw_assembler_->Parameter(Linkage::kInterpreterDispatchTableParameter);
105 Node* InterpreterAssembler::RegisterFrameOffset(Node* index) {
106 return WordShl(index, kPointerSizeLog2);
110 Node* InterpreterAssembler::RegisterLocation(Node* reg_index) {
111 return IntPtrAdd(RegisterFileRawPointer(), RegisterFrameOffset(reg_index));
115 Node* InterpreterAssembler::LoadRegister(Node* reg_index) {
116 return raw_assembler_->Load(kMachAnyTagged, RegisterFileRawPointer(),
117 RegisterFrameOffset(reg_index));
121 Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) {
122 return raw_assembler_->Store(kMachAnyTagged, RegisterFileRawPointer(),
123 RegisterFrameOffset(reg_index), value);
127 Node* InterpreterAssembler::BytecodeOperand(int operand_index) {
128 DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
129 return raw_assembler_->Load(
130 kMachUint8, BytecodeArrayTaggedPointer(),
131 IntPtrAdd(BytecodeOffset(), Int32Constant(1 + operand_index)));
135 Node* InterpreterAssembler::BytecodeOperandSignExtended(int operand_index) {
136 DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
137 Node* load = raw_assembler_->Load(
138 kMachInt8, BytecodeArrayTaggedPointer(),
139 IntPtrAdd(BytecodeOffset(), Int32Constant(1 + operand_index)));
140 // Ensure that we sign extend to full pointer size
141 if (kPointerSize == 8) {
142 load = raw_assembler_->ChangeInt32ToInt64(load);
148 Node* InterpreterAssembler::BytecodeOperandCount(int operand_index) {
149 DCHECK_EQ(interpreter::OperandType::kCount,
150 interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
151 return BytecodeOperand(operand_index);
155 Node* InterpreterAssembler::BytecodeOperandImm8(int operand_index) {
156 DCHECK_EQ(interpreter::OperandType::kImm8,
157 interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
158 return BytecodeOperandSignExtended(operand_index);
162 Node* InterpreterAssembler::BytecodeOperandIdx(int operand_index) {
163 DCHECK_EQ(interpreter::OperandType::kIdx,
164 interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
165 return BytecodeOperand(operand_index);
169 Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) {
170 DCHECK_EQ(interpreter::OperandType::kReg,
171 interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
172 return BytecodeOperandSignExtended(operand_index);
176 Node* InterpreterAssembler::Int32Constant(int value) {
177 return raw_assembler_->Int32Constant(value);
181 Node* InterpreterAssembler::IntPtrConstant(intptr_t value) {
182 return raw_assembler_->IntPtrConstant(value);
186 Node* InterpreterAssembler::NumberConstant(double value) {
187 return raw_assembler_->NumberConstant(value);
191 Node* InterpreterAssembler::HeapConstant(Handle<HeapObject> object) {
192 return raw_assembler_->HeapConstant(object);
196 Node* InterpreterAssembler::BooleanConstant(bool value) {
197 return raw_assembler_->BooleanConstant(value);
201 Node* InterpreterAssembler::SmiShiftBitsConstant() {
202 return Int32Constant(kSmiShiftSize + kSmiTagSize);
206 Node* InterpreterAssembler::SmiTag(Node* value) {
207 return raw_assembler_->WordShl(value, SmiShiftBitsConstant());
211 Node* InterpreterAssembler::SmiUntag(Node* value) {
212 return raw_assembler_->WordSar(value, SmiShiftBitsConstant());
216 Node* InterpreterAssembler::IntPtrAdd(Node* a, Node* b) {
217 return raw_assembler_->IntPtrAdd(a, b);
221 Node* InterpreterAssembler::IntPtrSub(Node* a, Node* b) {
222 return raw_assembler_->IntPtrSub(a, b);
226 Node* InterpreterAssembler::WordShl(Node* value, int shift) {
227 return raw_assembler_->WordShl(value, Int32Constant(shift));
231 Node* InterpreterAssembler::LoadConstantPoolEntry(Node* index) {
232 Node* constant_pool = LoadObjectField(BytecodeArrayTaggedPointer(),
233 BytecodeArray::kConstantPoolOffset);
235 IntPtrAdd(IntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag),
236 WordShl(index, kPointerSizeLog2));
237 return raw_assembler_->Load(kMachAnyTagged, constant_pool, entry_offset);
241 Node* InterpreterAssembler::LoadObjectField(Node* object, int offset) {
242 return raw_assembler_->Load(kMachAnyTagged, object,
243 IntPtrConstant(offset - kHeapObjectTag));
247 Node* InterpreterAssembler::LoadContextSlot(Node* context, int slot_index) {
248 return raw_assembler_->Load(kMachAnyTagged, context,
249 IntPtrConstant(Context::SlotOffset(slot_index)));
253 Node* InterpreterAssembler::LoadContextSlot(int slot_index) {
254 return LoadContextSlot(ContextTaggedPointer(), slot_index);
258 Node* InterpreterAssembler::LoadTypeFeedbackVector() {
259 Node* function = raw_assembler_->Load(
260 kMachAnyTagged, RegisterFileRawPointer(),
261 IntPtrConstant(InterpreterFrameConstants::kFunctionFromRegisterPointer));
263 LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset);
265 LoadObjectField(shared_info, SharedFunctionInfo::kFeedbackVectorOffset);
270 Node* InterpreterAssembler::CallJS(Node* function, Node* first_arg,
272 Callable builtin = CodeFactory::PushArgsAndCall(isolate());
273 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
274 isolate(), zone(), builtin.descriptor(), 0, CallDescriptor::kNoFlags);
276 Node* code_target = HeapConstant(builtin.code());
278 Node** args = zone()->NewArray<Node*>(4);
282 args[3] = ContextTaggedPointer();
284 return raw_assembler_->CallN(descriptor, code_target, args);
288 Node* InterpreterAssembler::CallIC(CallInterfaceDescriptor descriptor,
289 Node* target, Node** args) {
290 CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
291 isolate(), zone(), descriptor, 0, CallDescriptor::kNoFlags);
292 return raw_assembler_->CallN(call_descriptor, target, args);
296 Node* InterpreterAssembler::CallIC(CallInterfaceDescriptor descriptor,
297 Node* target, Node* arg1, Node* arg2,
298 Node* arg3, Node* arg4) {
299 Node** args = zone()->NewArray<Node*>(5);
304 args[4] = ContextTaggedPointer();
305 return CallIC(descriptor, target, args);
309 Node* InterpreterAssembler::CallIC(CallInterfaceDescriptor descriptor,
310 Node* target, Node* arg1, Node* arg2,
311 Node* arg3, Node* arg4, Node* arg5) {
312 Node** args = zone()->NewArray<Node*>(6);
318 args[5] = ContextTaggedPointer();
319 return CallIC(descriptor, target, args);
323 Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id,
325 return raw_assembler_->CallRuntime1(function_id, arg1,
326 ContextTaggedPointer());
330 Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id,
331 Node* arg1, Node* arg2) {
332 return raw_assembler_->CallRuntime2(function_id, arg1, arg2,
333 ContextTaggedPointer());
337 void InterpreterAssembler::Return() {
338 Node* exit_trampoline_code_object =
339 HeapConstant(isolate()->builtins()->InterpreterExitTrampoline());
340 // If the order of the parameters you need to change the call signature below.
341 STATIC_ASSERT(0 == Linkage::kInterpreterAccumulatorParameter);
342 STATIC_ASSERT(1 == Linkage::kInterpreterRegisterFileParameter);
343 STATIC_ASSERT(2 == Linkage::kInterpreterBytecodeOffsetParameter);
344 STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
345 STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
346 STATIC_ASSERT(5 == Linkage::kInterpreterContextParameter);
347 Node* args[] = { GetAccumulator(),
348 RegisterFileRawPointer(),
350 BytecodeArrayTaggedPointer(),
351 DispatchTableRawPointer(),
352 ContextTaggedPointer() };
353 Node* tail_call = raw_assembler_->TailCallN(
354 call_descriptor(), exit_trampoline_code_object, args);
355 // This should always be the end node.
356 AddEndInput(tail_call);
360 Node* InterpreterAssembler::Advance(int delta) {
361 return IntPtrAdd(BytecodeOffset(), Int32Constant(delta));
365 Node* InterpreterAssembler::Advance(Node* delta) {
366 return raw_assembler_->IntPtrAdd(BytecodeOffset(), delta);
370 void InterpreterAssembler::Jump(Node* delta) { DispatchTo(Advance(delta)); }
373 void InterpreterAssembler::JumpIfWordEqual(Node* lhs, Node* rhs, Node* delta) {
374 RawMachineAssembler::Label match, no_match;
375 Node* condition = raw_assembler_->WordEqual(lhs, rhs);
376 raw_assembler_->Branch(condition, &match, &no_match);
377 raw_assembler_->Bind(&match);
378 DispatchTo(Advance(delta));
379 raw_assembler_->Bind(&no_match);
384 void InterpreterAssembler::Dispatch() {
385 DispatchTo(Advance(interpreter::Bytecodes::Size(bytecode_)));
389 void InterpreterAssembler::DispatchTo(Node* new_bytecode_offset) {
390 Node* target_bytecode = raw_assembler_->Load(
391 kMachUint8, BytecodeArrayTaggedPointer(), new_bytecode_offset);
393 // TODO(rmcilroy): Create a code target dispatch table to avoid conversion
394 // from code object on every dispatch.
395 Node* target_code_object = raw_assembler_->Load(
396 kMachPtr, DispatchTableRawPointer(),
397 raw_assembler_->Word32Shl(target_bytecode,
398 Int32Constant(kPointerSizeLog2)));
400 // If the order of the parameters you need to change the call signature below.
401 STATIC_ASSERT(0 == Linkage::kInterpreterAccumulatorParameter);
402 STATIC_ASSERT(1 == Linkage::kInterpreterRegisterFileParameter);
403 STATIC_ASSERT(2 == Linkage::kInterpreterBytecodeOffsetParameter);
404 STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
405 STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
406 STATIC_ASSERT(5 == Linkage::kInterpreterContextParameter);
407 Node* args[] = { GetAccumulator(),
408 RegisterFileRawPointer(),
410 BytecodeArrayTaggedPointer(),
411 DispatchTableRawPointer(),
412 ContextTaggedPointer() };
414 raw_assembler_->TailCallN(call_descriptor(), target_code_object, args);
415 // This should always be the end node.
416 AddEndInput(tail_call);
420 void InterpreterAssembler::AddEndInput(Node* input) {
421 DCHECK_NOT_NULL(input);
422 end_nodes_.push_back(input);
426 void InterpreterAssembler::End() {
427 DCHECK(!end_nodes_.empty());
428 int end_count = static_cast<int>(end_nodes_.size());
429 Node* end = graph()->NewNode(raw_assembler_->common()->End(end_count),
430 end_count, &end_nodes_[0]);
431 graph()->SetEnd(end);
435 // RawMachineAssembler delegate helpers:
436 Isolate* InterpreterAssembler::isolate() { return raw_assembler_->isolate(); }
439 Graph* InterpreterAssembler::graph() { return raw_assembler_->graph(); }
442 CallDescriptor* InterpreterAssembler::call_descriptor() const {
443 return raw_assembler_->call_descriptor();
447 Schedule* InterpreterAssembler::schedule() {
448 return raw_assembler_->schedule();
452 Zone* InterpreterAssembler::zone() { return raw_assembler_->zone(); }
455 } // namespace compiler
456 } // namespace internal