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