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