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 namespace v8 {
8 namespace internal {
9 namespace interpreter {
10 
11 class BytecodeArrayBuilder::PreviousBytecodeHelper {
12  public:
PreviousBytecodeHelper(const BytecodeArrayBuilder & array_builder)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.
GetBytecode() const22   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.
GetOperand(int operand_index) const30   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 
GetConstantForIndexOperand(int operand_index) const54   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 
BytecodeArrayBuilder(Isolate * isolate,Zone * zone)67 BytecodeArrayBuilder::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 
~BytecodeArrayBuilder()84 BytecodeArrayBuilder::~BytecodeArrayBuilder() { DCHECK_EQ(0, unbound_jumps_); }
85 
86 
set_locals_count(int number_of_locals)87 void 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 
set_parameter_count(int number_of_parameters)93 void BytecodeArrayBuilder::set_parameter_count(int number_of_parameters) {
94   parameter_count_ = number_of_parameters;
95 }
96 
97 
set_context_count(int number_of_contexts)98 void 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 
first_context_register() const104 Register BytecodeArrayBuilder::first_context_register() const {
105   DCHECK_GT(context_register_count_, 0);
106   return Register(local_register_count_);
107 }
108 
109 
last_context_register() const110 Register 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 
first_temporary_register() const116 Register BytecodeArrayBuilder::first_temporary_register() const {
117   DCHECK_GT(temporary_register_count_, 0);
118   return Register(fixed_register_count());
119 }
120 
121 
last_temporary_register() const122 Register 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 
Parameter(int parameter_index) const128 Register BytecodeArrayBuilder::Parameter(int parameter_index) const {
129   DCHECK_GE(parameter_index, 0);
130   return Register::FromParameterIndex(parameter_index, parameter_count());
131 }
132 
133 
RegisterIsParameterOrLocal(Register reg) const134 bool BytecodeArrayBuilder::RegisterIsParameterOrLocal(Register reg) const {
135   return reg.is_parameter() || reg.index() < locals_count();
136 }
137 
138 
RegisterIsTemporary(Register reg) const139 bool BytecodeArrayBuilder::RegisterIsTemporary(Register reg) const {
140   return temporary_register_count_ > 0 && first_temporary_register() <= reg &&
141          reg <= last_temporary_register();
142 }
143 
144 
ToBytecodeArray()145 Handle<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 
163 template <size_t N>
Output(Bytecode bytecode,uint32_t (& operands)[N])164 void 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 
Output(Bytecode bytecode,uint32_t operand0,uint32_t operand1,uint32_t operand2,uint32_t operand3)191 void 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 
Output(Bytecode bytecode,uint32_t operand0,uint32_t operand1,uint32_t operand2)199 void 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 
Output(Bytecode bytecode,uint32_t operand0,uint32_t operand1)206 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0,
207                                   uint32_t operand1) {
208   uint32_t operands[] = {operand0, operand1};
209   Output(bytecode, operands);
210 }
211 
212 
Output(Bytecode bytecode,uint32_t operand0)213 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0) {
214   uint32_t operands[] = {operand0};
215   Output(bytecode, operands);
216 }
217 
218 
Output(Bytecode bytecode)219 void 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 
BinaryOperation(Token::Value op,Register reg,Strength strength)229 BytecodeArrayBuilder& 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 
CountOperation(Token::Value op,Strength strength)241 BytecodeArrayBuilder& 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 
LogicalNot()252 BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() {
253   Output(Bytecode::kLogicalNot);
254   return *this;
255 }
256 
257 
TypeOf()258 BytecodeArrayBuilder& BytecodeArrayBuilder::TypeOf() {
259   Output(Bytecode::kTypeOf);
260   return *this;
261 }
262 
263 
CompareOperation(Token::Value op,Register reg,Strength strength)264 BytecodeArrayBuilder& 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 
LoadLiteral(v8::internal::Smi * smi)275 BytecodeArrayBuilder& 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 
LoadLiteral(Handle<Object> object)289 BytecodeArrayBuilder& 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 
LoadUndefined()302 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() {
303   Output(Bytecode::kLdaUndefined);
304   return *this;
305 }
306 
307 
LoadNull()308 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() {
309   Output(Bytecode::kLdaNull);
310   return *this;
311 }
312 
313 
LoadTheHole()314 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() {
315   Output(Bytecode::kLdaTheHole);
316   return *this;
317 }
318 
319 
LoadTrue()320 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() {
321   Output(Bytecode::kLdaTrue);
322   return *this;
323 }
324 
325 
LoadFalse()326 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() {
327   Output(Bytecode::kLdaFalse);
328   return *this;
329 }
330 
331 
LoadBooleanConstant(bool value)332 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadBooleanConstant(bool value) {
333   if (value) {
334     LoadTrue();
335   } else {
336     LoadFalse();
337   }
338   return *this;
339 }
340 
341 
LoadAccumulatorWithRegister(Register reg)342 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister(
343     Register reg) {
344   if (!IsRegisterInAccumulator(reg)) {
345     Output(Bytecode::kLdar, reg.ToOperand());
346   }
347   return *this;
348 }
349 
350 
StoreAccumulatorInRegister(Register reg)351 BytecodeArrayBuilder& 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 
MoveRegister(Register from,Register to)367 BytecodeArrayBuilder& 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 
ExchangeRegisters(Register reg0,Register reg1)375 BytecodeArrayBuilder& 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 
LoadGlobal(const Handle<String> name,int feedback_slot,LanguageMode language_mode,TypeofMode typeof_mode)389 BytecodeArrayBuilder& 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 
StoreGlobal(const Handle<String> name,int feedback_slot,LanguageMode language_mode)410 BytecodeArrayBuilder& 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 
LoadContextSlot(Register context,int slot_index)428 BytecodeArrayBuilder& 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 
StoreContextSlot(Register context,int slot_index)444 BytecodeArrayBuilder& 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 
LoadLookupSlot(const Handle<String> name,TypeofMode typeof_mode)460 BytecodeArrayBuilder& 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 
StoreLookupSlot(const Handle<String> name,LanguageMode language_mode)478 BytecodeArrayBuilder& 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 
LoadNamedProperty(Register object,const Handle<String> name,int feedback_slot,LanguageMode language_mode)494 BytecodeArrayBuilder& 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 
LoadKeyedProperty(Register object,int feedback_slot,LanguageMode language_mode)514 BytecodeArrayBuilder& 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 
StoreNamedProperty(Register object,const Handle<String> name,int feedback_slot,LanguageMode language_mode)529 BytecodeArrayBuilder& 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 
StoreKeyedProperty(Register object,Register key,int feedback_slot,LanguageMode language_mode)549 BytecodeArrayBuilder& 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 
CreateClosure(Handle<SharedFunctionInfo> shared_info,PretenureFlag tenured)566 BytecodeArrayBuilder& 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 
CreateArguments(CreateArgumentsType type)583 BytecodeArrayBuilder& 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 
CreateRegExpLiteral(Handle<String> pattern,int literal_index,int flags)594 BytecodeArrayBuilder& 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 
CreateArrayLiteral(Handle<FixedArray> constant_elements,int literal_index,int flags)613 BytecodeArrayBuilder& 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 
CreateObjectLiteral(Handle<FixedArray> constant_properties,int literal_index,int flags)634 BytecodeArrayBuilder& 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 
PushContext(Register context)655 BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) {
656   Output(Bytecode::kPushContext, context.ToOperand());
657   return *this;
658 }
659 
660 
PopContext(Register context)661 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) {
662   Output(Bytecode::kPopContext, context.ToOperand());
663   return *this;
664 }
665 
666 
NeedToBooleanCast()667 bool 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 
CastAccumulatorToJSObject()695 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() {
696   Output(Bytecode::kToObject);
697   return *this;
698 }
699 
700 
CastAccumulatorToName()701 BytecodeArrayBuilder& 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 
CastAccumulatorToNumber()723 BytecodeArrayBuilder& 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 
Bind(BytecodeLabel * label)731 BytecodeArrayBuilder& 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 
Bind(const BytecodeLabel & target,BytecodeLabel * label)743 BytecodeArrayBuilder& 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
GetJumpWithConstantOperand(Bytecode jump_bytecode)756 Bytecode 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
GetJumpWithConstantWideOperand(Bytecode jump_bytecode)781 Bytecode 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
GetJumpWithToBoolean(Bytecode jump_bytecode)806 Bytecode 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 
PatchIndirectJumpWith8BitOperand(const ZoneVector<uint8_t>::iterator & jump_location,int delta)823 void 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 
PatchIndirectJumpWith16BitOperand(const ZoneVector<uint8_t>::iterator & jump_location,int delta)848 void 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 
PatchJump(const ZoneVector<uint8_t>::iterator & jump_target,const ZoneVector<uint8_t>::iterator & jump_location)863 void 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 
OutputJump(Bytecode jump_bytecode,BytecodeLabel * label)883 BytecodeArrayBuilder& 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 
Jump(BytecodeLabel * label)943 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) {
944   return OutputJump(Bytecode::kJump, label);
945 }
946 
947 
JumpIfTrue(BytecodeLabel * label)948 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(BytecodeLabel* label) {
949   return OutputJump(Bytecode::kJumpIfTrue, label);
950 }
951 
952 
JumpIfFalse(BytecodeLabel * label)953 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) {
954   return OutputJump(Bytecode::kJumpIfFalse, label);
955 }
956 
957 
JumpIfNull(BytecodeLabel * label)958 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) {
959   return OutputJump(Bytecode::kJumpIfNull, label);
960 }
961 
962 
JumpIfUndefined(BytecodeLabel * label)963 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined(
964     BytecodeLabel* label) {
965   return OutputJump(Bytecode::kJumpIfUndefined, label);
966 }
967 
968 
Throw()969 BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() {
970   Output(Bytecode::kThrow);
971   exit_seen_in_block_ = true;
972   return *this;
973 }
974 
975 
Return()976 BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
977   Output(Bytecode::kReturn);
978   exit_seen_in_block_ = true;
979   return *this;
980 }
981 
982 
ForInPrepare(Register cache_type,Register cache_array,Register cache_length)983 BytecodeArrayBuilder& 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 
ForInDone(Register index,Register cache_length)991 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInDone(Register index,
992                                                       Register cache_length) {
993   Output(Bytecode::kForInDone, index.ToOperand(), cache_length.ToOperand());
994   return *this;
995 }
996 
997 
ForInNext(Register receiver,Register cache_type,Register cache_array,Register index)998 BytecodeArrayBuilder& 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 
ForInStep(Register index)1008 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) {
1009   Output(Bytecode::kForInStep, index.ToOperand());
1010   return *this;
1011 }
1012 
1013 
LeaveBasicBlock()1014 void BytecodeArrayBuilder::LeaveBasicBlock() {
1015   last_block_end_ = bytecodes()->size();
1016   exit_seen_in_block_ = false;
1017 }
1018 
1019 
EnsureReturn()1020 void BytecodeArrayBuilder::EnsureReturn() {
1021   if (!exit_seen_in_block_) {
1022     LoadUndefined();
1023     Return();
1024   }
1025 }
1026 
1027 
Call(Register callable,Register receiver,size_t arg_count,int feedback_slot)1028 BytecodeArrayBuilder& 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 
New(Register constructor,Register first_arg,size_t arg_count)1048 BytecodeArrayBuilder& 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 
CallRuntime(Runtime::FunctionId function_id,Register first_arg,size_t arg_count)1062 BytecodeArrayBuilder& 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 
CallRuntimeForPair(Runtime::FunctionId function_id,Register first_arg,size_t arg_count,Register first_return)1077 BytecodeArrayBuilder& 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 
CallJSRuntime(int context_index,Register receiver,size_t arg_count)1094 BytecodeArrayBuilder& 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 
Delete(Register object,LanguageMode language_mode)1105 BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object,
1106                                                    LanguageMode language_mode) {
1107   Output(BytecodeForDelete(language_mode), object.ToOperand());
1108   return *this;
1109 }
1110 
1111 
DeleteLookupSlot()1112 BytecodeArrayBuilder& BytecodeArrayBuilder::DeleteLookupSlot() {
1113   Output(Bytecode::kDeleteLookupSlot);
1114   return *this;
1115 }
1116 
1117 
GetConstantPoolEntry(Handle<Object> object)1118 size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) {
1119   return constant_array_builder()->Insert(object);
1120 }
1121 
1122 
BorrowTemporaryRegister()1123 int 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 
BorrowTemporaryRegisterNotInRange(int start_index,int end_index)1136 int 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 
BorrowConsecutiveTemporaryRegister(int reg_index)1158 void BytecodeArrayBuilder::BorrowConsecutiveTemporaryRegister(int reg_index) {
1159   DCHECK(free_temporaries_.find(reg_index) != free_temporaries_.end());
1160   free_temporaries_.erase(reg_index);
1161 }
1162 
1163 
ReturnTemporaryRegister(int reg_index)1164 void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_index) {
1165   DCHECK(free_temporaries_.find(reg_index) == free_temporaries_.end());
1166   free_temporaries_.insert(reg_index);
1167 }
1168 
1169 
PrepareForConsecutiveTemporaryRegisters(size_t count)1170 int 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 
TemporaryRegisterIsLive(Register reg) const1206 bool 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 
RegisterIsValid(Register reg) const1217 bool 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 
OperandIsValid(Bytecode bytecode,int operand_index,uint32_t operand_value) const1232 bool 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 
LastBytecodeInSameBlock() const1272 bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const {
1273   return last_bytecode_start_ < bytecodes()->size() &&
1274          last_bytecode_start_ >= last_block_end_;
1275 }
1276 
1277 
IsRegisterInAccumulator(Register reg)1278 bool 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
BytecodeForBinaryOperation(Token::Value op)1292 Bytecode 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
BytecodeForCountOperation(Token::Value op)1324 Bytecode 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
BytecodeForCompareOperation(Token::Value op)1338 Bytecode 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
BytecodeForWideOperands(Bytecode bytecode)1368 Bytecode 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
BytecodeForLoadIC(LanguageMode language_mode)1414 Bytecode 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
BytecodeForKeyedLoadIC(LanguageMode language_mode)1430 Bytecode 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
BytecodeForStoreIC(LanguageMode language_mode)1447 Bytecode 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
BytecodeForKeyedStoreIC(LanguageMode language_mode)1463 Bytecode 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
BytecodeForLoadGlobal(LanguageMode language_mode,TypeofMode typeof_mode)1480 Bytecode 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
BytecodeForStoreGlobal(LanguageMode language_mode)1501 Bytecode 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
BytecodeForStoreLookupSlot(LanguageMode language_mode)1518 Bytecode 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
BytecodeForCreateArguments(CreateArgumentsType type)1535 Bytecode 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
BytecodeForDelete(LanguageMode language_mode)1550 Bytecode 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
FitsInIdx8Operand(int value)1566 bool BytecodeArrayBuilder::FitsInIdx8Operand(int value) {
1567   return kMinUInt8 <= value && value <= kMaxUInt8;
1568 }
1569 
1570 
1571 // static
FitsInIdx8Operand(size_t value)1572 bool BytecodeArrayBuilder::FitsInIdx8Operand(size_t value) {
1573   return value <= static_cast<size_t>(kMaxUInt8);
1574 }
1575 
1576 
1577 // static
FitsInImm8Operand(int value)1578 bool BytecodeArrayBuilder::FitsInImm8Operand(int value) {
1579   return kMinInt8 <= value && value <= kMaxInt8;
1580 }
1581 
1582 
1583 // static
FitsInIdx16Operand(int value)1584 bool BytecodeArrayBuilder::FitsInIdx16Operand(int value) {
1585   return kMinUInt16 <= value && value <= kMaxUInt16;
1586 }
1587 
1588 
1589 // static
FitsInIdx16Operand(size_t value)1590 bool BytecodeArrayBuilder::FitsInIdx16Operand(size_t value) {
1591   return value <= static_cast<size_t>(kMaxUInt16);
1592 }
1593 
1594 
1595 // static
FitsInReg8Operand(Register value)1596 bool BytecodeArrayBuilder::FitsInReg8Operand(Register value) {
1597   return kMinInt8 <= value.index() && value.index() <= kMaxInt8;
1598 }
1599 
1600 
1601 // static
FitsInReg16Operand(Register value)1602 bool BytecodeArrayBuilder::FitsInReg16Operand(Register value) {
1603   return kMinInt16 <= value.index() && value.index() <= kMaxInt16;
1604 }
1605 
1606 }  // namespace interpreter
1607 }  // namespace internal
1608 }  // namespace v8
1609