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.
4
5 #include "src/compiler/interpreter-assembler.h"
6
7 #include <ostream>
8
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/pipeline.h"
14 #include "src/compiler/raw-machine-assembler.h"
15 #include "src/compiler/schedule.h"
16 #include "src/frames.h"
17 #include "src/interface-descriptors.h"
18 #include "src/interpreter/bytecodes.h"
19 #include "src/machine-type.h"
20 #include "src/macro-assembler.h"
21 #include "src/zone.h"
22
23 namespace v8 {
24 namespace internal {
25 namespace compiler {
26
27
InterpreterAssembler(Isolate * isolate,Zone * zone,interpreter::Bytecode bytecode)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),
34 MachineType::PointerRepresentation(),
35 InstructionSelector::SupportedMachineOperatorFlags())),
36 accumulator_(
37 raw_assembler_->Parameter(Linkage::kInterpreterAccumulatorParameter)),
38 bytecode_offset_(raw_assembler_->Parameter(
39 Linkage::kInterpreterBytecodeOffsetParameter)),
40 context_(
41 raw_assembler_->Parameter(Linkage::kInterpreterContextParameter)),
42 code_generated_(false) {}
43
44
~InterpreterAssembler()45 InterpreterAssembler::~InterpreterAssembler() {}
46
47
GenerateCode()48 Handle<Code> InterpreterAssembler::GenerateCode() {
49 DCHECK(!code_generated_);
50
51 // Disallow empty handlers that never return.
52 DCHECK_NE(0, graph()->end()->InputCount());
53
54 const char* bytecode_name = interpreter::Bytecodes::ToString(bytecode_);
55 Schedule* schedule = raw_assembler_->Export();
56 Handle<Code> code = Pipeline::GenerateCodeForCodeStub(
57 isolate(), raw_assembler_->call_descriptor(), graph(), schedule,
58 Code::STUB, bytecode_name);
59
60 #ifdef ENABLE_DISASSEMBLER
61 if (FLAG_trace_ignition_codegen) {
62 OFStream os(stdout);
63 code->Disassemble(bytecode_name, os);
64 os << std::flush;
65 }
66 #endif
67
68 code_generated_ = true;
69 return code;
70 }
71
72
GetAccumulator()73 Node* InterpreterAssembler::GetAccumulator() { return accumulator_; }
74
75
SetAccumulator(Node * value)76 void InterpreterAssembler::SetAccumulator(Node* value) { accumulator_ = value; }
77
78
GetContext()79 Node* InterpreterAssembler::GetContext() { return context_; }
80
81
SetContext(Node * value)82 void InterpreterAssembler::SetContext(Node* value) { context_ = value; }
83
84
BytecodeOffset()85 Node* InterpreterAssembler::BytecodeOffset() { return bytecode_offset_; }
86
87
RegisterFileRawPointer()88 Node* InterpreterAssembler::RegisterFileRawPointer() {
89 return raw_assembler_->Parameter(Linkage::kInterpreterRegisterFileParameter);
90 }
91
92
BytecodeArrayTaggedPointer()93 Node* InterpreterAssembler::BytecodeArrayTaggedPointer() {
94 return raw_assembler_->Parameter(Linkage::kInterpreterBytecodeArrayParameter);
95 }
96
97
DispatchTableRawPointer()98 Node* InterpreterAssembler::DispatchTableRawPointer() {
99 return raw_assembler_->Parameter(Linkage::kInterpreterDispatchTableParameter);
100 }
101
102
RegisterLocation(Node * reg_index)103 Node* InterpreterAssembler::RegisterLocation(Node* reg_index) {
104 return IntPtrAdd(RegisterFileRawPointer(), RegisterFrameOffset(reg_index));
105 }
106
107
LoadRegister(int offset)108 Node* InterpreterAssembler::LoadRegister(int offset) {
109 return raw_assembler_->Load(MachineType::AnyTagged(),
110 RegisterFileRawPointer(), Int32Constant(offset));
111 }
112
113
LoadRegister(interpreter::Register reg)114 Node* InterpreterAssembler::LoadRegister(interpreter::Register reg) {
115 return LoadRegister(reg.ToOperand() << kPointerSizeLog2);
116 }
117
118
RegisterFrameOffset(Node * index)119 Node* InterpreterAssembler::RegisterFrameOffset(Node* index) {
120 return WordShl(index, kPointerSizeLog2);
121 }
122
123
LoadRegister(Node * reg_index)124 Node* InterpreterAssembler::LoadRegister(Node* reg_index) {
125 return raw_assembler_->Load(MachineType::AnyTagged(),
126 RegisterFileRawPointer(),
127 RegisterFrameOffset(reg_index));
128 }
129
130
StoreRegister(Node * value,int offset)131 Node* InterpreterAssembler::StoreRegister(Node* value, int offset) {
132 return raw_assembler_->Store(MachineRepresentation::kTagged,
133 RegisterFileRawPointer(), Int32Constant(offset),
134 value, kNoWriteBarrier);
135 }
136
137
StoreRegister(Node * value,interpreter::Register reg)138 Node* InterpreterAssembler::StoreRegister(Node* value,
139 interpreter::Register reg) {
140 return StoreRegister(value, reg.ToOperand() << kPointerSizeLog2);
141 }
142
143
StoreRegister(Node * value,Node * reg_index)144 Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) {
145 return raw_assembler_->Store(
146 MachineRepresentation::kTagged, RegisterFileRawPointer(),
147 RegisterFrameOffset(reg_index), value, kNoWriteBarrier);
148 }
149
150
NextRegister(Node * reg_index)151 Node* InterpreterAssembler::NextRegister(Node* reg_index) {
152 // Register indexes are negative, so the next index is minus one.
153 return IntPtrAdd(reg_index, Int32Constant(-1));
154 }
155
156
BytecodeOperand(int operand_index)157 Node* InterpreterAssembler::BytecodeOperand(int operand_index) {
158 DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
159 DCHECK_EQ(interpreter::OperandSize::kByte,
160 interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
161 return raw_assembler_->Load(
162 MachineType::Uint8(), BytecodeArrayTaggedPointer(),
163 IntPtrAdd(BytecodeOffset(),
164 Int32Constant(interpreter::Bytecodes::GetOperandOffset(
165 bytecode_, operand_index))));
166 }
167
168
BytecodeOperandSignExtended(int operand_index)169 Node* InterpreterAssembler::BytecodeOperandSignExtended(int operand_index) {
170 DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
171 DCHECK_EQ(interpreter::OperandSize::kByte,
172 interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
173 Node* load = raw_assembler_->Load(
174 MachineType::Int8(), BytecodeArrayTaggedPointer(),
175 IntPtrAdd(BytecodeOffset(),
176 Int32Constant(interpreter::Bytecodes::GetOperandOffset(
177 bytecode_, operand_index))));
178 // Ensure that we sign extend to full pointer size
179 if (kPointerSize == 8) {
180 load = raw_assembler_->ChangeInt32ToInt64(load);
181 }
182 return load;
183 }
184
185
BytecodeOperandShort(int operand_index)186 Node* InterpreterAssembler::BytecodeOperandShort(int operand_index) {
187 DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
188 DCHECK_EQ(interpreter::OperandSize::kShort,
189 interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
190 if (TargetSupportsUnalignedAccess()) {
191 return raw_assembler_->Load(
192 MachineType::Uint16(), BytecodeArrayTaggedPointer(),
193 IntPtrAdd(BytecodeOffset(),
194 Int32Constant(interpreter::Bytecodes::GetOperandOffset(
195 bytecode_, operand_index))));
196 } else {
197 int offset =
198 interpreter::Bytecodes::GetOperandOffset(bytecode_, operand_index);
199 Node* first_byte = raw_assembler_->Load(
200 MachineType::Uint8(), BytecodeArrayTaggedPointer(),
201 IntPtrAdd(BytecodeOffset(), Int32Constant(offset)));
202 Node* second_byte = raw_assembler_->Load(
203 MachineType::Uint8(), BytecodeArrayTaggedPointer(),
204 IntPtrAdd(BytecodeOffset(), Int32Constant(offset + 1)));
205 #if V8_TARGET_LITTLE_ENDIAN
206 return raw_assembler_->WordOr(WordShl(second_byte, kBitsPerByte),
207 first_byte);
208 #elif V8_TARGET_BIG_ENDIAN
209 return raw_assembler_->WordOr(WordShl(first_byte, kBitsPerByte),
210 second_byte);
211 #else
212 #error "Unknown Architecture"
213 #endif
214 }
215 }
216
217
BytecodeOperandShortSignExtended(int operand_index)218 Node* InterpreterAssembler::BytecodeOperandShortSignExtended(
219 int operand_index) {
220 DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
221 DCHECK_EQ(interpreter::OperandSize::kShort,
222 interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
223 int operand_offset =
224 interpreter::Bytecodes::GetOperandOffset(bytecode_, operand_index);
225 Node* load;
226 if (TargetSupportsUnalignedAccess()) {
227 load = raw_assembler_->Load(
228 MachineType::Int16(), BytecodeArrayTaggedPointer(),
229 IntPtrAdd(BytecodeOffset(), Int32Constant(operand_offset)));
230 } else {
231 #if V8_TARGET_LITTLE_ENDIAN
232 Node* hi_byte_offset = Int32Constant(operand_offset + 1);
233 Node* lo_byte_offset = Int32Constant(operand_offset);
234 #elif V8_TARGET_BIG_ENDIAN
235 Node* hi_byte_offset = Int32Constant(operand_offset);
236 Node* lo_byte_offset = Int32Constant(operand_offset + 1);
237 #else
238 #error "Unknown Architecture"
239 #endif
240 Node* hi_byte =
241 raw_assembler_->Load(MachineType::Int8(), BytecodeArrayTaggedPointer(),
242 IntPtrAdd(BytecodeOffset(), hi_byte_offset));
243 Node* lo_byte =
244 raw_assembler_->Load(MachineType::Uint8(), BytecodeArrayTaggedPointer(),
245 IntPtrAdd(BytecodeOffset(), lo_byte_offset));
246 hi_byte = raw_assembler_->Word32Shl(hi_byte, Int32Constant(kBitsPerByte));
247 load = raw_assembler_->Word32Or(hi_byte, lo_byte);
248 }
249
250 // Ensure that we sign extend to full pointer size
251 if (kPointerSize == 8) {
252 load = raw_assembler_->ChangeInt32ToInt64(load);
253 }
254 return load;
255 }
256
257
BytecodeOperandCount(int operand_index)258 Node* InterpreterAssembler::BytecodeOperandCount(int operand_index) {
259 switch (interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index)) {
260 case interpreter::OperandSize::kByte:
261 DCHECK_EQ(
262 interpreter::OperandType::kCount8,
263 interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
264 return BytecodeOperand(operand_index);
265 case interpreter::OperandSize::kShort:
266 DCHECK_EQ(
267 interpreter::OperandType::kCount16,
268 interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
269 return BytecodeOperandShort(operand_index);
270 default:
271 UNREACHABLE();
272 return nullptr;
273 }
274 }
275
276
BytecodeOperandImm(int operand_index)277 Node* InterpreterAssembler::BytecodeOperandImm(int operand_index) {
278 DCHECK_EQ(interpreter::OperandType::kImm8,
279 interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
280 return BytecodeOperandSignExtended(operand_index);
281 }
282
283
BytecodeOperandIdx(int operand_index)284 Node* InterpreterAssembler::BytecodeOperandIdx(int operand_index) {
285 switch (interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index)) {
286 case interpreter::OperandSize::kByte:
287 DCHECK_EQ(
288 interpreter::OperandType::kIdx8,
289 interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
290 return BytecodeOperand(operand_index);
291 case interpreter::OperandSize::kShort:
292 DCHECK_EQ(
293 interpreter::OperandType::kIdx16,
294 interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
295 return BytecodeOperandShort(operand_index);
296 default:
297 UNREACHABLE();
298 return nullptr;
299 }
300 }
301
302
BytecodeOperandReg(int operand_index)303 Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) {
304 switch (interpreter::Bytecodes::GetOperandType(bytecode_, operand_index)) {
305 case interpreter::OperandType::kReg8:
306 case interpreter::OperandType::kRegPair8:
307 case interpreter::OperandType::kMaybeReg8:
308 DCHECK_EQ(
309 interpreter::OperandSize::kByte,
310 interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
311 return BytecodeOperandSignExtended(operand_index);
312 case interpreter::OperandType::kReg16:
313 DCHECK_EQ(
314 interpreter::OperandSize::kShort,
315 interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
316 return BytecodeOperandShortSignExtended(operand_index);
317 default:
318 UNREACHABLE();
319 return nullptr;
320 }
321 }
322
323
Int32Constant(int value)324 Node* InterpreterAssembler::Int32Constant(int value) {
325 return raw_assembler_->Int32Constant(value);
326 }
327
328
IntPtrConstant(intptr_t value)329 Node* InterpreterAssembler::IntPtrConstant(intptr_t value) {
330 return raw_assembler_->IntPtrConstant(value);
331 }
332
333
NumberConstant(double value)334 Node* InterpreterAssembler::NumberConstant(double value) {
335 return raw_assembler_->NumberConstant(value);
336 }
337
338
HeapConstant(Handle<HeapObject> object)339 Node* InterpreterAssembler::HeapConstant(Handle<HeapObject> object) {
340 return raw_assembler_->HeapConstant(object);
341 }
342
343
BooleanConstant(bool value)344 Node* InterpreterAssembler::BooleanConstant(bool value) {
345 return raw_assembler_->BooleanConstant(value);
346 }
347
348
SmiShiftBitsConstant()349 Node* InterpreterAssembler::SmiShiftBitsConstant() {
350 return Int32Constant(kSmiShiftSize + kSmiTagSize);
351 }
352
353
SmiTag(Node * value)354 Node* InterpreterAssembler::SmiTag(Node* value) {
355 return raw_assembler_->WordShl(value, SmiShiftBitsConstant());
356 }
357
358
SmiUntag(Node * value)359 Node* InterpreterAssembler::SmiUntag(Node* value) {
360 return raw_assembler_->WordSar(value, SmiShiftBitsConstant());
361 }
362
363
IntPtrAdd(Node * a,Node * b)364 Node* InterpreterAssembler::IntPtrAdd(Node* a, Node* b) {
365 return raw_assembler_->IntPtrAdd(a, b);
366 }
367
368
IntPtrSub(Node * a,Node * b)369 Node* InterpreterAssembler::IntPtrSub(Node* a, Node* b) {
370 return raw_assembler_->IntPtrSub(a, b);
371 }
372
373
WordShl(Node * value,int shift)374 Node* InterpreterAssembler::WordShl(Node* value, int shift) {
375 return raw_assembler_->WordShl(value, Int32Constant(shift));
376 }
377
378
LoadConstantPoolEntry(Node * index)379 Node* InterpreterAssembler::LoadConstantPoolEntry(Node* index) {
380 Node* constant_pool = LoadObjectField(BytecodeArrayTaggedPointer(),
381 BytecodeArray::kConstantPoolOffset);
382 Node* entry_offset =
383 IntPtrAdd(IntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag),
384 WordShl(index, kPointerSizeLog2));
385 return raw_assembler_->Load(MachineType::AnyTagged(), constant_pool,
386 entry_offset);
387 }
388
389
LoadFixedArrayElement(Node * fixed_array,int index)390 Node* InterpreterAssembler::LoadFixedArrayElement(Node* fixed_array,
391 int index) {
392 Node* entry_offset =
393 IntPtrAdd(IntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag),
394 WordShl(Int32Constant(index), kPointerSizeLog2));
395 return raw_assembler_->Load(MachineType::AnyTagged(), fixed_array,
396 entry_offset);
397 }
398
399
LoadObjectField(Node * object,int offset)400 Node* InterpreterAssembler::LoadObjectField(Node* object, int offset) {
401 return raw_assembler_->Load(MachineType::AnyTagged(), object,
402 IntPtrConstant(offset - kHeapObjectTag));
403 }
404
405
LoadContextSlot(Node * context,int slot_index)406 Node* InterpreterAssembler::LoadContextSlot(Node* context, int slot_index) {
407 return raw_assembler_->Load(MachineType::AnyTagged(), context,
408 IntPtrConstant(Context::SlotOffset(slot_index)));
409 }
410
411
LoadContextSlot(Node * context,Node * slot_index)412 Node* InterpreterAssembler::LoadContextSlot(Node* context, Node* slot_index) {
413 Node* offset =
414 IntPtrAdd(WordShl(slot_index, kPointerSizeLog2),
415 Int32Constant(Context::kHeaderSize - kHeapObjectTag));
416 return raw_assembler_->Load(MachineType::AnyTagged(), context, offset);
417 }
418
419
StoreContextSlot(Node * context,Node * slot_index,Node * value)420 Node* InterpreterAssembler::StoreContextSlot(Node* context, Node* slot_index,
421 Node* value) {
422 Node* offset =
423 IntPtrAdd(WordShl(slot_index, kPointerSizeLog2),
424 Int32Constant(Context::kHeaderSize - kHeapObjectTag));
425 return raw_assembler_->Store(MachineRepresentation::kTagged, context, offset,
426 value, kFullWriteBarrier);
427 }
428
429
LoadTypeFeedbackVector()430 Node* InterpreterAssembler::LoadTypeFeedbackVector() {
431 Node* function = raw_assembler_->Load(
432 MachineType::AnyTagged(), RegisterFileRawPointer(),
433 IntPtrConstant(InterpreterFrameConstants::kFunctionFromRegisterPointer));
434 Node* shared_info =
435 LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset);
436 Node* vector =
437 LoadObjectField(shared_info, SharedFunctionInfo::kFeedbackVectorOffset);
438 return vector;
439 }
440
441
Projection(int index,Node * node)442 Node* InterpreterAssembler::Projection(int index, Node* node) {
443 return raw_assembler_->Projection(index, node);
444 }
445
446
CallConstruct(Node * new_target,Node * constructor,Node * first_arg,Node * arg_count)447 Node* InterpreterAssembler::CallConstruct(Node* new_target, Node* constructor,
448 Node* first_arg, Node* arg_count) {
449 Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(isolate());
450 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
451 isolate(), zone(), callable.descriptor(), 0, CallDescriptor::kNoFlags);
452
453 Node* code_target = HeapConstant(callable.code());
454
455 Node** args = zone()->NewArray<Node*>(5);
456 args[0] = arg_count;
457 args[1] = new_target;
458 args[2] = constructor;
459 args[3] = first_arg;
460 args[4] = GetContext();
461
462 return CallN(descriptor, code_target, args);
463 }
464
465
CallPrologue()466 void InterpreterAssembler::CallPrologue() {
467 StoreRegister(SmiTag(bytecode_offset_),
468 InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer);
469 }
470
471
CallEpilogue()472 void InterpreterAssembler::CallEpilogue() {
473 // Restore the bytecode offset from the stack frame.
474 bytecode_offset_ = SmiUntag(LoadRegister(
475 InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer));
476 }
477
478
CallN(CallDescriptor * descriptor,Node * code_target,Node ** args)479 Node* InterpreterAssembler::CallN(CallDescriptor* descriptor, Node* code_target,
480 Node** args) {
481 CallPrologue();
482
483 Node* stack_pointer_before_call = nullptr;
484 if (FLAG_debug_code) {
485 stack_pointer_before_call = raw_assembler_->LoadStackPointer();
486 }
487 Node* return_val = raw_assembler_->CallN(descriptor, code_target, args);
488 if (FLAG_debug_code) {
489 Node* stack_pointer_after_call = raw_assembler_->LoadStackPointer();
490 AbortIfWordNotEqual(stack_pointer_before_call, stack_pointer_after_call,
491 kUnexpectedStackPointer);
492 }
493
494 CallEpilogue();
495 return return_val;
496 }
497
498
CallJS(Node * function,Node * first_arg,Node * arg_count)499 Node* InterpreterAssembler::CallJS(Node* function, Node* first_arg,
500 Node* arg_count) {
501 Callable callable = CodeFactory::InterpreterPushArgsAndCall(isolate());
502 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
503 isolate(), zone(), callable.descriptor(), 0, CallDescriptor::kNoFlags);
504
505 Node* code_target = HeapConstant(callable.code());
506
507 Node** args = zone()->NewArray<Node*>(4);
508 args[0] = arg_count;
509 args[1] = first_arg;
510 args[2] = function;
511 args[3] = GetContext();
512
513 return CallN(descriptor, code_target, args);
514 }
515
516
CallIC(CallInterfaceDescriptor descriptor,Node * target,Node ** args)517 Node* InterpreterAssembler::CallIC(CallInterfaceDescriptor descriptor,
518 Node* target, Node** args) {
519 CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
520 isolate(), zone(), descriptor, 0, CallDescriptor::kNoFlags);
521 return CallN(call_descriptor, target, args);
522 }
523
524
CallIC(CallInterfaceDescriptor descriptor,Node * target,Node * arg1,Node * arg2,Node * arg3)525 Node* InterpreterAssembler::CallIC(CallInterfaceDescriptor descriptor,
526 Node* target, Node* arg1, Node* arg2,
527 Node* arg3) {
528 Node** args = zone()->NewArray<Node*>(4);
529 args[0] = arg1;
530 args[1] = arg2;
531 args[2] = arg3;
532 args[3] = GetContext();
533 return CallIC(descriptor, target, args);
534 }
535
536
CallIC(CallInterfaceDescriptor descriptor,Node * target,Node * arg1,Node * arg2,Node * arg3,Node * arg4)537 Node* InterpreterAssembler::CallIC(CallInterfaceDescriptor descriptor,
538 Node* target, Node* arg1, Node* arg2,
539 Node* arg3, Node* arg4) {
540 Node** args = zone()->NewArray<Node*>(5);
541 args[0] = arg1;
542 args[1] = arg2;
543 args[2] = arg3;
544 args[3] = arg4;
545 args[4] = GetContext();
546 return CallIC(descriptor, target, args);
547 }
548
549
CallIC(CallInterfaceDescriptor descriptor,Node * target,Node * arg1,Node * arg2,Node * arg3,Node * arg4,Node * arg5)550 Node* InterpreterAssembler::CallIC(CallInterfaceDescriptor descriptor,
551 Node* target, Node* arg1, Node* arg2,
552 Node* arg3, Node* arg4, Node* arg5) {
553 Node** args = zone()->NewArray<Node*>(6);
554 args[0] = arg1;
555 args[1] = arg2;
556 args[2] = arg3;
557 args[3] = arg4;
558 args[4] = arg5;
559 args[5] = GetContext();
560 return CallIC(descriptor, target, args);
561 }
562
563
CallRuntime(Node * function_id,Node * first_arg,Node * arg_count,int result_size)564 Node* InterpreterAssembler::CallRuntime(Node* function_id, Node* first_arg,
565 Node* arg_count, int result_size) {
566 Callable callable = CodeFactory::InterpreterCEntry(isolate(), result_size);
567 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
568 isolate(), zone(), callable.descriptor(), 0, CallDescriptor::kNoFlags,
569 Operator::kNoProperties, MachineType::AnyTagged(), result_size);
570 Node* code_target = HeapConstant(callable.code());
571
572 // Get the function entry from the function id.
573 Node* function_table = raw_assembler_->ExternalConstant(
574 ExternalReference::runtime_function_table_address(isolate()));
575 Node* function_offset = raw_assembler_->Int32Mul(
576 function_id, Int32Constant(sizeof(Runtime::Function)));
577 Node* function = IntPtrAdd(function_table, function_offset);
578 Node* function_entry =
579 raw_assembler_->Load(MachineType::Pointer(), function,
580 Int32Constant(offsetof(Runtime::Function, entry)));
581
582 Node** args = zone()->NewArray<Node*>(4);
583 args[0] = arg_count;
584 args[1] = first_arg;
585 args[2] = function_entry;
586 args[3] = GetContext();
587
588 return CallN(descriptor, code_target, args);
589 }
590
591
CallRuntime(Runtime::FunctionId function_id,Node * arg1)592 Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id,
593 Node* arg1) {
594 CallPrologue();
595 Node* return_val =
596 raw_assembler_->CallRuntime1(function_id, arg1, GetContext());
597 CallEpilogue();
598 return return_val;
599 }
600
601
CallRuntime(Runtime::FunctionId function_id,Node * arg1,Node * arg2)602 Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id,
603 Node* arg1, Node* arg2) {
604 CallPrologue();
605 Node* return_val =
606 raw_assembler_->CallRuntime2(function_id, arg1, arg2, GetContext());
607 CallEpilogue();
608 return return_val;
609 }
610
611
CallRuntime(Runtime::FunctionId function_id,Node * arg1,Node * arg2,Node * arg3,Node * arg4)612 Node* InterpreterAssembler::CallRuntime(Runtime::FunctionId function_id,
613 Node* arg1, Node* arg2, Node* arg3,
614 Node* arg4) {
615 CallPrologue();
616 Node* return_val = raw_assembler_->CallRuntime4(function_id, arg1, arg2, arg3,
617 arg4, GetContext());
618 CallEpilogue();
619 return return_val;
620 }
621
622
Return()623 void InterpreterAssembler::Return() {
624 Node* exit_trampoline_code_object =
625 HeapConstant(isolate()->builtins()->InterpreterExitTrampoline());
626 // If the order of the parameters you need to change the call signature below.
627 STATIC_ASSERT(0 == Linkage::kInterpreterAccumulatorParameter);
628 STATIC_ASSERT(1 == Linkage::kInterpreterRegisterFileParameter);
629 STATIC_ASSERT(2 == Linkage::kInterpreterBytecodeOffsetParameter);
630 STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
631 STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
632 STATIC_ASSERT(5 == Linkage::kInterpreterContextParameter);
633 Node* args[] = { GetAccumulator(),
634 RegisterFileRawPointer(),
635 BytecodeOffset(),
636 BytecodeArrayTaggedPointer(),
637 DispatchTableRawPointer(),
638 GetContext() };
639 raw_assembler_->TailCallN(call_descriptor(), exit_trampoline_code_object,
640 args);
641 }
642
643
Advance(int delta)644 Node* InterpreterAssembler::Advance(int delta) {
645 return IntPtrAdd(BytecodeOffset(), Int32Constant(delta));
646 }
647
648
Advance(Node * delta)649 Node* InterpreterAssembler::Advance(Node* delta) {
650 return raw_assembler_->IntPtrAdd(BytecodeOffset(), delta);
651 }
652
653
Jump(Node * delta)654 void InterpreterAssembler::Jump(Node* delta) { DispatchTo(Advance(delta)); }
655
656
JumpIfWordEqual(Node * lhs,Node * rhs,Node * delta)657 void InterpreterAssembler::JumpIfWordEqual(Node* lhs, Node* rhs, Node* delta) {
658 RawMachineLabel match, no_match;
659 Node* condition = raw_assembler_->WordEqual(lhs, rhs);
660 raw_assembler_->Branch(condition, &match, &no_match);
661 raw_assembler_->Bind(&match);
662 DispatchTo(Advance(delta));
663 raw_assembler_->Bind(&no_match);
664 Dispatch();
665 }
666
667
Dispatch()668 void InterpreterAssembler::Dispatch() {
669 DispatchTo(Advance(interpreter::Bytecodes::Size(bytecode_)));
670 }
671
672
DispatchTo(Node * new_bytecode_offset)673 void InterpreterAssembler::DispatchTo(Node* new_bytecode_offset) {
674 Node* target_bytecode = raw_assembler_->Load(
675 MachineType::Uint8(), BytecodeArrayTaggedPointer(), new_bytecode_offset);
676
677 // TODO(rmcilroy): Create a code target dispatch table to avoid conversion
678 // from code object on every dispatch.
679 Node* target_code_object = raw_assembler_->Load(
680 MachineType::Pointer(), DispatchTableRawPointer(),
681 raw_assembler_->Word32Shl(target_bytecode,
682 Int32Constant(kPointerSizeLog2)));
683
684 // If the order of the parameters you need to change the call signature below.
685 STATIC_ASSERT(0 == Linkage::kInterpreterAccumulatorParameter);
686 STATIC_ASSERT(1 == Linkage::kInterpreterRegisterFileParameter);
687 STATIC_ASSERT(2 == Linkage::kInterpreterBytecodeOffsetParameter);
688 STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
689 STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
690 STATIC_ASSERT(5 == Linkage::kInterpreterContextParameter);
691 Node* args[] = { GetAccumulator(),
692 RegisterFileRawPointer(),
693 new_bytecode_offset,
694 BytecodeArrayTaggedPointer(),
695 DispatchTableRawPointer(),
696 GetContext() };
697 raw_assembler_->TailCallN(call_descriptor(), target_code_object, args);
698 }
699
700
Abort(BailoutReason bailout_reason)701 void InterpreterAssembler::Abort(BailoutReason bailout_reason) {
702 Node* abort_id = SmiTag(Int32Constant(bailout_reason));
703 Node* ret_value = CallRuntime(Runtime::kAbort, abort_id);
704 // Unreached, but keeps turbofan happy.
705 raw_assembler_->Return(ret_value);
706 }
707
708
AbortIfWordNotEqual(Node * lhs,Node * rhs,BailoutReason bailout_reason)709 void InterpreterAssembler::AbortIfWordNotEqual(Node* lhs, Node* rhs,
710 BailoutReason bailout_reason) {
711 RawMachineLabel match, no_match;
712 Node* condition = raw_assembler_->WordEqual(lhs, rhs);
713 raw_assembler_->Branch(condition, &match, &no_match);
714 raw_assembler_->Bind(&no_match);
715 Abort(bailout_reason);
716 raw_assembler_->Bind(&match);
717 }
718
719
720 // static
TargetSupportsUnalignedAccess()721 bool InterpreterAssembler::TargetSupportsUnalignedAccess() {
722 #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
723 return false;
724 #elif V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_PPC
725 return CpuFeatures::IsSupported(UNALIGNED_ACCESSES);
726 #elif V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_X87
727 return true;
728 #else
729 #error "Unknown Architecture"
730 #endif
731 }
732
733
734 // RawMachineAssembler delegate helpers:
isolate()735 Isolate* InterpreterAssembler::isolate() { return raw_assembler_->isolate(); }
736
737
graph()738 Graph* InterpreterAssembler::graph() { return raw_assembler_->graph(); }
739
740
call_descriptor() const741 CallDescriptor* InterpreterAssembler::call_descriptor() const {
742 return raw_assembler_->call_descriptor();
743 }
744
745
zone()746 Zone* InterpreterAssembler::zone() { return raw_assembler_->zone(); }
747
748
749 } // namespace compiler
750 } // namespace internal
751 } // namespace v8
752