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