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/interpreter/interpreter-assembler.h"
6
7 #include <limits>
8 #include <ostream>
9
10 #include "src/code-factory.h"
11 #include "src/frames.h"
12 #include "src/interface-descriptors.h"
13 #include "src/interpreter/bytecodes.h"
14 #include "src/interpreter/interpreter.h"
15 #include "src/machine-type.h"
16 #include "src/macro-assembler.h"
17 #include "src/zone.h"
18
19 namespace v8 {
20 namespace internal {
21 namespace interpreter {
22
23 using compiler::Node;
24
InterpreterAssembler(Isolate * isolate,Zone * zone,Bytecode bytecode,OperandScale operand_scale)25 InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone,
26 Bytecode bytecode,
27 OperandScale operand_scale)
28 : CodeStubAssembler(isolate, zone, InterpreterDispatchDescriptor(isolate),
29 Code::ComputeFlags(Code::BYTECODE_HANDLER),
30 Bytecodes::ToString(bytecode),
31 Bytecodes::ReturnCount(bytecode)),
32 bytecode_(bytecode),
33 operand_scale_(operand_scale),
34 interpreted_frame_pointer_(this, MachineType::PointerRepresentation()),
35 accumulator_(this, MachineRepresentation::kTagged),
36 accumulator_use_(AccumulatorUse::kNone),
37 made_call_(false),
38 disable_stack_check_across_call_(false),
39 stack_pointer_before_call_(nullptr) {
40 accumulator_.Bind(
41 Parameter(InterpreterDispatchDescriptor::kAccumulatorParameter));
42 if (FLAG_trace_ignition) {
43 TraceBytecode(Runtime::kInterpreterTraceBytecodeEntry);
44 }
45 }
46
~InterpreterAssembler()47 InterpreterAssembler::~InterpreterAssembler() {
48 // If the following check fails the handler does not use the
49 // accumulator in the way described in the bytecode definitions in
50 // bytecodes.h.
51 DCHECK_EQ(accumulator_use_, Bytecodes::GetAccumulatorUse(bytecode_));
52 }
53
GetInterpretedFramePointer()54 Node* InterpreterAssembler::GetInterpretedFramePointer() {
55 if (!interpreted_frame_pointer_.IsBound()) {
56 interpreted_frame_pointer_.Bind(LoadParentFramePointer());
57 }
58 return interpreted_frame_pointer_.value();
59 }
60
GetAccumulatorUnchecked()61 Node* InterpreterAssembler::GetAccumulatorUnchecked() {
62 return accumulator_.value();
63 }
64
GetAccumulator()65 Node* InterpreterAssembler::GetAccumulator() {
66 DCHECK(Bytecodes::ReadsAccumulator(bytecode_));
67 accumulator_use_ = accumulator_use_ | AccumulatorUse::kRead;
68 return GetAccumulatorUnchecked();
69 }
70
SetAccumulator(Node * value)71 void InterpreterAssembler::SetAccumulator(Node* value) {
72 DCHECK(Bytecodes::WritesAccumulator(bytecode_));
73 accumulator_use_ = accumulator_use_ | AccumulatorUse::kWrite;
74 accumulator_.Bind(value);
75 }
76
GetContext()77 Node* InterpreterAssembler::GetContext() {
78 return LoadRegister(Register::current_context());
79 }
80
SetContext(Node * value)81 void InterpreterAssembler::SetContext(Node* value) {
82 StoreRegister(value, Register::current_context());
83 }
84
BytecodeOffset()85 Node* InterpreterAssembler::BytecodeOffset() {
86 return Parameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter);
87 }
88
BytecodeArrayTaggedPointer()89 Node* InterpreterAssembler::BytecodeArrayTaggedPointer() {
90 if (made_call_) {
91 // If we have made a call, restore bytecode array from stack frame in case
92 // the debugger has swapped us to the patched debugger bytecode array.
93 return LoadRegister(Register::bytecode_array());
94 } else {
95 return Parameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter);
96 }
97 }
98
DispatchTableRawPointer()99 Node* InterpreterAssembler::DispatchTableRawPointer() {
100 return Parameter(InterpreterDispatchDescriptor::kDispatchTableParameter);
101 }
102
RegisterLocation(Node * reg_index)103 Node* InterpreterAssembler::RegisterLocation(Node* reg_index) {
104 return IntPtrAdd(GetInterpretedFramePointer(),
105 RegisterFrameOffset(reg_index));
106 }
107
RegisterFrameOffset(Node * index)108 Node* InterpreterAssembler::RegisterFrameOffset(Node* index) {
109 return WordShl(index, kPointerSizeLog2);
110 }
111
LoadRegister(Register reg)112 Node* InterpreterAssembler::LoadRegister(Register reg) {
113 return Load(MachineType::AnyTagged(), GetInterpretedFramePointer(),
114 IntPtrConstant(reg.ToOperand() << kPointerSizeLog2));
115 }
116
LoadRegister(Node * reg_index)117 Node* InterpreterAssembler::LoadRegister(Node* reg_index) {
118 return Load(MachineType::AnyTagged(), GetInterpretedFramePointer(),
119 RegisterFrameOffset(reg_index));
120 }
121
StoreRegister(Node * value,Register reg)122 Node* InterpreterAssembler::StoreRegister(Node* value, Register reg) {
123 return StoreNoWriteBarrier(
124 MachineRepresentation::kTagged, GetInterpretedFramePointer(),
125 IntPtrConstant(reg.ToOperand() << kPointerSizeLog2), value);
126 }
127
StoreRegister(Node * value,Node * reg_index)128 Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) {
129 return StoreNoWriteBarrier(MachineRepresentation::kTagged,
130 GetInterpretedFramePointer(),
131 RegisterFrameOffset(reg_index), value);
132 }
133
NextRegister(Node * reg_index)134 Node* InterpreterAssembler::NextRegister(Node* reg_index) {
135 // Register indexes are negative, so the next index is minus one.
136 return IntPtrAdd(reg_index, IntPtrConstant(-1));
137 }
138
OperandOffset(int operand_index)139 Node* InterpreterAssembler::OperandOffset(int operand_index) {
140 return IntPtrConstant(
141 Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale()));
142 }
143
BytecodeOperandUnsignedByte(int operand_index)144 Node* InterpreterAssembler::BytecodeOperandUnsignedByte(int operand_index) {
145 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_));
146 DCHECK_EQ(OperandSize::kByte, Bytecodes::GetOperandSize(
147 bytecode_, operand_index, operand_scale()));
148 Node* operand_offset = OperandOffset(operand_index);
149 return Load(MachineType::Uint8(), BytecodeArrayTaggedPointer(),
150 IntPtrAdd(BytecodeOffset(), operand_offset));
151 }
152
BytecodeOperandSignedByte(int operand_index)153 Node* InterpreterAssembler::BytecodeOperandSignedByte(int operand_index) {
154 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_));
155 DCHECK_EQ(OperandSize::kByte, Bytecodes::GetOperandSize(
156 bytecode_, operand_index, operand_scale()));
157 Node* operand_offset = OperandOffset(operand_index);
158 Node* load = Load(MachineType::Int8(), BytecodeArrayTaggedPointer(),
159 IntPtrAdd(BytecodeOffset(), operand_offset));
160
161 // Ensure that we sign extend to full pointer size
162 if (kPointerSize == 8) {
163 load = ChangeInt32ToInt64(load);
164 }
165 return load;
166 }
167
BytecodeOperandReadUnaligned(int relative_offset,MachineType result_type)168 compiler::Node* InterpreterAssembler::BytecodeOperandReadUnaligned(
169 int relative_offset, MachineType result_type) {
170 static const int kMaxCount = 4;
171 DCHECK(!TargetSupportsUnalignedAccess());
172
173 int count;
174 switch (result_type.representation()) {
175 case MachineRepresentation::kWord16:
176 count = 2;
177 break;
178 case MachineRepresentation::kWord32:
179 count = 4;
180 break;
181 default:
182 UNREACHABLE();
183 break;
184 }
185 MachineType msb_type =
186 result_type.IsSigned() ? MachineType::Int8() : MachineType::Uint8();
187
188 #if V8_TARGET_LITTLE_ENDIAN
189 const int kStep = -1;
190 int msb_offset = count - 1;
191 #elif V8_TARGET_BIG_ENDIAN
192 const int kStep = 1;
193 int msb_offset = 0;
194 #else
195 #error "Unknown Architecture"
196 #endif
197
198 // Read the most signicant bytecode into bytes[0] and then in order
199 // down to least significant in bytes[count - 1].
200 DCHECK(count <= kMaxCount);
201 compiler::Node* bytes[kMaxCount];
202 for (int i = 0; i < count; i++) {
203 MachineType machine_type = (i == 0) ? msb_type : MachineType::Uint8();
204 Node* offset = IntPtrConstant(relative_offset + msb_offset + i * kStep);
205 Node* array_offset = IntPtrAdd(BytecodeOffset(), offset);
206 bytes[i] = Load(machine_type, BytecodeArrayTaggedPointer(), array_offset);
207 }
208
209 // Pack LSB to MSB.
210 Node* result = bytes[--count];
211 for (int i = 1; --count >= 0; i++) {
212 Node* shift = Int32Constant(i * kBitsPerByte);
213 Node* value = Word32Shl(bytes[count], shift);
214 result = Word32Or(value, result);
215 }
216 return result;
217 }
218
BytecodeOperandUnsignedShort(int operand_index)219 Node* InterpreterAssembler::BytecodeOperandUnsignedShort(int operand_index) {
220 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_));
221 DCHECK_EQ(
222 OperandSize::kShort,
223 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()));
224 int operand_offset =
225 Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale());
226 if (TargetSupportsUnalignedAccess()) {
227 return Load(MachineType::Uint16(), BytecodeArrayTaggedPointer(),
228 IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset)));
229 } else {
230 return BytecodeOperandReadUnaligned(operand_offset, MachineType::Uint16());
231 }
232 }
233
BytecodeOperandSignedShort(int operand_index)234 Node* InterpreterAssembler::BytecodeOperandSignedShort(int operand_index) {
235 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_));
236 DCHECK_EQ(
237 OperandSize::kShort,
238 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()));
239 int operand_offset =
240 Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale());
241 Node* load;
242 if (TargetSupportsUnalignedAccess()) {
243 load = Load(MachineType::Int16(), BytecodeArrayTaggedPointer(),
244 IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset)));
245 } else {
246 load = BytecodeOperandReadUnaligned(operand_offset, MachineType::Int16());
247 }
248
249 // Ensure that we sign extend to full pointer size
250 if (kPointerSize == 8) {
251 load = ChangeInt32ToInt64(load);
252 }
253 return load;
254 }
255
BytecodeOperandUnsignedQuad(int operand_index)256 Node* InterpreterAssembler::BytecodeOperandUnsignedQuad(int operand_index) {
257 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_));
258 DCHECK_EQ(OperandSize::kQuad, Bytecodes::GetOperandSize(
259 bytecode_, operand_index, operand_scale()));
260 int operand_offset =
261 Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale());
262 if (TargetSupportsUnalignedAccess()) {
263 return Load(MachineType::Uint32(), BytecodeArrayTaggedPointer(),
264 IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset)));
265 } else {
266 return BytecodeOperandReadUnaligned(operand_offset, MachineType::Uint32());
267 }
268 }
269
BytecodeOperandSignedQuad(int operand_index)270 Node* InterpreterAssembler::BytecodeOperandSignedQuad(int operand_index) {
271 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_));
272 DCHECK_EQ(OperandSize::kQuad, Bytecodes::GetOperandSize(
273 bytecode_, operand_index, operand_scale()));
274 int operand_offset =
275 Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale());
276 Node* load;
277 if (TargetSupportsUnalignedAccess()) {
278 load = Load(MachineType::Int32(), BytecodeArrayTaggedPointer(),
279 IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset)));
280 } else {
281 load = BytecodeOperandReadUnaligned(operand_offset, MachineType::Int32());
282 }
283
284 // Ensure that we sign extend to full pointer size
285 if (kPointerSize == 8) {
286 load = ChangeInt32ToInt64(load);
287 }
288 return load;
289 }
290
BytecodeSignedOperand(int operand_index,OperandSize operand_size)291 Node* InterpreterAssembler::BytecodeSignedOperand(int operand_index,
292 OperandSize operand_size) {
293 DCHECK(!Bytecodes::IsUnsignedOperandType(
294 Bytecodes::GetOperandType(bytecode_, operand_index)));
295 switch (operand_size) {
296 case OperandSize::kByte:
297 return BytecodeOperandSignedByte(operand_index);
298 case OperandSize::kShort:
299 return BytecodeOperandSignedShort(operand_index);
300 case OperandSize::kQuad:
301 return BytecodeOperandSignedQuad(operand_index);
302 case OperandSize::kNone:
303 UNREACHABLE();
304 }
305 return nullptr;
306 }
307
BytecodeUnsignedOperand(int operand_index,OperandSize operand_size)308 Node* InterpreterAssembler::BytecodeUnsignedOperand(int operand_index,
309 OperandSize operand_size) {
310 DCHECK(Bytecodes::IsUnsignedOperandType(
311 Bytecodes::GetOperandType(bytecode_, operand_index)));
312 switch (operand_size) {
313 case OperandSize::kByte:
314 return BytecodeOperandUnsignedByte(operand_index);
315 case OperandSize::kShort:
316 return BytecodeOperandUnsignedShort(operand_index);
317 case OperandSize::kQuad:
318 return BytecodeOperandUnsignedQuad(operand_index);
319 case OperandSize::kNone:
320 UNREACHABLE();
321 }
322 return nullptr;
323 }
324
BytecodeOperandCount(int operand_index)325 Node* InterpreterAssembler::BytecodeOperandCount(int operand_index) {
326 DCHECK_EQ(OperandType::kRegCount,
327 Bytecodes::GetOperandType(bytecode_, operand_index));
328 OperandSize operand_size =
329 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale());
330 return BytecodeUnsignedOperand(operand_index, operand_size);
331 }
332
BytecodeOperandFlag(int operand_index)333 Node* InterpreterAssembler::BytecodeOperandFlag(int operand_index) {
334 DCHECK_EQ(OperandType::kFlag8,
335 Bytecodes::GetOperandType(bytecode_, operand_index));
336 OperandSize operand_size =
337 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale());
338 DCHECK_EQ(operand_size, OperandSize::kByte);
339 return BytecodeUnsignedOperand(operand_index, operand_size);
340 }
341
BytecodeOperandImm(int operand_index)342 Node* InterpreterAssembler::BytecodeOperandImm(int operand_index) {
343 DCHECK_EQ(OperandType::kImm,
344 Bytecodes::GetOperandType(bytecode_, operand_index));
345 OperandSize operand_size =
346 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale());
347 return BytecodeSignedOperand(operand_index, operand_size);
348 }
349
BytecodeOperandIdx(int operand_index)350 Node* InterpreterAssembler::BytecodeOperandIdx(int operand_index) {
351 DCHECK(OperandType::kIdx ==
352 Bytecodes::GetOperandType(bytecode_, operand_index));
353 OperandSize operand_size =
354 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale());
355 return BytecodeUnsignedOperand(operand_index, operand_size);
356 }
357
BytecodeOperandReg(int operand_index)358 Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) {
359 DCHECK(Bytecodes::IsRegisterOperandType(
360 Bytecodes::GetOperandType(bytecode_, operand_index)));
361 OperandSize operand_size =
362 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale());
363 return BytecodeSignedOperand(operand_index, operand_size);
364 }
365
BytecodeOperandRuntimeId(int operand_index)366 Node* InterpreterAssembler::BytecodeOperandRuntimeId(int operand_index) {
367 DCHECK(OperandType::kRuntimeId ==
368 Bytecodes::GetOperandType(bytecode_, operand_index));
369 OperandSize operand_size =
370 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale());
371 DCHECK_EQ(operand_size, OperandSize::kShort);
372 return BytecodeUnsignedOperand(operand_index, operand_size);
373 }
374
BytecodeOperandIntrinsicId(int operand_index)375 Node* InterpreterAssembler::BytecodeOperandIntrinsicId(int operand_index) {
376 DCHECK(OperandType::kIntrinsicId ==
377 Bytecodes::GetOperandType(bytecode_, operand_index));
378 OperandSize operand_size =
379 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale());
380 DCHECK_EQ(operand_size, OperandSize::kByte);
381 return BytecodeUnsignedOperand(operand_index, operand_size);
382 }
383
LoadConstantPoolEntry(Node * index)384 Node* InterpreterAssembler::LoadConstantPoolEntry(Node* index) {
385 Node* constant_pool = LoadObjectField(BytecodeArrayTaggedPointer(),
386 BytecodeArray::kConstantPoolOffset);
387 Node* entry_offset =
388 IntPtrAdd(IntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag),
389 WordShl(index, kPointerSizeLog2));
390 return Load(MachineType::AnyTagged(), constant_pool, entry_offset);
391 }
392
LoadContextSlot(Node * context,int slot_index)393 Node* InterpreterAssembler::LoadContextSlot(Node* context, int slot_index) {
394 return Load(MachineType::AnyTagged(), context,
395 IntPtrConstant(Context::SlotOffset(slot_index)));
396 }
397
LoadContextSlot(Node * context,Node * slot_index)398 Node* InterpreterAssembler::LoadContextSlot(Node* context, Node* slot_index) {
399 Node* offset =
400 IntPtrAdd(WordShl(slot_index, kPointerSizeLog2),
401 IntPtrConstant(Context::kHeaderSize - kHeapObjectTag));
402 return Load(MachineType::AnyTagged(), context, offset);
403 }
404
StoreContextSlot(Node * context,Node * slot_index,Node * value)405 Node* InterpreterAssembler::StoreContextSlot(Node* context, Node* slot_index,
406 Node* value) {
407 Node* offset =
408 IntPtrAdd(WordShl(slot_index, kPointerSizeLog2),
409 IntPtrConstant(Context::kHeaderSize - kHeapObjectTag));
410 return Store(MachineRepresentation::kTagged, context, offset, value);
411 }
412
LoadTypeFeedbackVector()413 Node* InterpreterAssembler::LoadTypeFeedbackVector() {
414 Node* function = LoadRegister(Register::function_closure());
415 Node* literals = LoadObjectField(function, JSFunction::kLiteralsOffset);
416 Node* vector =
417 LoadObjectField(literals, LiteralsArray::kFeedbackVectorOffset);
418 return vector;
419 }
420
CallPrologue()421 void InterpreterAssembler::CallPrologue() {
422 StoreRegister(SmiTag(BytecodeOffset()), Register::bytecode_offset());
423
424 if (FLAG_debug_code && !disable_stack_check_across_call_) {
425 DCHECK(stack_pointer_before_call_ == nullptr);
426 stack_pointer_before_call_ = LoadStackPointer();
427 }
428 made_call_ = true;
429 }
430
CallEpilogue()431 void InterpreterAssembler::CallEpilogue() {
432 if (FLAG_debug_code && !disable_stack_check_across_call_) {
433 Node* stack_pointer_after_call = LoadStackPointer();
434 Node* stack_pointer_before_call = stack_pointer_before_call_;
435 stack_pointer_before_call_ = nullptr;
436 AbortIfWordNotEqual(stack_pointer_before_call, stack_pointer_after_call,
437 kUnexpectedStackPointer);
438 }
439 }
440
CallJS(Node * function,Node * context,Node * first_arg,Node * arg_count,TailCallMode tail_call_mode)441 Node* InterpreterAssembler::CallJS(Node* function, Node* context,
442 Node* first_arg, Node* arg_count,
443 TailCallMode tail_call_mode) {
444 Callable callable =
445 CodeFactory::InterpreterPushArgsAndCall(isolate(), tail_call_mode);
446 Node* code_target = HeapConstant(callable.code());
447 return CallStub(callable.descriptor(), code_target, context, arg_count,
448 first_arg, function);
449 }
450
CallConstruct(Node * constructor,Node * context,Node * new_target,Node * first_arg,Node * arg_count)451 Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context,
452 Node* new_target, Node* first_arg,
453 Node* arg_count) {
454 Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(isolate());
455 Node* code_target = HeapConstant(callable.code());
456 return CallStub(callable.descriptor(), code_target, context, arg_count,
457 new_target, constructor, first_arg);
458 }
459
CallRuntimeN(Node * function_id,Node * context,Node * first_arg,Node * arg_count,int result_size)460 Node* InterpreterAssembler::CallRuntimeN(Node* function_id, Node* context,
461 Node* first_arg, Node* arg_count,
462 int result_size) {
463 Callable callable = CodeFactory::InterpreterCEntry(isolate(), result_size);
464 Node* code_target = HeapConstant(callable.code());
465
466 // Get the function entry from the function id.
467 Node* function_table = ExternalConstant(
468 ExternalReference::runtime_function_table_address(isolate()));
469 Node* function_offset =
470 Int32Mul(function_id, Int32Constant(sizeof(Runtime::Function)));
471 Node* function = IntPtrAdd(function_table, function_offset);
472 Node* function_entry =
473 Load(MachineType::Pointer(), function,
474 IntPtrConstant(offsetof(Runtime::Function, entry)));
475
476 return CallStub(callable.descriptor(), code_target, context, arg_count,
477 first_arg, function_entry, result_size);
478 }
479
UpdateInterruptBudget(Node * weight)480 void InterpreterAssembler::UpdateInterruptBudget(Node* weight) {
481 Label ok(this), interrupt_check(this, Label::kDeferred), end(this);
482 Node* budget_offset =
483 IntPtrConstant(BytecodeArray::kInterruptBudgetOffset - kHeapObjectTag);
484
485 // Update budget by |weight| and check if it reaches zero.
486 Variable new_budget(this, MachineRepresentation::kWord32);
487 Node* old_budget =
488 Load(MachineType::Int32(), BytecodeArrayTaggedPointer(), budget_offset);
489 new_budget.Bind(Int32Add(old_budget, weight));
490 Node* condition =
491 Int32GreaterThanOrEqual(new_budget.value(), Int32Constant(0));
492 Branch(condition, &ok, &interrupt_check);
493
494 // Perform interrupt and reset budget.
495 Bind(&interrupt_check);
496 {
497 CallRuntime(Runtime::kInterrupt, GetContext());
498 new_budget.Bind(Int32Constant(Interpreter::InterruptBudget()));
499 Goto(&ok);
500 }
501
502 // Update budget.
503 Bind(&ok);
504 StoreNoWriteBarrier(MachineRepresentation::kWord32,
505 BytecodeArrayTaggedPointer(), budget_offset,
506 new_budget.value());
507 }
508
Advance(int delta)509 Node* InterpreterAssembler::Advance(int delta) {
510 return IntPtrAdd(BytecodeOffset(), IntPtrConstant(delta));
511 }
512
Advance(Node * delta)513 Node* InterpreterAssembler::Advance(Node* delta) {
514 return IntPtrAdd(BytecodeOffset(), delta);
515 }
516
Jump(Node * delta)517 Node* InterpreterAssembler::Jump(Node* delta) {
518 UpdateInterruptBudget(delta);
519 return DispatchTo(Advance(delta));
520 }
521
JumpConditional(Node * condition,Node * delta)522 void InterpreterAssembler::JumpConditional(Node* condition, Node* delta) {
523 Label match(this), no_match(this);
524
525 BranchIf(condition, &match, &no_match);
526 Bind(&match);
527 Jump(delta);
528 Bind(&no_match);
529 Dispatch();
530 }
531
JumpIfWordEqual(Node * lhs,Node * rhs,Node * delta)532 void InterpreterAssembler::JumpIfWordEqual(Node* lhs, Node* rhs, Node* delta) {
533 JumpConditional(WordEqual(lhs, rhs), delta);
534 }
535
JumpIfWordNotEqual(Node * lhs,Node * rhs,Node * delta)536 void InterpreterAssembler::JumpIfWordNotEqual(Node* lhs, Node* rhs,
537 Node* delta) {
538 JumpConditional(WordNotEqual(lhs, rhs), delta);
539 }
540
Dispatch()541 Node* InterpreterAssembler::Dispatch() {
542 return DispatchTo(Advance(Bytecodes::Size(bytecode_, operand_scale_)));
543 }
544
DispatchTo(Node * new_bytecode_offset)545 Node* InterpreterAssembler::DispatchTo(Node* new_bytecode_offset) {
546 Node* target_bytecode = Load(
547 MachineType::Uint8(), BytecodeArrayTaggedPointer(), new_bytecode_offset);
548 if (kPointerSize == 8) {
549 target_bytecode = ChangeUint32ToUint64(target_bytecode);
550 }
551
552 if (FLAG_trace_ignition_dispatches) {
553 TraceBytecodeDispatch(target_bytecode);
554 }
555
556 Node* target_code_entry =
557 Load(MachineType::Pointer(), DispatchTableRawPointer(),
558 WordShl(target_bytecode, IntPtrConstant(kPointerSizeLog2)));
559
560 return DispatchToBytecodeHandlerEntry(target_code_entry, new_bytecode_offset);
561 }
562
DispatchToBytecodeHandler(Node * handler,Node * bytecode_offset)563 Node* InterpreterAssembler::DispatchToBytecodeHandler(Node* handler,
564 Node* bytecode_offset) {
565 Node* handler_entry =
566 IntPtrAdd(handler, IntPtrConstant(Code::kHeaderSize - kHeapObjectTag));
567 return DispatchToBytecodeHandlerEntry(handler_entry, bytecode_offset);
568 }
569
DispatchToBytecodeHandlerEntry(Node * handler_entry,Node * bytecode_offset)570 Node* InterpreterAssembler::DispatchToBytecodeHandlerEntry(
571 Node* handler_entry, Node* bytecode_offset) {
572 if (FLAG_trace_ignition) {
573 TraceBytecode(Runtime::kInterpreterTraceBytecodeExit);
574 }
575
576 InterpreterDispatchDescriptor descriptor(isolate());
577 Node* args[] = {GetAccumulatorUnchecked(), bytecode_offset,
578 BytecodeArrayTaggedPointer(), DispatchTableRawPointer()};
579 return TailCallBytecodeDispatch(descriptor, handler_entry, args);
580 }
581
DispatchWide(OperandScale operand_scale)582 void InterpreterAssembler::DispatchWide(OperandScale operand_scale) {
583 // Dispatching a wide bytecode requires treating the prefix
584 // bytecode a base pointer into the dispatch table and dispatching
585 // the bytecode that follows relative to this base.
586 //
587 // Indices 0-255 correspond to bytecodes with operand_scale == 0
588 // Indices 256-511 correspond to bytecodes with operand_scale == 1
589 // Indices 512-767 correspond to bytecodes with operand_scale == 2
590 Node* next_bytecode_offset = Advance(1);
591 Node* next_bytecode = Load(MachineType::Uint8(), BytecodeArrayTaggedPointer(),
592 next_bytecode_offset);
593 if (kPointerSize == 8) {
594 next_bytecode = ChangeUint32ToUint64(next_bytecode);
595 }
596
597 if (FLAG_trace_ignition_dispatches) {
598 TraceBytecodeDispatch(next_bytecode);
599 }
600
601 Node* base_index;
602 switch (operand_scale) {
603 case OperandScale::kDouble:
604 base_index = IntPtrConstant(1 << kBitsPerByte);
605 break;
606 case OperandScale::kQuadruple:
607 base_index = IntPtrConstant(2 << kBitsPerByte);
608 break;
609 default:
610 UNREACHABLE();
611 base_index = nullptr;
612 }
613 Node* target_index = IntPtrAdd(base_index, next_bytecode);
614 Node* target_code_entry =
615 Load(MachineType::Pointer(), DispatchTableRawPointer(),
616 WordShl(target_index, kPointerSizeLog2));
617
618 DispatchToBytecodeHandlerEntry(target_code_entry, next_bytecode_offset);
619 }
620
UpdateInterruptBudgetOnReturn()621 void InterpreterAssembler::UpdateInterruptBudgetOnReturn() {
622 // TODO(rmcilroy): Investigate whether it is worth supporting self
623 // optimization of primitive functions like FullCodegen.
624
625 // Update profiling count by -BytecodeOffset to simulate backedge to start of
626 // function.
627 Node* profiling_weight =
628 Int32Sub(Int32Constant(kHeapObjectTag + BytecodeArray::kHeaderSize),
629 BytecodeOffset());
630 UpdateInterruptBudget(profiling_weight);
631 }
632
StackCheckTriggeredInterrupt()633 Node* InterpreterAssembler::StackCheckTriggeredInterrupt() {
634 Node* sp = LoadStackPointer();
635 Node* stack_limit = Load(
636 MachineType::Pointer(),
637 ExternalConstant(ExternalReference::address_of_stack_limit(isolate())));
638 return UintPtrLessThan(sp, stack_limit);
639 }
640
Abort(BailoutReason bailout_reason)641 void InterpreterAssembler::Abort(BailoutReason bailout_reason) {
642 disable_stack_check_across_call_ = true;
643 Node* abort_id = SmiTag(Int32Constant(bailout_reason));
644 CallRuntime(Runtime::kAbort, GetContext(), abort_id);
645 disable_stack_check_across_call_ = false;
646 }
647
AbortIfWordNotEqual(Node * lhs,Node * rhs,BailoutReason bailout_reason)648 void InterpreterAssembler::AbortIfWordNotEqual(Node* lhs, Node* rhs,
649 BailoutReason bailout_reason) {
650 Label ok(this), abort(this, Label::kDeferred);
651 BranchIfWordEqual(lhs, rhs, &ok, &abort);
652
653 Bind(&abort);
654 Abort(bailout_reason);
655 Goto(&ok);
656
657 Bind(&ok);
658 }
659
TraceBytecode(Runtime::FunctionId function_id)660 void InterpreterAssembler::TraceBytecode(Runtime::FunctionId function_id) {
661 CallRuntime(function_id, GetContext(), BytecodeArrayTaggedPointer(),
662 SmiTag(BytecodeOffset()), GetAccumulatorUnchecked());
663 }
664
TraceBytecodeDispatch(Node * target_bytecode)665 void InterpreterAssembler::TraceBytecodeDispatch(Node* target_bytecode) {
666 Node* counters_table = ExternalConstant(
667 ExternalReference::interpreter_dispatch_counters(isolate()));
668 Node* source_bytecode_table_index = IntPtrConstant(
669 static_cast<int>(bytecode_) * (static_cast<int>(Bytecode::kLast) + 1));
670
671 Node* counter_offset =
672 WordShl(IntPtrAdd(source_bytecode_table_index, target_bytecode),
673 IntPtrConstant(kPointerSizeLog2));
674 Node* old_counter =
675 Load(MachineType::IntPtr(), counters_table, counter_offset);
676
677 Label counter_ok(this), counter_saturated(this, Label::kDeferred);
678
679 Node* counter_reached_max = WordEqual(
680 old_counter, IntPtrConstant(std::numeric_limits<uintptr_t>::max()));
681 BranchIf(counter_reached_max, &counter_saturated, &counter_ok);
682
683 Bind(&counter_ok);
684 {
685 Node* new_counter = IntPtrAdd(old_counter, IntPtrConstant(1));
686 StoreNoWriteBarrier(MachineType::PointerRepresentation(), counters_table,
687 counter_offset, new_counter);
688 Goto(&counter_saturated);
689 }
690
691 Bind(&counter_saturated);
692 }
693
694 // static
TargetSupportsUnalignedAccess()695 bool InterpreterAssembler::TargetSupportsUnalignedAccess() {
696 #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
697 return false;
698 #elif V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_PPC
699 return CpuFeatures::IsSupported(UNALIGNED_ACCESSES);
700 #elif V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_X87 || \
701 V8_TARGET_ARCH_S390
702 return true;
703 #else
704 #error "Unknown Architecture"
705 #endif
706 }
707
RegisterCount()708 Node* InterpreterAssembler::RegisterCount() {
709 Node* bytecode_array = LoadRegister(Register::bytecode_array());
710 Node* frame_size = LoadObjectField(
711 bytecode_array, BytecodeArray::kFrameSizeOffset, MachineType::Int32());
712 return Word32Sar(frame_size, Int32Constant(kPointerSizeLog2));
713 }
714
ExportRegisterFile(Node * array)715 Node* InterpreterAssembler::ExportRegisterFile(Node* array) {
716 if (FLAG_debug_code) {
717 Node* array_size = SmiUntag(LoadFixedArrayBaseLength(array));
718 AbortIfWordNotEqual(
719 array_size, RegisterCount(), kInvalidRegisterFileInGenerator);
720 }
721
722 Variable var_index(this, MachineRepresentation::kWord32);
723 var_index.Bind(Int32Constant(0));
724
725 // Iterate over register file and write values into array.
726 // The mapping of register to array index must match that used in
727 // BytecodeGraphBuilder::VisitResumeGenerator.
728 Label loop(this, &var_index), done_loop(this);
729 Goto(&loop);
730 Bind(&loop);
731 {
732 Node* index = var_index.value();
733 Node* condition = Int32LessThan(index, RegisterCount());
734 GotoUnless(condition, &done_loop);
735
736 Node* reg_index =
737 Int32Sub(Int32Constant(Register(0).ToOperand()), index);
738 Node* value = LoadRegister(ChangeInt32ToIntPtr(reg_index));
739
740 StoreFixedArrayElement(array, index, value);
741
742 var_index.Bind(Int32Add(index, Int32Constant(1)));
743 Goto(&loop);
744 }
745 Bind(&done_loop);
746
747 return array;
748 }
749
ImportRegisterFile(Node * array)750 Node* InterpreterAssembler::ImportRegisterFile(Node* array) {
751 if (FLAG_debug_code) {
752 Node* array_size = SmiUntag(LoadFixedArrayBaseLength(array));
753 AbortIfWordNotEqual(
754 array_size, RegisterCount(), kInvalidRegisterFileInGenerator);
755 }
756
757 Variable var_index(this, MachineRepresentation::kWord32);
758 var_index.Bind(Int32Constant(0));
759
760 // Iterate over array and write values into register file. Also erase the
761 // array contents to not keep them alive artificially.
762 Label loop(this, &var_index), done_loop(this);
763 Goto(&loop);
764 Bind(&loop);
765 {
766 Node* index = var_index.value();
767 Node* condition = Int32LessThan(index, RegisterCount());
768 GotoUnless(condition, &done_loop);
769
770 Node* value = LoadFixedArrayElement(array, index);
771
772 Node* reg_index =
773 Int32Sub(Int32Constant(Register(0).ToOperand()), index);
774 StoreRegister(value, ChangeInt32ToIntPtr(reg_index));
775
776 StoreFixedArrayElement(array, index, StaleRegisterConstant());
777
778 var_index.Bind(Int32Add(index, Int32Constant(1)));
779 Goto(&loop);
780 }
781 Bind(&done_loop);
782
783 return array;
784 }
785
786 } // namespace interpreter
787 } // namespace internal
788 } // namespace v8
789