1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/interpreter/bytecode-array-builder.h"
6
7 #include "src/globals.h"
8 #include "src/interpreter/bytecode-array-writer.h"
9 #include "src/interpreter/bytecode-dead-code-optimizer.h"
10 #include "src/interpreter/bytecode-label.h"
11 #include "src/interpreter/bytecode-peephole-optimizer.h"
12 #include "src/interpreter/bytecode-register-optimizer.h"
13 #include "src/interpreter/interpreter-intrinsics.h"
14 #include "src/objects-inl.h"
15
16 namespace v8 {
17 namespace internal {
18 namespace interpreter {
19
BytecodeArrayBuilder(Isolate * isolate,Zone * zone,int parameter_count,int context_count,int locals_count,FunctionLiteral * literal,SourcePositionTableBuilder::RecordingMode source_position_mode)20 BytecodeArrayBuilder::BytecodeArrayBuilder(
21 Isolate* isolate, Zone* zone, int parameter_count, int context_count,
22 int locals_count, FunctionLiteral* literal,
23 SourcePositionTableBuilder::RecordingMode source_position_mode)
24 : zone_(zone),
25 literal_(literal),
26 bytecode_generated_(false),
27 constant_array_builder_(zone),
28 handler_table_builder_(zone),
29 return_seen_in_block_(false),
30 parameter_count_(parameter_count),
31 local_register_count_(locals_count),
32 context_register_count_(context_count),
33 register_allocator_(fixed_register_count()),
34 bytecode_array_writer_(zone, &constant_array_builder_,
35 source_position_mode),
36 pipeline_(&bytecode_array_writer_),
37 register_optimizer_(nullptr) {
38 DCHECK_GE(parameter_count_, 0);
39 DCHECK_GE(context_register_count_, 0);
40 DCHECK_GE(local_register_count_, 0);
41
42 if (FLAG_ignition_deadcode) {
43 pipeline_ = new (zone) BytecodeDeadCodeOptimizer(pipeline_);
44 }
45
46 if (FLAG_ignition_peephole) {
47 pipeline_ = new (zone) BytecodePeepholeOptimizer(pipeline_);
48 }
49
50 if (FLAG_ignition_reo) {
51 register_optimizer_ = new (zone) BytecodeRegisterOptimizer(
52 zone, ®ister_allocator_, fixed_register_count(), parameter_count,
53 pipeline_);
54 }
55
56 return_position_ = literal ? literal->return_position() : kNoSourcePosition;
57 }
58
first_context_register() const59 Register BytecodeArrayBuilder::first_context_register() const {
60 DCHECK_GT(context_register_count_, 0);
61 return Register(local_register_count_);
62 }
63
last_context_register() const64 Register BytecodeArrayBuilder::last_context_register() const {
65 DCHECK_GT(context_register_count_, 0);
66 return Register(local_register_count_ + context_register_count_ - 1);
67 }
68
Parameter(int parameter_index) const69 Register BytecodeArrayBuilder::Parameter(int parameter_index) const {
70 DCHECK_GE(parameter_index, 0);
71 return Register::FromParameterIndex(parameter_index, parameter_count());
72 }
73
Local(int index) const74 Register BytecodeArrayBuilder::Local(int index) const {
75 // TODO(marja): Make a DCHECK once crbug.com/706234 is fixed.
76 CHECK_LT(index, locals_count());
77 return Register(index);
78 }
79
ToBytecodeArray(Isolate * isolate)80 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) {
81 DCHECK(return_seen_in_block_);
82 DCHECK(!bytecode_generated_);
83 bytecode_generated_ = true;
84
85 int register_count = total_register_count();
86
87 if (register_optimizer_) {
88 register_optimizer_->Flush();
89 register_count = register_optimizer_->maxiumum_register_index() + 1;
90 }
91
92 Handle<FixedArray> handler_table =
93 handler_table_builder()->ToHandlerTable(isolate);
94 return pipeline_->ToBytecodeArray(isolate, register_count, parameter_count(),
95 handler_table);
96 }
97
CurrentSourcePosition(Bytecode bytecode)98 BytecodeSourceInfo BytecodeArrayBuilder::CurrentSourcePosition(
99 Bytecode bytecode) {
100 BytecodeSourceInfo source_position;
101 if (latest_source_info_.is_valid()) {
102 // Statement positions need to be emitted immediately. Expression
103 // positions can be pushed back until a bytecode is found that can
104 // throw (if expression position filtering is turned on). We only
105 // invalidate the existing source position information if it is used.
106 if (latest_source_info_.is_statement() ||
107 !FLAG_ignition_filter_expression_positions ||
108 !Bytecodes::IsWithoutExternalSideEffects(bytecode)) {
109 source_position = latest_source_info_;
110 latest_source_info_.set_invalid();
111 }
112 }
113 return source_position;
114 }
115
116 namespace {
117
118 template <OperandTypeInfo type_info>
119 class UnsignedOperandHelper {
120 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,size_t value))121 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, size_t value)) {
122 DCHECK(IsValid(value));
123 return static_cast<uint32_t>(value);
124 }
125
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,int value))126 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, int value)) {
127 DCHECK_GE(value, 0);
128 return Convert(builder, static_cast<size_t>(value));
129 }
130
131 private:
IsValid(size_t value)132 static bool IsValid(size_t value) {
133 switch (type_info) {
134 case OperandTypeInfo::kFixedUnsignedByte:
135 return value <= kMaxUInt8;
136 case OperandTypeInfo::kFixedUnsignedShort:
137 return value <= kMaxUInt16;
138 case OperandTypeInfo::kScalableUnsignedByte:
139 return value <= kMaxUInt32;
140 default:
141 UNREACHABLE();
142 return false;
143 }
144 }
145 };
146
147 template <OperandType>
148 class OperandHelper {};
149
150 #define DEFINE_UNSIGNED_OPERAND_HELPER(Name, Type) \
151 template <> \
152 class OperandHelper<OperandType::k##Name> \
153 : public UnsignedOperandHelper<Type> {};
154 UNSIGNED_FIXED_SCALAR_OPERAND_TYPE_LIST(DEFINE_UNSIGNED_OPERAND_HELPER)
155 UNSIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(DEFINE_UNSIGNED_OPERAND_HELPER)
156 #undef DEFINE_UNSIGNED_OPERAND_HELPER
157
158 template <>
159 class OperandHelper<OperandType::kImm> {
160 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,int value))161 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, int value)) {
162 return static_cast<uint32_t>(value);
163 }
164 };
165
166 template <>
167 class OperandHelper<OperandType::kReg> {
168 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,Register reg))169 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, Register reg)) {
170 return builder->GetInputRegisterOperand(reg);
171 }
172 };
173
174 template <>
175 class OperandHelper<OperandType::kRegList> {
176 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,RegisterList reg_list))177 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder,
178 RegisterList reg_list)) {
179 return builder->GetInputRegisterListOperand(reg_list);
180 }
181 };
182
183 template <>
184 class OperandHelper<OperandType::kRegPair> {
185 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,RegisterList reg_list))186 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder,
187 RegisterList reg_list)) {
188 DCHECK_EQ(reg_list.register_count(), 2);
189 return builder->GetInputRegisterListOperand(reg_list);
190 }
191 };
192
193 template <>
194 class OperandHelper<OperandType::kRegOut> {
195 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,Register reg))196 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, Register reg)) {
197 return builder->GetOutputRegisterOperand(reg);
198 }
199 };
200
201 template <>
202 class OperandHelper<OperandType::kRegOutPair> {
203 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,RegisterList reg_list))204 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder,
205 RegisterList reg_list)) {
206 DCHECK_EQ(2, reg_list.register_count());
207 return builder->GetOutputRegisterListOperand(reg_list);
208 }
209 };
210
211 template <>
212 class OperandHelper<OperandType::kRegOutTriple> {
213 public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,RegisterList reg_list))214 INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder,
215 RegisterList reg_list)) {
216 DCHECK_EQ(3, reg_list.register_count());
217 return builder->GetOutputRegisterListOperand(reg_list);
218 }
219 };
220
221 } // namespace
222
223 template <Bytecode bytecode, AccumulatorUse accumulator_use,
224 OperandType... operand_types>
225 class BytecodeNodeBuilder {
226 public:
227 template <typename... Operands>
INLINE(static BytecodeNode Make (BytecodeArrayBuilder * builder,BytecodeSourceInfo source_info,Operands...operands))228 INLINE(static BytecodeNode Make(BytecodeArrayBuilder* builder,
229 BytecodeSourceInfo source_info,
230 Operands... operands)) {
231 builder->PrepareToOutputBytecode<bytecode, accumulator_use>();
232 // The "OperandHelper<operand_types>::Convert(builder, operands)..." will
233 // expand both the OperandType... and Operands... parameter packs e.g. for:
234 // BytecodeNodeBuilder<OperandType::kReg, OperandType::kImm>::Make<
235 // Register, int>(..., Register reg, int immediate)
236 // the code will expand into:
237 // OperandHelper<OperandType::kReg>::Convert(builder, reg),
238 // OperandHelper<OperandType::kImm>::Convert(builder, immediate),
239 return BytecodeNode::Create<bytecode, accumulator_use, operand_types...>(
240 source_info,
241 OperandHelper<operand_types>::Convert(builder, operands)...);
242 }
243 };
244
245 #define DEFINE_BYTECODE_OUTPUT(name, ...) \
246 template <typename... Operands> \
247 void BytecodeArrayBuilder::Output##name(Operands... operands) { \
248 static_assert(sizeof...(Operands) <= Bytecodes::kMaxOperands, \
249 "too many operands for bytecode"); \
250 BytecodeNode node( \
251 BytecodeNodeBuilder<Bytecode::k##name, __VA_ARGS__>::Make< \
252 Operands...>(this, CurrentSourcePosition(Bytecode::k##name), \
253 operands...)); \
254 pipeline()->Write(&node); \
255 } \
256 \
257 template <typename... Operands> \
258 void BytecodeArrayBuilder::Output##name(BytecodeLabel* label, \
259 Operands... operands) { \
260 DCHECK(Bytecodes::IsJump(Bytecode::k##name)); \
261 BytecodeNode node( \
262 BytecodeNodeBuilder<Bytecode::k##name, __VA_ARGS__>::Make< \
263 Operands...>(this, CurrentSourcePosition(Bytecode::k##name), \
264 operands...)); \
265 pipeline()->WriteJump(&node, label); \
266 LeaveBasicBlock(); \
267 }
BYTECODE_LIST(DEFINE_BYTECODE_OUTPUT)268 BYTECODE_LIST(DEFINE_BYTECODE_OUTPUT)
269 #undef DEFINE_BYTECODE_OUTPUT
270
271 BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op,
272 Register reg,
273 int feedback_slot) {
274 switch (op) {
275 case Token::Value::ADD:
276 OutputAdd(reg, feedback_slot);
277 break;
278 case Token::Value::SUB:
279 OutputSub(reg, feedback_slot);
280 break;
281 case Token::Value::MUL:
282 OutputMul(reg, feedback_slot);
283 break;
284 case Token::Value::DIV:
285 OutputDiv(reg, feedback_slot);
286 break;
287 case Token::Value::MOD:
288 OutputMod(reg, feedback_slot);
289 break;
290 case Token::Value::BIT_OR:
291 OutputBitwiseOr(reg, feedback_slot);
292 break;
293 case Token::Value::BIT_XOR:
294 OutputBitwiseXor(reg, feedback_slot);
295 break;
296 case Token::Value::BIT_AND:
297 OutputBitwiseAnd(reg, feedback_slot);
298 break;
299 case Token::Value::SHL:
300 OutputShiftLeft(reg, feedback_slot);
301 break;
302 case Token::Value::SAR:
303 OutputShiftRight(reg, feedback_slot);
304 break;
305 case Token::Value::SHR:
306 OutputShiftRightLogical(reg, feedback_slot);
307 break;
308 default:
309 UNREACHABLE();
310 }
311 return *this;
312 }
313
CountOperation(Token::Value op,int feedback_slot)314 BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op,
315 int feedback_slot) {
316 if (op == Token::Value::ADD) {
317 OutputInc(feedback_slot);
318 } else {
319 DCHECK_EQ(op, Token::Value::SUB);
320 OutputDec(feedback_slot);
321 }
322 return *this;
323 }
324
LogicalNot()325 BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() {
326 OutputToBooleanLogicalNot();
327 return *this;
328 }
329
TypeOf()330 BytecodeArrayBuilder& BytecodeArrayBuilder::TypeOf() {
331 OutputTypeOf();
332 return *this;
333 }
334
GetSuperConstructor(Register out)335 BytecodeArrayBuilder& BytecodeArrayBuilder::GetSuperConstructor(Register out) {
336 OutputGetSuperConstructor(out);
337 return *this;
338 }
339
CompareOperation(Token::Value op,Register reg,int feedback_slot)340 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(
341 Token::Value op, Register reg, int feedback_slot) {
342 switch (op) {
343 case Token::Value::EQ:
344 OutputTestEqual(reg, feedback_slot);
345 break;
346 case Token::Value::NE:
347 OutputTestNotEqual(reg, feedback_slot);
348 break;
349 case Token::Value::EQ_STRICT:
350 OutputTestEqualStrict(reg, feedback_slot);
351 break;
352 case Token::Value::LT:
353 OutputTestLessThan(reg, feedback_slot);
354 break;
355 case Token::Value::GT:
356 OutputTestGreaterThan(reg, feedback_slot);
357 break;
358 case Token::Value::LTE:
359 OutputTestLessThanOrEqual(reg, feedback_slot);
360 break;
361 case Token::Value::GTE:
362 OutputTestGreaterThanOrEqual(reg, feedback_slot);
363 break;
364 case Token::Value::INSTANCEOF:
365 OutputTestInstanceOf(reg);
366 break;
367 case Token::Value::IN:
368 OutputTestIn(reg);
369 break;
370 default:
371 UNREACHABLE();
372 }
373 return *this;
374 }
375
LoadConstantPoolEntry(size_t entry)376 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadConstantPoolEntry(
377 size_t entry) {
378 OutputLdaConstant(entry);
379 return *this;
380 }
381
LoadLiteral(v8::internal::Smi * smi)382 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
383 v8::internal::Smi* smi) {
384 int32_t raw_smi = smi->value();
385 if (raw_smi == 0) {
386 OutputLdaZero();
387 } else {
388 OutputLdaSmi(raw_smi);
389 }
390 return *this;
391 }
392
LoadLiteral(const AstRawString * raw_string)393 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
394 const AstRawString* raw_string) {
395 size_t entry = GetConstantPoolEntry(raw_string);
396 OutputLdaConstant(entry);
397 return *this;
398 }
399
LoadLiteral(const Scope * scope)400 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(const Scope* scope) {
401 size_t entry = GetConstantPoolEntry(scope);
402 OutputLdaConstant(entry);
403 return *this;
404 }
405
LoadLiteral(const AstValue * ast_value)406 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
407 const AstValue* ast_value) {
408 if (ast_value->IsSmi()) {
409 return LoadLiteral(ast_value->AsSmi());
410 } else if (ast_value->IsUndefined()) {
411 return LoadUndefined();
412 } else if (ast_value->IsTrue()) {
413 return LoadTrue();
414 } else if (ast_value->IsFalse()) {
415 return LoadFalse();
416 } else if (ast_value->IsNull()) {
417 return LoadNull();
418 } else if (ast_value->IsTheHole()) {
419 return LoadTheHole();
420 } else if (ast_value->IsString()) {
421 return LoadLiteral(ast_value->AsString());
422 } else if (ast_value->IsHeapNumber()) {
423 size_t entry = GetConstantPoolEntry(ast_value);
424 OutputLdaConstant(entry);
425 return *this;
426 } else {
427 // This should be the only ast value type left.
428 DCHECK(ast_value->IsSymbol());
429 size_t entry;
430 switch (ast_value->AsSymbol()) {
431 case AstSymbol::kHomeObjectSymbol:
432 entry = HomeObjectSymbolConstantPoolEntry();
433 break;
434 // No default case so that we get a warning if AstSymbol changes
435 }
436 OutputLdaConstant(entry);
437 return *this;
438 }
439 }
440
LoadUndefined()441 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() {
442 OutputLdaUndefined();
443 return *this;
444 }
445
LoadNull()446 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() {
447 OutputLdaNull();
448 return *this;
449 }
450
LoadTheHole()451 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() {
452 OutputLdaTheHole();
453 return *this;
454 }
455
LoadTrue()456 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() {
457 OutputLdaTrue();
458 return *this;
459 }
460
LoadFalse()461 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() {
462 OutputLdaFalse();
463 return *this;
464 }
465
LoadAccumulatorWithRegister(Register reg)466 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister(
467 Register reg) {
468 if (register_optimizer_) {
469 register_optimizer_->DoLdar(reg, CurrentSourcePosition(Bytecode::kLdar));
470 } else {
471 OutputLdar(reg);
472 }
473 return *this;
474 }
475
StoreAccumulatorInRegister(Register reg)476 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
477 Register reg) {
478 if (register_optimizer_) {
479 register_optimizer_->DoStar(reg, CurrentSourcePosition(Bytecode::kStar));
480 } else {
481 OutputStar(reg);
482 }
483 return *this;
484 }
485
MoveRegister(Register from,Register to)486 BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from,
487 Register to) {
488 DCHECK(from != to);
489 if (register_optimizer_) {
490 register_optimizer_->DoMov(from, to, CurrentSourcePosition(Bytecode::kMov));
491 } else {
492 OutputMov(from, to);
493 }
494 return *this;
495 }
496
LoadGlobal(const AstRawString * name,int feedback_slot,TypeofMode typeof_mode)497 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(const AstRawString* name,
498 int feedback_slot,
499 TypeofMode typeof_mode) {
500 size_t name_index = GetConstantPoolEntry(name);
501 // Ensure that typeof mode is in sync with the IC slot kind if the function
502 // literal is available (not a unit test case).
503 // TODO(ishell): check only in debug mode.
504 if (literal_) {
505 FeedbackSlot slot = FeedbackVector::ToSlot(feedback_slot);
506 CHECK_EQ(GetTypeofModeFromSlotKind(feedback_vector_spec()->GetKind(slot)),
507 typeof_mode);
508 }
509 if (typeof_mode == INSIDE_TYPEOF) {
510 OutputLdaGlobalInsideTypeof(name_index, feedback_slot);
511 } else {
512 DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF);
513 OutputLdaGlobal(name_index, feedback_slot);
514 }
515 return *this;
516 }
517
StoreGlobal(const AstRawString * name,int feedback_slot,LanguageMode language_mode)518 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal(
519 const AstRawString* name, int feedback_slot, LanguageMode language_mode) {
520 size_t name_index = GetConstantPoolEntry(name);
521 if (language_mode == SLOPPY) {
522 OutputStaGlobalSloppy(name_index, feedback_slot);
523 } else {
524 DCHECK_EQ(language_mode, STRICT);
525 OutputStaGlobalStrict(name_index, feedback_slot);
526 }
527 return *this;
528 }
529
LoadContextSlot(Register context,int slot_index,int depth,ContextSlotMutability mutability)530 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(
531 Register context, int slot_index, int depth,
532 ContextSlotMutability mutability) {
533 if (context.is_current_context() && depth == 0) {
534 if (mutability == kImmutableSlot) {
535 OutputLdaImmutableCurrentContextSlot(slot_index);
536 } else {
537 DCHECK_EQ(kMutableSlot, mutability);
538 OutputLdaCurrentContextSlot(slot_index);
539 }
540 } else if (mutability == kImmutableSlot) {
541 OutputLdaImmutableContextSlot(context, slot_index, depth);
542 } else {
543 DCHECK_EQ(mutability, kMutableSlot);
544 OutputLdaContextSlot(context, slot_index, depth);
545 }
546 return *this;
547 }
548
StoreContextSlot(Register context,int slot_index,int depth)549 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context,
550 int slot_index,
551 int depth) {
552 if (context.is_current_context() && depth == 0) {
553 OutputStaCurrentContextSlot(slot_index);
554 } else {
555 OutputStaContextSlot(context, slot_index, depth);
556 }
557 return *this;
558 }
559
LoadLookupSlot(const AstRawString * name,TypeofMode typeof_mode)560 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot(
561 const AstRawString* name, TypeofMode typeof_mode) {
562 size_t name_index = GetConstantPoolEntry(name);
563 if (typeof_mode == INSIDE_TYPEOF) {
564 OutputLdaLookupSlotInsideTypeof(name_index);
565 } else {
566 DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF);
567 OutputLdaLookupSlot(name_index);
568 }
569 return *this;
570 }
571
LoadLookupContextSlot(const AstRawString * name,TypeofMode typeof_mode,int slot_index,int depth)572 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupContextSlot(
573 const AstRawString* name, TypeofMode typeof_mode, int slot_index,
574 int depth) {
575 size_t name_index = GetConstantPoolEntry(name);
576 if (typeof_mode == INSIDE_TYPEOF) {
577 OutputLdaLookupContextSlotInsideTypeof(name_index, slot_index, depth);
578 } else {
579 DCHECK(typeof_mode == NOT_INSIDE_TYPEOF);
580 OutputLdaLookupContextSlot(name_index, slot_index, depth);
581 }
582 return *this;
583 }
584
LoadLookupGlobalSlot(const AstRawString * name,TypeofMode typeof_mode,int feedback_slot,int depth)585 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupGlobalSlot(
586 const AstRawString* name, TypeofMode typeof_mode, int feedback_slot,
587 int depth) {
588 size_t name_index = GetConstantPoolEntry(name);
589 if (typeof_mode == INSIDE_TYPEOF) {
590 OutputLdaLookupGlobalSlotInsideTypeof(name_index, feedback_slot, depth);
591 } else {
592 DCHECK(typeof_mode == NOT_INSIDE_TYPEOF);
593 OutputLdaLookupGlobalSlot(name_index, feedback_slot, depth);
594 }
595 return *this;
596 }
597
StoreLookupSlot(const AstRawString * name,LanguageMode language_mode)598 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot(
599 const AstRawString* name, LanguageMode language_mode) {
600 size_t name_index = GetConstantPoolEntry(name);
601 if (language_mode == SLOPPY) {
602 OutputStaLookupSlotSloppy(name_index);
603 } else {
604 DCHECK_EQ(language_mode, STRICT);
605 OutputStaLookupSlotStrict(name_index);
606 }
607 return *this;
608 }
609
LoadNamedProperty(Register object,const AstRawString * name,int feedback_slot)610 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
611 Register object, const AstRawString* name, int feedback_slot) {
612 size_t name_index = GetConstantPoolEntry(name);
613 OutputLdaNamedProperty(object, name_index, feedback_slot);
614 return *this;
615 }
616
LoadKeyedProperty(Register object,int feedback_slot)617 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty(
618 Register object, int feedback_slot) {
619 OutputLdaKeyedProperty(object, feedback_slot);
620 return *this;
621 }
622
LoadIteratorProperty(Register object,int feedback_slot)623 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadIteratorProperty(
624 Register object, int feedback_slot) {
625 size_t name_index = IteratorSymbolConstantPoolEntry();
626 OutputLdaNamedProperty(object, name_index, feedback_slot);
627 return *this;
628 }
629
LoadAsyncIteratorProperty(Register object,int feedback_slot)630 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAsyncIteratorProperty(
631 Register object, int feedback_slot) {
632 size_t name_index = AsyncIteratorSymbolConstantPoolEntry();
633 OutputLdaNamedProperty(object, name_index, feedback_slot);
634 return *this;
635 }
636
StoreDataPropertyInLiteral(Register object,Register name,DataPropertyInLiteralFlags flags,int feedback_slot)637 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreDataPropertyInLiteral(
638 Register object, Register name, DataPropertyInLiteralFlags flags,
639 int feedback_slot) {
640 OutputStaDataPropertyInLiteral(object, name, flags, feedback_slot);
641 return *this;
642 }
643
StoreNamedProperty(Register object,size_t name_index,int feedback_slot,LanguageMode language_mode)644 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty(
645 Register object, size_t name_index, int feedback_slot,
646 LanguageMode language_mode) {
647 // Ensure that language mode is in sync with the IC slot kind if the function
648 // literal is available (not a unit test case).
649 // TODO(ishell): check only in debug mode.
650 if (literal_) {
651 FeedbackSlot slot = FeedbackVector::ToSlot(feedback_slot);
652 CHECK_EQ(GetLanguageModeFromSlotKind(feedback_vector_spec()->GetKind(slot)),
653 language_mode);
654 }
655 if (language_mode == SLOPPY) {
656 OutputStaNamedPropertySloppy(object, name_index, feedback_slot);
657 } else {
658 DCHECK_EQ(language_mode, STRICT);
659 OutputStaNamedPropertyStrict(object, name_index, feedback_slot);
660 }
661 return *this;
662 }
663
StoreNamedProperty(Register object,const AstRawString * name,int feedback_slot,LanguageMode language_mode)664 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty(
665 Register object, const AstRawString* name, int feedback_slot,
666 LanguageMode language_mode) {
667 size_t name_index = GetConstantPoolEntry(name);
668 return StoreNamedProperty(object, name_index, feedback_slot, language_mode);
669 }
670
StoreNamedOwnProperty(Register object,const AstRawString * name,int feedback_slot)671 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedOwnProperty(
672 Register object, const AstRawString* name, int feedback_slot) {
673 size_t name_index = GetConstantPoolEntry(name);
674 // Ensure that the store operation is in sync with the IC slot kind if
675 // the function literal is available (not a unit test case).
676 // TODO(ishell): check only in debug mode.
677 if (literal_) {
678 FeedbackSlot slot = FeedbackVector::ToSlot(feedback_slot);
679 CHECK_EQ(FeedbackSlotKind::kStoreOwnNamed,
680 feedback_vector_spec()->GetKind(slot));
681 }
682 OutputStaNamedOwnProperty(object, name_index, feedback_slot);
683 return *this;
684 }
685
StoreKeyedProperty(Register object,Register key,int feedback_slot,LanguageMode language_mode)686 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
687 Register object, Register key, int feedback_slot,
688 LanguageMode language_mode) {
689 // Ensure that language mode is in sync with the IC slot kind if the function
690 // literal is available (not a unit test case).
691 // TODO(ishell): check only in debug mode.
692 if (literal_) {
693 FeedbackSlot slot = FeedbackVector::ToSlot(feedback_slot);
694 CHECK_EQ(GetLanguageModeFromSlotKind(feedback_vector_spec()->GetKind(slot)),
695 language_mode);
696 }
697 if (language_mode == SLOPPY) {
698 OutputStaKeyedPropertySloppy(object, key, feedback_slot);
699 } else {
700 DCHECK_EQ(language_mode, STRICT);
701 OutputStaKeyedPropertyStrict(object, key, feedback_slot);
702 }
703 return *this;
704 }
705
StoreHomeObjectProperty(Register object,int feedback_slot,LanguageMode language_mode)706 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreHomeObjectProperty(
707 Register object, int feedback_slot, LanguageMode language_mode) {
708 size_t name_index = HomeObjectSymbolConstantPoolEntry();
709 return StoreNamedProperty(object, name_index, feedback_slot, language_mode);
710 }
711
CreateClosure(size_t shared_function_info_entry,int slot,int flags)712 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure(
713 size_t shared_function_info_entry, int slot, int flags) {
714 OutputCreateClosure(shared_function_info_entry, slot, flags);
715 return *this;
716 }
717
CreateBlockContext(const Scope * scope)718 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateBlockContext(
719 const Scope* scope) {
720 size_t entry = GetConstantPoolEntry(scope);
721 OutputCreateBlockContext(entry);
722 return *this;
723 }
724
CreateCatchContext(Register exception,const AstRawString * name,const Scope * scope)725 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateCatchContext(
726 Register exception, const AstRawString* name, const Scope* scope) {
727 size_t name_index = GetConstantPoolEntry(name);
728 size_t scope_index = GetConstantPoolEntry(scope);
729 OutputCreateCatchContext(exception, name_index, scope_index);
730 return *this;
731 }
732
CreateFunctionContext(int slots)733 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateFunctionContext(int slots) {
734 OutputCreateFunctionContext(slots);
735 return *this;
736 }
737
CreateEvalContext(int slots)738 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateEvalContext(int slots) {
739 OutputCreateEvalContext(slots);
740 return *this;
741 }
742
CreateWithContext(Register object,const Scope * scope)743 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateWithContext(
744 Register object, const Scope* scope) {
745 size_t scope_index = GetConstantPoolEntry(scope);
746 OutputCreateWithContext(object, scope_index);
747 return *this;
748 }
749
CreateArguments(CreateArgumentsType type)750 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments(
751 CreateArgumentsType type) {
752 switch (type) {
753 case CreateArgumentsType::kMappedArguments:
754 OutputCreateMappedArguments();
755 break;
756 case CreateArgumentsType::kUnmappedArguments:
757 OutputCreateUnmappedArguments();
758 break;
759 case CreateArgumentsType::kRestParameter:
760 OutputCreateRestParameter();
761 break;
762 default:
763 UNREACHABLE();
764 }
765 return *this;
766 }
767
CreateRegExpLiteral(const AstRawString * pattern,int literal_index,int flags)768 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral(
769 const AstRawString* pattern, int literal_index, int flags) {
770 size_t pattern_entry = GetConstantPoolEntry(pattern);
771 OutputCreateRegExpLiteral(pattern_entry, literal_index, flags);
772 return *this;
773 }
774
CreateArrayLiteral(size_t constant_elements_entry,int literal_index,int flags)775 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral(
776 size_t constant_elements_entry, int literal_index, int flags) {
777 OutputCreateArrayLiteral(constant_elements_entry, literal_index, flags);
778 return *this;
779 }
780
CreateObjectLiteral(size_t constant_properties_entry,int literal_index,int flags,Register output)781 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral(
782 size_t constant_properties_entry, int literal_index, int flags,
783 Register output) {
784 OutputCreateObjectLiteral(constant_properties_entry, literal_index, flags,
785 output);
786 return *this;
787 }
788
PushContext(Register context)789 BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) {
790 OutputPushContext(context);
791 return *this;
792 }
793
PopContext(Register context)794 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) {
795 OutputPopContext(context);
796 return *this;
797 }
798
ConvertAccumulatorToObject(Register out)799 BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToObject(
800 Register out) {
801 OutputToObject(out);
802 return *this;
803 }
804
ConvertAccumulatorToName(Register out)805 BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToName(
806 Register out) {
807 OutputToName(out);
808 return *this;
809 }
810
ConvertAccumulatorToNumber(Register out)811 BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToNumber(
812 Register out) {
813 OutputToNumber(out);
814 return *this;
815 }
816
Bind(BytecodeLabel * label)817 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) {
818 // Flush the register optimizer when binding a label to ensure all
819 // expected registers are valid when jumping to this label.
820 if (register_optimizer_) register_optimizer_->Flush();
821 pipeline_->BindLabel(label);
822 LeaveBasicBlock();
823 return *this;
824 }
825
Bind(const BytecodeLabel & target,BytecodeLabel * label)826 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target,
827 BytecodeLabel* label) {
828 pipeline_->BindLabel(target, label);
829 LeaveBasicBlock();
830 return *this;
831 }
832
Jump(BytecodeLabel * label)833 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) {
834 DCHECK(!label->is_bound());
835 OutputJump(label, 0);
836 return *this;
837 }
838
JumpIfTrue(BytecodeLabel * label)839 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(BytecodeLabel* label) {
840 // The peephole optimizer attempts to simplify JumpIfToBooleanTrue
841 // to JumpIfTrue.
842 DCHECK(!label->is_bound());
843 OutputJumpIfToBooleanTrue(label, 0);
844 return *this;
845 }
846
JumpIfFalse(BytecodeLabel * label)847 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) {
848 DCHECK(!label->is_bound());
849 OutputJumpIfToBooleanFalse(label, 0);
850 return *this;
851 }
852
JumpIfNull(BytecodeLabel * label)853 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) {
854 DCHECK(!label->is_bound());
855 OutputJumpIfNull(label, 0);
856 return *this;
857 }
858
JumpIfUndefined(BytecodeLabel * label)859 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined(
860 BytecodeLabel* label) {
861 DCHECK(!label->is_bound());
862 OutputJumpIfUndefined(label, 0);
863 return *this;
864 }
865
JumpIfNotHole(BytecodeLabel * label)866 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotHole(
867 BytecodeLabel* label) {
868 DCHECK(!label->is_bound());
869 OutputJumpIfNotHole(label, 0);
870 return *this;
871 }
872
JumpIfJSReceiver(BytecodeLabel * label)873 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfJSReceiver(
874 BytecodeLabel* label) {
875 DCHECK(!label->is_bound());
876 OutputJumpIfJSReceiver(label, 0);
877 return *this;
878 }
879
JumpLoop(BytecodeLabel * label,int loop_depth)880 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpLoop(BytecodeLabel* label,
881 int loop_depth) {
882 DCHECK(label->is_bound());
883 OutputJumpLoop(label, 0, loop_depth);
884 return *this;
885 }
886
StackCheck(int position)887 BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck(int position) {
888 if (position != kNoSourcePosition) {
889 // We need to attach a non-breakable source position to a stack
890 // check, so we simply add it as expression position. There can be
891 // a prior statement position from constructs like:
892 //
893 // do var x; while (false);
894 //
895 // A Nop could be inserted for empty statements, but since no code
896 // is associated with these positions, instead we force the stack
897 // check's expression position which eliminates the empty
898 // statement's position.
899 latest_source_info_.ForceExpressionPosition(position);
900 }
901 OutputStackCheck();
902 return *this;
903 }
904
SetPendingMessage()905 BytecodeArrayBuilder& BytecodeArrayBuilder::SetPendingMessage() {
906 OutputSetPendingMessage();
907 return *this;
908 }
909
Throw()910 BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() {
911 OutputThrow();
912 return *this;
913 }
914
ReThrow()915 BytecodeArrayBuilder& BytecodeArrayBuilder::ReThrow() {
916 OutputReThrow();
917 return *this;
918 }
919
Return()920 BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
921 SetReturnPosition();
922 OutputReturn();
923 return_seen_in_block_ = true;
924 return *this;
925 }
926
Debugger()927 BytecodeArrayBuilder& BytecodeArrayBuilder::Debugger() {
928 OutputDebugger();
929 return *this;
930 }
931
ForInPrepare(Register receiver,RegisterList cache_info_triple)932 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare(
933 Register receiver, RegisterList cache_info_triple) {
934 DCHECK_EQ(3, cache_info_triple.register_count());
935 OutputForInPrepare(receiver, cache_info_triple);
936 return *this;
937 }
938
ForInContinue(Register index,Register cache_length)939 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInContinue(
940 Register index, Register cache_length) {
941 OutputForInContinue(index, cache_length);
942 return *this;
943 }
944
ForInNext(Register receiver,Register index,RegisterList cache_type_array_pair,int feedback_slot)945 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext(
946 Register receiver, Register index, RegisterList cache_type_array_pair,
947 int feedback_slot) {
948 DCHECK_EQ(2, cache_type_array_pair.register_count());
949 OutputForInNext(receiver, index, cache_type_array_pair, feedback_slot);
950 return *this;
951 }
952
ForInStep(Register index)953 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) {
954 OutputForInStep(index);
955 return *this;
956 }
957
StoreModuleVariable(int cell_index,int depth)958 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreModuleVariable(int cell_index,
959 int depth) {
960 OutputStaModuleVariable(cell_index, depth);
961 return *this;
962 }
963
LoadModuleVariable(int cell_index,int depth)964 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadModuleVariable(int cell_index,
965 int depth) {
966 OutputLdaModuleVariable(cell_index, depth);
967 return *this;
968 }
969
SuspendGenerator(Register generator)970 BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator(
971 Register generator) {
972 OutputSuspendGenerator(generator);
973 return *this;
974 }
975
ResumeGenerator(Register generator)976 BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator(
977 Register generator) {
978 OutputResumeGenerator(generator);
979 return *this;
980 }
981
MarkHandler(int handler_id,HandlerTable::CatchPrediction catch_prediction)982 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkHandler(
983 int handler_id, HandlerTable::CatchPrediction catch_prediction) {
984 BytecodeLabel handler;
985 Bind(&handler);
986 handler_table_builder()->SetHandlerTarget(handler_id, handler.offset());
987 handler_table_builder()->SetPrediction(handler_id, catch_prediction);
988 return *this;
989 }
990
MarkTryBegin(int handler_id,Register context)991 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryBegin(int handler_id,
992 Register context) {
993 BytecodeLabel try_begin;
994 Bind(&try_begin);
995 handler_table_builder()->SetTryRegionStart(handler_id, try_begin.offset());
996 handler_table_builder()->SetContextRegister(handler_id, context);
997 return *this;
998 }
999
MarkTryEnd(int handler_id)1000 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryEnd(int handler_id) {
1001 BytecodeLabel try_end;
1002 Bind(&try_end);
1003 handler_table_builder()->SetTryRegionEnd(handler_id, try_end.offset());
1004 return *this;
1005 }
1006
Call(Register callable,RegisterList args,int feedback_slot,Call::CallType call_type,TailCallMode tail_call_mode)1007 BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
1008 RegisterList args,
1009 int feedback_slot,
1010 Call::CallType call_type,
1011 TailCallMode tail_call_mode) {
1012 if (tail_call_mode == TailCallMode::kDisallow) {
1013 if (call_type == Call::NAMED_PROPERTY_CALL ||
1014 call_type == Call::KEYED_PROPERTY_CALL) {
1015 OutputCallProperty(callable, args, args.register_count(), feedback_slot);
1016 } else {
1017 OutputCall(callable, args, args.register_count(), feedback_slot);
1018 }
1019 } else {
1020 DCHECK(tail_call_mode == TailCallMode::kAllow);
1021 OutputTailCall(callable, args, args.register_count(), feedback_slot);
1022 }
1023 return *this;
1024 }
1025
CallWithSpread(Register callable,RegisterList args)1026 BytecodeArrayBuilder& BytecodeArrayBuilder::CallWithSpread(Register callable,
1027 RegisterList args) {
1028 OutputCallWithSpread(callable, args, args.register_count());
1029 return *this;
1030 }
1031
Construct(Register constructor,RegisterList args,int feedback_slot_id)1032 BytecodeArrayBuilder& BytecodeArrayBuilder::Construct(Register constructor,
1033 RegisterList args,
1034 int feedback_slot_id) {
1035 OutputConstruct(constructor, args, args.register_count(), feedback_slot_id);
1036 return *this;
1037 }
1038
ConstructWithSpread(Register constructor,RegisterList args)1039 BytecodeArrayBuilder& BytecodeArrayBuilder::ConstructWithSpread(
1040 Register constructor, RegisterList args) {
1041 OutputConstructWithSpread(constructor, args, args.register_count());
1042 return *this;
1043 }
1044
CallRuntime(Runtime::FunctionId function_id,RegisterList args)1045 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
1046 Runtime::FunctionId function_id, RegisterList args) {
1047 DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size);
1048 DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort);
1049 if (IntrinsicsHelper::IsSupported(function_id)) {
1050 IntrinsicsHelper::IntrinsicId intrinsic_id =
1051 IntrinsicsHelper::FromRuntimeId(function_id);
1052 OutputInvokeIntrinsic(static_cast<int>(intrinsic_id), args,
1053 args.register_count());
1054 } else {
1055 OutputCallRuntime(static_cast<int>(function_id), args,
1056 args.register_count());
1057 }
1058 return *this;
1059 }
1060
CallRuntime(Runtime::FunctionId function_id,Register arg)1061 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
1062 Runtime::FunctionId function_id, Register arg) {
1063 return CallRuntime(function_id, RegisterList(arg.index(), 1));
1064 }
1065
CallRuntime(Runtime::FunctionId function_id)1066 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
1067 Runtime::FunctionId function_id) {
1068 return CallRuntime(function_id, RegisterList());
1069 }
1070
CallRuntimeForPair(Runtime::FunctionId function_id,RegisterList args,RegisterList return_pair)1071 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
1072 Runtime::FunctionId function_id, RegisterList args,
1073 RegisterList return_pair) {
1074 DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size);
1075 DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort);
1076 DCHECK_EQ(2, return_pair.register_count());
1077 OutputCallRuntimeForPair(static_cast<uint16_t>(function_id), args,
1078 args.register_count(), return_pair);
1079 return *this;
1080 }
1081
CallRuntimeForPair(Runtime::FunctionId function_id,Register arg,RegisterList return_pair)1082 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
1083 Runtime::FunctionId function_id, Register arg, RegisterList return_pair) {
1084 return CallRuntimeForPair(function_id, RegisterList(arg.index(), 1),
1085 return_pair);
1086 }
1087
CallJSRuntime(int context_index,RegisterList args)1088 BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime(int context_index,
1089 RegisterList args) {
1090 OutputCallJSRuntime(context_index, args, args.register_count());
1091 return *this;
1092 }
1093
Delete(Register object,LanguageMode language_mode)1094 BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object,
1095 LanguageMode language_mode) {
1096 if (language_mode == SLOPPY) {
1097 OutputDeletePropertySloppy(object);
1098 } else {
1099 DCHECK_EQ(language_mode, STRICT);
1100 OutputDeletePropertyStrict(object);
1101 }
1102 return *this;
1103 }
1104
GetConstantPoolEntry(const AstRawString * raw_string)1105 size_t BytecodeArrayBuilder::GetConstantPoolEntry(
1106 const AstRawString* raw_string) {
1107 return constant_array_builder()->Insert(raw_string);
1108 }
1109
GetConstantPoolEntry(const AstValue * heap_number)1110 size_t BytecodeArrayBuilder::GetConstantPoolEntry(const AstValue* heap_number) {
1111 DCHECK(heap_number->IsHeapNumber());
1112 return constant_array_builder()->Insert(heap_number);
1113 }
1114
GetConstantPoolEntry(const Scope * scope)1115 size_t BytecodeArrayBuilder::GetConstantPoolEntry(const Scope* scope) {
1116 return constant_array_builder()->Insert(scope);
1117 }
1118
1119 #define ENTRY_GETTER(NAME, ...) \
1120 size_t BytecodeArrayBuilder::NAME##ConstantPoolEntry() { \
1121 return constant_array_builder()->Insert##NAME(); \
1122 }
SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_GETTER)1123 SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_GETTER)
1124 #undef ENTRY_GETTER
1125
1126 size_t BytecodeArrayBuilder::AllocateDeferredConstantPoolEntry() {
1127 return constant_array_builder()->InsertDeferred();
1128 }
1129
SetDeferredConstantPoolEntry(size_t entry,Handle<Object> object)1130 void BytecodeArrayBuilder::SetDeferredConstantPoolEntry(size_t entry,
1131 Handle<Object> object) {
1132 constant_array_builder()->SetDeferredAt(entry, object);
1133 }
1134
SetReturnPosition()1135 void BytecodeArrayBuilder::SetReturnPosition() {
1136 if (return_position_ == kNoSourcePosition) return;
1137 latest_source_info_.MakeStatementPosition(return_position_);
1138 }
1139
RegisterIsValid(Register reg) const1140 bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const {
1141 if (!reg.is_valid()) {
1142 return false;
1143 }
1144
1145 if (reg.is_current_context() || reg.is_function_closure() ||
1146 reg.is_new_target()) {
1147 return true;
1148 } else if (reg.is_parameter()) {
1149 int parameter_index = reg.ToParameterIndex(parameter_count());
1150 return parameter_index >= 0 && parameter_index < parameter_count();
1151 } else if (reg.index() < fixed_register_count()) {
1152 return true;
1153 } else {
1154 return register_allocator()->RegisterIsLive(reg);
1155 }
1156 }
1157
RegisterListIsValid(RegisterList reg_list) const1158 bool BytecodeArrayBuilder::RegisterListIsValid(RegisterList reg_list) const {
1159 if (reg_list.register_count() == 0) {
1160 return reg_list.first_register() == Register(0);
1161 } else {
1162 int first_reg_index = reg_list.first_register().index();
1163 for (int i = 0; i < reg_list.register_count(); i++) {
1164 if (!RegisterIsValid(Register(first_reg_index + i))) {
1165 return false;
1166 }
1167 }
1168 return true;
1169 }
1170 }
1171
1172 template <Bytecode bytecode, AccumulatorUse accumulator_use>
PrepareToOutputBytecode()1173 void BytecodeArrayBuilder::PrepareToOutputBytecode() {
1174 if (register_optimizer_)
1175 register_optimizer_->PrepareForBytecode<bytecode, accumulator_use>();
1176 }
1177
GetInputRegisterOperand(Register reg)1178 uint32_t BytecodeArrayBuilder::GetInputRegisterOperand(Register reg) {
1179 DCHECK(RegisterIsValid(reg));
1180 if (register_optimizer_) reg = register_optimizer_->GetInputRegister(reg);
1181 return static_cast<uint32_t>(reg.ToOperand());
1182 }
1183
GetOutputRegisterOperand(Register reg)1184 uint32_t BytecodeArrayBuilder::GetOutputRegisterOperand(Register reg) {
1185 DCHECK(RegisterIsValid(reg));
1186 if (register_optimizer_) register_optimizer_->PrepareOutputRegister(reg);
1187 return static_cast<uint32_t>(reg.ToOperand());
1188 }
1189
GetInputRegisterListOperand(RegisterList reg_list)1190 uint32_t BytecodeArrayBuilder::GetInputRegisterListOperand(
1191 RegisterList reg_list) {
1192 DCHECK(RegisterListIsValid(reg_list));
1193 if (register_optimizer_)
1194 reg_list = register_optimizer_->GetInputRegisterList(reg_list);
1195 return static_cast<uint32_t>(reg_list.first_register().ToOperand());
1196 }
1197
GetOutputRegisterListOperand(RegisterList reg_list)1198 uint32_t BytecodeArrayBuilder::GetOutputRegisterListOperand(
1199 RegisterList reg_list) {
1200 DCHECK(RegisterListIsValid(reg_list));
1201 if (register_optimizer_)
1202 register_optimizer_->PrepareOutputRegisterList(reg_list);
1203 return static_cast<uint32_t>(reg_list.first_register().ToOperand());
1204 }
1205
1206 } // namespace interpreter
1207 } // namespace internal
1208 } // namespace v8
1209