blob: 1b15fc666866589257a593c0a232cbc1c3437900 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
7namespace v8 {
8namespace internal {
9namespace interpreter {
10
11class BytecodeArrayBuilder::PreviousBytecodeHelper {
12 public:
13 explicit PreviousBytecodeHelper(const BytecodeArrayBuilder& array_builder)
14 : array_builder_(array_builder),
15 previous_bytecode_start_(array_builder_.last_bytecode_start_) {
16 // This helper is expected to be instantiated only when the last bytecode is
17 // in the same basic block.
18 DCHECK(array_builder_.LastBytecodeInSameBlock());
19 }
20
21 // Returns the previous bytecode in the same basic block.
22 MUST_USE_RESULT Bytecode GetBytecode() const {
23 DCHECK_EQ(array_builder_.last_bytecode_start_, previous_bytecode_start_);
24 return Bytecodes::FromByte(
25 array_builder_.bytecodes()->at(previous_bytecode_start_));
26 }
27
28 // Returns the operand at operand_index for the previous bytecode in the
29 // same basic block.
30 MUST_USE_RESULT uint32_t GetOperand(int operand_index) const {
31 DCHECK_EQ(array_builder_.last_bytecode_start_, previous_bytecode_start_);
32 Bytecode bytecode = GetBytecode();
33 DCHECK_GE(operand_index, 0);
34 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode));
35 size_t operand_offset =
36 previous_bytecode_start_ +
37 Bytecodes::GetOperandOffset(bytecode, operand_index);
38 OperandSize size = Bytecodes::GetOperandSize(bytecode, operand_index);
39 switch (size) {
40 default:
41 case OperandSize::kNone:
42 UNREACHABLE();
43 case OperandSize::kByte:
44 return static_cast<uint32_t>(
45 array_builder_.bytecodes()->at(operand_offset));
46 case OperandSize::kShort:
47 uint16_t operand =
48 (array_builder_.bytecodes()->at(operand_offset) << 8) +
49 array_builder_.bytecodes()->at(operand_offset + 1);
50 return static_cast<uint32_t>(operand);
51 }
52 }
53
54 Handle<Object> GetConstantForIndexOperand(int operand_index) const {
55 return array_builder_.constant_array_builder()->At(
56 GetOperand(operand_index));
57 }
58
59 private:
60 const BytecodeArrayBuilder& array_builder_;
61 size_t previous_bytecode_start_;
62
63 DISALLOW_COPY_AND_ASSIGN(PreviousBytecodeHelper);
64};
65
66
67BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone)
68 : isolate_(isolate),
69 zone_(zone),
70 bytecodes_(zone),
71 bytecode_generated_(false),
72 constant_array_builder_(isolate, zone),
73 last_block_end_(0),
74 last_bytecode_start_(~0),
75 exit_seen_in_block_(false),
76 unbound_jumps_(0),
77 parameter_count_(-1),
78 local_register_count_(-1),
79 context_register_count_(-1),
80 temporary_register_count_(0),
81 free_temporaries_(zone) {}
82
83
84BytecodeArrayBuilder::~BytecodeArrayBuilder() { DCHECK_EQ(0, unbound_jumps_); }
85
86
87void BytecodeArrayBuilder::set_locals_count(int number_of_locals) {
88 local_register_count_ = number_of_locals;
89 DCHECK_LE(context_register_count_, 0);
90}
91
92
93void BytecodeArrayBuilder::set_parameter_count(int number_of_parameters) {
94 parameter_count_ = number_of_parameters;
95}
96
97
98void BytecodeArrayBuilder::set_context_count(int number_of_contexts) {
99 context_register_count_ = number_of_contexts;
100 DCHECK_GE(local_register_count_, 0);
101}
102
103
104Register BytecodeArrayBuilder::first_context_register() const {
105 DCHECK_GT(context_register_count_, 0);
106 return Register(local_register_count_);
107}
108
109
110Register BytecodeArrayBuilder::last_context_register() const {
111 DCHECK_GT(context_register_count_, 0);
112 return Register(local_register_count_ + context_register_count_ - 1);
113}
114
115
116Register BytecodeArrayBuilder::first_temporary_register() const {
117 DCHECK_GT(temporary_register_count_, 0);
118 return Register(fixed_register_count());
119}
120
121
122Register BytecodeArrayBuilder::last_temporary_register() const {
123 DCHECK_GT(temporary_register_count_, 0);
124 return Register(fixed_register_count() + temporary_register_count_ - 1);
125}
126
127
128Register BytecodeArrayBuilder::Parameter(int parameter_index) const {
129 DCHECK_GE(parameter_index, 0);
130 return Register::FromParameterIndex(parameter_index, parameter_count());
131}
132
133
134bool BytecodeArrayBuilder::RegisterIsParameterOrLocal(Register reg) const {
135 return reg.is_parameter() || reg.index() < locals_count();
136}
137
138
139bool BytecodeArrayBuilder::RegisterIsTemporary(Register reg) const {
140 return temporary_register_count_ > 0 && first_temporary_register() <= reg &&
141 reg <= last_temporary_register();
142}
143
144
145Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
146 DCHECK_EQ(bytecode_generated_, false);
147 EnsureReturn();
148
149 int bytecode_size = static_cast<int>(bytecodes_.size());
150 int register_count = fixed_register_count() + temporary_register_count_;
151 int frame_size = register_count * kPointerSize;
152 Factory* factory = isolate_->factory();
153 Handle<FixedArray> constant_pool =
154 constant_array_builder()->ToFixedArray(factory);
155 Handle<BytecodeArray> output =
156 factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size,
157 parameter_count(), constant_pool);
158 bytecode_generated_ = true;
159 return output;
160}
161
162
163template <size_t N>
164void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t(&operands)[N]) {
165 // Don't output dead code.
166 if (exit_seen_in_block_) return;
167
168 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), static_cast<int>(N));
169 last_bytecode_start_ = bytecodes()->size();
170 bytecodes()->push_back(Bytecodes::ToByte(bytecode));
171 for (int i = 0; i < static_cast<int>(N); i++) {
172 DCHECK(OperandIsValid(bytecode, i, operands[i]));
173 switch (Bytecodes::GetOperandSize(bytecode, i)) {
174 case OperandSize::kNone:
175 UNREACHABLE();
176 case OperandSize::kByte:
177 bytecodes()->push_back(static_cast<uint8_t>(operands[i]));
178 break;
179 case OperandSize::kShort: {
180 uint8_t operand_bytes[2];
181 WriteUnalignedUInt16(operand_bytes, operands[i]);
182 bytecodes()->insert(bytecodes()->end(), operand_bytes,
183 operand_bytes + 2);
184 break;
185 }
186 }
187 }
188}
189
190
191void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0,
192 uint32_t operand1, uint32_t operand2,
193 uint32_t operand3) {
194 uint32_t operands[] = {operand0, operand1, operand2, operand3};
195 Output(bytecode, operands);
196}
197
198
199void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0,
200 uint32_t operand1, uint32_t operand2) {
201 uint32_t operands[] = {operand0, operand1, operand2};
202 Output(bytecode, operands);
203}
204
205
206void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0,
207 uint32_t operand1) {
208 uint32_t operands[] = {operand0, operand1};
209 Output(bytecode, operands);
210}
211
212
213void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0) {
214 uint32_t operands[] = {operand0};
215 Output(bytecode, operands);
216}
217
218
219void BytecodeArrayBuilder::Output(Bytecode bytecode) {
220 // Don't output dead code.
221 if (exit_seen_in_block_) return;
222
223 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 0);
224 last_bytecode_start_ = bytecodes()->size();
225 bytecodes()->push_back(Bytecodes::ToByte(bytecode));
226}
227
228
229BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op,
230 Register reg,
231 Strength strength) {
232 if (is_strong(strength)) {
233 UNIMPLEMENTED();
234 }
235
236 Output(BytecodeForBinaryOperation(op), reg.ToOperand());
237 return *this;
238}
239
240
241BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op,
242 Strength strength) {
243 if (is_strong(strength)) {
244 UNIMPLEMENTED();
245 }
246
247 Output(BytecodeForCountOperation(op));
248 return *this;
249}
250
251
252BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() {
253 Output(Bytecode::kLogicalNot);
254 return *this;
255}
256
257
258BytecodeArrayBuilder& BytecodeArrayBuilder::TypeOf() {
259 Output(Bytecode::kTypeOf);
260 return *this;
261}
262
263
264BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(
265 Token::Value op, Register reg, Strength strength) {
266 if (is_strong(strength)) {
267 UNIMPLEMENTED();
268 }
269
270 Output(BytecodeForCompareOperation(op), reg.ToOperand());
271 return *this;
272}
273
274
275BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
276 v8::internal::Smi* smi) {
277 int32_t raw_smi = smi->value();
278 if (raw_smi == 0) {
279 Output(Bytecode::kLdaZero);
280 } else if (raw_smi >= -128 && raw_smi <= 127) {
281 Output(Bytecode::kLdaSmi8, static_cast<uint8_t>(raw_smi));
282 } else {
283 LoadLiteral(Handle<Object>(smi, isolate_));
284 }
285 return *this;
286}
287
288
289BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) {
290 size_t entry = GetConstantPoolEntry(object);
291 if (FitsInIdx8Operand(entry)) {
292 Output(Bytecode::kLdaConstant, static_cast<uint8_t>(entry));
293 } else if (FitsInIdx16Operand(entry)) {
294 Output(Bytecode::kLdaConstantWide, static_cast<uint16_t>(entry));
295 } else {
296 UNIMPLEMENTED();
297 }
298 return *this;
299}
300
301
302BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() {
303 Output(Bytecode::kLdaUndefined);
304 return *this;
305}
306
307
308BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() {
309 Output(Bytecode::kLdaNull);
310 return *this;
311}
312
313
314BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() {
315 Output(Bytecode::kLdaTheHole);
316 return *this;
317}
318
319
320BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() {
321 Output(Bytecode::kLdaTrue);
322 return *this;
323}
324
325
326BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() {
327 Output(Bytecode::kLdaFalse);
328 return *this;
329}
330
331
332BytecodeArrayBuilder& BytecodeArrayBuilder::LoadBooleanConstant(bool value) {
333 if (value) {
334 LoadTrue();
335 } else {
336 LoadFalse();
337 }
338 return *this;
339}
340
341
342BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister(
343 Register reg) {
344 if (!IsRegisterInAccumulator(reg)) {
345 Output(Bytecode::kLdar, reg.ToOperand());
346 }
347 return *this;
348}
349
350
351BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
352 Register reg) {
353 // TODO(oth): Avoid storing the accumulator in the register if the
354 // previous bytecode loaded the accumulator with the same register.
355 //
356 // TODO(oth): If the previous bytecode is a MOV into this register,
357 // the previous instruction can be removed. The logic for determining
358 // these redundant MOVs appears complex.
359 Output(Bytecode::kStar, reg.ToOperand());
360 if (!IsRegisterInAccumulator(reg)) {
361 Output(Bytecode::kStar, reg.ToOperand());
362 }
363 return *this;
364}
365
366
367BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from,
368 Register to) {
369 DCHECK(from != to);
370 Output(Bytecode::kMov, from.ToOperand(), to.ToOperand());
371 return *this;
372}
373
374
375BytecodeArrayBuilder& BytecodeArrayBuilder::ExchangeRegisters(Register reg0,
376 Register reg1) {
377 DCHECK(reg0 != reg1);
378 if (FitsInReg8Operand(reg0)) {
379 Output(Bytecode::kExchange, reg0.ToOperand(), reg1.ToWideOperand());
380 } else if (FitsInReg8Operand(reg1)) {
381 Output(Bytecode::kExchange, reg1.ToOperand(), reg0.ToWideOperand());
382 } else {
383 Output(Bytecode::kExchangeWide, reg0.ToWideOperand(), reg1.ToWideOperand());
384 }
385 return *this;
386}
387
388
389BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(
390 const Handle<String> name, int feedback_slot, LanguageMode language_mode,
391 TypeofMode typeof_mode) {
392 // TODO(rmcilroy): Potentially store language and typeof information in an
393 // operand rather than having extra bytecodes.
394 Bytecode bytecode = BytecodeForLoadGlobal(language_mode, typeof_mode);
395 size_t name_index = GetConstantPoolEntry(name);
396 if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) {
397 Output(bytecode, static_cast<uint8_t>(name_index),
398 static_cast<uint8_t>(feedback_slot));
399 } else if (FitsInIdx16Operand(name_index) &&
400 FitsInIdx16Operand(feedback_slot)) {
401 Output(BytecodeForWideOperands(bytecode), static_cast<uint16_t>(name_index),
402 static_cast<uint16_t>(feedback_slot));
403 } else {
404 UNIMPLEMENTED();
405 }
406 return *this;
407}
408
409
410BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal(
411 const Handle<String> name, int feedback_slot, LanguageMode language_mode) {
412 Bytecode bytecode = BytecodeForStoreGlobal(language_mode);
413 size_t name_index = GetConstantPoolEntry(name);
414 if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) {
415 Output(bytecode, static_cast<uint8_t>(name_index),
416 static_cast<uint8_t>(feedback_slot));
417 } else if (FitsInIdx16Operand(name_index) &&
418 FitsInIdx16Operand(feedback_slot)) {
419 Output(BytecodeForWideOperands(bytecode), static_cast<uint16_t>(name_index),
420 static_cast<uint16_t>(feedback_slot));
421 } else {
422 UNIMPLEMENTED();
423 }
424 return *this;
425}
426
427
428BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context,
429 int slot_index) {
430 DCHECK(slot_index >= 0);
431 if (FitsInIdx8Operand(slot_index)) {
432 Output(Bytecode::kLdaContextSlot, context.ToOperand(),
433 static_cast<uint8_t>(slot_index));
434 } else if (FitsInIdx16Operand(slot_index)) {
435 Output(Bytecode::kLdaContextSlotWide, context.ToOperand(),
436 static_cast<uint16_t>(slot_index));
437 } else {
438 UNIMPLEMENTED();
439 }
440 return *this;
441}
442
443
444BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context,
445 int slot_index) {
446 DCHECK(slot_index >= 0);
447 if (FitsInIdx8Operand(slot_index)) {
448 Output(Bytecode::kStaContextSlot, context.ToOperand(),
449 static_cast<uint8_t>(slot_index));
450 } else if (FitsInIdx16Operand(slot_index)) {
451 Output(Bytecode::kStaContextSlotWide, context.ToOperand(),
452 static_cast<uint16_t>(slot_index));
453 } else {
454 UNIMPLEMENTED();
455 }
456 return *this;
457}
458
459
460BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot(
461 const Handle<String> name, TypeofMode typeof_mode) {
462 Bytecode bytecode = (typeof_mode == INSIDE_TYPEOF)
463 ? Bytecode::kLdaLookupSlotInsideTypeof
464 : Bytecode::kLdaLookupSlot;
465 size_t name_index = GetConstantPoolEntry(name);
466 if (FitsInIdx8Operand(name_index)) {
467 Output(bytecode, static_cast<uint8_t>(name_index));
468 } else if (FitsInIdx16Operand(name_index)) {
469 Output(BytecodeForWideOperands(bytecode),
470 static_cast<uint16_t>(name_index));
471 } else {
472 UNIMPLEMENTED();
473 }
474 return *this;
475}
476
477
478BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot(
479 const Handle<String> name, LanguageMode language_mode) {
480 Bytecode bytecode = BytecodeForStoreLookupSlot(language_mode);
481 size_t name_index = GetConstantPoolEntry(name);
482 if (FitsInIdx8Operand(name_index)) {
483 Output(bytecode, static_cast<uint8_t>(name_index));
484 } else if (FitsInIdx16Operand(name_index)) {
485 Output(BytecodeForWideOperands(bytecode),
486 static_cast<uint16_t>(name_index));
487 } else {
488 UNIMPLEMENTED();
489 }
490 return *this;
491}
492
493
494BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
495 Register object, const Handle<String> name, int feedback_slot,
496 LanguageMode language_mode) {
497 Bytecode bytecode = BytecodeForLoadIC(language_mode);
498 size_t name_index = GetConstantPoolEntry(name);
499 if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) {
500 Output(bytecode, object.ToOperand(), static_cast<uint8_t>(name_index),
501 static_cast<uint8_t>(feedback_slot));
502 } else if (FitsInIdx16Operand(name_index) &&
503 FitsInIdx16Operand(feedback_slot)) {
504 Output(BytecodeForWideOperands(bytecode), object.ToOperand(),
505 static_cast<uint16_t>(name_index),
506 static_cast<uint16_t>(feedback_slot));
507 } else {
508 UNIMPLEMENTED();
509 }
510 return *this;
511}
512
513
514BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty(
515 Register object, int feedback_slot, LanguageMode language_mode) {
516 Bytecode bytecode = BytecodeForKeyedLoadIC(language_mode);
517 if (FitsInIdx8Operand(feedback_slot)) {
518 Output(bytecode, object.ToOperand(), static_cast<uint8_t>(feedback_slot));
519 } else if (FitsInIdx16Operand(feedback_slot)) {
520 Output(BytecodeForWideOperands(bytecode), object.ToOperand(),
521 static_cast<uint16_t>(feedback_slot));
522 } else {
523 UNIMPLEMENTED();
524 }
525 return *this;
526}
527
528
529BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty(
530 Register object, const Handle<String> name, int feedback_slot,
531 LanguageMode language_mode) {
532 Bytecode bytecode = BytecodeForStoreIC(language_mode);
533 size_t name_index = GetConstantPoolEntry(name);
534 if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) {
535 Output(bytecode, object.ToOperand(), static_cast<uint8_t>(name_index),
536 static_cast<uint8_t>(feedback_slot));
537 } else if (FitsInIdx16Operand(name_index) &&
538 FitsInIdx16Operand(feedback_slot)) {
539 Output(BytecodeForWideOperands(bytecode), object.ToOperand(),
540 static_cast<uint16_t>(name_index),
541 static_cast<uint16_t>(feedback_slot));
542 } else {
543 UNIMPLEMENTED();
544 }
545 return *this;
546}
547
548
549BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
550 Register object, Register key, int feedback_slot,
551 LanguageMode language_mode) {
552 Bytecode bytecode = BytecodeForKeyedStoreIC(language_mode);
553 if (FitsInIdx8Operand(feedback_slot)) {
554 Output(bytecode, object.ToOperand(), key.ToOperand(),
555 static_cast<uint8_t>(feedback_slot));
556 } else if (FitsInIdx16Operand(feedback_slot)) {
557 Output(BytecodeForWideOperands(bytecode), object.ToOperand(),
558 key.ToOperand(), static_cast<uint16_t>(feedback_slot));
559 } else {
560 UNIMPLEMENTED();
561 }
562 return *this;
563}
564
565
566BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure(
567 Handle<SharedFunctionInfo> shared_info, PretenureFlag tenured) {
568 size_t entry = GetConstantPoolEntry(shared_info);
569 DCHECK(FitsInImm8Operand(tenured));
570 if (FitsInIdx8Operand(entry)) {
571 Output(Bytecode::kCreateClosure, static_cast<uint8_t>(entry),
572 static_cast<uint8_t>(tenured));
573 } else if (FitsInIdx16Operand(entry)) {
574 Output(Bytecode::kCreateClosureWide, static_cast<uint16_t>(entry),
575 static_cast<uint8_t>(tenured));
576 } else {
577 UNIMPLEMENTED();
578 }
579 return *this;
580}
581
582
583BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments(
584 CreateArgumentsType type) {
585 // TODO(rmcilroy): Consider passing the type as a bytecode operand rather
586 // than having two different bytecodes once we have better support for
587 // branches in the InterpreterAssembler.
588 Bytecode bytecode = BytecodeForCreateArguments(type);
589 Output(bytecode);
590 return *this;
591}
592
593
594BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral(
595 Handle<String> pattern, int literal_index, int flags) {
596 DCHECK(FitsInImm8Operand(flags)); // Flags should fit in 8 bits.
597 size_t pattern_entry = GetConstantPoolEntry(pattern);
598 if (FitsInIdx8Operand(literal_index) && FitsInIdx8Operand(pattern_entry)) {
599 Output(Bytecode::kCreateRegExpLiteral, static_cast<uint8_t>(pattern_entry),
600 static_cast<uint8_t>(literal_index), static_cast<uint8_t>(flags));
601 } else if (FitsInIdx16Operand(literal_index) &&
602 FitsInIdx16Operand(pattern_entry)) {
603 Output(Bytecode::kCreateRegExpLiteralWide,
604 static_cast<uint16_t>(pattern_entry),
605 static_cast<uint16_t>(literal_index), static_cast<uint8_t>(flags));
606 } else {
607 UNIMPLEMENTED();
608 }
609 return *this;
610}
611
612
613BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral(
614 Handle<FixedArray> constant_elements, int literal_index, int flags) {
615 DCHECK(FitsInImm8Operand(flags)); // Flags should fit in 8 bits.
616 size_t constant_elements_entry = GetConstantPoolEntry(constant_elements);
617 if (FitsInIdx8Operand(literal_index) &&
618 FitsInIdx8Operand(constant_elements_entry)) {
619 Output(Bytecode::kCreateArrayLiteral,
620 static_cast<uint8_t>(constant_elements_entry),
621 static_cast<uint8_t>(literal_index), static_cast<uint8_t>(flags));
622 } else if (FitsInIdx16Operand(literal_index) &&
623 FitsInIdx16Operand(constant_elements_entry)) {
624 Output(Bytecode::kCreateArrayLiteralWide,
625 static_cast<uint16_t>(constant_elements_entry),
626 static_cast<uint16_t>(literal_index), static_cast<uint8_t>(flags));
627 } else {
628 UNIMPLEMENTED();
629 }
630 return *this;
631}
632
633
634BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral(
635 Handle<FixedArray> constant_properties, int literal_index, int flags) {
636 DCHECK(FitsInImm8Operand(flags)); // Flags should fit in 8 bits.
637 size_t constant_properties_entry = GetConstantPoolEntry(constant_properties);
638 if (FitsInIdx8Operand(literal_index) &&
639 FitsInIdx8Operand(constant_properties_entry)) {
640 Output(Bytecode::kCreateObjectLiteral,
641 static_cast<uint8_t>(constant_properties_entry),
642 static_cast<uint8_t>(literal_index), static_cast<uint8_t>(flags));
643 } else if (FitsInIdx16Operand(literal_index) &&
644 FitsInIdx16Operand(constant_properties_entry)) {
645 Output(Bytecode::kCreateObjectLiteralWide,
646 static_cast<uint16_t>(constant_properties_entry),
647 static_cast<uint16_t>(literal_index), static_cast<uint8_t>(flags));
648 } else {
649 UNIMPLEMENTED();
650 }
651 return *this;
652}
653
654
655BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) {
656 Output(Bytecode::kPushContext, context.ToOperand());
657 return *this;
658}
659
660
661BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) {
662 Output(Bytecode::kPopContext, context.ToOperand());
663 return *this;
664}
665
666
667bool BytecodeArrayBuilder::NeedToBooleanCast() {
668 if (!LastBytecodeInSameBlock()) {
669 return true;
670 }
671 PreviousBytecodeHelper previous_bytecode(*this);
672 switch (previous_bytecode.GetBytecode()) {
673 // If the previous bytecode puts a boolean in the accumulator return true.
674 case Bytecode::kLdaTrue:
675 case Bytecode::kLdaFalse:
676 case Bytecode::kLogicalNot:
677 case Bytecode::kTestEqual:
678 case Bytecode::kTestNotEqual:
679 case Bytecode::kTestEqualStrict:
680 case Bytecode::kTestNotEqualStrict:
681 case Bytecode::kTestLessThan:
682 case Bytecode::kTestLessThanOrEqual:
683 case Bytecode::kTestGreaterThan:
684 case Bytecode::kTestGreaterThanOrEqual:
685 case Bytecode::kTestInstanceOf:
686 case Bytecode::kTestIn:
687 case Bytecode::kForInDone:
688 return false;
689 default:
690 return true;
691 }
692}
693
694
695BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() {
696 Output(Bytecode::kToObject);
697 return *this;
698}
699
700
701BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() {
702 if (LastBytecodeInSameBlock()) {
703 PreviousBytecodeHelper previous_bytecode(*this);
704 switch (previous_bytecode.GetBytecode()) {
705 case Bytecode::kToName:
706 case Bytecode::kTypeOf:
707 return *this;
708 case Bytecode::kLdaConstantWide:
709 case Bytecode::kLdaConstant: {
710 Handle<Object> object = previous_bytecode.GetConstantForIndexOperand(0);
711 if (object->IsName()) return *this;
712 break;
713 }
714 default:
715 break;
716 }
717 }
718 Output(Bytecode::kToName);
719 return *this;
720}
721
722
723BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToNumber() {
724 // TODO(rmcilroy): consider omitting if the preceeding bytecode always returns
725 // a number.
726 Output(Bytecode::kToNumber);
727 return *this;
728}
729
730
731BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) {
732 if (label->is_forward_target()) {
733 // An earlier jump instruction refers to this label. Update it's location.
734 PatchJump(bytecodes()->end(), bytecodes()->begin() + label->offset());
735 // Now treat as if the label will only be back referred to.
736 }
737 label->bind_to(bytecodes()->size());
738 LeaveBasicBlock();
739 return *this;
740}
741
742
743BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target,
744 BytecodeLabel* label) {
745 DCHECK(!label->is_bound());
746 DCHECK(target.is_bound());
747 PatchJump(bytecodes()->begin() + target.offset(),
748 bytecodes()->begin() + label->offset());
749 label->bind_to(target.offset());
750 LeaveBasicBlock();
751 return *this;
752}
753
754
755// static
756Bytecode BytecodeArrayBuilder::GetJumpWithConstantOperand(
757 Bytecode jump_bytecode) {
758 switch (jump_bytecode) {
759 case Bytecode::kJump:
760 return Bytecode::kJumpConstant;
761 case Bytecode::kJumpIfTrue:
762 return Bytecode::kJumpIfTrueConstant;
763 case Bytecode::kJumpIfFalse:
764 return Bytecode::kJumpIfFalseConstant;
765 case Bytecode::kJumpIfToBooleanTrue:
766 return Bytecode::kJumpIfToBooleanTrueConstant;
767 case Bytecode::kJumpIfToBooleanFalse:
768 return Bytecode::kJumpIfToBooleanFalseConstant;
769 case Bytecode::kJumpIfNull:
770 return Bytecode::kJumpIfNullConstant;
771 case Bytecode::kJumpIfUndefined:
772 return Bytecode::kJumpIfUndefinedConstant;
773 default:
774 UNREACHABLE();
775 return static_cast<Bytecode>(-1);
776 }
777}
778
779
780// static
781Bytecode BytecodeArrayBuilder::GetJumpWithConstantWideOperand(
782 Bytecode jump_bytecode) {
783 switch (jump_bytecode) {
784 case Bytecode::kJump:
785 return Bytecode::kJumpConstantWide;
786 case Bytecode::kJumpIfTrue:
787 return Bytecode::kJumpIfTrueConstantWide;
788 case Bytecode::kJumpIfFalse:
789 return Bytecode::kJumpIfFalseConstantWide;
790 case Bytecode::kJumpIfToBooleanTrue:
791 return Bytecode::kJumpIfToBooleanTrueConstantWide;
792 case Bytecode::kJumpIfToBooleanFalse:
793 return Bytecode::kJumpIfToBooleanFalseConstantWide;
794 case Bytecode::kJumpIfNull:
795 return Bytecode::kJumpIfNullConstantWide;
796 case Bytecode::kJumpIfUndefined:
797 return Bytecode::kJumpIfUndefinedConstantWide;
798 default:
799 UNREACHABLE();
800 return static_cast<Bytecode>(-1);
801 }
802}
803
804
805// static
806Bytecode BytecodeArrayBuilder::GetJumpWithToBoolean(Bytecode jump_bytecode) {
807 switch (jump_bytecode) {
808 case Bytecode::kJump:
809 case Bytecode::kJumpIfNull:
810 case Bytecode::kJumpIfUndefined:
811 return jump_bytecode;
812 case Bytecode::kJumpIfTrue:
813 return Bytecode::kJumpIfToBooleanTrue;
814 case Bytecode::kJumpIfFalse:
815 return Bytecode::kJumpIfToBooleanFalse;
816 default:
817 UNREACHABLE();
818 }
819 return static_cast<Bytecode>(-1);
820}
821
822
823void BytecodeArrayBuilder::PatchIndirectJumpWith8BitOperand(
824 const ZoneVector<uint8_t>::iterator& jump_location, int delta) {
825 Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location);
826 DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
827 ZoneVector<uint8_t>::iterator operand_location = jump_location + 1;
828 DCHECK_EQ(*operand_location, 0);
829 if (FitsInImm8Operand(delta)) {
830 // The jump fits within the range of an Imm8 operand, so cancel
831 // the reservation and jump directly.
832 constant_array_builder()->DiscardReservedEntry(OperandSize::kByte);
833 *operand_location = static_cast<uint8_t>(delta);
834 } else {
835 // The jump does not fit within the range of an Imm8 operand, so
836 // commit reservation putting the offset into the constant pool,
837 // and update the jump instruction and operand.
838 size_t entry = constant_array_builder()->CommitReservedEntry(
839 OperandSize::kByte, handle(Smi::FromInt(delta), isolate()));
840 DCHECK(FitsInIdx8Operand(entry));
841 jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
842 *jump_location = Bytecodes::ToByte(jump_bytecode);
843 *operand_location = static_cast<uint8_t>(entry);
844 }
845}
846
847
848void BytecodeArrayBuilder::PatchIndirectJumpWith16BitOperand(
849 const ZoneVector<uint8_t>::iterator& jump_location, int delta) {
850 DCHECK(Bytecodes::IsJumpConstantWide(Bytecodes::FromByte(*jump_location)));
851 ZoneVector<uint8_t>::iterator operand_location = jump_location + 1;
852 size_t entry = constant_array_builder()->CommitReservedEntry(
853 OperandSize::kShort, handle(Smi::FromInt(delta), isolate()));
854 DCHECK(FitsInIdx16Operand(entry));
855 uint8_t operand_bytes[2];
856 WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry));
857 DCHECK(*operand_location == 0 && *(operand_location + 1) == 0);
858 *operand_location++ = operand_bytes[0];
859 *operand_location = operand_bytes[1];
860}
861
862
863void BytecodeArrayBuilder::PatchJump(
864 const ZoneVector<uint8_t>::iterator& jump_target,
865 const ZoneVector<uint8_t>::iterator& jump_location) {
866 Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location);
867 int delta = static_cast<int>(jump_target - jump_location);
868 DCHECK(Bytecodes::IsJump(jump_bytecode));
869 switch (Bytecodes::GetOperandSize(jump_bytecode, 0)) {
870 case OperandSize::kByte:
871 PatchIndirectJumpWith8BitOperand(jump_location, delta);
872 break;
873 case OperandSize::kShort:
874 PatchIndirectJumpWith16BitOperand(jump_location, delta);
875 break;
876 case OperandSize::kNone:
877 UNREACHABLE();
878 }
879 unbound_jumps_--;
880}
881
882
883BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode,
884 BytecodeLabel* label) {
885 // Don't emit dead code.
886 if (exit_seen_in_block_) return *this;
887
888 // Check if the value in accumulator is boolean, if not choose an
889 // appropriate JumpIfToBoolean bytecode.
890 if (NeedToBooleanCast()) {
891 jump_bytecode = GetJumpWithToBoolean(jump_bytecode);
892 }
893
894 if (label->is_bound()) {
895 // Label has been bound already so this is a backwards jump.
896 CHECK_GE(bytecodes()->size(), label->offset());
897 CHECK_LE(bytecodes()->size(), static_cast<size_t>(kMaxInt));
898 size_t abs_delta = bytecodes()->size() - label->offset();
899 int delta = -static_cast<int>(abs_delta);
900
901 if (FitsInImm8Operand(delta)) {
902 Output(jump_bytecode, static_cast<uint8_t>(delta));
903 } else {
904 size_t entry =
905 GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate()));
906 if (FitsInIdx8Operand(entry)) {
907 Output(GetJumpWithConstantOperand(jump_bytecode),
908 static_cast<uint8_t>(entry));
909 } else if (FitsInIdx16Operand(entry)) {
910 Output(GetJumpWithConstantWideOperand(jump_bytecode),
911 static_cast<uint16_t>(entry));
912 } else {
913 UNREACHABLE();
914 }
915 }
916 } else {
917 // The label has not yet been bound so this is a forward reference
918 // that will be patched when the label is bound. We create a
919 // reservation in the constant pool so the jump can be patched
920 // when the label is bound. The reservation means the maximum size
921 // of the operand for the constant is known and the jump can
922 // be emitted into the bytecode stream with space for the operand.
923 label->set_referrer(bytecodes()->size());
924 unbound_jumps_++;
925 OperandSize reserved_operand_size =
926 constant_array_builder()->CreateReservedEntry();
927 switch (reserved_operand_size) {
928 case OperandSize::kByte:
929 Output(jump_bytecode, 0);
930 break;
931 case OperandSize::kShort:
932 Output(GetJumpWithConstantWideOperand(jump_bytecode), 0);
933 break;
934 case OperandSize::kNone:
935 UNREACHABLE();
936 }
937 }
938 LeaveBasicBlock();
939 return *this;
940}
941
942
943BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) {
944 return OutputJump(Bytecode::kJump, label);
945}
946
947
948BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(BytecodeLabel* label) {
949 return OutputJump(Bytecode::kJumpIfTrue, label);
950}
951
952
953BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) {
954 return OutputJump(Bytecode::kJumpIfFalse, label);
955}
956
957
958BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) {
959 return OutputJump(Bytecode::kJumpIfNull, label);
960}
961
962
963BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined(
964 BytecodeLabel* label) {
965 return OutputJump(Bytecode::kJumpIfUndefined, label);
966}
967
968
969BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() {
970 Output(Bytecode::kThrow);
971 exit_seen_in_block_ = true;
972 return *this;
973}
974
975
976BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
977 Output(Bytecode::kReturn);
978 exit_seen_in_block_ = true;
979 return *this;
980}
981
982
983BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare(
984 Register cache_type, Register cache_array, Register cache_length) {
985 Output(Bytecode::kForInPrepare, cache_type.ToOperand(),
986 cache_array.ToOperand(), cache_length.ToOperand());
987 return *this;
988}
989
990
991BytecodeArrayBuilder& BytecodeArrayBuilder::ForInDone(Register index,
992 Register cache_length) {
993 Output(Bytecode::kForInDone, index.ToOperand(), cache_length.ToOperand());
994 return *this;
995}
996
997
998BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext(Register receiver,
999 Register cache_type,
1000 Register cache_array,
1001 Register index) {
1002 Output(Bytecode::kForInNext, receiver.ToOperand(), cache_type.ToOperand(),
1003 cache_array.ToOperand(), index.ToOperand());
1004 return *this;
1005}
1006
1007
1008BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) {
1009 Output(Bytecode::kForInStep, index.ToOperand());
1010 return *this;
1011}
1012
1013
1014void BytecodeArrayBuilder::LeaveBasicBlock() {
1015 last_block_end_ = bytecodes()->size();
1016 exit_seen_in_block_ = false;
1017}
1018
1019
1020void BytecodeArrayBuilder::EnsureReturn() {
1021 if (!exit_seen_in_block_) {
1022 LoadUndefined();
1023 Return();
1024 }
1025}
1026
1027
1028BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
1029 Register receiver,
1030 size_t arg_count,
1031 int feedback_slot) {
1032 if (FitsInIdx8Operand(arg_count) && FitsInIdx8Operand(feedback_slot)) {
1033 Output(Bytecode::kCall, callable.ToOperand(), receiver.ToOperand(),
1034 static_cast<uint8_t>(arg_count),
1035 static_cast<uint8_t>(feedback_slot));
1036 } else if (FitsInIdx16Operand(arg_count) &&
1037 FitsInIdx16Operand(feedback_slot)) {
1038 Output(Bytecode::kCallWide, callable.ToOperand(), receiver.ToOperand(),
1039 static_cast<uint16_t>(arg_count),
1040 static_cast<uint16_t>(feedback_slot));
1041 } else {
1042 UNIMPLEMENTED();
1043 }
1044 return *this;
1045}
1046
1047
1048BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor,
1049 Register first_arg,
1050 size_t arg_count) {
1051 if (!first_arg.is_valid()) {
1052 DCHECK_EQ(0u, arg_count);
1053 first_arg = Register(0);
1054 }
1055 DCHECK(FitsInIdx8Operand(arg_count));
1056 Output(Bytecode::kNew, constructor.ToOperand(), first_arg.ToOperand(),
1057 static_cast<uint8_t>(arg_count));
1058 return *this;
1059}
1060
1061
1062BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
1063 Runtime::FunctionId function_id, Register first_arg, size_t arg_count) {
1064 DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size);
1065 DCHECK(FitsInIdx16Operand(function_id));
1066 DCHECK(FitsInIdx8Operand(arg_count));
1067 if (!first_arg.is_valid()) {
1068 DCHECK_EQ(0u, arg_count);
1069 first_arg = Register(0);
1070 }
1071 Output(Bytecode::kCallRuntime, static_cast<uint16_t>(function_id),
1072 first_arg.ToOperand(), static_cast<uint8_t>(arg_count));
1073 return *this;
1074}
1075
1076
1077BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
1078 Runtime::FunctionId function_id, Register first_arg, size_t arg_count,
1079 Register first_return) {
1080 DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size);
1081 DCHECK(FitsInIdx16Operand(function_id));
1082 DCHECK(FitsInIdx8Operand(arg_count));
1083 if (!first_arg.is_valid()) {
1084 DCHECK_EQ(0u, arg_count);
1085 first_arg = Register(0);
1086 }
1087 Output(Bytecode::kCallRuntimeForPair, static_cast<uint16_t>(function_id),
1088 first_arg.ToOperand(), static_cast<uint8_t>(arg_count),
1089 first_return.ToOperand());
1090 return *this;
1091}
1092
1093
1094BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime(int context_index,
1095 Register receiver,
1096 size_t arg_count) {
1097 DCHECK(FitsInIdx16Operand(context_index));
1098 DCHECK(FitsInIdx8Operand(arg_count));
1099 Output(Bytecode::kCallJSRuntime, static_cast<uint16_t>(context_index),
1100 receiver.ToOperand(), static_cast<uint8_t>(arg_count));
1101 return *this;
1102}
1103
1104
1105BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object,
1106 LanguageMode language_mode) {
1107 Output(BytecodeForDelete(language_mode), object.ToOperand());
1108 return *this;
1109}
1110
1111
1112BytecodeArrayBuilder& BytecodeArrayBuilder::DeleteLookupSlot() {
1113 Output(Bytecode::kDeleteLookupSlot);
1114 return *this;
1115}
1116
1117
1118size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) {
1119 return constant_array_builder()->Insert(object);
1120}
1121
1122
1123int BytecodeArrayBuilder::BorrowTemporaryRegister() {
1124 if (free_temporaries_.empty()) {
1125 temporary_register_count_ += 1;
1126 return last_temporary_register().index();
1127 } else {
1128 auto pos = free_temporaries_.begin();
1129 int retval = *pos;
1130 free_temporaries_.erase(pos);
1131 return retval;
1132 }
1133}
1134
1135
1136int BytecodeArrayBuilder::BorrowTemporaryRegisterNotInRange(int start_index,
1137 int end_index) {
1138 auto index = free_temporaries_.lower_bound(start_index);
1139 if (index == free_temporaries_.begin()) {
1140 // If start_index is the first free register, check for a register
1141 // greater than end_index.
1142 index = free_temporaries_.upper_bound(end_index);
1143 if (index == free_temporaries_.end()) {
1144 temporary_register_count_ += 1;
1145 return last_temporary_register().index();
1146 }
1147 } else {
1148 // If there is a free register < start_index
1149 index--;
1150 }
1151
1152 int retval = *index;
1153 free_temporaries_.erase(index);
1154 return retval;
1155}
1156
1157
1158void BytecodeArrayBuilder::BorrowConsecutiveTemporaryRegister(int reg_index) {
1159 DCHECK(free_temporaries_.find(reg_index) != free_temporaries_.end());
1160 free_temporaries_.erase(reg_index);
1161}
1162
1163
1164void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_index) {
1165 DCHECK(free_temporaries_.find(reg_index) == free_temporaries_.end());
1166 free_temporaries_.insert(reg_index);
1167}
1168
1169
1170int BytecodeArrayBuilder::PrepareForConsecutiveTemporaryRegisters(
1171 size_t count) {
1172 if (count == 0) {
1173 return -1;
1174 }
1175
1176 // Search within existing temporaries for a run.
1177 auto start = free_temporaries_.begin();
1178 size_t run_length = 0;
1179 for (auto run_end = start; run_end != free_temporaries_.end(); run_end++) {
1180 if (*run_end != *start + static_cast<int>(run_length)) {
1181 start = run_end;
1182 run_length = 0;
1183 }
1184 if (++run_length == count) {
1185 return *start;
1186 }
1187 }
1188
1189 // Continue run if possible across existing last temporary.
1190 if (temporary_register_count_ > 0 &&
1191 (start == free_temporaries_.end() ||
1192 *start + static_cast<int>(run_length) !=
1193 last_temporary_register().index() + 1)) {
1194 run_length = 0;
1195 }
1196
1197 // Ensure enough registers for run.
1198 while (run_length++ < count) {
1199 temporary_register_count_++;
1200 free_temporaries_.insert(last_temporary_register().index());
1201 }
1202 return last_temporary_register().index() - static_cast<int>(count) + 1;
1203}
1204
1205
1206bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const {
1207 if (temporary_register_count_ > 0) {
1208 DCHECK(reg.index() >= first_temporary_register().index() &&
1209 reg.index() <= last_temporary_register().index());
1210 return free_temporaries_.find(reg.index()) == free_temporaries_.end();
1211 } else {
1212 return false;
1213 }
1214}
1215
1216
1217bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const {
1218 if (reg.is_function_context() || reg.is_function_closure() ||
1219 reg.is_new_target()) {
1220 return true;
1221 } else if (reg.is_parameter()) {
1222 int parameter_index = reg.ToParameterIndex(parameter_count_);
1223 return parameter_index >= 0 && parameter_index < parameter_count_;
1224 } else if (reg.index() < fixed_register_count()) {
1225 return true;
1226 } else {
1227 return TemporaryRegisterIsLive(reg);
1228 }
1229}
1230
1231
1232bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
1233 uint32_t operand_value) const {
1234 OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index);
1235 switch (operand_type) {
1236 case OperandType::kNone:
1237 return false;
1238 case OperandType::kCount16:
1239 case OperandType::kIdx16:
1240 return static_cast<uint16_t>(operand_value) == operand_value;
1241 case OperandType::kCount8:
1242 case OperandType::kImm8:
1243 case OperandType::kIdx8:
1244 return static_cast<uint8_t>(operand_value) == operand_value;
1245 case OperandType::kMaybeReg8:
1246 if (operand_value == 0) {
1247 return true;
1248 }
1249 // Fall-through to kReg8 case.
1250 case OperandType::kReg8:
1251 return RegisterIsValid(
1252 Register::FromOperand(static_cast<uint8_t>(operand_value)));
1253 case OperandType::kRegPair8: {
1254 Register reg0 =
1255 Register::FromOperand(static_cast<uint8_t>(operand_value));
1256 Register reg1 = Register(reg0.index() + 1);
1257 return RegisterIsValid(reg0) && RegisterIsValid(reg1);
1258 }
1259 case OperandType::kReg16:
1260 if (bytecode != Bytecode::kExchange &&
1261 bytecode != Bytecode::kExchangeWide) {
1262 return false;
1263 }
1264 return RegisterIsValid(
1265 Register::FromWideOperand(static_cast<uint16_t>(operand_value)));
1266 }
1267 UNREACHABLE();
1268 return false;
1269}
1270
1271
1272bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const {
1273 return last_bytecode_start_ < bytecodes()->size() &&
1274 last_bytecode_start_ >= last_block_end_;
1275}
1276
1277
1278bool BytecodeArrayBuilder::IsRegisterInAccumulator(Register reg) {
1279 if (LastBytecodeInSameBlock()) {
1280 PreviousBytecodeHelper previous_bytecode(*this);
1281 Bytecode bytecode = previous_bytecode.GetBytecode();
1282 if ((bytecode == Bytecode::kLdar || bytecode == Bytecode::kStar) &&
1283 (reg == Register::FromOperand(previous_bytecode.GetOperand(0)))) {
1284 return true;
1285 }
1286 }
1287 return false;
1288}
1289
1290
1291// static
1292Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) {
1293 switch (op) {
1294 case Token::Value::ADD:
1295 return Bytecode::kAdd;
1296 case Token::Value::SUB:
1297 return Bytecode::kSub;
1298 case Token::Value::MUL:
1299 return Bytecode::kMul;
1300 case Token::Value::DIV:
1301 return Bytecode::kDiv;
1302 case Token::Value::MOD:
1303 return Bytecode::kMod;
1304 case Token::Value::BIT_OR:
1305 return Bytecode::kBitwiseOr;
1306 case Token::Value::BIT_XOR:
1307 return Bytecode::kBitwiseXor;
1308 case Token::Value::BIT_AND:
1309 return Bytecode::kBitwiseAnd;
1310 case Token::Value::SHL:
1311 return Bytecode::kShiftLeft;
1312 case Token::Value::SAR:
1313 return Bytecode::kShiftRight;
1314 case Token::Value::SHR:
1315 return Bytecode::kShiftRightLogical;
1316 default:
1317 UNREACHABLE();
1318 return static_cast<Bytecode>(-1);
1319 }
1320}
1321
1322
1323// static
1324Bytecode BytecodeArrayBuilder::BytecodeForCountOperation(Token::Value op) {
1325 switch (op) {
1326 case Token::Value::ADD:
1327 return Bytecode::kInc;
1328 case Token::Value::SUB:
1329 return Bytecode::kDec;
1330 default:
1331 UNREACHABLE();
1332 return static_cast<Bytecode>(-1);
1333 }
1334}
1335
1336
1337// static
1338Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) {
1339 switch (op) {
1340 case Token::Value::EQ:
1341 return Bytecode::kTestEqual;
1342 case Token::Value::NE:
1343 return Bytecode::kTestNotEqual;
1344 case Token::Value::EQ_STRICT:
1345 return Bytecode::kTestEqualStrict;
1346 case Token::Value::NE_STRICT:
1347 return Bytecode::kTestNotEqualStrict;
1348 case Token::Value::LT:
1349 return Bytecode::kTestLessThan;
1350 case Token::Value::GT:
1351 return Bytecode::kTestGreaterThan;
1352 case Token::Value::LTE:
1353 return Bytecode::kTestLessThanOrEqual;
1354 case Token::Value::GTE:
1355 return Bytecode::kTestGreaterThanOrEqual;
1356 case Token::Value::INSTANCEOF:
1357 return Bytecode::kTestInstanceOf;
1358 case Token::Value::IN:
1359 return Bytecode::kTestIn;
1360 default:
1361 UNREACHABLE();
1362 return static_cast<Bytecode>(-1);
1363 }
1364}
1365
1366
1367// static
1368Bytecode BytecodeArrayBuilder::BytecodeForWideOperands(Bytecode bytecode) {
1369 switch (bytecode) {
1370 case Bytecode::kLoadICSloppy:
1371 return Bytecode::kLoadICSloppyWide;
1372 case Bytecode::kLoadICStrict:
1373 return Bytecode::kLoadICStrictWide;
1374 case Bytecode::kKeyedLoadICSloppy:
1375 return Bytecode::kKeyedLoadICSloppyWide;
1376 case Bytecode::kKeyedLoadICStrict:
1377 return Bytecode::kKeyedLoadICStrictWide;
1378 case Bytecode::kStoreICSloppy:
1379 return Bytecode::kStoreICSloppyWide;
1380 case Bytecode::kStoreICStrict:
1381 return Bytecode::kStoreICStrictWide;
1382 case Bytecode::kKeyedStoreICSloppy:
1383 return Bytecode::kKeyedStoreICSloppyWide;
1384 case Bytecode::kKeyedStoreICStrict:
1385 return Bytecode::kKeyedStoreICStrictWide;
1386 case Bytecode::kLdaGlobalSloppy:
1387 return Bytecode::kLdaGlobalSloppyWide;
1388 case Bytecode::kLdaGlobalStrict:
1389 return Bytecode::kLdaGlobalStrictWide;
1390 case Bytecode::kLdaGlobalInsideTypeofSloppy:
1391 return Bytecode::kLdaGlobalInsideTypeofSloppyWide;
1392 case Bytecode::kLdaGlobalInsideTypeofStrict:
1393 return Bytecode::kLdaGlobalInsideTypeofStrictWide;
1394 case Bytecode::kStaGlobalSloppy:
1395 return Bytecode::kStaGlobalSloppyWide;
1396 case Bytecode::kStaGlobalStrict:
1397 return Bytecode::kStaGlobalStrictWide;
1398 case Bytecode::kLdaLookupSlot:
1399 return Bytecode::kLdaLookupSlotWide;
1400 case Bytecode::kLdaLookupSlotInsideTypeof:
1401 return Bytecode::kLdaLookupSlotInsideTypeofWide;
1402 case Bytecode::kStaLookupSlotStrict:
1403 return Bytecode::kStaLookupSlotStrictWide;
1404 case Bytecode::kStaLookupSlotSloppy:
1405 return Bytecode::kStaLookupSlotSloppyWide;
1406 default:
1407 UNREACHABLE();
1408 return static_cast<Bytecode>(-1);
1409 }
1410}
1411
1412
1413// static
1414Bytecode BytecodeArrayBuilder::BytecodeForLoadIC(LanguageMode language_mode) {
1415 switch (language_mode) {
1416 case SLOPPY:
1417 return Bytecode::kLoadICSloppy;
1418 case STRICT:
1419 return Bytecode::kLoadICStrict;
1420 case STRONG:
1421 UNIMPLEMENTED();
1422 default:
1423 UNREACHABLE();
1424 }
1425 return static_cast<Bytecode>(-1);
1426}
1427
1428
1429// static
1430Bytecode BytecodeArrayBuilder::BytecodeForKeyedLoadIC(
1431 LanguageMode language_mode) {
1432 switch (language_mode) {
1433 case SLOPPY:
1434 return Bytecode::kKeyedLoadICSloppy;
1435 case STRICT:
1436 return Bytecode::kKeyedLoadICStrict;
1437 case STRONG:
1438 UNIMPLEMENTED();
1439 default:
1440 UNREACHABLE();
1441 }
1442 return static_cast<Bytecode>(-1);
1443}
1444
1445
1446// static
1447Bytecode BytecodeArrayBuilder::BytecodeForStoreIC(LanguageMode language_mode) {
1448 switch (language_mode) {
1449 case SLOPPY:
1450 return Bytecode::kStoreICSloppy;
1451 case STRICT:
1452 return Bytecode::kStoreICStrict;
1453 case STRONG:
1454 UNIMPLEMENTED();
1455 default:
1456 UNREACHABLE();
1457 }
1458 return static_cast<Bytecode>(-1);
1459}
1460
1461
1462// static
1463Bytecode BytecodeArrayBuilder::BytecodeForKeyedStoreIC(
1464 LanguageMode language_mode) {
1465 switch (language_mode) {
1466 case SLOPPY:
1467 return Bytecode::kKeyedStoreICSloppy;
1468 case STRICT:
1469 return Bytecode::kKeyedStoreICStrict;
1470 case STRONG:
1471 UNIMPLEMENTED();
1472 default:
1473 UNREACHABLE();
1474 }
1475 return static_cast<Bytecode>(-1);
1476}
1477
1478
1479// static
1480Bytecode BytecodeArrayBuilder::BytecodeForLoadGlobal(LanguageMode language_mode,
1481 TypeofMode typeof_mode) {
1482 switch (language_mode) {
1483 case SLOPPY:
1484 return typeof_mode == INSIDE_TYPEOF
1485 ? Bytecode::kLdaGlobalInsideTypeofSloppy
1486 : Bytecode::kLdaGlobalSloppy;
1487 case STRICT:
1488 return typeof_mode == INSIDE_TYPEOF
1489 ? Bytecode::kLdaGlobalInsideTypeofStrict
1490 : Bytecode::kLdaGlobalStrict;
1491 case STRONG:
1492 UNIMPLEMENTED();
1493 default:
1494 UNREACHABLE();
1495 }
1496 return static_cast<Bytecode>(-1);
1497}
1498
1499
1500// static
1501Bytecode BytecodeArrayBuilder::BytecodeForStoreGlobal(
1502 LanguageMode language_mode) {
1503 switch (language_mode) {
1504 case SLOPPY:
1505 return Bytecode::kStaGlobalSloppy;
1506 case STRICT:
1507 return Bytecode::kStaGlobalStrict;
1508 case STRONG:
1509 UNIMPLEMENTED();
1510 default:
1511 UNREACHABLE();
1512 }
1513 return static_cast<Bytecode>(-1);
1514}
1515
1516
1517// static
1518Bytecode BytecodeArrayBuilder::BytecodeForStoreLookupSlot(
1519 LanguageMode language_mode) {
1520 switch (language_mode) {
1521 case SLOPPY:
1522 return Bytecode::kStaLookupSlotSloppy;
1523 case STRICT:
1524 return Bytecode::kStaLookupSlotStrict;
1525 case STRONG:
1526 UNIMPLEMENTED();
1527 default:
1528 UNREACHABLE();
1529 }
1530 return static_cast<Bytecode>(-1);
1531}
1532
1533
1534// static
1535Bytecode BytecodeArrayBuilder::BytecodeForCreateArguments(
1536 CreateArgumentsType type) {
1537 switch (type) {
1538 case CreateArgumentsType::kMappedArguments:
1539 return Bytecode::kCreateMappedArguments;
1540 case CreateArgumentsType::kUnmappedArguments:
1541 return Bytecode::kCreateUnmappedArguments;
1542 default:
1543 UNREACHABLE();
1544 }
1545 return static_cast<Bytecode>(-1);
1546}
1547
1548
1549// static
1550Bytecode BytecodeArrayBuilder::BytecodeForDelete(LanguageMode language_mode) {
1551 switch (language_mode) {
1552 case SLOPPY:
1553 return Bytecode::kDeletePropertySloppy;
1554 case STRICT:
1555 return Bytecode::kDeletePropertyStrict;
1556 case STRONG:
1557 UNIMPLEMENTED();
1558 default:
1559 UNREACHABLE();
1560 }
1561 return static_cast<Bytecode>(-1);
1562}
1563
1564
1565// static
1566bool BytecodeArrayBuilder::FitsInIdx8Operand(int value) {
1567 return kMinUInt8 <= value && value <= kMaxUInt8;
1568}
1569
1570
1571// static
1572bool BytecodeArrayBuilder::FitsInIdx8Operand(size_t value) {
1573 return value <= static_cast<size_t>(kMaxUInt8);
1574}
1575
1576
1577// static
1578bool BytecodeArrayBuilder::FitsInImm8Operand(int value) {
1579 return kMinInt8 <= value && value <= kMaxInt8;
1580}
1581
1582
1583// static
1584bool BytecodeArrayBuilder::FitsInIdx16Operand(int value) {
1585 return kMinUInt16 <= value && value <= kMaxUInt16;
1586}
1587
1588
1589// static
1590bool BytecodeArrayBuilder::FitsInIdx16Operand(size_t value) {
1591 return value <= static_cast<size_t>(kMaxUInt16);
1592}
1593
1594
1595// static
1596bool BytecodeArrayBuilder::FitsInReg8Operand(Register value) {
1597 return kMinInt8 <= value.index() && value.index() <= kMaxInt8;
1598}
1599
1600
1601// static
1602bool BytecodeArrayBuilder::FitsInReg16Operand(Register value) {
1603 return kMinInt16 <= value.index() && value.index() <= kMaxInt16;
1604}
1605
1606} // namespace interpreter
1607} // namespace internal
1608} // namespace v8