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/bytecode-array-builder.h"
6
7 #include "src/globals.h"
8 #include "src/interpreter/bytecode-array-writer.h"
9 #include "src/interpreter/bytecode-dead-code-optimizer.h"
10 #include "src/interpreter/bytecode-label.h"
11 #include "src/interpreter/bytecode-peephole-optimizer.h"
12 #include "src/interpreter/bytecode-register-optimizer.h"
13 #include "src/interpreter/interpreter-intrinsics.h"
14
15 namespace v8 {
16 namespace internal {
17 namespace interpreter {
18
BytecodeArrayBuilder(Isolate * isolate,Zone * zone,int parameter_count,int context_count,int locals_count,FunctionLiteral * literal,SourcePositionTableBuilder::RecordingMode source_position_mode)19 BytecodeArrayBuilder::BytecodeArrayBuilder(
20 Isolate* isolate, Zone* zone, int parameter_count, int context_count,
21 int locals_count, FunctionLiteral* literal,
22 SourcePositionTableBuilder::RecordingMode source_position_mode)
23 : zone_(zone),
24 bytecode_generated_(false),
25 constant_array_builder_(zone, isolate->factory()->the_hole_value()),
26 handler_table_builder_(zone),
27 return_seen_in_block_(false),
28 parameter_count_(parameter_count),
29 local_register_count_(locals_count),
30 context_register_count_(context_count),
31 register_allocator_(fixed_register_count()),
32 bytecode_array_writer_(zone, &constant_array_builder_,
33 source_position_mode),
34 pipeline_(&bytecode_array_writer_),
35 register_optimizer_(nullptr) {
36 DCHECK_GE(parameter_count_, 0);
37 DCHECK_GE(context_register_count_, 0);
38 DCHECK_GE(local_register_count_, 0);
39
40 if (FLAG_ignition_deadcode) {
41 pipeline_ = new (zone) BytecodeDeadCodeOptimizer(pipeline_);
42 }
43
44 if (FLAG_ignition_peephole) {
45 pipeline_ = new (zone) BytecodePeepholeOptimizer(pipeline_);
46 }
47
48 if (FLAG_ignition_reo) {
49 register_optimizer_ = new (zone) BytecodeRegisterOptimizer(
50 zone, ®ister_allocator_, fixed_register_count(), parameter_count,
51 pipeline_);
52 }
53
54 return_position_ = literal ? literal->return_position() : kNoSourcePosition;
55 }
56
first_context_register() const57 Register BytecodeArrayBuilder::first_context_register() const {
58 DCHECK_GT(context_register_count_, 0);
59 return Register(local_register_count_);
60 }
61
last_context_register() const62 Register BytecodeArrayBuilder::last_context_register() const {
63 DCHECK_GT(context_register_count_, 0);
64 return Register(local_register_count_ + context_register_count_ - 1);
65 }
66
Parameter(int parameter_index) const67 Register BytecodeArrayBuilder::Parameter(int parameter_index) const {
68 DCHECK_GE(parameter_index, 0);
69 return Register::FromParameterIndex(parameter_index, parameter_count());
70 }
71
ToBytecodeArray(Isolate * isolate)72 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) {
73 DCHECK(return_seen_in_block_);
74 DCHECK(!bytecode_generated_);
75 bytecode_generated_ = true;
76
77 int register_count = total_register_count();
78
79 if (register_optimizer_) {
80 register_optimizer_->Flush();
81 register_count = register_optimizer_->maxiumum_register_index() + 1;
82 }
83
84 Handle<FixedArray> handler_table =
85 handler_table_builder()->ToHandlerTable(isolate);
86 return pipeline_->ToBytecodeArray(isolate, register_count, parameter_count(),
87 handler_table);
88 }
89
CurrentSourcePosition(Bytecode bytecode)90 BytecodeSourceInfo BytecodeArrayBuilder::CurrentSourcePosition(
91 Bytecode bytecode) {
92 BytecodeSourceInfo source_position;
93 if (latest_source_info_.is_valid()) {
94 // Statement positions need to be emitted immediately. Expression
95 // positions can be pushed back until a bytecode is found that can
96 // throw (if expression position filtering is turned on). We only
97 // invalidate the existing source position information if it is used.
98 if (latest_source_info_.is_statement() ||
99 !FLAG_ignition_filter_expression_positions ||
100 !Bytecodes::IsWithoutExternalSideEffects(bytecode)) {
101 source_position = latest_source_info_;
102 latest_source_info_.set_invalid();
103 }
104 }
105 return source_position;
106 }
107
108 namespace {
109
110 template <OperandTypeInfo type_info>
111 class UnsignedOperandHelper {
112 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,size_t value))113 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, size_t value)) {
114 DCHECK(IsValid(value));
115 return static_cast<uint32_t>(value);
116 }
117
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,int value))118 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, int value)) {
119 DCHECK_GE(value, 0);
120 return Convert(builder, static_cast<size_t>(value));
121 }
122
123 private:
IsValid(size_t value)124 static bool IsValid(size_t value) {
125 switch (type_info) {
126 case OperandTypeInfo::kFixedUnsignedByte:
127 return value <= kMaxUInt8;
128 case OperandTypeInfo::kFixedUnsignedShort:
129 return value <= kMaxUInt16;
130 case OperandTypeInfo::kScalableUnsignedByte:
131 return value <= kMaxUInt32;
132 default:
133 UNREACHABLE();
134 return false;
135 }
136 }
137 };
138
139 template <OperandType>
140 class OperandHelper {};
141
142 #define DEFINE_UNSIGNED_OPERAND_HELPER(Name, Type) \
143 template <> \
144 class OperandHelper<OperandType::k##Name> \
145 : public UnsignedOperandHelper<Type> {};
146 UNSIGNED_SCALAR_OPERAND_TYPE_LIST(DEFINE_UNSIGNED_OPERAND_HELPER)
147 #undef DEFINE_UNSIGNED_OPERAND_HELPER
148
149 template <>
150 class OperandHelper<OperandType::kImm> {
151 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,int value))152 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, int value)) {
153 return static_cast<uint32_t>(value);
154 }
155 };
156
157 template <>
158 class OperandHelper<OperandType::kReg> {
159 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,Register reg))160 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, Register reg)) {
161 return builder->GetInputRegisterOperand(reg);
162 }
163 };
164
165 template <>
166 class OperandHelper<OperandType::kRegList> {
167 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,RegisterList reg_list))168 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder,
169 RegisterList reg_list)) {
170 return builder->GetInputRegisterListOperand(reg_list);
171 }
172 };
173
174 template <>
175 class OperandHelper<OperandType::kRegPair> {
176 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,RegisterList reg_list))177 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder,
178 RegisterList reg_list)) {
179 DCHECK_EQ(reg_list.register_count(), 2);
180 return builder->GetInputRegisterListOperand(reg_list);
181 }
182 };
183
184 template <>
185 class OperandHelper<OperandType::kRegOut> {
186 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,Register reg))187 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, Register reg)) {
188 return builder->GetOutputRegisterOperand(reg);
189 }
190 };
191
192 template <>
193 class OperandHelper<OperandType::kRegOutPair> {
194 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,RegisterList reg_list))195 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder,
196 RegisterList reg_list)) {
197 DCHECK_EQ(2, reg_list.register_count());
198 return builder->GetOutputRegisterListOperand(reg_list);
199 }
200 };
201
202 template <>
203 class OperandHelper<OperandType::kRegOutTriple> {
204 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,RegisterList reg_list))205 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder,
206 RegisterList reg_list)) {
207 DCHECK_EQ(3, reg_list.register_count());
208 return builder->GetOutputRegisterListOperand(reg_list);
209 }
210 };
211
212 } // namespace
213
214 template <OperandType... operand_types>
215 class BytecodeNodeBuilder {
216 public:
217 template <typename... Operands>
INLINE(static BytecodeNode Make (BytecodeArrayBuilder * builder,BytecodeSourceInfo source_info,Bytecode bytecode,Operands...operands))218 INLINE(static BytecodeNode Make(BytecodeArrayBuilder* builder,
219 BytecodeSourceInfo source_info,
220 Bytecode bytecode, Operands... operands)) {
221 builder->PrepareToOutputBytecode(bytecode);
222 // The "OperandHelper<operand_types>::Convert(builder, operands)..." will
223 // expand both the OperandType... and Operands... parameter packs e.g. for:
224 // BytecodeNodeBuilder<OperandType::kReg, OperandType::kImm>::Make<
225 // Register, int>(..., Register reg, int immediate)
226 // the code will expand into:
227 // OperandHelper<OperandType::kReg>::Convert(builder, reg),
228 // OperandHelper<OperandType::kImm>::Convert(builder, immediate),
229 return BytecodeNode(
230 bytecode, OperandHelper<operand_types>::Convert(builder, operands)...,
231 source_info);
232 }
233 };
234
235 #define DEFINE_BYTECODE_OUTPUT(name, accumulator_use, ...) \
236 template <typename... Operands> \
237 void BytecodeArrayBuilder::Output##name(Operands... operands) { \
238 BytecodeNode node(BytecodeNodeBuilder<__VA_ARGS__>::Make<Operands...>( \
239 this, CurrentSourcePosition(Bytecode::k##name), Bytecode::k##name, \
240 operands...)); \
241 pipeline()->Write(&node); \
242 } \
243 \
244 template <typename... Operands> \
245 void BytecodeArrayBuilder::Output##name(BytecodeLabel* label, \
246 Operands... operands) { \
247 DCHECK(Bytecodes::IsJump(Bytecode::k##name)); \
248 BytecodeNode node(BytecodeNodeBuilder<__VA_ARGS__>::Make<Operands...>( \
249 this, CurrentSourcePosition(Bytecode::k##name), Bytecode::k##name, \
250 operands...)); \
251 pipeline()->WriteJump(&node, label); \
252 LeaveBasicBlock(); \
253 }
BYTECODE_LIST(DEFINE_BYTECODE_OUTPUT)254 BYTECODE_LIST(DEFINE_BYTECODE_OUTPUT)
255 #undef DEFINE_BYTECODE_OUTPUT
256
257 BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op,
258 Register reg,
259 int feedback_slot) {
260 switch (op) {
261 case Token::Value::ADD:
262 OutputAdd(reg, feedback_slot);
263 break;
264 case Token::Value::SUB:
265 OutputSub(reg, feedback_slot);
266 break;
267 case Token::Value::MUL:
268 OutputMul(reg, feedback_slot);
269 break;
270 case Token::Value::DIV:
271 OutputDiv(reg, feedback_slot);
272 break;
273 case Token::Value::MOD:
274 OutputMod(reg, feedback_slot);
275 break;
276 case Token::Value::BIT_OR:
277 OutputBitwiseOr(reg, feedback_slot);
278 break;
279 case Token::Value::BIT_XOR:
280 OutputBitwiseXor(reg, feedback_slot);
281 break;
282 case Token::Value::BIT_AND:
283 OutputBitwiseAnd(reg, feedback_slot);
284 break;
285 case Token::Value::SHL:
286 OutputShiftLeft(reg, feedback_slot);
287 break;
288 case Token::Value::SAR:
289 OutputShiftRight(reg, feedback_slot);
290 break;
291 case Token::Value::SHR:
292 OutputShiftRightLogical(reg, feedback_slot);
293 break;
294 default:
295 UNREACHABLE();
296 }
297 return *this;
298 }
299
CountOperation(Token::Value op,int feedback_slot)300 BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op,
301 int feedback_slot) {
302 if (op == Token::Value::ADD) {
303 OutputInc(feedback_slot);
304 } else {
305 DCHECK_EQ(op, Token::Value::SUB);
306 OutputDec(feedback_slot);
307 }
308 return *this;
309 }
310
LogicalNot()311 BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() {
312 OutputToBooleanLogicalNot();
313 return *this;
314 }
315
TypeOf()316 BytecodeArrayBuilder& BytecodeArrayBuilder::TypeOf() {
317 OutputTypeOf();
318 return *this;
319 }
320
CompareOperation(Token::Value op,Register reg,int feedback_slot)321 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(
322 Token::Value op, Register reg, int feedback_slot) {
323 switch (op) {
324 case Token::Value::EQ:
325 OutputTestEqual(reg, feedback_slot);
326 break;
327 case Token::Value::NE:
328 OutputTestNotEqual(reg, feedback_slot);
329 break;
330 case Token::Value::EQ_STRICT:
331 OutputTestEqualStrict(reg, feedback_slot);
332 break;
333 case Token::Value::LT:
334 OutputTestLessThan(reg, feedback_slot);
335 break;
336 case Token::Value::GT:
337 OutputTestGreaterThan(reg, feedback_slot);
338 break;
339 case Token::Value::LTE:
340 OutputTestLessThanOrEqual(reg, feedback_slot);
341 break;
342 case Token::Value::GTE:
343 OutputTestGreaterThanOrEqual(reg, feedback_slot);
344 break;
345 case Token::Value::INSTANCEOF:
346 OutputTestInstanceOf(reg);
347 break;
348 case Token::Value::IN:
349 OutputTestIn(reg);
350 break;
351 default:
352 UNREACHABLE();
353 }
354 return *this;
355 }
356
LoadConstantPoolEntry(size_t entry)357 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadConstantPoolEntry(
358 size_t entry) {
359 OutputLdaConstant(entry);
360 return *this;
361 }
362
LoadLiteral(v8::internal::Smi * smi)363 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
364 v8::internal::Smi* smi) {
365 int32_t raw_smi = smi->value();
366 if (raw_smi == 0) {
367 OutputLdaZero();
368 } else {
369 OutputLdaSmi(raw_smi);
370 }
371 return *this;
372 }
373
LoadLiteral(Handle<Object> object)374 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) {
375 size_t entry = GetConstantPoolEntry(object);
376 OutputLdaConstant(entry);
377 return *this;
378 }
379
LoadUndefined()380 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() {
381 OutputLdaUndefined();
382 return *this;
383 }
384
LoadNull()385 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() {
386 OutputLdaNull();
387 return *this;
388 }
389
LoadTheHole()390 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() {
391 OutputLdaTheHole();
392 return *this;
393 }
394
LoadTrue()395 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() {
396 OutputLdaTrue();
397 return *this;
398 }
399
LoadFalse()400 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() {
401 OutputLdaFalse();
402 return *this;
403 }
404
LoadAccumulatorWithRegister(Register reg)405 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister(
406 Register reg) {
407 if (register_optimizer_) {
408 register_optimizer_->DoLdar(reg, CurrentSourcePosition(Bytecode::kLdar));
409 } else {
410 OutputLdar(reg);
411 }
412 return *this;
413 }
414
StoreAccumulatorInRegister(Register reg)415 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
416 Register reg) {
417 if (register_optimizer_) {
418 register_optimizer_->DoStar(reg, CurrentSourcePosition(Bytecode::kStar));
419 } else {
420 OutputStar(reg);
421 }
422 return *this;
423 }
424
MoveRegister(Register from,Register to)425 BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from,
426 Register to) {
427 DCHECK(from != to);
428 if (register_optimizer_) {
429 register_optimizer_->DoMov(from, to, CurrentSourcePosition(Bytecode::kMov));
430 } else {
431 OutputMov(from, to);
432 }
433 return *this;
434 }
435
LoadGlobal(int feedback_slot,TypeofMode typeof_mode)436 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(int feedback_slot,
437 TypeofMode typeof_mode) {
438 if (typeof_mode == INSIDE_TYPEOF) {
439 OutputLdaGlobalInsideTypeof(feedback_slot);
440 } else {
441 DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF);
442 OutputLdaGlobal(feedback_slot);
443 }
444 return *this;
445 }
446
StoreGlobal(const Handle<String> name,int feedback_slot,LanguageMode language_mode)447 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal(
448 const Handle<String> name, int feedback_slot, LanguageMode language_mode) {
449 size_t name_index = GetConstantPoolEntry(name);
450 if (language_mode == SLOPPY) {
451 OutputStaGlobalSloppy(name_index, feedback_slot);
452 } else {
453 DCHECK_EQ(language_mode, STRICT);
454 OutputStaGlobalStrict(name_index, feedback_slot);
455 }
456 return *this;
457 }
458
LoadContextSlot(Register context,int slot_index,int depth)459 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context,
460 int slot_index,
461 int depth) {
462 if (context.is_current_context() && depth == 0) {
463 OutputLdaCurrentContextSlot(slot_index);
464 } else {
465 OutputLdaContextSlot(context, slot_index, depth);
466 }
467 return *this;
468 }
469
StoreContextSlot(Register context,int slot_index,int depth)470 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context,
471 int slot_index,
472 int depth) {
473 if (context.is_current_context() && depth == 0) {
474 OutputStaCurrentContextSlot(slot_index);
475 } else {
476 OutputStaContextSlot(context, slot_index, depth);
477 }
478 return *this;
479 }
480
LoadLookupSlot(const Handle<String> name,TypeofMode typeof_mode)481 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot(
482 const Handle<String> name, TypeofMode typeof_mode) {
483 size_t name_index = GetConstantPoolEntry(name);
484 if (typeof_mode == INSIDE_TYPEOF) {
485 OutputLdaLookupSlotInsideTypeof(name_index);
486 } else {
487 DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF);
488 OutputLdaLookupSlot(name_index);
489 }
490 return *this;
491 }
492
LoadLookupContextSlot(const Handle<String> name,TypeofMode typeof_mode,int slot_index,int depth)493 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupContextSlot(
494 const Handle<String> name, TypeofMode typeof_mode, int slot_index,
495 int depth) {
496 size_t name_index = GetConstantPoolEntry(name);
497 if (typeof_mode == INSIDE_TYPEOF) {
498 OutputLdaLookupContextSlotInsideTypeof(name_index, slot_index, depth);
499 } else {
500 DCHECK(typeof_mode == NOT_INSIDE_TYPEOF);
501 OutputLdaLookupContextSlot(name_index, slot_index, depth);
502 }
503 return *this;
504 }
505
LoadLookupGlobalSlot(const Handle<String> name,TypeofMode typeof_mode,int feedback_slot,int depth)506 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupGlobalSlot(
507 const Handle<String> name, TypeofMode typeof_mode, int feedback_slot,
508 int depth) {
509 size_t name_index = GetConstantPoolEntry(name);
510 if (typeof_mode == INSIDE_TYPEOF) {
511 OutputLdaLookupGlobalSlotInsideTypeof(name_index, feedback_slot, depth);
512 } else {
513 DCHECK(typeof_mode == NOT_INSIDE_TYPEOF);
514 OutputLdaLookupGlobalSlot(name_index, feedback_slot, depth);
515 }
516 return *this;
517 }
518
StoreLookupSlot(const Handle<String> name,LanguageMode language_mode)519 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot(
520 const Handle<String> name, LanguageMode language_mode) {
521 size_t name_index = GetConstantPoolEntry(name);
522 if (language_mode == SLOPPY) {
523 OutputStaLookupSlotSloppy(name_index);
524 } else {
525 DCHECK_EQ(language_mode, STRICT);
526 OutputStaLookupSlotStrict(name_index);
527 }
528 return *this;
529 }
530
LoadNamedProperty(Register object,const Handle<Name> name,int feedback_slot)531 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
532 Register object, const Handle<Name> name, int feedback_slot) {
533 size_t name_index = GetConstantPoolEntry(name);
534 OutputLdaNamedProperty(object, name_index, feedback_slot);
535 return *this;
536 }
537
LoadKeyedProperty(Register object,int feedback_slot)538 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty(
539 Register object, int feedback_slot) {
540 OutputLdaKeyedProperty(object, feedback_slot);
541 return *this;
542 }
543
StoreNamedProperty(Register object,const Handle<Name> name,int feedback_slot,LanguageMode language_mode)544 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty(
545 Register object, const Handle<Name> name, int feedback_slot,
546 LanguageMode language_mode) {
547 size_t name_index = GetConstantPoolEntry(name);
548 if (language_mode == SLOPPY) {
549 OutputStaNamedPropertySloppy(object, name_index, feedback_slot);
550 } else {
551 DCHECK_EQ(language_mode, STRICT);
552 OutputStaNamedPropertyStrict(object, name_index, feedback_slot);
553 }
554 return *this;
555 }
556
StoreKeyedProperty(Register object,Register key,int feedback_slot,LanguageMode language_mode)557 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
558 Register object, Register key, int feedback_slot,
559 LanguageMode language_mode) {
560 if (language_mode == SLOPPY) {
561 OutputStaKeyedPropertySloppy(object, key, feedback_slot);
562 } else {
563 DCHECK_EQ(language_mode, STRICT);
564 OutputStaKeyedPropertyStrict(object, key, feedback_slot);
565 }
566 return *this;
567 }
568
CreateClosure(size_t entry,int flags)569 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure(size_t entry,
570 int flags) {
571 OutputCreateClosure(entry, flags);
572 return *this;
573 }
574
CreateBlockContext(Handle<ScopeInfo> scope_info)575 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateBlockContext(
576 Handle<ScopeInfo> scope_info) {
577 size_t entry = GetConstantPoolEntry(scope_info);
578 OutputCreateBlockContext(entry);
579 return *this;
580 }
581
CreateCatchContext(Register exception,Handle<String> name,Handle<ScopeInfo> scope_info)582 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateCatchContext(
583 Register exception, Handle<String> name, Handle<ScopeInfo> scope_info) {
584 size_t name_index = GetConstantPoolEntry(name);
585 size_t scope_info_index = GetConstantPoolEntry(scope_info);
586 OutputCreateCatchContext(exception, name_index, scope_info_index);
587 return *this;
588 }
589
CreateFunctionContext(int slots)590 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateFunctionContext(int slots) {
591 OutputCreateFunctionContext(slots);
592 return *this;
593 }
594
CreateWithContext(Register object,Handle<ScopeInfo> scope_info)595 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateWithContext(
596 Register object, Handle<ScopeInfo> scope_info) {
597 size_t scope_info_index = GetConstantPoolEntry(scope_info);
598 OutputCreateWithContext(object, scope_info_index);
599 return *this;
600 }
601
CreateArguments(CreateArgumentsType type)602 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments(
603 CreateArgumentsType type) {
604 switch (type) {
605 case CreateArgumentsType::kMappedArguments:
606 OutputCreateMappedArguments();
607 break;
608 case CreateArgumentsType::kUnmappedArguments:
609 OutputCreateUnmappedArguments();
610 break;
611 case CreateArgumentsType::kRestParameter:
612 OutputCreateRestParameter();
613 break;
614 default:
615 UNREACHABLE();
616 }
617 return *this;
618 }
619
CreateRegExpLiteral(Handle<String> pattern,int literal_index,int flags)620 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral(
621 Handle<String> pattern, int literal_index, int flags) {
622 size_t pattern_entry = GetConstantPoolEntry(pattern);
623 OutputCreateRegExpLiteral(pattern_entry, literal_index, flags);
624 return *this;
625 }
626
CreateArrayLiteral(Handle<FixedArray> constant_elements,int literal_index,int flags)627 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral(
628 Handle<FixedArray> constant_elements, int literal_index, int flags) {
629 size_t constant_elements_entry = GetConstantPoolEntry(constant_elements);
630 OutputCreateArrayLiteral(constant_elements_entry, literal_index, flags);
631 return *this;
632 }
633
CreateObjectLiteral(Handle<FixedArray> constant_properties,int literal_index,int flags,Register output)634 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral(
635 Handle<FixedArray> constant_properties, int literal_index, int flags,
636 Register output) {
637 size_t constant_properties_entry = GetConstantPoolEntry(constant_properties);
638 OutputCreateObjectLiteral(constant_properties_entry, literal_index, flags,
639 output);
640 return *this;
641 }
642
PushContext(Register context)643 BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) {
644 OutputPushContext(context);
645 return *this;
646 }
647
PopContext(Register context)648 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) {
649 OutputPopContext(context);
650 return *this;
651 }
652
ConvertAccumulatorToObject(Register out)653 BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToObject(
654 Register out) {
655 OutputToObject(out);
656 return *this;
657 }
658
ConvertAccumulatorToName(Register out)659 BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToName(
660 Register out) {
661 OutputToName(out);
662 return *this;
663 }
664
ConvertAccumulatorToNumber(Register out)665 BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToNumber(
666 Register out) {
667 OutputToNumber(out);
668 return *this;
669 }
670
Bind(BytecodeLabel * label)671 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) {
672 // Flush the register optimizer when binding a label to ensure all
673 // expected registers are valid when jumping to this label.
674 if (register_optimizer_) register_optimizer_->Flush();
675 pipeline_->BindLabel(label);
676 LeaveBasicBlock();
677 return *this;
678 }
679
Bind(const BytecodeLabel & target,BytecodeLabel * label)680 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target,
681 BytecodeLabel* label) {
682 pipeline_->BindLabel(target, label);
683 LeaveBasicBlock();
684 return *this;
685 }
686
Jump(BytecodeLabel * label)687 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) {
688 OutputJump(label, 0);
689 return *this;
690 }
691
JumpIfTrue(BytecodeLabel * label)692 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(BytecodeLabel* label) {
693 // The peephole optimizer attempts to simplify JumpIfToBooleanTrue
694 // to JumpIfTrue.
695 OutputJumpIfToBooleanTrue(label, 0);
696 return *this;
697 }
698
JumpIfFalse(BytecodeLabel * label)699 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) {
700 OutputJumpIfToBooleanFalse(label, 0);
701 return *this;
702 }
703
JumpIfNull(BytecodeLabel * label)704 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) {
705 OutputJumpIfNull(label, 0);
706 return *this;
707 }
708
JumpIfUndefined(BytecodeLabel * label)709 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined(
710 BytecodeLabel* label) {
711 OutputJumpIfUndefined(label, 0);
712 return *this;
713 }
714
JumpIfNotHole(BytecodeLabel * label)715 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotHole(
716 BytecodeLabel* label) {
717 OutputJumpIfNotHole(label, 0);
718 return *this;
719 }
720
JumpLoop(BytecodeLabel * label,int loop_depth)721 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpLoop(BytecodeLabel* label,
722 int loop_depth) {
723 OutputJumpLoop(label, 0, loop_depth);
724 return *this;
725 }
726
StackCheck(int position)727 BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck(int position) {
728 if (position != kNoSourcePosition) {
729 // We need to attach a non-breakable source position to a stack
730 // check, so we simply add it as expression position. There can be
731 // a prior statement position from constructs like:
732 //
733 // do var x; while (false);
734 //
735 // A Nop could be inserted for empty statements, but since no code
736 // is associated with these positions, instead we force the stack
737 // check's expression position which eliminates the empty
738 // statement's position.
739 latest_source_info_.ForceExpressionPosition(position);
740 }
741 OutputStackCheck();
742 return *this;
743 }
744
Throw()745 BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() {
746 OutputThrow();
747 return *this;
748 }
749
ReThrow()750 BytecodeArrayBuilder& BytecodeArrayBuilder::ReThrow() {
751 OutputReThrow();
752 return *this;
753 }
754
Return()755 BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
756 SetReturnPosition();
757 OutputReturn();
758 return_seen_in_block_ = true;
759 return *this;
760 }
761
Debugger()762 BytecodeArrayBuilder& BytecodeArrayBuilder::Debugger() {
763 OutputDebugger();
764 return *this;
765 }
766
ForInPrepare(Register receiver,RegisterList cache_info_triple)767 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare(
768 Register receiver, RegisterList cache_info_triple) {
769 DCHECK_EQ(3, cache_info_triple.register_count());
770 OutputForInPrepare(receiver, cache_info_triple);
771 return *this;
772 }
773
ForInContinue(Register index,Register cache_length)774 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInContinue(
775 Register index, Register cache_length) {
776 OutputForInContinue(index, cache_length);
777 return *this;
778 }
779
ForInNext(Register receiver,Register index,RegisterList cache_type_array_pair,int feedback_slot)780 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext(
781 Register receiver, Register index, RegisterList cache_type_array_pair,
782 int feedback_slot) {
783 DCHECK_EQ(2, cache_type_array_pair.register_count());
784 OutputForInNext(receiver, index, cache_type_array_pair, feedback_slot);
785 return *this;
786 }
787
ForInStep(Register index)788 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) {
789 OutputForInStep(index);
790 return *this;
791 }
792
StoreModuleVariable(int cell_index,int depth)793 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreModuleVariable(int cell_index,
794 int depth) {
795 OutputStaModuleVariable(cell_index, depth);
796 return *this;
797 }
798
LoadModuleVariable(int cell_index,int depth)799 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadModuleVariable(int cell_index,
800 int depth) {
801 OutputLdaModuleVariable(cell_index, depth);
802 return *this;
803 }
804
SuspendGenerator(Register generator)805 BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator(
806 Register generator) {
807 OutputSuspendGenerator(generator);
808 return *this;
809 }
810
ResumeGenerator(Register generator)811 BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator(
812 Register generator) {
813 OutputResumeGenerator(generator);
814 return *this;
815 }
816
MarkHandler(int handler_id,HandlerTable::CatchPrediction catch_prediction)817 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkHandler(
818 int handler_id, HandlerTable::CatchPrediction catch_prediction) {
819 BytecodeLabel handler;
820 Bind(&handler);
821 handler_table_builder()->SetHandlerTarget(handler_id, handler.offset());
822 handler_table_builder()->SetPrediction(handler_id, catch_prediction);
823 return *this;
824 }
825
MarkTryBegin(int handler_id,Register context)826 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryBegin(int handler_id,
827 Register context) {
828 BytecodeLabel try_begin;
829 Bind(&try_begin);
830 handler_table_builder()->SetTryRegionStart(handler_id, try_begin.offset());
831 handler_table_builder()->SetContextRegister(handler_id, context);
832 return *this;
833 }
834
MarkTryEnd(int handler_id)835 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryEnd(int handler_id) {
836 BytecodeLabel try_end;
837 Bind(&try_end);
838 handler_table_builder()->SetTryRegionEnd(handler_id, try_end.offset());
839 return *this;
840 }
841
Call(Register callable,RegisterList args,int feedback_slot,Call::CallType call_type,TailCallMode tail_call_mode)842 BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
843 RegisterList args,
844 int feedback_slot,
845 Call::CallType call_type,
846 TailCallMode tail_call_mode) {
847 if (tail_call_mode == TailCallMode::kDisallow) {
848 if (call_type == Call::NAMED_PROPERTY_CALL ||
849 call_type == Call::KEYED_PROPERTY_CALL) {
850 OutputCallProperty(callable, args, args.register_count(), feedback_slot);
851 } else {
852 OutputCall(callable, args, args.register_count(), feedback_slot);
853 }
854 } else {
855 DCHECK(tail_call_mode == TailCallMode::kAllow);
856 OutputTailCall(callable, args, args.register_count(), feedback_slot);
857 }
858 return *this;
859 }
860
New(Register constructor,RegisterList args,int feedback_slot_id)861 BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor,
862 RegisterList args,
863 int feedback_slot_id) {
864 OutputNew(constructor, args, args.register_count(), feedback_slot_id);
865 return *this;
866 }
867
CallRuntime(Runtime::FunctionId function_id,RegisterList args)868 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
869 Runtime::FunctionId function_id, RegisterList args) {
870 DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size);
871 DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort);
872 if (IntrinsicsHelper::IsSupported(function_id)) {
873 IntrinsicsHelper::IntrinsicId intrinsic_id =
874 IntrinsicsHelper::FromRuntimeId(function_id);
875 OutputInvokeIntrinsic(static_cast<int>(intrinsic_id), args,
876 args.register_count());
877 } else {
878 OutputCallRuntime(static_cast<int>(function_id), args,
879 args.register_count());
880 }
881 return *this;
882 }
883
CallRuntime(Runtime::FunctionId function_id,Register arg)884 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
885 Runtime::FunctionId function_id, Register arg) {
886 return CallRuntime(function_id, RegisterList(arg.index(), 1));
887 }
888
CallRuntime(Runtime::FunctionId function_id)889 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
890 Runtime::FunctionId function_id) {
891 return CallRuntime(function_id, RegisterList());
892 }
893
CallRuntimeForPair(Runtime::FunctionId function_id,RegisterList args,RegisterList return_pair)894 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
895 Runtime::FunctionId function_id, RegisterList args,
896 RegisterList return_pair) {
897 DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size);
898 DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort);
899 DCHECK_EQ(2, return_pair.register_count());
900 OutputCallRuntimeForPair(static_cast<uint16_t>(function_id), args,
901 args.register_count(), return_pair);
902 return *this;
903 }
904
CallRuntimeForPair(Runtime::FunctionId function_id,Register arg,RegisterList return_pair)905 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
906 Runtime::FunctionId function_id, Register arg, RegisterList return_pair) {
907 return CallRuntimeForPair(function_id, RegisterList(arg.index(), 1),
908 return_pair);
909 }
910
CallJSRuntime(int context_index,RegisterList args)911 BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime(int context_index,
912 RegisterList args) {
913 OutputCallJSRuntime(context_index, args, args.register_count());
914 return *this;
915 }
916
Delete(Register object,LanguageMode language_mode)917 BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object,
918 LanguageMode language_mode) {
919 if (language_mode == SLOPPY) {
920 OutputDeletePropertySloppy(object);
921 } else {
922 DCHECK_EQ(language_mode, STRICT);
923 OutputDeletePropertyStrict(object);
924 }
925 return *this;
926 }
927
GetConstantPoolEntry(Handle<Object> object)928 size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) {
929 return constant_array_builder()->Insert(object);
930 }
931
AllocateConstantPoolEntry()932 size_t BytecodeArrayBuilder::AllocateConstantPoolEntry() {
933 return constant_array_builder()->AllocateEntry();
934 }
935
InsertConstantPoolEntryAt(size_t entry,Handle<Object> object)936 void BytecodeArrayBuilder::InsertConstantPoolEntryAt(size_t entry,
937 Handle<Object> object) {
938 constant_array_builder()->InsertAllocatedEntry(entry, object);
939 }
940
SetReturnPosition()941 void BytecodeArrayBuilder::SetReturnPosition() {
942 if (return_position_ == kNoSourcePosition) return;
943 latest_source_info_.MakeStatementPosition(return_position_);
944 }
945
RegisterIsValid(Register reg) const946 bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const {
947 if (!reg.is_valid()) {
948 return false;
949 }
950
951 if (reg.is_current_context() || reg.is_function_closure() ||
952 reg.is_new_target()) {
953 return true;
954 } else if (reg.is_parameter()) {
955 int parameter_index = reg.ToParameterIndex(parameter_count());
956 return parameter_index >= 0 && parameter_index < parameter_count();
957 } else if (reg.index() < fixed_register_count()) {
958 return true;
959 } else {
960 return register_allocator()->RegisterIsLive(reg);
961 }
962 }
963
RegisterListIsValid(RegisterList reg_list) const964 bool BytecodeArrayBuilder::RegisterListIsValid(RegisterList reg_list) const {
965 if (reg_list.register_count() == 0) {
966 return reg_list.first_register() == Register(0);
967 } else {
968 int first_reg_index = reg_list.first_register().index();
969 for (int i = 0; i < reg_list.register_count(); i++) {
970 if (!RegisterIsValid(Register(first_reg_index + i))) {
971 return false;
972 }
973 }
974 return true;
975 }
976 }
977
PrepareToOutputBytecode(Bytecode bytecode)978 void BytecodeArrayBuilder::PrepareToOutputBytecode(Bytecode bytecode) {
979 if (register_optimizer_) register_optimizer_->PrepareForBytecode(bytecode);
980 }
981
GetInputRegisterOperand(Register reg)982 uint32_t BytecodeArrayBuilder::GetInputRegisterOperand(Register reg) {
983 DCHECK(RegisterIsValid(reg));
984 if (register_optimizer_) reg = register_optimizer_->GetInputRegister(reg);
985 return static_cast<uint32_t>(reg.ToOperand());
986 }
987
GetOutputRegisterOperand(Register reg)988 uint32_t BytecodeArrayBuilder::GetOutputRegisterOperand(Register reg) {
989 DCHECK(RegisterIsValid(reg));
990 if (register_optimizer_) register_optimizer_->PrepareOutputRegister(reg);
991 return static_cast<uint32_t>(reg.ToOperand());
992 }
993
GetInputRegisterListOperand(RegisterList reg_list)994 uint32_t BytecodeArrayBuilder::GetInputRegisterListOperand(
995 RegisterList reg_list) {
996 DCHECK(RegisterListIsValid(reg_list));
997 if (register_optimizer_)
998 reg_list = register_optimizer_->GetInputRegisterList(reg_list);
999 return static_cast<uint32_t>(reg_list.first_register().ToOperand());
1000 }
1001
GetOutputRegisterListOperand(RegisterList reg_list)1002 uint32_t BytecodeArrayBuilder::GetOutputRegisterListOperand(
1003 RegisterList reg_list) {
1004 DCHECK(RegisterListIsValid(reg_list));
1005 if (register_optimizer_)
1006 register_optimizer_->PrepareOutputRegisterList(reg_list);
1007 return static_cast<uint32_t>(reg_list.first_register().ToOperand());
1008 }
1009
1010 } // namespace interpreter
1011 } // namespace internal
1012 } // namespace v8
1013