• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/compiler.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 
15 namespace v8 {
16 namespace internal {
17 namespace interpreter {
18 
BytecodeArrayBuilder(Isolate * isolate,Zone * zone,int parameter_count,int context_count,int locals_count,FunctionLiteral * literal)19 BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone,
20                                            int parameter_count,
21                                            int context_count, int locals_count,
22                                            FunctionLiteral* literal)
23     : isolate_(isolate),
24       zone_(zone),
25       bytecode_generated_(false),
26       constant_array_builder_(isolate, zone),
27       handler_table_builder_(isolate, zone),
28       return_seen_in_block_(false),
29       parameter_count_(parameter_count),
30       local_register_count_(locals_count),
31       context_register_count_(context_count),
32       temporary_allocator_(zone, fixed_register_count()),
33       bytecode_array_writer_(isolate, zone, &constant_array_builder_),
34       pipeline_(&bytecode_array_writer_) {
35   DCHECK_GE(parameter_count_, 0);
36   DCHECK_GE(context_register_count_, 0);
37   DCHECK_GE(local_register_count_, 0);
38 
39   if (FLAG_ignition_deadcode) {
40     pipeline_ = new (zone) BytecodeDeadCodeOptimizer(pipeline_);
41   }
42 
43   if (FLAG_ignition_peephole) {
44     pipeline_ = new (zone)
45         BytecodePeepholeOptimizer(&constant_array_builder_, pipeline_);
46   }
47 
48   if (FLAG_ignition_reo) {
49     pipeline_ = new (zone) BytecodeRegisterOptimizer(
50         zone, &temporary_allocator_, parameter_count, pipeline_);
51   }
52 
53   return_position_ =
54       literal ? std::max(literal->start_position(), literal->end_position() - 1)
55               : RelocInfo::kNoPosition;
56 }
57 
first_context_register() const58 Register BytecodeArrayBuilder::first_context_register() const {
59   DCHECK_GT(context_register_count_, 0);
60   return Register(local_register_count_);
61 }
62 
last_context_register() const63 Register BytecodeArrayBuilder::last_context_register() const {
64   DCHECK_GT(context_register_count_, 0);
65   return Register(local_register_count_ + context_register_count_ - 1);
66 }
67 
Parameter(int parameter_index) const68 Register BytecodeArrayBuilder::Parameter(int parameter_index) const {
69   DCHECK_GE(parameter_index, 0);
70   return Register::FromParameterIndex(parameter_index, parameter_count());
71 }
72 
RegisterIsParameterOrLocal(Register reg) const73 bool BytecodeArrayBuilder::RegisterIsParameterOrLocal(Register reg) const {
74   return reg.is_parameter() || reg.index() < locals_count();
75 }
76 
ToBytecodeArray()77 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
78   DCHECK(return_seen_in_block_);
79   DCHECK(!bytecode_generated_);
80   bytecode_generated_ = true;
81 
82   Handle<FixedArray> handler_table = handler_table_builder()->ToHandlerTable();
83   return pipeline_->ToBytecodeArray(fixed_register_count(), parameter_count(),
84                                     handler_table);
85 }
86 
87 namespace {
88 
ExpressionPositionIsNeeded(Bytecode bytecode)89 static bool ExpressionPositionIsNeeded(Bytecode bytecode) {
90   // An expression position is always needed if filtering is turned
91   // off. Otherwise an expression is only needed if the bytecode has
92   // external side effects.
93   return !FLAG_ignition_filter_expression_positions ||
94          !Bytecodes::IsWithoutExternalSideEffects(bytecode);
95 }
96 
97 }  // namespace
98 
AttachSourceInfo(BytecodeNode * node)99 void BytecodeArrayBuilder::AttachSourceInfo(BytecodeNode* node) {
100   if (latest_source_info_.is_valid()) {
101     // Statement positions need to be emitted immediately.  Expression
102     // positions can be pushed back until a bytecode is found that can
103     // throw. Hence we only invalidate the existing source position
104     // information if it is used.
105     if (latest_source_info_.is_statement() ||
106         ExpressionPositionIsNeeded(node->bytecode())) {
107       node->source_info().Clone(latest_source_info_);
108       latest_source_info_.set_invalid();
109     }
110   }
111 }
112 
Output(Bytecode bytecode,uint32_t operand0,uint32_t operand1,uint32_t operand2,uint32_t operand3)113 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0,
114                                   uint32_t operand1, uint32_t operand2,
115                                   uint32_t operand3) {
116   DCHECK(OperandsAreValid(bytecode, 4, operand0, operand1, operand2, operand3));
117   BytecodeNode node(bytecode, operand0, operand1, operand2, operand3);
118   AttachSourceInfo(&node);
119   pipeline()->Write(&node);
120 }
121 
Output(Bytecode bytecode,uint32_t operand0,uint32_t operand1,uint32_t operand2)122 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0,
123                                   uint32_t operand1, uint32_t operand2) {
124   DCHECK(OperandsAreValid(bytecode, 3, operand0, operand1, operand2));
125   BytecodeNode node(bytecode, operand0, operand1, operand2);
126   AttachSourceInfo(&node);
127   pipeline()->Write(&node);
128 }
129 
Output(Bytecode bytecode,uint32_t operand0,uint32_t operand1)130 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0,
131                                   uint32_t operand1) {
132   DCHECK(OperandsAreValid(bytecode, 2, operand0, operand1));
133   BytecodeNode node(bytecode, operand0, operand1);
134   AttachSourceInfo(&node);
135   pipeline()->Write(&node);
136 }
137 
Output(Bytecode bytecode,uint32_t operand0)138 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0) {
139   DCHECK(OperandsAreValid(bytecode, 1, operand0));
140   BytecodeNode node(bytecode, operand0);
141   AttachSourceInfo(&node);
142   pipeline()->Write(&node);
143 }
144 
Output(Bytecode bytecode)145 void BytecodeArrayBuilder::Output(Bytecode bytecode) {
146   DCHECK(OperandsAreValid(bytecode, 0));
147   BytecodeNode node(bytecode);
148   AttachSourceInfo(&node);
149   pipeline()->Write(&node);
150 }
151 
BinaryOperation(Token::Value op,Register reg)152 BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op,
153                                                             Register reg) {
154   Output(BytecodeForBinaryOperation(op), RegisterOperand(reg));
155   return *this;
156 }
157 
CountOperation(Token::Value op)158 BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op) {
159   Output(BytecodeForCountOperation(op));
160   return *this;
161 }
162 
LogicalNot()163 BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() {
164   Output(Bytecode::kToBooleanLogicalNot);
165   return *this;
166 }
167 
168 
TypeOf()169 BytecodeArrayBuilder& BytecodeArrayBuilder::TypeOf() {
170   Output(Bytecode::kTypeOf);
171   return *this;
172 }
173 
CompareOperation(Token::Value op,Register reg)174 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(Token::Value op,
175                                                              Register reg) {
176   Output(BytecodeForCompareOperation(op), RegisterOperand(reg));
177   return *this;
178 }
179 
LoadLiteral(v8::internal::Smi * smi)180 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
181     v8::internal::Smi* smi) {
182   int32_t raw_smi = smi->value();
183   if (raw_smi == 0) {
184     Output(Bytecode::kLdaZero);
185   } else {
186     Output(Bytecode::kLdaSmi, SignedOperand(raw_smi));
187   }
188   return *this;
189 }
190 
LoadLiteral(Handle<Object> object)191 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) {
192   size_t entry = GetConstantPoolEntry(object);
193   Output(Bytecode::kLdaConstant, UnsignedOperand(entry));
194   return *this;
195 }
196 
LoadUndefined()197 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() {
198   Output(Bytecode::kLdaUndefined);
199   return *this;
200 }
201 
LoadNull()202 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() {
203   Output(Bytecode::kLdaNull);
204   return *this;
205 }
206 
LoadTheHole()207 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() {
208   Output(Bytecode::kLdaTheHole);
209   return *this;
210 }
211 
LoadTrue()212 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() {
213   Output(Bytecode::kLdaTrue);
214   return *this;
215 }
216 
LoadFalse()217 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() {
218   Output(Bytecode::kLdaFalse);
219   return *this;
220 }
221 
LoadAccumulatorWithRegister(Register reg)222 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister(
223     Register reg) {
224   Output(Bytecode::kLdar, RegisterOperand(reg));
225   return *this;
226 }
227 
StoreAccumulatorInRegister(Register reg)228 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
229     Register reg) {
230   Output(Bytecode::kStar, RegisterOperand(reg));
231   return *this;
232 }
233 
MoveRegister(Register from,Register to)234 BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from,
235                                                          Register to) {
236   DCHECK(from != to);
237   Output(Bytecode::kMov, RegisterOperand(from), RegisterOperand(to));
238   return *this;
239 }
240 
LoadGlobal(int feedback_slot,TypeofMode typeof_mode)241 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(int feedback_slot,
242                                                        TypeofMode typeof_mode) {
243   // TODO(rmcilroy): Potentially store typeof information in an
244   // operand rather than having extra bytecodes.
245   Bytecode bytecode = BytecodeForLoadGlobal(typeof_mode);
246   Output(bytecode, UnsignedOperand(feedback_slot));
247   return *this;
248 }
249 
StoreGlobal(const Handle<String> name,int feedback_slot,LanguageMode language_mode)250 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal(
251     const Handle<String> name, int feedback_slot, LanguageMode language_mode) {
252   Bytecode bytecode = BytecodeForStoreGlobal(language_mode);
253   size_t name_index = GetConstantPoolEntry(name);
254   Output(bytecode, UnsignedOperand(name_index), UnsignedOperand(feedback_slot));
255   return *this;
256 }
257 
LoadContextSlot(Register context,int slot_index)258 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context,
259                                                             int slot_index) {
260   Output(Bytecode::kLdaContextSlot, RegisterOperand(context),
261          UnsignedOperand(slot_index));
262   return *this;
263 }
264 
StoreContextSlot(Register context,int slot_index)265 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context,
266                                                              int slot_index) {
267   Output(Bytecode::kStaContextSlot, RegisterOperand(context),
268          UnsignedOperand(slot_index));
269   return *this;
270 }
271 
LoadLookupSlot(const Handle<String> name,TypeofMode typeof_mode)272 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot(
273     const Handle<String> name, TypeofMode typeof_mode) {
274   Bytecode bytecode = (typeof_mode == INSIDE_TYPEOF)
275                           ? Bytecode::kLdaLookupSlotInsideTypeof
276                           : Bytecode::kLdaLookupSlot;
277   size_t name_index = GetConstantPoolEntry(name);
278   Output(bytecode, UnsignedOperand(name_index));
279   return *this;
280 }
281 
StoreLookupSlot(const Handle<String> name,LanguageMode language_mode)282 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot(
283     const Handle<String> name, LanguageMode language_mode) {
284   Bytecode bytecode = BytecodeForStoreLookupSlot(language_mode);
285   size_t name_index = GetConstantPoolEntry(name);
286   Output(bytecode, UnsignedOperand(name_index));
287   return *this;
288 }
289 
LoadNamedProperty(Register object,const Handle<Name> name,int feedback_slot)290 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
291     Register object, const Handle<Name> name, int feedback_slot) {
292   size_t name_index = GetConstantPoolEntry(name);
293   Output(Bytecode::kLdaNamedProperty, RegisterOperand(object),
294          UnsignedOperand(name_index), UnsignedOperand(feedback_slot));
295   return *this;
296 }
297 
LoadKeyedProperty(Register object,int feedback_slot)298 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty(
299     Register object, int feedback_slot) {
300   Output(Bytecode::kLdaKeyedProperty, RegisterOperand(object),
301          UnsignedOperand(feedback_slot));
302   return *this;
303 }
304 
StoreNamedProperty(Register object,const Handle<Name> name,int feedback_slot,LanguageMode language_mode)305 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty(
306     Register object, const Handle<Name> name, int feedback_slot,
307     LanguageMode language_mode) {
308   Bytecode bytecode = BytecodeForStoreNamedProperty(language_mode);
309   size_t name_index = GetConstantPoolEntry(name);
310   Output(bytecode, RegisterOperand(object), UnsignedOperand(name_index),
311          UnsignedOperand(feedback_slot));
312   return *this;
313 }
314 
StoreKeyedProperty(Register object,Register key,int feedback_slot,LanguageMode language_mode)315 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
316     Register object, Register key, int feedback_slot,
317     LanguageMode language_mode) {
318   Bytecode bytecode = BytecodeForStoreKeyedProperty(language_mode);
319   Output(bytecode, RegisterOperand(object), RegisterOperand(key),
320          UnsignedOperand(feedback_slot));
321   return *this;
322 }
323 
CreateClosure(Handle<SharedFunctionInfo> shared_info,PretenureFlag tenured)324 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure(
325     Handle<SharedFunctionInfo> shared_info, PretenureFlag tenured) {
326   size_t entry = GetConstantPoolEntry(shared_info);
327   Output(Bytecode::kCreateClosure, UnsignedOperand(entry),
328          UnsignedOperand(static_cast<size_t>(tenured)));
329   return *this;
330 }
331 
CreateArguments(CreateArgumentsType type)332 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments(
333     CreateArgumentsType type) {
334   // TODO(rmcilroy): Consider passing the type as a bytecode operand rather
335   // than having two different bytecodes once we have better support for
336   // branches in the InterpreterAssembler.
337   Bytecode bytecode = BytecodeForCreateArguments(type);
338   Output(bytecode);
339   return *this;
340 }
341 
CreateRegExpLiteral(Handle<String> pattern,int literal_index,int flags)342 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral(
343     Handle<String> pattern, int literal_index, int flags) {
344   size_t pattern_entry = GetConstantPoolEntry(pattern);
345   Output(Bytecode::kCreateRegExpLiteral, UnsignedOperand(pattern_entry),
346          UnsignedOperand(literal_index), UnsignedOperand(flags));
347   return *this;
348 }
349 
CreateArrayLiteral(Handle<FixedArray> constant_elements,int literal_index,int flags)350 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral(
351     Handle<FixedArray> constant_elements, int literal_index, int flags) {
352   size_t constant_elements_entry = GetConstantPoolEntry(constant_elements);
353   Output(Bytecode::kCreateArrayLiteral,
354          UnsignedOperand(constant_elements_entry),
355          UnsignedOperand(literal_index), UnsignedOperand(flags));
356   return *this;
357 }
358 
CreateObjectLiteral(Handle<FixedArray> constant_properties,int literal_index,int flags)359 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral(
360     Handle<FixedArray> constant_properties, int literal_index, int flags) {
361   size_t constant_properties_entry = GetConstantPoolEntry(constant_properties);
362   Output(Bytecode::kCreateObjectLiteral,
363          UnsignedOperand(constant_properties_entry),
364          UnsignedOperand(literal_index), UnsignedOperand(flags));
365   return *this;
366 }
367 
PushContext(Register context)368 BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) {
369   Output(Bytecode::kPushContext, RegisterOperand(context));
370   return *this;
371 }
372 
PopContext(Register context)373 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) {
374   Output(Bytecode::kPopContext, RegisterOperand(context));
375   return *this;
376 }
377 
CastAccumulatorToJSObject()378 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() {
379   Output(Bytecode::kToObject);
380   return *this;
381 }
382 
CastAccumulatorToName()383 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() {
384   Output(Bytecode::kToName);
385   return *this;
386 }
387 
CastAccumulatorToNumber()388 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToNumber() {
389   Output(Bytecode::kToNumber);
390   return *this;
391 }
392 
Bind(BytecodeLabel * label)393 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) {
394   pipeline_->BindLabel(label);
395   LeaveBasicBlock();
396   return *this;
397 }
398 
Bind(const BytecodeLabel & target,BytecodeLabel * label)399 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target,
400                                                  BytecodeLabel* label) {
401   pipeline_->BindLabel(target, label);
402   LeaveBasicBlock();
403   return *this;
404 }
405 
OutputJump(Bytecode jump_bytecode,BytecodeLabel * label)406 BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode,
407                                                        BytecodeLabel* label) {
408   BytecodeNode node(jump_bytecode, 0);
409   AttachSourceInfo(&node);
410   pipeline_->WriteJump(&node, label);
411   LeaveBasicBlock();
412   return *this;
413 }
414 
Jump(BytecodeLabel * label)415 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) {
416   return OutputJump(Bytecode::kJump, label);
417 }
418 
JumpIfTrue(BytecodeLabel * label)419 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(BytecodeLabel* label) {
420   // The peephole optimizer attempts to simplify JumpIfToBooleanTrue
421   // to JumpIfTrue.
422   return OutputJump(Bytecode::kJumpIfToBooleanTrue, label);
423 }
424 
JumpIfFalse(BytecodeLabel * label)425 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) {
426   // The peephole optimizer attempts to simplify JumpIfToBooleanFalse
427   // to JumpIfFalse.
428   return OutputJump(Bytecode::kJumpIfToBooleanFalse, label);
429 }
430 
JumpIfNull(BytecodeLabel * label)431 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) {
432   return OutputJump(Bytecode::kJumpIfNull, label);
433 }
434 
JumpIfUndefined(BytecodeLabel * label)435 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined(
436     BytecodeLabel* label) {
437   return OutputJump(Bytecode::kJumpIfUndefined, label);
438 }
439 
JumpIfNotHole(BytecodeLabel * label)440 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotHole(
441     BytecodeLabel* label) {
442   return OutputJump(Bytecode::kJumpIfNotHole, label);
443 }
444 
StackCheck(int position)445 BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck(int position) {
446   if (position != RelocInfo::kNoPosition) {
447     // We need to attach a non-breakable source position to a stack
448     // check, so we simply add it as expression position. There can be
449     // a prior statement position from constructs like:
450     //
451     //    do var x;  while (false);
452     //
453     // A Nop could be inserted for empty statements, but since no code
454     // is associated with these positions, instead we force the stack
455     // check's expression position which eliminates the empty
456     // statement's position.
457     latest_source_info_.ForceExpressionPosition(position);
458   }
459   Output(Bytecode::kStackCheck);
460   return *this;
461 }
462 
Throw()463 BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() {
464   Output(Bytecode::kThrow);
465   return *this;
466 }
467 
ReThrow()468 BytecodeArrayBuilder& BytecodeArrayBuilder::ReThrow() {
469   Output(Bytecode::kReThrow);
470   return *this;
471 }
472 
Return()473 BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
474   SetReturnPosition();
475   Output(Bytecode::kReturn);
476   return_seen_in_block_ = true;
477   return *this;
478 }
479 
Debugger()480 BytecodeArrayBuilder& BytecodeArrayBuilder::Debugger() {
481   Output(Bytecode::kDebugger);
482   return *this;
483 }
484 
ForInPrepare(Register cache_info_triple)485 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare(
486     Register cache_info_triple) {
487   Output(Bytecode::kForInPrepare, RegisterOperand(cache_info_triple));
488   return *this;
489 }
490 
ForInDone(Register index,Register cache_length)491 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInDone(Register index,
492                                                       Register cache_length) {
493   Output(Bytecode::kForInDone, RegisterOperand(index),
494          RegisterOperand(cache_length));
495   return *this;
496 }
497 
ForInNext(Register receiver,Register index,Register cache_type_array_pair,int feedback_slot)498 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext(
499     Register receiver, Register index, Register cache_type_array_pair,
500     int feedback_slot) {
501   Output(Bytecode::kForInNext, RegisterOperand(receiver),
502          RegisterOperand(index), RegisterOperand(cache_type_array_pair),
503          UnsignedOperand(feedback_slot));
504   return *this;
505 }
506 
ForInStep(Register index)507 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) {
508   Output(Bytecode::kForInStep, RegisterOperand(index));
509   return *this;
510 }
511 
SuspendGenerator(Register generator)512 BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator(
513     Register generator) {
514   Output(Bytecode::kSuspendGenerator, RegisterOperand(generator));
515   return *this;
516 }
517 
ResumeGenerator(Register generator)518 BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator(
519     Register generator) {
520   Output(Bytecode::kResumeGenerator, RegisterOperand(generator));
521   return *this;
522 }
523 
MarkHandler(int handler_id,bool will_catch)524 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkHandler(int handler_id,
525                                                         bool will_catch) {
526   BytecodeLabel handler;
527   Bind(&handler);
528   handler_table_builder()->SetHandlerTarget(handler_id, handler.offset());
529   handler_table_builder()->SetPrediction(handler_id, will_catch);
530   return *this;
531 }
532 
MarkTryBegin(int handler_id,Register context)533 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryBegin(int handler_id,
534                                                          Register context) {
535   BytecodeLabel try_begin;
536   Bind(&try_begin);
537   handler_table_builder()->SetTryRegionStart(handler_id, try_begin.offset());
538   handler_table_builder()->SetContextRegister(handler_id, context);
539   return *this;
540 }
541 
MarkTryEnd(int handler_id)542 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryEnd(int handler_id) {
543   BytecodeLabel try_end;
544   Bind(&try_end);
545   handler_table_builder()->SetTryRegionEnd(handler_id, try_end.offset());
546   return *this;
547 }
548 
EnsureReturn()549 void BytecodeArrayBuilder::EnsureReturn() {
550   if (!return_seen_in_block_) {
551     LoadUndefined();
552     Return();
553   }
554   DCHECK(return_seen_in_block_);
555 }
556 
Call(Register callable,Register receiver_args,size_t receiver_args_count,int feedback_slot,TailCallMode tail_call_mode)557 BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
558                                                  Register receiver_args,
559                                                  size_t receiver_args_count,
560                                                  int feedback_slot,
561                                                  TailCallMode tail_call_mode) {
562   Bytecode bytecode = BytecodeForCall(tail_call_mode);
563   Output(bytecode, RegisterOperand(callable), RegisterOperand(receiver_args),
564          UnsignedOperand(receiver_args_count), UnsignedOperand(feedback_slot));
565   return *this;
566 }
567 
New(Register constructor,Register first_arg,size_t arg_count)568 BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor,
569                                                 Register first_arg,
570                                                 size_t arg_count) {
571   if (!first_arg.is_valid()) {
572     DCHECK_EQ(0u, arg_count);
573     first_arg = Register(0);
574   }
575   Output(Bytecode::kNew, RegisterOperand(constructor),
576          RegisterOperand(first_arg), UnsignedOperand(arg_count));
577   return *this;
578 }
579 
CallRuntime(Runtime::FunctionId function_id,Register first_arg,size_t arg_count)580 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
581     Runtime::FunctionId function_id, Register first_arg, size_t arg_count) {
582   DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size);
583   DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort);
584   if (!first_arg.is_valid()) {
585     DCHECK_EQ(0u, arg_count);
586     first_arg = Register(0);
587   }
588   Bytecode bytecode;
589   uint32_t id;
590   if (IntrinsicsHelper::IsSupported(function_id)) {
591     bytecode = Bytecode::kInvokeIntrinsic;
592     id = static_cast<uint32_t>(IntrinsicsHelper::FromRuntimeId(function_id));
593   } else {
594     bytecode = Bytecode::kCallRuntime;
595     id = static_cast<uint32_t>(function_id);
596   }
597   Output(bytecode, id, RegisterOperand(first_arg), UnsignedOperand(arg_count));
598   return *this;
599 }
600 
CallRuntimeForPair(Runtime::FunctionId function_id,Register first_arg,size_t arg_count,Register first_return)601 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
602     Runtime::FunctionId function_id, Register first_arg, size_t arg_count,
603     Register first_return) {
604   DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size);
605   DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort);
606   if (!first_arg.is_valid()) {
607     DCHECK_EQ(0u, arg_count);
608     first_arg = Register(0);
609   }
610   Output(Bytecode::kCallRuntimeForPair, static_cast<uint16_t>(function_id),
611          RegisterOperand(first_arg), UnsignedOperand(arg_count),
612          RegisterOperand(first_return));
613   return *this;
614 }
615 
CallJSRuntime(int context_index,Register receiver_args,size_t receiver_args_count)616 BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime(
617     int context_index, Register receiver_args, size_t receiver_args_count) {
618   Output(Bytecode::kCallJSRuntime, UnsignedOperand(context_index),
619          RegisterOperand(receiver_args), UnsignedOperand(receiver_args_count));
620   return *this;
621 }
622 
Delete(Register object,LanguageMode language_mode)623 BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object,
624                                                    LanguageMode language_mode) {
625   Output(BytecodeForDelete(language_mode), RegisterOperand(object));
626   return *this;
627 }
628 
GetConstantPoolEntry(Handle<Object> object)629 size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) {
630   return constant_array_builder()->Insert(object);
631 }
632 
SetReturnPosition()633 void BytecodeArrayBuilder::SetReturnPosition() {
634   if (return_position_ == RelocInfo::kNoPosition) return;
635   latest_source_info_.MakeStatementPosition(return_position_);
636 }
637 
SetStatementPosition(Statement * stmt)638 void BytecodeArrayBuilder::SetStatementPosition(Statement* stmt) {
639   if (stmt->position() == RelocInfo::kNoPosition) return;
640   latest_source_info_.MakeStatementPosition(stmt->position());
641 }
642 
SetExpressionPosition(Expression * expr)643 void BytecodeArrayBuilder::SetExpressionPosition(Expression* expr) {
644   if (expr->position() == RelocInfo::kNoPosition) return;
645   if (!latest_source_info_.is_statement()) {
646     // Ensure the current expression position is overwritten with the
647     // latest value.
648     latest_source_info_.MakeExpressionPosition(expr->position());
649   }
650 }
651 
SetExpressionAsStatementPosition(Expression * expr)652 void BytecodeArrayBuilder::SetExpressionAsStatementPosition(Expression* expr) {
653   if (expr->position() == RelocInfo::kNoPosition) return;
654   latest_source_info_.MakeStatementPosition(expr->position());
655 }
656 
TemporaryRegisterIsLive(Register reg) const657 bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const {
658   return temporary_register_allocator()->RegisterIsLive(reg);
659 }
660 
RegisterIsValid(Register reg) const661 bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const {
662   if (!reg.is_valid()) {
663     return false;
664   }
665 
666   if (reg.is_current_context() || reg.is_function_closure() ||
667       reg.is_new_target()) {
668     return true;
669   } else if (reg.is_parameter()) {
670     int parameter_index = reg.ToParameterIndex(parameter_count());
671     return parameter_index >= 0 && parameter_index < parameter_count();
672   } else if (reg.index() < fixed_register_count()) {
673     return true;
674   } else {
675     return TemporaryRegisterIsLive(reg);
676   }
677 }
678 
OperandsAreValid(Bytecode bytecode,int operand_count,uint32_t operand0,uint32_t operand1,uint32_t operand2,uint32_t operand3) const679 bool BytecodeArrayBuilder::OperandsAreValid(
680     Bytecode bytecode, int operand_count, uint32_t operand0, uint32_t operand1,
681     uint32_t operand2, uint32_t operand3) const {
682   if (Bytecodes::NumberOfOperands(bytecode) != operand_count) {
683     return false;
684   }
685 
686   uint32_t operands[] = {operand0, operand1, operand2, operand3};
687   const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode);
688   for (int i = 0; i < operand_count; ++i) {
689     switch (operand_types[i]) {
690       case OperandType::kNone:
691         return false;
692       case OperandType::kRegCount: {
693         CHECK_NE(i, 0);
694         CHECK(operand_types[i - 1] == OperandType::kMaybeReg ||
695               operand_types[i - 1] == OperandType::kReg);
696         if (i > 0 && operands[i] > 0) {
697           Register start = Register::FromOperand(operands[i - 1]);
698           Register end(start.index() + static_cast<int>(operands[i]) - 1);
699           if (!RegisterIsValid(start) || !RegisterIsValid(end) || start > end) {
700             return false;
701           }
702         }
703         break;
704       }
705       case OperandType::kFlag8:
706       case OperandType::kIntrinsicId:
707         if (Bytecodes::SizeForUnsignedOperand(operands[i]) >
708             OperandSize::kByte) {
709           return false;
710         }
711         break;
712       case OperandType::kRuntimeId:
713         if (Bytecodes::SizeForUnsignedOperand(operands[i]) >
714             OperandSize::kShort) {
715           return false;
716         }
717         break;
718       case OperandType::kIdx:
719         // TODO(oth): Consider splitting OperandType::kIdx into two
720         // operand types. One which is a constant pool index that can
721         // be checked, and the other is an unsigned value.
722         break;
723       case OperandType::kImm:
724         break;
725       case OperandType::kMaybeReg:
726         if (Register::FromOperand(operands[i]) == Register(0)) {
727           break;
728         }
729       // Fall-through to kReg case.
730       case OperandType::kReg:
731       case OperandType::kRegOut: {
732         Register reg = Register::FromOperand(operands[i]);
733         if (!RegisterIsValid(reg)) {
734           return false;
735         }
736         break;
737       }
738       case OperandType::kRegOutPair:
739       case OperandType::kRegPair: {
740         Register reg0 = Register::FromOperand(operands[i]);
741         Register reg1 = Register(reg0.index() + 1);
742         if (!RegisterIsValid(reg0) || !RegisterIsValid(reg1)) {
743           return false;
744         }
745         break;
746       }
747       case OperandType::kRegOutTriple: {
748         Register reg0 = Register::FromOperand(operands[i]);
749         Register reg1 = Register(reg0.index() + 1);
750         Register reg2 = Register(reg0.index() + 2);
751         if (!RegisterIsValid(reg0) || !RegisterIsValid(reg1) ||
752             !RegisterIsValid(reg2)) {
753           return false;
754         }
755         break;
756       }
757     }
758   }
759 
760   return true;
761 }
762 
763 // static
BytecodeForBinaryOperation(Token::Value op)764 Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) {
765   switch (op) {
766     case Token::Value::ADD:
767       return Bytecode::kAdd;
768     case Token::Value::SUB:
769       return Bytecode::kSub;
770     case Token::Value::MUL:
771       return Bytecode::kMul;
772     case Token::Value::DIV:
773       return Bytecode::kDiv;
774     case Token::Value::MOD:
775       return Bytecode::kMod;
776     case Token::Value::BIT_OR:
777       return Bytecode::kBitwiseOr;
778     case Token::Value::BIT_XOR:
779       return Bytecode::kBitwiseXor;
780     case Token::Value::BIT_AND:
781       return Bytecode::kBitwiseAnd;
782     case Token::Value::SHL:
783       return Bytecode::kShiftLeft;
784     case Token::Value::SAR:
785       return Bytecode::kShiftRight;
786     case Token::Value::SHR:
787       return Bytecode::kShiftRightLogical;
788     default:
789       UNREACHABLE();
790       return Bytecode::kIllegal;
791   }
792 }
793 
794 // static
BytecodeForCountOperation(Token::Value op)795 Bytecode BytecodeArrayBuilder::BytecodeForCountOperation(Token::Value op) {
796   switch (op) {
797     case Token::Value::ADD:
798       return Bytecode::kInc;
799     case Token::Value::SUB:
800       return Bytecode::kDec;
801     default:
802       UNREACHABLE();
803       return Bytecode::kIllegal;
804   }
805 }
806 
807 // static
BytecodeForCompareOperation(Token::Value op)808 Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) {
809   switch (op) {
810     case Token::Value::EQ:
811       return Bytecode::kTestEqual;
812     case Token::Value::NE:
813       return Bytecode::kTestNotEqual;
814     case Token::Value::EQ_STRICT:
815       return Bytecode::kTestEqualStrict;
816     case Token::Value::LT:
817       return Bytecode::kTestLessThan;
818     case Token::Value::GT:
819       return Bytecode::kTestGreaterThan;
820     case Token::Value::LTE:
821       return Bytecode::kTestLessThanOrEqual;
822     case Token::Value::GTE:
823       return Bytecode::kTestGreaterThanOrEqual;
824     case Token::Value::INSTANCEOF:
825       return Bytecode::kTestInstanceOf;
826     case Token::Value::IN:
827       return Bytecode::kTestIn;
828     default:
829       UNREACHABLE();
830       return Bytecode::kIllegal;
831   }
832 }
833 
834 // static
BytecodeForStoreNamedProperty(LanguageMode language_mode)835 Bytecode BytecodeArrayBuilder::BytecodeForStoreNamedProperty(
836     LanguageMode language_mode) {
837   switch (language_mode) {
838     case SLOPPY:
839       return Bytecode::kStaNamedPropertySloppy;
840     case STRICT:
841       return Bytecode::kStaNamedPropertyStrict;
842     default:
843       UNREACHABLE();
844   }
845   return Bytecode::kIllegal;
846 }
847 
848 // static
BytecodeForStoreKeyedProperty(LanguageMode language_mode)849 Bytecode BytecodeArrayBuilder::BytecodeForStoreKeyedProperty(
850     LanguageMode language_mode) {
851   switch (language_mode) {
852     case SLOPPY:
853       return Bytecode::kStaKeyedPropertySloppy;
854     case STRICT:
855       return Bytecode::kStaKeyedPropertyStrict;
856     default:
857       UNREACHABLE();
858   }
859   return Bytecode::kIllegal;
860 }
861 
862 // static
BytecodeForLoadGlobal(TypeofMode typeof_mode)863 Bytecode BytecodeArrayBuilder::BytecodeForLoadGlobal(TypeofMode typeof_mode) {
864   return typeof_mode == INSIDE_TYPEOF ? Bytecode::kLdaGlobalInsideTypeof
865                                       : Bytecode::kLdaGlobal;
866 }
867 
868 // static
BytecodeForStoreGlobal(LanguageMode language_mode)869 Bytecode BytecodeArrayBuilder::BytecodeForStoreGlobal(
870     LanguageMode language_mode) {
871   switch (language_mode) {
872     case SLOPPY:
873       return Bytecode::kStaGlobalSloppy;
874     case STRICT:
875       return Bytecode::kStaGlobalStrict;
876     default:
877       UNREACHABLE();
878   }
879   return Bytecode::kIllegal;
880 }
881 
882 // static
BytecodeForStoreLookupSlot(LanguageMode language_mode)883 Bytecode BytecodeArrayBuilder::BytecodeForStoreLookupSlot(
884     LanguageMode language_mode) {
885   switch (language_mode) {
886     case SLOPPY:
887       return Bytecode::kStaLookupSlotSloppy;
888     case STRICT:
889       return Bytecode::kStaLookupSlotStrict;
890     default:
891       UNREACHABLE();
892   }
893   return Bytecode::kIllegal;
894 }
895 
896 // static
BytecodeForCreateArguments(CreateArgumentsType type)897 Bytecode BytecodeArrayBuilder::BytecodeForCreateArguments(
898     CreateArgumentsType type) {
899   switch (type) {
900     case CreateArgumentsType::kMappedArguments:
901       return Bytecode::kCreateMappedArguments;
902     case CreateArgumentsType::kUnmappedArguments:
903       return Bytecode::kCreateUnmappedArguments;
904     case CreateArgumentsType::kRestParameter:
905       return Bytecode::kCreateRestParameter;
906   }
907   UNREACHABLE();
908   return Bytecode::kIllegal;
909 }
910 
911 // static
BytecodeForDelete(LanguageMode language_mode)912 Bytecode BytecodeArrayBuilder::BytecodeForDelete(LanguageMode language_mode) {
913   switch (language_mode) {
914     case SLOPPY:
915       return Bytecode::kDeletePropertySloppy;
916     case STRICT:
917       return Bytecode::kDeletePropertyStrict;
918     default:
919       UNREACHABLE();
920   }
921   return Bytecode::kIllegal;
922 }
923 
924 // static
BytecodeForCall(TailCallMode tail_call_mode)925 Bytecode BytecodeArrayBuilder::BytecodeForCall(TailCallMode tail_call_mode) {
926   switch (tail_call_mode) {
927     case TailCallMode::kDisallow:
928       return Bytecode::kCall;
929     case TailCallMode::kAllow:
930       return Bytecode::kTailCall;
931     default:
932       UNREACHABLE();
933   }
934   return Bytecode::kIllegal;
935 }
936 
937 }  // namespace interpreter
938 }  // namespace internal
939 }  // namespace v8
940