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-jump-table.h"
10 #include "src/interpreter/bytecode-label.h"
11 #include "src/interpreter/bytecode-node.h"
12 #include "src/interpreter/bytecode-register-optimizer.h"
13 #include "src/interpreter/bytecode-source-info.h"
14 #include "src/interpreter/interpreter-intrinsics.h"
15 #include "src/objects-inl.h"
16
17 namespace v8 {
18 namespace internal {
19 namespace interpreter {
20
21 class RegisterTransferWriter final
22 : public NON_EXPORTED_BASE(BytecodeRegisterOptimizer::BytecodeWriter),
23 public NON_EXPORTED_BASE(ZoneObject) {
24 public:
RegisterTransferWriter(BytecodeArrayBuilder * builder)25 RegisterTransferWriter(BytecodeArrayBuilder* builder) : builder_(builder) {}
~RegisterTransferWriter()26 ~RegisterTransferWriter() override {}
27
EmitLdar(Register input)28 void EmitLdar(Register input) override { builder_->OutputLdarRaw(input); }
29
EmitStar(Register output)30 void EmitStar(Register output) override { builder_->OutputStarRaw(output); }
31
EmitMov(Register input,Register output)32 void EmitMov(Register input, Register output) override {
33 builder_->OutputMovRaw(input, output);
34 }
35
36 private:
37 BytecodeArrayBuilder* builder_;
38 };
39
BytecodeArrayBuilder(Zone * zone,int parameter_count,int locals_count,FeedbackVectorSpec * feedback_vector_spec,SourcePositionTableBuilder::RecordingMode source_position_mode)40 BytecodeArrayBuilder::BytecodeArrayBuilder(
41 Zone* zone, int parameter_count, int locals_count,
42 FeedbackVectorSpec* feedback_vector_spec,
43 SourcePositionTableBuilder::RecordingMode source_position_mode)
44 : zone_(zone),
45 feedback_vector_spec_(feedback_vector_spec),
46 bytecode_generated_(false),
47 constant_array_builder_(zone),
48 handler_table_builder_(zone),
49 return_seen_in_block_(false),
50 parameter_count_(parameter_count),
51 local_register_count_(locals_count),
52 register_allocator_(fixed_register_count()),
53 bytecode_array_writer_(zone, &constant_array_builder_,
54 source_position_mode),
55 register_optimizer_(nullptr) {
56 DCHECK_GE(parameter_count_, 0);
57 DCHECK_GE(local_register_count_, 0);
58
59 if (FLAG_ignition_reo) {
60 register_optimizer_ = new (zone) BytecodeRegisterOptimizer(
61 zone, ®ister_allocator_, fixed_register_count(), parameter_count,
62 new (zone) RegisterTransferWriter(this));
63 }
64 }
65
Parameter(int parameter_index) const66 Register BytecodeArrayBuilder::Parameter(int parameter_index) const {
67 DCHECK_GE(parameter_index, 0);
68 // The parameter indices are shifted by 1 (receiver is the
69 // first entry).
70 return Register::FromParameterIndex(parameter_index + 1, parameter_count());
71 }
72
Receiver() const73 Register BytecodeArrayBuilder::Receiver() const {
74 return Register::FromParameterIndex(0, parameter_count());
75 }
76
Local(int index) const77 Register BytecodeArrayBuilder::Local(int index) const {
78 // TODO(marja): Make a DCHECK once crbug.com/706234 is fixed.
79 CHECK_LT(index, locals_count());
80 return Register(index);
81 }
82
ToBytecodeArray(Isolate * isolate)83 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) {
84 DCHECK(return_seen_in_block_);
85 DCHECK(!bytecode_generated_);
86 bytecode_generated_ = true;
87
88 int register_count = total_register_count();
89
90 if (register_optimizer_) {
91 register_optimizer_->Flush();
92 register_count = register_optimizer_->maxiumum_register_index() + 1;
93 }
94
95 Handle<ByteArray> handler_table =
96 handler_table_builder()->ToHandlerTable(isolate);
97 return bytecode_array_writer_.ToBytecodeArray(
98 isolate, register_count, parameter_count(), handler_table);
99 }
100
CurrentSourcePosition(Bytecode bytecode)101 BytecodeSourceInfo BytecodeArrayBuilder::CurrentSourcePosition(
102 Bytecode bytecode) {
103 BytecodeSourceInfo source_position;
104 if (latest_source_info_.is_valid()) {
105 // Statement positions need to be emitted immediately. Expression
106 // positions can be pushed back until a bytecode is found that can
107 // throw (if expression position filtering is turned on). We only
108 // invalidate the existing source position information if it is used.
109 if (latest_source_info_.is_statement() ||
110 !FLAG_ignition_filter_expression_positions ||
111 !Bytecodes::IsWithoutExternalSideEffects(bytecode)) {
112 source_position = latest_source_info_;
113 latest_source_info_.set_invalid();
114 }
115 }
116 return source_position;
117 }
118
SetDeferredSourceInfo(BytecodeSourceInfo source_info)119 void BytecodeArrayBuilder::SetDeferredSourceInfo(
120 BytecodeSourceInfo source_info) {
121 if (!source_info.is_valid()) return;
122 deferred_source_info_ = source_info;
123 }
124
AttachOrEmitDeferredSourceInfo(BytecodeNode * node)125 void BytecodeArrayBuilder::AttachOrEmitDeferredSourceInfo(BytecodeNode* node) {
126 if (!deferred_source_info_.is_valid()) return;
127 if (!node->source_info().is_valid()) {
128 node->set_source_info(deferred_source_info_);
129 } else if (deferred_source_info_.is_statement() &&
130 node->source_info().is_expression()) {
131 BytecodeSourceInfo source_position = node->source_info();
132 source_position.MakeStatementPosition(source_position.source_position());
133 node->set_source_info(source_position);
134 }
135 deferred_source_info_.set_invalid();
136 }
137
Write(BytecodeNode * node)138 void BytecodeArrayBuilder::Write(BytecodeNode* node) {
139 AttachOrEmitDeferredSourceInfo(node);
140 bytecode_array_writer_.Write(node);
141 }
142
WriteJump(BytecodeNode * node,BytecodeLabel * label)143 void BytecodeArrayBuilder::WriteJump(BytecodeNode* node, BytecodeLabel* label) {
144 AttachOrEmitDeferredSourceInfo(node);
145 bytecode_array_writer_.WriteJump(node, label);
146 }
147
WriteSwitch(BytecodeNode * node,BytecodeJumpTable * jump_table)148 void BytecodeArrayBuilder::WriteSwitch(BytecodeNode* node,
149 BytecodeJumpTable* jump_table) {
150 AttachOrEmitDeferredSourceInfo(node);
151 bytecode_array_writer_.WriteSwitch(node, jump_table);
152 }
153
OutputLdarRaw(Register reg)154 void BytecodeArrayBuilder::OutputLdarRaw(Register reg) {
155 uint32_t operand = static_cast<uint32_t>(reg.ToOperand());
156 BytecodeNode node(BytecodeNode::Ldar(BytecodeSourceInfo(), operand));
157 Write(&node);
158 }
159
OutputStarRaw(Register reg)160 void BytecodeArrayBuilder::OutputStarRaw(Register reg) {
161 uint32_t operand = static_cast<uint32_t>(reg.ToOperand());
162 BytecodeNode node(BytecodeNode::Star(BytecodeSourceInfo(), operand));
163 Write(&node);
164 }
165
OutputMovRaw(Register src,Register dest)166 void BytecodeArrayBuilder::OutputMovRaw(Register src, Register dest) {
167 uint32_t operand0 = static_cast<uint32_t>(src.ToOperand());
168 uint32_t operand1 = static_cast<uint32_t>(dest.ToOperand());
169 BytecodeNode node(
170 BytecodeNode::Mov(BytecodeSourceInfo(), operand0, operand1));
171 Write(&node);
172 }
173
174 namespace {
175
176 template <OperandTypeInfo type_info>
177 class UnsignedOperandHelper {
178 public:
Convert(BytecodeArrayBuilder * builder,size_t value)179 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
180 size_t value) {
181 DCHECK(IsValid(value));
182 return static_cast<uint32_t>(value);
183 }
184
Convert(BytecodeArrayBuilder * builder,int value)185 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, int value) {
186 DCHECK_GE(value, 0);
187 return Convert(builder, static_cast<size_t>(value));
188 }
189
190 private:
IsValid(size_t value)191 static bool IsValid(size_t value) {
192 switch (type_info) {
193 case OperandTypeInfo::kFixedUnsignedByte:
194 return value <= kMaxUInt8;
195 case OperandTypeInfo::kFixedUnsignedShort:
196 return value <= kMaxUInt16;
197 case OperandTypeInfo::kScalableUnsignedByte:
198 return value <= kMaxUInt32;
199 default:
200 UNREACHABLE();
201 }
202 }
203 };
204
205 template <OperandType>
206 class OperandHelper {};
207
208 #define DEFINE_UNSIGNED_OPERAND_HELPER(Name, Type) \
209 template <> \
210 class OperandHelper<OperandType::k##Name> \
211 : public UnsignedOperandHelper<Type> {};
212 UNSIGNED_FIXED_SCALAR_OPERAND_TYPE_LIST(DEFINE_UNSIGNED_OPERAND_HELPER)
213 UNSIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(DEFINE_UNSIGNED_OPERAND_HELPER)
214 #undef DEFINE_UNSIGNED_OPERAND_HELPER
215
216 template <>
217 class OperandHelper<OperandType::kImm> {
218 public:
Convert(BytecodeArrayBuilder * builder,int value)219 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder, int value) {
220 return static_cast<uint32_t>(value);
221 }
222 };
223
224 template <>
225 class OperandHelper<OperandType::kReg> {
226 public:
Convert(BytecodeArrayBuilder * builder,Register reg)227 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
228 Register reg) {
229 return builder->GetInputRegisterOperand(reg);
230 }
231 };
232
233 template <>
234 class OperandHelper<OperandType::kRegList> {
235 public:
Convert(BytecodeArrayBuilder * builder,RegisterList reg_list)236 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
237 RegisterList reg_list) {
238 return builder->GetInputRegisterListOperand(reg_list);
239 }
240 };
241
242 template <>
243 class OperandHelper<OperandType::kRegPair> {
244 public:
Convert(BytecodeArrayBuilder * builder,RegisterList reg_list)245 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
246 RegisterList reg_list) {
247 DCHECK_EQ(reg_list.register_count(), 2);
248 return builder->GetInputRegisterListOperand(reg_list);
249 }
250 };
251
252 template <>
253 class OperandHelper<OperandType::kRegOut> {
254 public:
Convert(BytecodeArrayBuilder * builder,Register reg)255 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
256 Register reg) {
257 return builder->GetOutputRegisterOperand(reg);
258 }
259 };
260
261 template <>
262 class OperandHelper<OperandType::kRegOutList> {
263 public:
Convert(BytecodeArrayBuilder * builder,RegisterList reg_list)264 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
265 RegisterList reg_list) {
266 return builder->GetOutputRegisterListOperand(reg_list);
267 }
268 };
269
270 template <>
271 class OperandHelper<OperandType::kRegOutPair> {
272 public:
Convert(BytecodeArrayBuilder * builder,RegisterList reg_list)273 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
274 RegisterList reg_list) {
275 DCHECK_EQ(2, reg_list.register_count());
276 return builder->GetOutputRegisterListOperand(reg_list);
277 }
278 };
279
280 template <>
281 class OperandHelper<OperandType::kRegOutTriple> {
282 public:
Convert(BytecodeArrayBuilder * builder,RegisterList reg_list)283 V8_INLINE static uint32_t Convert(BytecodeArrayBuilder* builder,
284 RegisterList reg_list) {
285 DCHECK_EQ(3, reg_list.register_count());
286 return builder->GetOutputRegisterListOperand(reg_list);
287 }
288 };
289
290 } // namespace
291
292 template <Bytecode bytecode, AccumulatorUse accumulator_use,
293 OperandType... operand_types>
294 class BytecodeNodeBuilder {
295 public:
296 template <typename... Operands>
Make(BytecodeArrayBuilder * builder,Operands...operands)297 V8_INLINE static BytecodeNode Make(BytecodeArrayBuilder* builder,
298 Operands... operands) {
299 static_assert(sizeof...(Operands) <= Bytecodes::kMaxOperands,
300 "too many operands for bytecode");
301 builder->PrepareToOutputBytecode<bytecode, accumulator_use>();
302 // The "OperandHelper<operand_types>::Convert(builder, operands)..." will
303 // expand both the OperandType... and Operands... parameter packs e.g. for:
304 // BytecodeNodeBuilder<OperandType::kReg, OperandType::kImm>::Make<
305 // Register, int>(..., Register reg, int immediate)
306 // the code will expand into:
307 // OperandHelper<OperandType::kReg>::Convert(builder, reg),
308 // OperandHelper<OperandType::kImm>::Convert(builder, immediate),
309 return BytecodeNode::Create<bytecode, accumulator_use, operand_types...>(
310 builder->CurrentSourcePosition(bytecode),
311 OperandHelper<operand_types>::Convert(builder, operands)...);
312 }
313 };
314
315 #define DEFINE_BYTECODE_OUTPUT(name, ...) \
316 template <typename... Operands> \
317 BytecodeNode BytecodeArrayBuilder::Create##name##Node( \
318 Operands... operands) { \
319 return BytecodeNodeBuilder<Bytecode::k##name, __VA_ARGS__>::Make( \
320 this, operands...); \
321 } \
322 \
323 template <typename... Operands> \
324 void BytecodeArrayBuilder::Output##name(Operands... operands) { \
325 BytecodeNode node(Create##name##Node(operands...)); \
326 Write(&node); \
327 } \
328 \
329 template <typename... Operands> \
330 void BytecodeArrayBuilder::Output##name(BytecodeLabel* label, \
331 Operands... operands) { \
332 DCHECK(Bytecodes::IsJump(Bytecode::k##name)); \
333 BytecodeNode node(Create##name##Node(operands...)); \
334 WriteJump(&node, label); \
335 LeaveBasicBlock(); \
336 }
BYTECODE_LIST(DEFINE_BYTECODE_OUTPUT)337 BYTECODE_LIST(DEFINE_BYTECODE_OUTPUT)
338 #undef DEFINE_BYTECODE_OUTPUT
339
340 void BytecodeArrayBuilder::OutputSwitchOnSmiNoFeedback(
341 BytecodeJumpTable* jump_table) {
342 BytecodeNode node(CreateSwitchOnSmiNoFeedbackNode(
343 jump_table->constant_pool_index(), jump_table->size(),
344 jump_table->case_value_base()));
345 WriteSwitch(&node, jump_table);
346 LeaveBasicBlock();
347 }
348
BinaryOperation(Token::Value op,Register reg,int feedback_slot)349 BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op,
350 Register reg,
351 int feedback_slot) {
352 switch (op) {
353 case Token::Value::ADD:
354 OutputAdd(reg, feedback_slot);
355 break;
356 case Token::Value::SUB:
357 OutputSub(reg, feedback_slot);
358 break;
359 case Token::Value::MUL:
360 OutputMul(reg, feedback_slot);
361 break;
362 case Token::Value::DIV:
363 OutputDiv(reg, feedback_slot);
364 break;
365 case Token::Value::MOD:
366 OutputMod(reg, feedback_slot);
367 break;
368 case Token::Value::EXP:
369 OutputExp(reg, feedback_slot);
370 break;
371 case Token::Value::BIT_OR:
372 OutputBitwiseOr(reg, feedback_slot);
373 break;
374 case Token::Value::BIT_XOR:
375 OutputBitwiseXor(reg, feedback_slot);
376 break;
377 case Token::Value::BIT_AND:
378 OutputBitwiseAnd(reg, feedback_slot);
379 break;
380 case Token::Value::SHL:
381 OutputShiftLeft(reg, feedback_slot);
382 break;
383 case Token::Value::SAR:
384 OutputShiftRight(reg, feedback_slot);
385 break;
386 case Token::Value::SHR:
387 OutputShiftRightLogical(reg, feedback_slot);
388 break;
389 default:
390 UNREACHABLE();
391 }
392 return *this;
393 }
394
BinaryOperationSmiLiteral(Token::Value op,Smi * literal,int feedback_slot)395 BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperationSmiLiteral(
396 Token::Value op, Smi* literal, int feedback_slot) {
397 switch (op) {
398 case Token::Value::ADD:
399 OutputAddSmi(literal->value(), feedback_slot);
400 break;
401 case Token::Value::SUB:
402 OutputSubSmi(literal->value(), feedback_slot);
403 break;
404 case Token::Value::MUL:
405 OutputMulSmi(literal->value(), feedback_slot);
406 break;
407 case Token::Value::DIV:
408 OutputDivSmi(literal->value(), feedback_slot);
409 break;
410 case Token::Value::MOD:
411 OutputModSmi(literal->value(), feedback_slot);
412 break;
413 case Token::Value::EXP:
414 OutputExpSmi(literal->value(), feedback_slot);
415 break;
416 case Token::Value::BIT_OR:
417 OutputBitwiseOrSmi(literal->value(), feedback_slot);
418 break;
419 case Token::Value::BIT_XOR:
420 OutputBitwiseXorSmi(literal->value(), feedback_slot);
421 break;
422 case Token::Value::BIT_AND:
423 OutputBitwiseAndSmi(literal->value(), feedback_slot);
424 break;
425 case Token::Value::SHL:
426 OutputShiftLeftSmi(literal->value(), feedback_slot);
427 break;
428 case Token::Value::SAR:
429 OutputShiftRightSmi(literal->value(), feedback_slot);
430 break;
431 case Token::Value::SHR:
432 OutputShiftRightLogicalSmi(literal->value(), feedback_slot);
433 break;
434 default:
435 UNREACHABLE();
436 }
437 return *this;
438 }
439
UnaryOperation(Token::Value op,int feedback_slot)440 BytecodeArrayBuilder& BytecodeArrayBuilder::UnaryOperation(Token::Value op,
441 int feedback_slot) {
442 switch (op) {
443 case Token::Value::INC:
444 OutputInc(feedback_slot);
445 break;
446 case Token::Value::DEC:
447 OutputDec(feedback_slot);
448 break;
449 case Token::Value::ADD:
450 OutputToNumber(feedback_slot);
451 break;
452 case Token::Value::SUB:
453 OutputNegate(feedback_slot);
454 break;
455 case Token::Value::BIT_NOT:
456 OutputBitwiseNot(feedback_slot);
457 break;
458 default:
459 UNREACHABLE();
460 }
461 return *this;
462 }
463
LogicalNot(ToBooleanMode mode)464 BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot(ToBooleanMode mode) {
465 if (mode == ToBooleanMode::kAlreadyBoolean) {
466 OutputLogicalNot();
467 } else {
468 DCHECK_EQ(mode, ToBooleanMode::kConvertToBoolean);
469 OutputToBooleanLogicalNot();
470 }
471 return *this;
472 }
473
TypeOf()474 BytecodeArrayBuilder& BytecodeArrayBuilder::TypeOf() {
475 OutputTypeOf();
476 return *this;
477 }
478
GetSuperConstructor(Register out)479 BytecodeArrayBuilder& BytecodeArrayBuilder::GetSuperConstructor(Register out) {
480 OutputGetSuperConstructor(out);
481 return *this;
482 }
483
CompareOperation(Token::Value op,Register reg,int feedback_slot)484 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(
485 Token::Value op, Register reg, int feedback_slot) {
486 switch (op) {
487 case Token::Value::EQ:
488 OutputTestEqual(reg, feedback_slot);
489 break;
490 case Token::Value::EQ_STRICT:
491 OutputTestEqualStrict(reg, feedback_slot);
492 break;
493 case Token::Value::LT:
494 OutputTestLessThan(reg, feedback_slot);
495 break;
496 case Token::Value::GT:
497 OutputTestGreaterThan(reg, feedback_slot);
498 break;
499 case Token::Value::LTE:
500 OutputTestLessThanOrEqual(reg, feedback_slot);
501 break;
502 case Token::Value::GTE:
503 OutputTestGreaterThanOrEqual(reg, feedback_slot);
504 break;
505 case Token::Value::INSTANCEOF:
506 OutputTestInstanceOf(reg, feedback_slot);
507 break;
508 default:
509 UNREACHABLE();
510 }
511 return *this;
512 }
513
CompareOperation(Token::Value op,Register reg)514 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(Token::Value op,
515 Register reg) {
516 switch (op) {
517 case Token::Value::IN:
518 OutputTestIn(reg);
519 break;
520 default:
521 UNREACHABLE();
522 }
523 return *this;
524 }
525
CompareReference(Register reg)526 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareReference(Register reg) {
527 OutputTestReferenceEqual(reg);
528 return *this;
529 }
530
CompareUndetectable()531 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareUndetectable() {
532 OutputTestUndetectable();
533 return *this;
534 }
535
CompareUndefined()536 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareUndefined() {
537 OutputTestUndefined();
538 return *this;
539 }
540
CompareNull()541 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareNull() {
542 OutputTestNull();
543 return *this;
544 }
545
CompareNil(Token::Value op,NilValue nil)546 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareNil(Token::Value op,
547 NilValue nil) {
548 if (op == Token::EQ) {
549 return CompareUndetectable();
550 } else {
551 DCHECK_EQ(Token::EQ_STRICT, op);
552 if (nil == kUndefinedValue) {
553 return CompareUndefined();
554 } else {
555 DCHECK_EQ(kNullValue, nil);
556 return CompareNull();
557 }
558 }
559 }
560
CompareTypeOf(TestTypeOfFlags::LiteralFlag literal_flag)561 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareTypeOf(
562 TestTypeOfFlags::LiteralFlag literal_flag) {
563 DCHECK_NE(literal_flag, TestTypeOfFlags::LiteralFlag::kOther);
564 OutputTestTypeOf(TestTypeOfFlags::Encode(literal_flag));
565 return *this;
566 }
567
LoadConstantPoolEntry(size_t entry)568 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadConstantPoolEntry(
569 size_t entry) {
570 OutputLdaConstant(entry);
571 return *this;
572 }
573
LoadLiteral(v8::internal::Smi * smi)574 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
575 v8::internal::Smi* smi) {
576 int32_t raw_smi = smi->value();
577 if (raw_smi == 0) {
578 OutputLdaZero();
579 } else {
580 OutputLdaSmi(raw_smi);
581 }
582 return *this;
583 }
584
LoadLiteral(double value)585 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(double value) {
586 size_t entry = GetConstantPoolEntry(value);
587 OutputLdaConstant(entry);
588 return *this;
589 }
590
LoadLiteral(const AstRawString * raw_string)591 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
592 const AstRawString* raw_string) {
593 size_t entry = GetConstantPoolEntry(raw_string);
594 OutputLdaConstant(entry);
595 return *this;
596 }
597
LoadLiteral(const Scope * scope)598 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(const Scope* scope) {
599 size_t entry = GetConstantPoolEntry(scope);
600 OutputLdaConstant(entry);
601 return *this;
602 }
603
LoadLiteral(AstBigInt bigint)604 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(AstBigInt bigint) {
605 size_t entry = GetConstantPoolEntry(bigint);
606 OutputLdaConstant(entry);
607 return *this;
608 }
609
LoadLiteral(AstSymbol symbol)610 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(AstSymbol symbol) {
611 size_t entry;
612 switch (symbol) {
613 case AstSymbol::kHomeObjectSymbol:
614 entry = HomeObjectSymbolConstantPoolEntry();
615 break;
616 // No default case so that we get a warning if AstSymbol changes
617 }
618 OutputLdaConstant(entry);
619 return *this;
620 }
621
LoadUndefined()622 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() {
623 OutputLdaUndefined();
624 return *this;
625 }
626
LoadNull()627 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() {
628 OutputLdaNull();
629 return *this;
630 }
631
LoadTheHole()632 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() {
633 OutputLdaTheHole();
634 return *this;
635 }
636
LoadTrue()637 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() {
638 OutputLdaTrue();
639 return *this;
640 }
641
LoadFalse()642 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() {
643 OutputLdaFalse();
644 return *this;
645 }
646
LoadBoolean(bool value)647 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadBoolean(bool value) {
648 return value ? LoadTrue() : LoadFalse();
649 }
650
LoadAccumulatorWithRegister(Register reg)651 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister(
652 Register reg) {
653 if (register_optimizer_) {
654 // Defer source info so that if we elide the bytecode transfer, we attach
655 // the source info to a subsequent bytecode if it exists.
656 SetDeferredSourceInfo(CurrentSourcePosition(Bytecode::kLdar));
657 register_optimizer_->DoLdar(reg);
658 } else {
659 OutputLdar(reg);
660 }
661 return *this;
662 }
663
StoreAccumulatorInRegister(Register reg)664 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
665 Register reg) {
666 if (register_optimizer_) {
667 // Defer source info so that if we elide the bytecode transfer, we attach
668 // the source info to a subsequent bytecode if it exists.
669 SetDeferredSourceInfo(CurrentSourcePosition(Bytecode::kStar));
670 register_optimizer_->DoStar(reg);
671 } else {
672 OutputStar(reg);
673 }
674 return *this;
675 }
676
MoveRegister(Register from,Register to)677 BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from,
678 Register to) {
679 DCHECK(from != to);
680 if (register_optimizer_) {
681 // Defer source info so that if we elide the bytecode transfer, we attach
682 // the source info to a subsequent bytecode if it exists.
683 SetDeferredSourceInfo(CurrentSourcePosition(Bytecode::kMov));
684 register_optimizer_->DoMov(from, to);
685 } else {
686 OutputMov(from, to);
687 }
688 return *this;
689 }
690
LoadGlobal(const AstRawString * name,int feedback_slot,TypeofMode typeof_mode)691 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(const AstRawString* name,
692 int feedback_slot,
693 TypeofMode typeof_mode) {
694 size_t name_index = GetConstantPoolEntry(name);
695 // Ensure that typeof mode is in sync with the IC slot kind.
696 DCHECK_EQ(GetTypeofModeFromSlotKind(feedback_vector_spec()->GetKind(
697 FeedbackVector::ToSlot(feedback_slot))),
698 typeof_mode);
699 if (typeof_mode == INSIDE_TYPEOF) {
700 OutputLdaGlobalInsideTypeof(name_index, feedback_slot);
701 } else {
702 DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF);
703 OutputLdaGlobal(name_index, feedback_slot);
704 }
705 return *this;
706 }
707
StoreGlobal(const AstRawString * name,int feedback_slot)708 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal(
709 const AstRawString* name, int feedback_slot) {
710 size_t name_index = GetConstantPoolEntry(name);
711 OutputStaGlobal(name_index, feedback_slot);
712 return *this;
713 }
714
LoadContextSlot(Register context,int slot_index,int depth,ContextSlotMutability mutability)715 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(
716 Register context, int slot_index, int depth,
717 ContextSlotMutability mutability) {
718 if (context.is_current_context() && depth == 0) {
719 if (mutability == kImmutableSlot) {
720 OutputLdaImmutableCurrentContextSlot(slot_index);
721 } else {
722 DCHECK_EQ(kMutableSlot, mutability);
723 OutputLdaCurrentContextSlot(slot_index);
724 }
725 } else if (mutability == kImmutableSlot) {
726 OutputLdaImmutableContextSlot(context, slot_index, depth);
727 } else {
728 DCHECK_EQ(mutability, kMutableSlot);
729 OutputLdaContextSlot(context, slot_index, depth);
730 }
731 return *this;
732 }
733
StoreContextSlot(Register context,int slot_index,int depth)734 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context,
735 int slot_index,
736 int depth) {
737 if (context.is_current_context() && depth == 0) {
738 OutputStaCurrentContextSlot(slot_index);
739 } else {
740 OutputStaContextSlot(context, slot_index, depth);
741 }
742 return *this;
743 }
744
LoadLookupSlot(const AstRawString * name,TypeofMode typeof_mode)745 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot(
746 const AstRawString* name, TypeofMode typeof_mode) {
747 size_t name_index = GetConstantPoolEntry(name);
748 if (typeof_mode == INSIDE_TYPEOF) {
749 OutputLdaLookupSlotInsideTypeof(name_index);
750 } else {
751 DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF);
752 OutputLdaLookupSlot(name_index);
753 }
754 return *this;
755 }
756
LoadLookupContextSlot(const AstRawString * name,TypeofMode typeof_mode,int slot_index,int depth)757 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupContextSlot(
758 const AstRawString* name, TypeofMode typeof_mode, int slot_index,
759 int depth) {
760 size_t name_index = GetConstantPoolEntry(name);
761 if (typeof_mode == INSIDE_TYPEOF) {
762 OutputLdaLookupContextSlotInsideTypeof(name_index, slot_index, depth);
763 } else {
764 DCHECK(typeof_mode == NOT_INSIDE_TYPEOF);
765 OutputLdaLookupContextSlot(name_index, slot_index, depth);
766 }
767 return *this;
768 }
769
LoadLookupGlobalSlot(const AstRawString * name,TypeofMode typeof_mode,int feedback_slot,int depth)770 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupGlobalSlot(
771 const AstRawString* name, TypeofMode typeof_mode, int feedback_slot,
772 int depth) {
773 size_t name_index = GetConstantPoolEntry(name);
774 if (typeof_mode == INSIDE_TYPEOF) {
775 OutputLdaLookupGlobalSlotInsideTypeof(name_index, feedback_slot, depth);
776 } else {
777 DCHECK(typeof_mode == NOT_INSIDE_TYPEOF);
778 OutputLdaLookupGlobalSlot(name_index, feedback_slot, depth);
779 }
780 return *this;
781 }
782
StoreLookupSlot(const AstRawString * name,LanguageMode language_mode,LookupHoistingMode lookup_hoisting_mode)783 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot(
784 const AstRawString* name, LanguageMode language_mode,
785 LookupHoistingMode lookup_hoisting_mode) {
786 size_t name_index = GetConstantPoolEntry(name);
787 uint8_t flags =
788 StoreLookupSlotFlags::Encode(language_mode, lookup_hoisting_mode);
789 OutputStaLookupSlot(name_index, flags);
790 return *this;
791 }
792
LoadNamedProperty(Register object,const AstRawString * name,int feedback_slot)793 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
794 Register object, const AstRawString* name, int feedback_slot) {
795 size_t name_index = GetConstantPoolEntry(name);
796 OutputLdaNamedProperty(object, name_index, feedback_slot);
797 return *this;
798 }
799
LoadKeyedProperty(Register object,int feedback_slot)800 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty(
801 Register object, int feedback_slot) {
802 OutputLdaKeyedProperty(object, feedback_slot);
803 return *this;
804 }
805
LoadIteratorProperty(Register object,int feedback_slot)806 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadIteratorProperty(
807 Register object, int feedback_slot) {
808 size_t name_index = IteratorSymbolConstantPoolEntry();
809 OutputLdaNamedProperty(object, name_index, feedback_slot);
810 return *this;
811 }
812
LoadAsyncIteratorProperty(Register object,int feedback_slot)813 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAsyncIteratorProperty(
814 Register object, int feedback_slot) {
815 size_t name_index = AsyncIteratorSymbolConstantPoolEntry();
816 OutputLdaNamedProperty(object, name_index, feedback_slot);
817 return *this;
818 }
819
StoreDataPropertyInLiteral(Register object,Register name,DataPropertyInLiteralFlags flags,int feedback_slot)820 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreDataPropertyInLiteral(
821 Register object, Register name, DataPropertyInLiteralFlags flags,
822 int feedback_slot) {
823 OutputStaDataPropertyInLiteral(object, name, flags, feedback_slot);
824 return *this;
825 }
826
CollectTypeProfile(int position)827 BytecodeArrayBuilder& BytecodeArrayBuilder::CollectTypeProfile(int position) {
828 OutputCollectTypeProfile(position);
829 return *this;
830 }
831
StoreNamedProperty(Register object,size_t name_index,int feedback_slot,LanguageMode language_mode)832 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty(
833 Register object, size_t name_index, int feedback_slot,
834 LanguageMode language_mode) {
835 // Ensure that language mode is in sync with the IC slot kind.
836 DCHECK_EQ(GetLanguageModeFromSlotKind(feedback_vector_spec()->GetKind(
837 FeedbackVector::ToSlot(feedback_slot))),
838 language_mode);
839 OutputStaNamedProperty(object, name_index, feedback_slot);
840 return *this;
841 }
842
StoreNamedProperty(Register object,const AstRawString * name,int feedback_slot,LanguageMode language_mode)843 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty(
844 Register object, const AstRawString* name, int feedback_slot,
845 LanguageMode language_mode) {
846 size_t name_index = GetConstantPoolEntry(name);
847 return StoreNamedProperty(object, name_index, feedback_slot, language_mode);
848 }
849
StoreNamedOwnProperty(Register object,const AstRawString * name,int feedback_slot)850 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedOwnProperty(
851 Register object, const AstRawString* name, int feedback_slot) {
852 size_t name_index = GetConstantPoolEntry(name);
853 // Ensure that the store operation is in sync with the IC slot kind.
854 DCHECK_EQ(
855 FeedbackSlotKind::kStoreOwnNamed,
856 feedback_vector_spec()->GetKind(FeedbackVector::ToSlot(feedback_slot)));
857 OutputStaNamedOwnProperty(object, name_index, feedback_slot);
858 return *this;
859 }
860
StoreKeyedProperty(Register object,Register key,int feedback_slot,LanguageMode language_mode)861 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
862 Register object, Register key, int feedback_slot,
863 LanguageMode language_mode) {
864 // Ensure that language mode is in sync with the IC slot kind.
865 DCHECK_EQ(GetLanguageModeFromSlotKind(feedback_vector_spec()->GetKind(
866 FeedbackVector::ToSlot(feedback_slot))),
867 language_mode);
868 OutputStaKeyedProperty(object, key, feedback_slot);
869 return *this;
870 }
871
StoreInArrayLiteral(Register array,Register index,int feedback_slot)872 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreInArrayLiteral(
873 Register array, Register index, int feedback_slot) {
874 OutputStaInArrayLiteral(array, index, feedback_slot);
875 return *this;
876 }
877
StoreHomeObjectProperty(Register object,int feedback_slot,LanguageMode language_mode)878 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreHomeObjectProperty(
879 Register object, int feedback_slot, LanguageMode language_mode) {
880 size_t name_index = HomeObjectSymbolConstantPoolEntry();
881 return StoreNamedProperty(object, name_index, feedback_slot, language_mode);
882 }
883
StoreClassFieldsInitializer(Register constructor,int feedback_slot)884 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreClassFieldsInitializer(
885 Register constructor, int feedback_slot) {
886 size_t name_index = ClassFieldsSymbolConstantPoolEntry();
887 return StoreNamedProperty(constructor, name_index, feedback_slot,
888 LanguageMode::kStrict);
889 }
890
LoadClassFieldsInitializer(Register constructor,int feedback_slot)891 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadClassFieldsInitializer(
892 Register constructor, int feedback_slot) {
893 size_t name_index = ClassFieldsSymbolConstantPoolEntry();
894 OutputLdaNamedProperty(constructor, name_index, feedback_slot);
895 return *this;
896 }
897
CreateClosure(size_t shared_function_info_entry,int slot,int flags)898 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure(
899 size_t shared_function_info_entry, int slot, int flags) {
900 OutputCreateClosure(shared_function_info_entry, slot, flags);
901 return *this;
902 }
903
CreateBlockContext(const Scope * scope)904 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateBlockContext(
905 const Scope* scope) {
906 size_t entry = GetConstantPoolEntry(scope);
907 OutputCreateBlockContext(entry);
908 return *this;
909 }
910
CreateCatchContext(Register exception,const Scope * scope)911 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateCatchContext(
912 Register exception, const Scope* scope) {
913 size_t scope_index = GetConstantPoolEntry(scope);
914 OutputCreateCatchContext(exception, scope_index);
915 return *this;
916 }
917
CreateFunctionContext(const Scope * scope,int slots)918 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateFunctionContext(
919 const Scope* scope, int slots) {
920 size_t scope_index = GetConstantPoolEntry(scope);
921 OutputCreateFunctionContext(scope_index, slots);
922 return *this;
923 }
924
CreateEvalContext(const Scope * scope,int slots)925 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateEvalContext(
926 const Scope* scope, int slots) {
927 size_t scope_index = GetConstantPoolEntry(scope);
928 OutputCreateEvalContext(scope_index, slots);
929 return *this;
930 }
931
CreateWithContext(Register object,const Scope * scope)932 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateWithContext(
933 Register object, const Scope* scope) {
934 size_t scope_index = GetConstantPoolEntry(scope);
935 OutputCreateWithContext(object, scope_index);
936 return *this;
937 }
938
CreateArguments(CreateArgumentsType type)939 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments(
940 CreateArgumentsType type) {
941 switch (type) {
942 case CreateArgumentsType::kMappedArguments:
943 OutputCreateMappedArguments();
944 break;
945 case CreateArgumentsType::kUnmappedArguments:
946 OutputCreateUnmappedArguments();
947 break;
948 case CreateArgumentsType::kRestParameter:
949 OutputCreateRestParameter();
950 break;
951 default:
952 UNREACHABLE();
953 }
954 return *this;
955 }
956
CreateRegExpLiteral(const AstRawString * pattern,int literal_index,int flags)957 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral(
958 const AstRawString* pattern, int literal_index, int flags) {
959 size_t pattern_entry = GetConstantPoolEntry(pattern);
960 OutputCreateRegExpLiteral(pattern_entry, literal_index, flags);
961 return *this;
962 }
963
CreateEmptyArrayLiteral(int literal_index)964 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateEmptyArrayLiteral(
965 int literal_index) {
966 OutputCreateEmptyArrayLiteral(literal_index);
967 return *this;
968 }
969
CreateArrayLiteral(size_t constant_elements_entry,int literal_index,int flags)970 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral(
971 size_t constant_elements_entry, int literal_index, int flags) {
972 OutputCreateArrayLiteral(constant_elements_entry, literal_index, flags);
973 return *this;
974 }
975
CreateObjectLiteral(size_t constant_properties_entry,int literal_index,int flags,Register output)976 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral(
977 size_t constant_properties_entry, int literal_index, int flags,
978 Register output) {
979 OutputCreateObjectLiteral(constant_properties_entry, literal_index, flags,
980 output);
981 return *this;
982 }
983
CreateEmptyObjectLiteral()984 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateEmptyObjectLiteral() {
985 OutputCreateEmptyObjectLiteral();
986 return *this;
987 }
988
CloneObject(Register source,int flags,int feedback_slot)989 BytecodeArrayBuilder& BytecodeArrayBuilder::CloneObject(Register source,
990 int flags,
991 int feedback_slot) {
992 OutputCloneObject(source, flags, feedback_slot);
993 return *this;
994 }
995
GetTemplateObject(size_t template_object_description_entry,int feedback_slot)996 BytecodeArrayBuilder& BytecodeArrayBuilder::GetTemplateObject(
997 size_t template_object_description_entry, int feedback_slot) {
998 OutputGetTemplateObject(template_object_description_entry, feedback_slot);
999 return *this;
1000 }
1001
PushContext(Register context)1002 BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) {
1003 OutputPushContext(context);
1004 return *this;
1005 }
1006
PopContext(Register context)1007 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) {
1008 OutputPopContext(context);
1009 return *this;
1010 }
1011
ToObject(Register out)1012 BytecodeArrayBuilder& BytecodeArrayBuilder::ToObject(Register out) {
1013 OutputToObject(out);
1014 return *this;
1015 }
1016
ToName(Register out)1017 BytecodeArrayBuilder& BytecodeArrayBuilder::ToName(Register out) {
1018 OutputToName(out);
1019 return *this;
1020 }
1021
ToString()1022 BytecodeArrayBuilder& BytecodeArrayBuilder::ToString() {
1023 OutputToString();
1024 return *this;
1025 }
1026
ToNumber(int feedback_slot)1027 BytecodeArrayBuilder& BytecodeArrayBuilder::ToNumber(int feedback_slot) {
1028 OutputToNumber(feedback_slot);
1029 return *this;
1030 }
1031
ToNumeric(int feedback_slot)1032 BytecodeArrayBuilder& BytecodeArrayBuilder::ToNumeric(int feedback_slot) {
1033 OutputToNumeric(feedback_slot);
1034 return *this;
1035 }
1036
Bind(BytecodeLabel * label)1037 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) {
1038 // Flush the register optimizer when binding a label to ensure all
1039 // expected registers are valid when jumping to this label.
1040 if (register_optimizer_) register_optimizer_->Flush();
1041 bytecode_array_writer_.BindLabel(label);
1042 LeaveBasicBlock();
1043 return *this;
1044 }
1045
Bind(const BytecodeLabel & target,BytecodeLabel * label)1046 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target,
1047 BytecodeLabel* label) {
1048 bytecode_array_writer_.BindLabel(target, label);
1049 LeaveBasicBlock();
1050 return *this;
1051 }
1052
Bind(BytecodeJumpTable * jump_table,int case_value)1053 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeJumpTable* jump_table,
1054 int case_value) {
1055 // Flush the register optimizer when binding a jump table entry to ensure
1056 // all expected registers are valid when jumping to this location.
1057 if (register_optimizer_) register_optimizer_->Flush();
1058 bytecode_array_writer_.BindJumpTableEntry(jump_table, case_value);
1059 LeaveBasicBlock();
1060 return *this;
1061 }
1062
Jump(BytecodeLabel * label)1063 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) {
1064 DCHECK(!label->is_bound());
1065 OutputJump(label, 0);
1066 return *this;
1067 }
1068
JumpIfTrue(ToBooleanMode mode,BytecodeLabel * label)1069 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(ToBooleanMode mode,
1070 BytecodeLabel* label) {
1071 DCHECK(!label->is_bound());
1072 if (mode == ToBooleanMode::kAlreadyBoolean) {
1073 OutputJumpIfTrue(label, 0);
1074 } else {
1075 DCHECK_EQ(mode, ToBooleanMode::kConvertToBoolean);
1076 OutputJumpIfToBooleanTrue(label, 0);
1077 }
1078 return *this;
1079 }
1080
JumpIfFalse(ToBooleanMode mode,BytecodeLabel * label)1081 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(ToBooleanMode mode,
1082 BytecodeLabel* label) {
1083 DCHECK(!label->is_bound());
1084 if (mode == ToBooleanMode::kAlreadyBoolean) {
1085 OutputJumpIfFalse(label, 0);
1086 } else {
1087 DCHECK_EQ(mode, ToBooleanMode::kConvertToBoolean);
1088 OutputJumpIfToBooleanFalse(label, 0);
1089 }
1090 return *this;
1091 }
1092
JumpIfNull(BytecodeLabel * label)1093 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) {
1094 DCHECK(!label->is_bound());
1095 OutputJumpIfNull(label, 0);
1096 return *this;
1097 }
1098
JumpIfNotNull(BytecodeLabel * label)1099 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotNull(
1100 BytecodeLabel* label) {
1101 DCHECK(!label->is_bound());
1102 OutputJumpIfNotNull(label, 0);
1103 return *this;
1104 }
1105
JumpIfUndefined(BytecodeLabel * label)1106 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined(
1107 BytecodeLabel* label) {
1108 DCHECK(!label->is_bound());
1109 OutputJumpIfUndefined(label, 0);
1110 return *this;
1111 }
1112
JumpIfNotUndefined(BytecodeLabel * label)1113 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotUndefined(
1114 BytecodeLabel* label) {
1115 DCHECK(!label->is_bound());
1116 OutputJumpIfNotUndefined(label, 0);
1117 return *this;
1118 }
1119
JumpIfNil(BytecodeLabel * label,Token::Value op,NilValue nil)1120 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNil(BytecodeLabel* label,
1121 Token::Value op,
1122 NilValue nil) {
1123 if (op == Token::EQ) {
1124 // TODO(rmcilroy): Implement JumpIfUndetectable.
1125 return CompareUndetectable().JumpIfTrue(ToBooleanMode::kAlreadyBoolean,
1126 label);
1127 } else {
1128 DCHECK_EQ(Token::EQ_STRICT, op);
1129 if (nil == kUndefinedValue) {
1130 return JumpIfUndefined(label);
1131 } else {
1132 DCHECK_EQ(kNullValue, nil);
1133 return JumpIfNull(label);
1134 }
1135 }
1136 }
1137
JumpIfNotNil(BytecodeLabel * label,Token::Value op,NilValue nil)1138 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotNil(BytecodeLabel* label,
1139 Token::Value op,
1140 NilValue nil) {
1141 if (op == Token::EQ) {
1142 // TODO(rmcilroy): Implement JumpIfUndetectable.
1143 return CompareUndetectable().JumpIfFalse(ToBooleanMode::kAlreadyBoolean,
1144 label);
1145 } else {
1146 DCHECK_EQ(Token::EQ_STRICT, op);
1147 if (nil == kUndefinedValue) {
1148 return JumpIfNotUndefined(label);
1149 } else {
1150 DCHECK_EQ(kNullValue, nil);
1151 return JumpIfNotNull(label);
1152 }
1153 }
1154 }
1155
JumpIfJSReceiver(BytecodeLabel * label)1156 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfJSReceiver(
1157 BytecodeLabel* label) {
1158 DCHECK(!label->is_bound());
1159 OutputJumpIfJSReceiver(label, 0);
1160 return *this;
1161 }
1162
JumpLoop(BytecodeLabel * label,int loop_depth)1163 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpLoop(BytecodeLabel* label,
1164 int loop_depth) {
1165 DCHECK(label->is_bound());
1166 OutputJumpLoop(label, 0, loop_depth);
1167 return *this;
1168 }
1169
SwitchOnSmiNoFeedback(BytecodeJumpTable * jump_table)1170 BytecodeArrayBuilder& BytecodeArrayBuilder::SwitchOnSmiNoFeedback(
1171 BytecodeJumpTable* jump_table) {
1172 OutputSwitchOnSmiNoFeedback(jump_table);
1173 return *this;
1174 }
1175
StackCheck(int position)1176 BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck(int position) {
1177 if (position != kNoSourcePosition) {
1178 // We need to attach a non-breakable source position to a stack
1179 // check, so we simply add it as expression position. There can be
1180 // a prior statement position from constructs like:
1181 //
1182 // do var x; while (false);
1183 //
1184 // A Nop could be inserted for empty statements, but since no code
1185 // is associated with these positions, instead we force the stack
1186 // check's expression position which eliminates the empty
1187 // statement's position.
1188 latest_source_info_.ForceExpressionPosition(position);
1189 }
1190 OutputStackCheck();
1191 return *this;
1192 }
1193
SetPendingMessage()1194 BytecodeArrayBuilder& BytecodeArrayBuilder::SetPendingMessage() {
1195 OutputSetPendingMessage();
1196 return *this;
1197 }
1198
Throw()1199 BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() {
1200 OutputThrow();
1201 return *this;
1202 }
1203
ReThrow()1204 BytecodeArrayBuilder& BytecodeArrayBuilder::ReThrow() {
1205 OutputReThrow();
1206 return *this;
1207 }
1208
Abort(AbortReason reason)1209 BytecodeArrayBuilder& BytecodeArrayBuilder::Abort(AbortReason reason) {
1210 DCHECK_LT(reason, AbortReason::kLastErrorMessage);
1211 DCHECK_GE(reason, AbortReason::kNoReason);
1212 OutputAbort(static_cast<int>(reason));
1213 return *this;
1214 }
1215
Return()1216 BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
1217 OutputReturn();
1218 return_seen_in_block_ = true;
1219 return *this;
1220 }
1221
ThrowReferenceErrorIfHole(const AstRawString * name)1222 BytecodeArrayBuilder& BytecodeArrayBuilder::ThrowReferenceErrorIfHole(
1223 const AstRawString* name) {
1224 size_t entry = GetConstantPoolEntry(name);
1225 OutputThrowReferenceErrorIfHole(entry);
1226 return *this;
1227 }
1228
ThrowSuperNotCalledIfHole()1229 BytecodeArrayBuilder& BytecodeArrayBuilder::ThrowSuperNotCalledIfHole() {
1230 OutputThrowSuperNotCalledIfHole();
1231 return *this;
1232 }
1233
ThrowSuperAlreadyCalledIfNotHole()1234 BytecodeArrayBuilder& BytecodeArrayBuilder::ThrowSuperAlreadyCalledIfNotHole() {
1235 OutputThrowSuperAlreadyCalledIfNotHole();
1236 return *this;
1237 }
1238
Debugger()1239 BytecodeArrayBuilder& BytecodeArrayBuilder::Debugger() {
1240 OutputDebugger();
1241 return *this;
1242 }
1243
IncBlockCounter(int coverage_array_slot)1244 BytecodeArrayBuilder& BytecodeArrayBuilder::IncBlockCounter(
1245 int coverage_array_slot) {
1246 OutputIncBlockCounter(coverage_array_slot);
1247 return *this;
1248 }
1249
ForInEnumerate(Register receiver)1250 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInEnumerate(Register receiver) {
1251 OutputForInEnumerate(receiver);
1252 return *this;
1253 }
1254
ForInPrepare(RegisterList cache_info_triple,int feedback_slot)1255 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare(
1256 RegisterList cache_info_triple, int feedback_slot) {
1257 DCHECK_EQ(3, cache_info_triple.register_count());
1258 OutputForInPrepare(cache_info_triple, feedback_slot);
1259 return *this;
1260 }
1261
ForInContinue(Register index,Register cache_length)1262 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInContinue(
1263 Register index, Register cache_length) {
1264 OutputForInContinue(index, cache_length);
1265 return *this;
1266 }
1267
ForInNext(Register receiver,Register index,RegisterList cache_type_array_pair,int feedback_slot)1268 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext(
1269 Register receiver, Register index, RegisterList cache_type_array_pair,
1270 int feedback_slot) {
1271 DCHECK_EQ(2, cache_type_array_pair.register_count());
1272 OutputForInNext(receiver, index, cache_type_array_pair, feedback_slot);
1273 return *this;
1274 }
1275
ForInStep(Register index)1276 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) {
1277 OutputForInStep(index);
1278 return *this;
1279 }
1280
StoreModuleVariable(int cell_index,int depth)1281 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreModuleVariable(int cell_index,
1282 int depth) {
1283 OutputStaModuleVariable(cell_index, depth);
1284 return *this;
1285 }
1286
LoadModuleVariable(int cell_index,int depth)1287 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadModuleVariable(int cell_index,
1288 int depth) {
1289 OutputLdaModuleVariable(cell_index, depth);
1290 return *this;
1291 }
1292
SuspendGenerator(Register generator,RegisterList registers,int suspend_id)1293 BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator(
1294 Register generator, RegisterList registers, int suspend_id) {
1295 OutputSuspendGenerator(generator, registers, registers.register_count(),
1296 suspend_id);
1297 return *this;
1298 }
1299
SwitchOnGeneratorState(Register generator,BytecodeJumpTable * jump_table)1300 BytecodeArrayBuilder& BytecodeArrayBuilder::SwitchOnGeneratorState(
1301 Register generator, BytecodeJumpTable* jump_table) {
1302 DCHECK_EQ(jump_table->case_value_base(), 0);
1303 BytecodeNode node(CreateSwitchOnGeneratorStateNode(
1304 generator, jump_table->constant_pool_index(), jump_table->size()));
1305 WriteSwitch(&node, jump_table);
1306 LeaveBasicBlock();
1307 return *this;
1308 }
1309
ResumeGenerator(Register generator,RegisterList registers)1310 BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator(
1311 Register generator, RegisterList registers) {
1312 OutputResumeGenerator(generator, registers, registers.register_count());
1313 return *this;
1314 }
1315
MarkHandler(int handler_id,HandlerTable::CatchPrediction catch_prediction)1316 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkHandler(
1317 int handler_id, HandlerTable::CatchPrediction catch_prediction) {
1318 BytecodeLabel handler;
1319 Bind(&handler);
1320 handler_table_builder()->SetHandlerTarget(handler_id, handler.offset());
1321 handler_table_builder()->SetPrediction(handler_id, catch_prediction);
1322 return *this;
1323 }
1324
MarkTryBegin(int handler_id,Register context)1325 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryBegin(int handler_id,
1326 Register context) {
1327 BytecodeLabel try_begin;
1328 Bind(&try_begin);
1329 handler_table_builder()->SetTryRegionStart(handler_id, try_begin.offset());
1330 handler_table_builder()->SetContextRegister(handler_id, context);
1331 return *this;
1332 }
1333
MarkTryEnd(int handler_id)1334 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryEnd(int handler_id) {
1335 BytecodeLabel try_end;
1336 Bind(&try_end);
1337 handler_table_builder()->SetTryRegionEnd(handler_id, try_end.offset());
1338 return *this;
1339 }
1340
CallProperty(Register callable,RegisterList args,int feedback_slot)1341 BytecodeArrayBuilder& BytecodeArrayBuilder::CallProperty(Register callable,
1342 RegisterList args,
1343 int feedback_slot) {
1344 if (args.register_count() == 1) {
1345 OutputCallProperty0(callable, args[0], feedback_slot);
1346 } else if (args.register_count() == 2) {
1347 OutputCallProperty1(callable, args[0], args[1], feedback_slot);
1348 } else if (args.register_count() == 3) {
1349 OutputCallProperty2(callable, args[0], args[1], args[2], feedback_slot);
1350 } else {
1351 OutputCallProperty(callable, args, args.register_count(), feedback_slot);
1352 }
1353 return *this;
1354 }
1355
CallUndefinedReceiver(Register callable,RegisterList args,int feedback_slot)1356 BytecodeArrayBuilder& BytecodeArrayBuilder::CallUndefinedReceiver(
1357 Register callable, RegisterList args, int feedback_slot) {
1358 if (args.register_count() == 0) {
1359 OutputCallUndefinedReceiver0(callable, feedback_slot);
1360 } else if (args.register_count() == 1) {
1361 OutputCallUndefinedReceiver1(callable, args[0], feedback_slot);
1362 } else if (args.register_count() == 2) {
1363 OutputCallUndefinedReceiver2(callable, args[0], args[1], feedback_slot);
1364 } else {
1365 OutputCallUndefinedReceiver(callable, args, args.register_count(),
1366 feedback_slot);
1367 }
1368 return *this;
1369 }
1370
CallAnyReceiver(Register callable,RegisterList args,int feedback_slot)1371 BytecodeArrayBuilder& BytecodeArrayBuilder::CallAnyReceiver(Register callable,
1372 RegisterList args,
1373 int feedback_slot) {
1374 OutputCallAnyReceiver(callable, args, args.register_count(), feedback_slot);
1375 return *this;
1376 }
1377
CallWithSpread(Register callable,RegisterList args,int feedback_slot)1378 BytecodeArrayBuilder& BytecodeArrayBuilder::CallWithSpread(Register callable,
1379 RegisterList args,
1380 int feedback_slot) {
1381 OutputCallWithSpread(callable, args, args.register_count(), feedback_slot);
1382 return *this;
1383 }
1384
Construct(Register constructor,RegisterList args,int feedback_slot_id)1385 BytecodeArrayBuilder& BytecodeArrayBuilder::Construct(Register constructor,
1386 RegisterList args,
1387 int feedback_slot_id) {
1388 OutputConstruct(constructor, args, args.register_count(), feedback_slot_id);
1389 return *this;
1390 }
1391
ConstructWithSpread(Register constructor,RegisterList args,int feedback_slot_id)1392 BytecodeArrayBuilder& BytecodeArrayBuilder::ConstructWithSpread(
1393 Register constructor, RegisterList args, int feedback_slot_id) {
1394 OutputConstructWithSpread(constructor, args, args.register_count(),
1395 feedback_slot_id);
1396 return *this;
1397 }
1398
CallRuntime(Runtime::FunctionId function_id,RegisterList args)1399 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
1400 Runtime::FunctionId function_id, RegisterList args) {
1401 DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size);
1402 DCHECK_LE(Bytecodes::SizeForUnsignedOperand(function_id),
1403 OperandSize::kShort);
1404 if (IntrinsicsHelper::IsSupported(function_id)) {
1405 IntrinsicsHelper::IntrinsicId intrinsic_id =
1406 IntrinsicsHelper::FromRuntimeId(function_id);
1407 OutputInvokeIntrinsic(static_cast<int>(intrinsic_id), args,
1408 args.register_count());
1409 } else {
1410 OutputCallRuntime(static_cast<int>(function_id), args,
1411 args.register_count());
1412 }
1413 return *this;
1414 }
1415
CallRuntime(Runtime::FunctionId function_id,Register arg)1416 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
1417 Runtime::FunctionId function_id, Register arg) {
1418 return CallRuntime(function_id, RegisterList(arg));
1419 }
1420
CallRuntime(Runtime::FunctionId function_id)1421 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
1422 Runtime::FunctionId function_id) {
1423 return CallRuntime(function_id, RegisterList());
1424 }
1425
CallRuntimeForPair(Runtime::FunctionId function_id,RegisterList args,RegisterList return_pair)1426 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
1427 Runtime::FunctionId function_id, RegisterList args,
1428 RegisterList return_pair) {
1429 DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size);
1430 DCHECK_LE(Bytecodes::SizeForUnsignedOperand(function_id),
1431 OperandSize::kShort);
1432 DCHECK_EQ(2, return_pair.register_count());
1433 OutputCallRuntimeForPair(static_cast<uint16_t>(function_id), args,
1434 args.register_count(), return_pair);
1435 return *this;
1436 }
1437
CallRuntimeForPair(Runtime::FunctionId function_id,Register arg,RegisterList return_pair)1438 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
1439 Runtime::FunctionId function_id, Register arg, RegisterList return_pair) {
1440 return CallRuntimeForPair(function_id, RegisterList(arg), return_pair);
1441 }
1442
CallJSRuntime(int context_index,RegisterList args)1443 BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime(int context_index,
1444 RegisterList args) {
1445 OutputCallJSRuntime(context_index, args, args.register_count());
1446 return *this;
1447 }
1448
Delete(Register object,LanguageMode language_mode)1449 BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object,
1450 LanguageMode language_mode) {
1451 if (language_mode == LanguageMode::kSloppy) {
1452 OutputDeletePropertySloppy(object);
1453 } else {
1454 DCHECK_EQ(language_mode, LanguageMode::kStrict);
1455 OutputDeletePropertyStrict(object);
1456 }
1457 return *this;
1458 }
1459
GetConstantPoolEntry(const AstRawString * raw_string)1460 size_t BytecodeArrayBuilder::GetConstantPoolEntry(
1461 const AstRawString* raw_string) {
1462 return constant_array_builder()->Insert(raw_string);
1463 }
1464
GetConstantPoolEntry(AstBigInt bigint)1465 size_t BytecodeArrayBuilder::GetConstantPoolEntry(AstBigInt bigint) {
1466 return constant_array_builder()->Insert(bigint);
1467 }
1468
GetConstantPoolEntry(const Scope * scope)1469 size_t BytecodeArrayBuilder::GetConstantPoolEntry(const Scope* scope) {
1470 return constant_array_builder()->Insert(scope);
1471 }
1472
GetConstantPoolEntry(double number)1473 size_t BytecodeArrayBuilder::GetConstantPoolEntry(double number) {
1474 return constant_array_builder()->Insert(number);
1475 }
1476
1477 #define ENTRY_GETTER(NAME, ...) \
1478 size_t BytecodeArrayBuilder::NAME##ConstantPoolEntry() { \
1479 return constant_array_builder()->Insert##NAME(); \
1480 }
SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_GETTER)1481 SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_GETTER)
1482 #undef ENTRY_GETTER
1483
1484 BytecodeJumpTable* BytecodeArrayBuilder::AllocateJumpTable(
1485 int size, int case_value_base) {
1486 DCHECK_GT(size, 0);
1487
1488 size_t constant_pool_index = constant_array_builder()->InsertJumpTable(size);
1489
1490 return new (zone())
1491 BytecodeJumpTable(constant_pool_index, size, case_value_base, zone());
1492 }
1493
AllocateDeferredConstantPoolEntry()1494 size_t BytecodeArrayBuilder::AllocateDeferredConstantPoolEntry() {
1495 return constant_array_builder()->InsertDeferred();
1496 }
1497
SetDeferredConstantPoolEntry(size_t entry,Handle<Object> object)1498 void BytecodeArrayBuilder::SetDeferredConstantPoolEntry(size_t entry,
1499 Handle<Object> object) {
1500 constant_array_builder()->SetDeferredAt(entry, object);
1501 }
1502
RegisterIsValid(Register reg) const1503 bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const {
1504 if (!reg.is_valid()) {
1505 return false;
1506 }
1507
1508 if (reg.is_current_context() || reg.is_function_closure()) {
1509 return true;
1510 } else if (reg.is_parameter()) {
1511 int parameter_index = reg.ToParameterIndex(parameter_count());
1512 return parameter_index >= 0 && parameter_index < parameter_count();
1513 } else if (reg.index() < fixed_register_count()) {
1514 return true;
1515 } else {
1516 return register_allocator()->RegisterIsLive(reg);
1517 }
1518 }
1519
RegisterListIsValid(RegisterList reg_list) const1520 bool BytecodeArrayBuilder::RegisterListIsValid(RegisterList reg_list) const {
1521 if (reg_list.register_count() == 0) {
1522 return reg_list.first_register() == Register(0);
1523 } else {
1524 int first_reg_index = reg_list.first_register().index();
1525 for (int i = 0; i < reg_list.register_count(); i++) {
1526 if (!RegisterIsValid(Register(first_reg_index + i))) {
1527 return false;
1528 }
1529 }
1530 return true;
1531 }
1532 }
1533
1534 template <Bytecode bytecode, AccumulatorUse accumulator_use>
PrepareToOutputBytecode()1535 void BytecodeArrayBuilder::PrepareToOutputBytecode() {
1536 if (register_optimizer_)
1537 register_optimizer_->PrepareForBytecode<bytecode, accumulator_use>();
1538 }
1539
GetInputRegisterOperand(Register reg)1540 uint32_t BytecodeArrayBuilder::GetInputRegisterOperand(Register reg) {
1541 DCHECK(RegisterIsValid(reg));
1542 if (register_optimizer_) reg = register_optimizer_->GetInputRegister(reg);
1543 return static_cast<uint32_t>(reg.ToOperand());
1544 }
1545
GetOutputRegisterOperand(Register reg)1546 uint32_t BytecodeArrayBuilder::GetOutputRegisterOperand(Register reg) {
1547 DCHECK(RegisterIsValid(reg));
1548 if (register_optimizer_) register_optimizer_->PrepareOutputRegister(reg);
1549 return static_cast<uint32_t>(reg.ToOperand());
1550 }
1551
GetInputRegisterListOperand(RegisterList reg_list)1552 uint32_t BytecodeArrayBuilder::GetInputRegisterListOperand(
1553 RegisterList reg_list) {
1554 DCHECK(RegisterListIsValid(reg_list));
1555 if (register_optimizer_)
1556 reg_list = register_optimizer_->GetInputRegisterList(reg_list);
1557 return static_cast<uint32_t>(reg_list.first_register().ToOperand());
1558 }
1559
GetOutputRegisterListOperand(RegisterList reg_list)1560 uint32_t BytecodeArrayBuilder::GetOutputRegisterListOperand(
1561 RegisterList reg_list) {
1562 DCHECK(RegisterListIsValid(reg_list));
1563 if (register_optimizer_)
1564 register_optimizer_->PrepareOutputRegisterList(reg_list);
1565 return static_cast<uint32_t>(reg_list.first_register().ToOperand());
1566 }
1567
operator <<(std::ostream & os,const BytecodeArrayBuilder::ToBooleanMode & mode)1568 std::ostream& operator<<(std::ostream& os,
1569 const BytecodeArrayBuilder::ToBooleanMode& mode) {
1570 switch (mode) {
1571 case BytecodeArrayBuilder::ToBooleanMode::kAlreadyBoolean:
1572 return os << "AlreadyBoolean";
1573 case BytecodeArrayBuilder::ToBooleanMode::kConvertToBoolean:
1574 return os << "ConvertToBoolean";
1575 }
1576 UNREACHABLE();
1577 }
1578
1579 } // namespace interpreter
1580 } // namespace internal
1581 } // namespace v8
1582