Index: src/interpreter/bytecode-array-builder.cc |
diff --git a/src/interpreter/bytecode-array-builder.cc b/src/interpreter/bytecode-array-builder.cc |
index dfa395095abaf72da5407a415b7af5edb58b1410..7f22ccbb4b7eb00efcecdecc0b6e0f38c59bf9fc 100644 |
--- a/src/interpreter/bytecode-array-builder.cc |
+++ b/src/interpreter/bytecode-array-builder.cc |
@@ -31,7 +31,8 @@ BytecodeArrayBuilder::BytecodeArrayBuilder( |
register_allocator_(fixed_register_count()), |
bytecode_array_writer_(zone, &constant_array_builder_, |
source_position_mode), |
- pipeline_(&bytecode_array_writer_) { |
+ pipeline_(&bytecode_array_writer_), |
+ register_optimizer_(nullptr) { |
DCHECK_GE(parameter_count_, 0); |
DCHECK_GE(context_register_count_, 0); |
DCHECK_GE(local_register_count_, 0); |
@@ -45,7 +46,7 @@ BytecodeArrayBuilder::BytecodeArrayBuilder( |
} |
if (FLAG_ignition_reo) { |
- pipeline_ = new (zone) BytecodeRegisterOptimizer( |
+ register_optimizer_ = new (zone) BytecodeRegisterOptimizer( |
zone, ®ister_allocator_, fixed_register_count(), parameter_count, |
pipeline_); |
} |
@@ -75,108 +76,222 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) { |
DCHECK(!bytecode_generated_); |
bytecode_generated_ = true; |
+ int register_count = total_register_count(); |
+ |
+ if (register_optimizer_) { |
+ register_optimizer_->Flush(); |
+ register_count = register_optimizer_->maxiumum_register_index() + 1; |
+ } |
+ |
Handle<FixedArray> handler_table = |
handler_table_builder()->ToHandlerTable(isolate); |
- return pipeline_->ToBytecodeArray(isolate, total_register_count(), |
- parameter_count(), handler_table); |
-} |
- |
-void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0, |
- uint32_t operand1, uint32_t operand2, |
- uint32_t operand3) { |
- DCHECK(OperandsAreValid(bytecode, 4, operand0, operand1, operand2, operand3)); |
- BytecodeNode node(bytecode, operand0, operand1, operand2, operand3, |
- &latest_source_info_); |
- pipeline()->Write(&node); |
+ return pipeline_->ToBytecodeArray(isolate, register_count, parameter_count(), |
+ handler_table); |
+} |
+ |
+BytecodeSourceInfo BytecodeArrayBuilder::CurrentSourcePosition( |
+ Bytecode bytecode) { |
+ BytecodeSourceInfo source_position; |
+ if (latest_source_info_.is_valid()) { |
+ // Statement positions need to be emitted immediately. Expression |
+ // positions can be pushed back until a bytecode is found that can |
+ // throw (if expression position filtering is turned on). We only |
+ // invalidate the existing source position information if it is used. |
+ if (latest_source_info_.is_statement() || |
+ !FLAG_ignition_filter_expression_positions || |
+ !Bytecodes::IsWithoutExternalSideEffects(bytecode)) { |
+ source_position = latest_source_info_; |
+ latest_source_info_.set_invalid(); |
+ } |
+ } |
+ return source_position; |
} |
-void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0, |
- uint32_t operand1, uint32_t operand2) { |
- DCHECK(OperandsAreValid(bytecode, 3, operand0, operand1, operand2)); |
- BytecodeNode node(bytecode, operand0, operand1, operand2, |
- &latest_source_info_); |
- pipeline()->Write(&node); |
-} |
+namespace { |
-void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0, |
- uint32_t operand1) { |
- DCHECK(OperandsAreValid(bytecode, 2, operand0, operand1)); |
- BytecodeNode node(bytecode, operand0, operand1, &latest_source_info_); |
- pipeline()->Write(&node); |
-} |
+template <OperandTypeInfo type_info> |
+class UnsignedOperandHelper { |
+ public: |
+ INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, size_t value)) { |
+ DCHECK(IsValid(value)); |
+ return static_cast<uint32_t>(value); |
+ } |
-void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0) { |
- DCHECK(OperandsAreValid(bytecode, 1, operand0)); |
- BytecodeNode node(bytecode, operand0, &latest_source_info_); |
- pipeline()->Write(&node); |
-} |
+ INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, int value)) { |
+ DCHECK_GE(value, 0); |
+ return Convert(builder, static_cast<size_t>(value)); |
+ } |
-void BytecodeArrayBuilder::Output(Bytecode bytecode) { |
- DCHECK(OperandsAreValid(bytecode, 0)); |
- BytecodeNode node(bytecode, &latest_source_info_); |
- pipeline()->Write(&node); |
-} |
+ private: |
+ static bool IsValid(size_t value) { |
+ switch (type_info) { |
+ case OperandTypeInfo::kFixedUnsignedByte: |
+ return value <= kMaxUInt8; |
+ case OperandTypeInfo::kFixedUnsignedShort: |
+ return value <= kMaxUInt16; |
+ case OperandTypeInfo::kScalableUnsignedByte: |
+ return value <= kMaxUInt32; |
+ default: |
+ UNREACHABLE(); |
+ return false; |
+ } |
+ } |
+}; |
+ |
+template <OperandType> |
+class OperandHelper {}; |
+ |
+#define DEFINE_UNSIGNED_OPERAND_HELPER(Name, Type) \ |
+ template <> \ |
+ class OperandHelper<OperandType::k##Name> \ |
+ : public UnsignedOperandHelper<Type> {}; |
+UNSIGNED_SCALAR_OPERAND_TYPE_LIST(DEFINE_UNSIGNED_OPERAND_HELPER) |
+#undef DEFINE_UNSIGNED_OPERAND_HELPER |
+ |
+template <> |
+class OperandHelper<OperandType::kImm> { |
+ public: |
+ INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, int value)) { |
+ return static_cast<uint32_t>(value); |
+ } |
+}; |
-void BytecodeArrayBuilder::OutputJump(Bytecode bytecode, BytecodeLabel* label) { |
- BytecodeNode node(bytecode, 0, &latest_source_info_); |
- pipeline_->WriteJump(&node, label); |
- LeaveBasicBlock(); |
-} |
+template <> |
+class OperandHelper<OperandType::kReg> { |
+ public: |
+ INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, Register reg)) { |
+ return builder->GetInputRegisterOperand(reg); |
+ } |
+}; |
+ |
+template <> |
+class OperandHelper<OperandType::kRegList> { |
+ public: |
+ INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, |
+ RegisterList reg_list)) { |
+ return builder->GetInputRegisterListOperand(reg_list); |
+ } |
+}; |
+ |
+template <> |
+class OperandHelper<OperandType::kRegPair> { |
+ public: |
+ INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, |
+ RegisterList reg_list)) { |
+ DCHECK_EQ(reg_list.register_count(), 2); |
+ return builder->GetInputRegisterListOperand(reg_list); |
+ } |
+}; |
-void BytecodeArrayBuilder::OutputJump(Bytecode bytecode, uint32_t operand0, |
- BytecodeLabel* label) { |
- BytecodeNode node(bytecode, 0, operand0, &latest_source_info_); |
- pipeline_->WriteJump(&node, label); |
- LeaveBasicBlock(); |
-} |
+template <> |
+class OperandHelper<OperandType::kRegOut> { |
+ public: |
+ INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, Register reg)) { |
+ return builder->GetOutputRegisterOperand(reg); |
+ } |
+}; |
+ |
+template <> |
+class OperandHelper<OperandType::kRegOutPair> { |
+ public: |
+ INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, |
+ RegisterList reg_list)) { |
+ DCHECK_EQ(2, reg_list.register_count()); |
+ return builder->GetOutputRegisterListOperand(reg_list); |
+ } |
+}; |
+ |
+template <> |
+class OperandHelper<OperandType::kRegOutTriple> { |
+ public: |
+ INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, |
+ RegisterList reg_list)) { |
+ DCHECK_EQ(3, reg_list.register_count()); |
+ return builder->GetOutputRegisterListOperand(reg_list); |
+ } |
+}; |
+ |
+} // namespace |
+ |
+template <OperandType... operand_types> |
+class BytecodeNodeBuilder { |
+ public: |
+ template <typename... Operands> |
+ INLINE(static BytecodeNode Make(BytecodeArrayBuilder* builder, |
+ BytecodeSourceInfo source_info, |
+ Bytecode bytecode, Operands... operands)) { |
+ builder->PrepareToOutputBytecode(bytecode); |
+ // The "OperandHelper<operand_types>::Convert(builder, operands)..." will |
+ // expand both the OperandType... and Operands... parameter packs e.g. for: |
+ // BytecodeNodeBuilder<OperandType::kReg, OperandType::kImm>::Make< |
+ // Register, int>(..., Register reg, int immediate) |
+ // the code will expand into: |
+ // OperandHelper<OperandType::kReg>::Convert(builder, reg), |
+ // OperandHelper<OperandType::kImm>::Convert(builder, immediate), |
+ return BytecodeNode( |
+ bytecode, OperandHelper<operand_types>::Convert(builder, operands)..., |
+ source_info); |
+ } |
+}; |
+ |
+#define DEFINE_BYTECODE_OUTPUT(name, accumulator_use, ...) \ |
+ template <typename... Operands> \ |
+ void BytecodeArrayBuilder::Output##name(Operands... operands) { \ |
+ BytecodeNode node(BytecodeNodeBuilder<__VA_ARGS__>::Make<Operands...>( \ |
+ this, CurrentSourcePosition(Bytecode::k##name), Bytecode::k##name, \ |
+ operands...)); \ |
+ pipeline()->Write(&node); \ |
+ } \ |
+ \ |
+ template <typename... Operands> \ |
+ void BytecodeArrayBuilder::Output##name(BytecodeLabel* label, \ |
+ Operands... operands) { \ |
+ DCHECK(Bytecodes::IsJump(Bytecode::k##name)); \ |
+ BytecodeNode node(BytecodeNodeBuilder<__VA_ARGS__>::Make<Operands...>( \ |
+ this, CurrentSourcePosition(Bytecode::k##name), Bytecode::k##name, \ |
+ operands...)); \ |
+ pipeline()->WriteJump(&node, label); \ |
+ LeaveBasicBlock(); \ |
+ } |
+BYTECODE_LIST(DEFINE_BYTECODE_OUTPUT) |
+#undef DEFINE_BYTECODE_OUTPUT |
BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op, |
Register reg, |
int feedback_slot) { |
switch (op) { |
case Token::Value::ADD: |
- Output(Bytecode::kAdd, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputAdd(reg, feedback_slot); |
break; |
case Token::Value::SUB: |
- Output(Bytecode::kSub, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputSub(reg, feedback_slot); |
break; |
case Token::Value::MUL: |
- Output(Bytecode::kMul, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputMul(reg, feedback_slot); |
break; |
case Token::Value::DIV: |
- Output(Bytecode::kDiv, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputDiv(reg, feedback_slot); |
break; |
case Token::Value::MOD: |
- Output(Bytecode::kMod, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputMod(reg, feedback_slot); |
break; |
case Token::Value::BIT_OR: |
- Output(Bytecode::kBitwiseOr, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputBitwiseOr(reg, feedback_slot); |
break; |
case Token::Value::BIT_XOR: |
- Output(Bytecode::kBitwiseXor, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputBitwiseXor(reg, feedback_slot); |
break; |
case Token::Value::BIT_AND: |
- Output(Bytecode::kBitwiseAnd, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputBitwiseAnd(reg, feedback_slot); |
break; |
case Token::Value::SHL: |
- Output(Bytecode::kShiftLeft, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputShiftLeft(reg, feedback_slot); |
break; |
case Token::Value::SAR: |
- Output(Bytecode::kShiftRight, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputShiftRight(reg, feedback_slot); |
break; |
case Token::Value::SHR: |
- Output(Bytecode::kShiftRightLogical, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputShiftRightLogical(reg, feedback_slot); |
break; |
default: |
UNREACHABLE(); |
@@ -187,21 +302,21 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op, |
BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op, |
int feedback_slot) { |
if (op == Token::Value::ADD) { |
- Output(Bytecode::kInc, UnsignedOperand(feedback_slot)); |
+ OutputInc(feedback_slot); |
} else { |
DCHECK_EQ(op, Token::Value::SUB); |
- Output(Bytecode::kDec, UnsignedOperand(feedback_slot)); |
+ OutputDec(feedback_slot); |
} |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() { |
- Output(Bytecode::kToBooleanLogicalNot); |
+ OutputToBooleanLogicalNot(); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::TypeOf() { |
- Output(Bytecode::kTypeOf); |
+ OutputTypeOf(); |
return *this; |
} |
@@ -209,38 +324,31 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation( |
Token::Value op, Register reg, int feedback_slot) { |
switch (op) { |
case Token::Value::EQ: |
- Output(Bytecode::kTestEqual, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputTestEqual(reg, feedback_slot); |
break; |
case Token::Value::NE: |
- Output(Bytecode::kTestNotEqual, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputTestNotEqual(reg, feedback_slot); |
break; |
case Token::Value::EQ_STRICT: |
- Output(Bytecode::kTestEqualStrict, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputTestEqualStrict(reg, feedback_slot); |
break; |
case Token::Value::LT: |
- Output(Bytecode::kTestLessThan, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputTestLessThan(reg, feedback_slot); |
break; |
case Token::Value::GT: |
- Output(Bytecode::kTestGreaterThan, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputTestGreaterThan(reg, feedback_slot); |
break; |
case Token::Value::LTE: |
- Output(Bytecode::kTestLessThanOrEqual, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputTestLessThanOrEqual(reg, feedback_slot); |
break; |
case Token::Value::GTE: |
- Output(Bytecode::kTestGreaterThanOrEqual, RegisterOperand(reg), |
- UnsignedOperand(feedback_slot)); |
+ OutputTestGreaterThanOrEqual(reg, feedback_slot); |
break; |
case Token::Value::INSTANCEOF: |
- Output(Bytecode::kTestInstanceOf, RegisterOperand(reg)); |
+ OutputTestInstanceOf(reg); |
break; |
case Token::Value::IN: |
- Output(Bytecode::kTestIn, RegisterOperand(reg)); |
+ OutputTestIn(reg); |
break; |
default: |
UNREACHABLE(); |
@@ -250,7 +358,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation( |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadConstantPoolEntry( |
size_t entry) { |
- Output(Bytecode::kLdaConstant, UnsignedOperand(entry)); |
+ OutputLdaConstant(entry); |
return *this; |
} |
@@ -258,70 +366,82 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( |
v8::internal::Smi* smi) { |
int32_t raw_smi = smi->value(); |
if (raw_smi == 0) { |
- Output(Bytecode::kLdaZero); |
+ OutputLdaZero(); |
} else { |
- Output(Bytecode::kLdaSmi, SignedOperand(raw_smi)); |
+ OutputLdaSmi(raw_smi); |
} |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) { |
size_t entry = GetConstantPoolEntry(object); |
- Output(Bytecode::kLdaConstant, UnsignedOperand(entry)); |
+ OutputLdaConstant(entry); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() { |
- Output(Bytecode::kLdaUndefined); |
+ OutputLdaUndefined(); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() { |
- Output(Bytecode::kLdaNull); |
+ OutputLdaNull(); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() { |
- Output(Bytecode::kLdaTheHole); |
+ OutputLdaTheHole(); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() { |
- Output(Bytecode::kLdaTrue); |
+ OutputLdaTrue(); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() { |
- Output(Bytecode::kLdaFalse); |
+ OutputLdaFalse(); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister( |
Register reg) { |
- Output(Bytecode::kLdar, RegisterOperand(reg)); |
+ if (register_optimizer_) { |
+ register_optimizer_->DoLdar(reg, CurrentSourcePosition(Bytecode::kLdar)); |
+ } else { |
+ OutputLdar(reg); |
+ } |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister( |
Register reg) { |
- Output(Bytecode::kStar, RegisterOperand(reg)); |
+ if (register_optimizer_) { |
+ register_optimizer_->DoStar(reg, CurrentSourcePosition(Bytecode::kStar)); |
+ } else { |
+ OutputStar(reg); |
+ } |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from, |
Register to) { |
DCHECK(from != to); |
- Output(Bytecode::kMov, RegisterOperand(from), RegisterOperand(to)); |
+ if (register_optimizer_) { |
+ register_optimizer_->DoMov(from, to, CurrentSourcePosition(Bytecode::kMov)); |
+ } else { |
+ OutputMov(from, to); |
+ } |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(int feedback_slot, |
TypeofMode typeof_mode) { |
if (typeof_mode == INSIDE_TYPEOF) { |
- Output(Bytecode::kLdaGlobalInsideTypeof, feedback_slot); |
+ OutputLdaGlobalInsideTypeof(feedback_slot); |
} else { |
DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF); |
- Output(Bytecode::kLdaGlobal, UnsignedOperand(feedback_slot)); |
+ OutputLdaGlobal(feedback_slot); |
} |
return *this; |
} |
@@ -330,12 +450,10 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal( |
const Handle<String> name, int feedback_slot, LanguageMode language_mode) { |
size_t name_index = GetConstantPoolEntry(name); |
if (language_mode == SLOPPY) { |
- Output(Bytecode::kStaGlobalSloppy, UnsignedOperand(name_index), |
- UnsignedOperand(feedback_slot)); |
+ OutputStaGlobalSloppy(name_index, feedback_slot); |
} else { |
DCHECK_EQ(language_mode, STRICT); |
- Output(Bytecode::kStaGlobalStrict, UnsignedOperand(name_index), |
- UnsignedOperand(feedback_slot)); |
+ OutputStaGlobalStrict(name_index, feedback_slot); |
} |
return *this; |
} |
@@ -343,16 +461,14 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal( |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context, |
int slot_index, |
int depth) { |
- Output(Bytecode::kLdaContextSlot, RegisterOperand(context), |
- UnsignedOperand(slot_index), UnsignedOperand(depth)); |
+ OutputLdaContextSlot(context, slot_index, depth); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context, |
int slot_index, |
int depth) { |
- Output(Bytecode::kStaContextSlot, RegisterOperand(context), |
- UnsignedOperand(slot_index), UnsignedOperand(depth)); |
+ OutputStaContextSlot(context, slot_index, depth); |
return *this; |
} |
@@ -360,10 +476,10 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot( |
const Handle<String> name, TypeofMode typeof_mode) { |
size_t name_index = GetConstantPoolEntry(name); |
if (typeof_mode == INSIDE_TYPEOF) { |
- Output(Bytecode::kLdaLookupSlotInsideTypeof, UnsignedOperand(name_index)); |
+ OutputLdaLookupSlotInsideTypeof(name_index); |
} else { |
DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF); |
- Output(Bytecode::kLdaLookupSlot, UnsignedOperand(name_index)); |
+ OutputLdaLookupSlot(name_index); |
} |
return *this; |
} |
@@ -371,24 +487,26 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot( |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupContextSlot( |
const Handle<String> name, TypeofMode typeof_mode, int slot_index, |
int depth) { |
- Bytecode bytecode = (typeof_mode == INSIDE_TYPEOF) |
- ? Bytecode::kLdaLookupContextSlotInsideTypeof |
- : Bytecode::kLdaLookupContextSlot; |
size_t name_index = GetConstantPoolEntry(name); |
- Output(bytecode, UnsignedOperand(name_index), UnsignedOperand(slot_index), |
- UnsignedOperand(depth)); |
+ if (typeof_mode == INSIDE_TYPEOF) { |
+ OutputLdaLookupContextSlotInsideTypeof(name_index, slot_index, depth); |
+ } else { |
+ DCHECK(typeof_mode == NOT_INSIDE_TYPEOF); |
+ OutputLdaLookupContextSlot(name_index, slot_index, depth); |
+ } |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupGlobalSlot( |
const Handle<String> name, TypeofMode typeof_mode, int feedback_slot, |
int depth) { |
- Bytecode bytecode = (typeof_mode == INSIDE_TYPEOF) |
- ? Bytecode::kLdaLookupGlobalSlotInsideTypeof |
- : Bytecode::kLdaLookupGlobalSlot; |
size_t name_index = GetConstantPoolEntry(name); |
- Output(bytecode, UnsignedOperand(name_index), UnsignedOperand(feedback_slot), |
- UnsignedOperand(depth)); |
+ if (typeof_mode == INSIDE_TYPEOF) { |
+ OutputLdaLookupGlobalSlotInsideTypeof(name_index, feedback_slot, depth); |
+ } else { |
+ DCHECK(typeof_mode == NOT_INSIDE_TYPEOF); |
+ OutputLdaLookupGlobalSlot(name_index, feedback_slot, depth); |
+ } |
return *this; |
} |
@@ -396,10 +514,10 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot( |
const Handle<String> name, LanguageMode language_mode) { |
size_t name_index = GetConstantPoolEntry(name); |
if (language_mode == SLOPPY) { |
- Output(Bytecode::kStaLookupSlotSloppy, UnsignedOperand(name_index)); |
+ OutputStaLookupSlotSloppy(name_index); |
} else { |
DCHECK_EQ(language_mode, STRICT); |
- Output(Bytecode::kStaLookupSlotStrict, UnsignedOperand(name_index)); |
+ OutputStaLookupSlotStrict(name_index); |
} |
return *this; |
} |
@@ -407,15 +525,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot( |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty( |
Register object, const Handle<Name> name, int feedback_slot) { |
size_t name_index = GetConstantPoolEntry(name); |
- Output(Bytecode::kLdaNamedProperty, RegisterOperand(object), |
- UnsignedOperand(name_index), UnsignedOperand(feedback_slot)); |
+ OutputLdaNamedProperty(object, name_index, feedback_slot); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty( |
Register object, int feedback_slot) { |
- Output(Bytecode::kLdaKeyedProperty, RegisterOperand(object), |
- UnsignedOperand(feedback_slot)); |
+ OutputLdaKeyedProperty(object, feedback_slot); |
return *this; |
} |
@@ -424,12 +540,10 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty( |
LanguageMode language_mode) { |
size_t name_index = GetConstantPoolEntry(name); |
if (language_mode == SLOPPY) { |
- Output(Bytecode::kStaNamedPropertySloppy, RegisterOperand(object), |
- UnsignedOperand(name_index), UnsignedOperand(feedback_slot)); |
+ OutputStaNamedPropertySloppy(object, name_index, feedback_slot); |
} else { |
DCHECK_EQ(language_mode, STRICT); |
- Output(Bytecode::kStaNamedPropertyStrict, RegisterOperand(object), |
- UnsignedOperand(name_index), UnsignedOperand(feedback_slot)); |
+ OutputStaNamedPropertyStrict(object, name_index, feedback_slot); |
} |
return *this; |
} |
@@ -438,27 +552,24 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty( |
Register object, Register key, int feedback_slot, |
LanguageMode language_mode) { |
if (language_mode == SLOPPY) { |
- Output(Bytecode::kStaKeyedPropertySloppy, RegisterOperand(object), |
- RegisterOperand(key), UnsignedOperand(feedback_slot)); |
+ OutputStaKeyedPropertySloppy(object, key, feedback_slot); |
} else { |
DCHECK_EQ(language_mode, STRICT); |
- Output(Bytecode::kStaKeyedPropertyStrict, RegisterOperand(object), |
- RegisterOperand(key), UnsignedOperand(feedback_slot)); |
+ OutputStaKeyedPropertyStrict(object, key, feedback_slot); |
} |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure(size_t entry, |
int flags) { |
- Output(Bytecode::kCreateClosure, UnsignedOperand(entry), |
- UnsignedOperand(flags)); |
+ OutputCreateClosure(entry, flags); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateBlockContext( |
Handle<ScopeInfo> scope_info) { |
size_t entry = GetConstantPoolEntry(scope_info); |
- Output(Bytecode::kCreateBlockContext, UnsignedOperand(entry)); |
+ OutputCreateBlockContext(entry); |
return *this; |
} |
@@ -466,21 +577,19 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateCatchContext( |
Register exception, Handle<String> name, Handle<ScopeInfo> scope_info) { |
size_t name_index = GetConstantPoolEntry(name); |
size_t scope_info_index = GetConstantPoolEntry(scope_info); |
- Output(Bytecode::kCreateCatchContext, RegisterOperand(exception), |
- UnsignedOperand(name_index), UnsignedOperand(scope_info_index)); |
+ OutputCreateCatchContext(exception, name_index, scope_info_index); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateFunctionContext(int slots) { |
- Output(Bytecode::kCreateFunctionContext, UnsignedOperand(slots)); |
+ OutputCreateFunctionContext(slots); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateWithContext( |
Register object, Handle<ScopeInfo> scope_info) { |
size_t scope_info_index = GetConstantPoolEntry(scope_info); |
- Output(Bytecode::kCreateWithContext, RegisterOperand(object), |
- UnsignedOperand(scope_info_index)); |
+ OutputCreateWithContext(object, scope_info_index); |
return *this; |
} |
@@ -488,13 +597,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments( |
CreateArgumentsType type) { |
switch (type) { |
case CreateArgumentsType::kMappedArguments: |
- Output(Bytecode::kCreateMappedArguments); |
+ OutputCreateMappedArguments(); |
break; |
case CreateArgumentsType::kUnmappedArguments: |
- Output(Bytecode::kCreateUnmappedArguments); |
+ OutputCreateUnmappedArguments(); |
break; |
case CreateArgumentsType::kRestParameter: |
- Output(Bytecode::kCreateRestParameter); |
+ OutputCreateRestParameter(); |
break; |
default: |
UNREACHABLE(); |
@@ -505,17 +614,14 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments( |
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral( |
Handle<String> pattern, int literal_index, int flags) { |
size_t pattern_entry = GetConstantPoolEntry(pattern); |
- Output(Bytecode::kCreateRegExpLiteral, UnsignedOperand(pattern_entry), |
- UnsignedOperand(literal_index), UnsignedOperand(flags)); |
+ OutputCreateRegExpLiteral(pattern_entry, literal_index, flags); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral( |
Handle<FixedArray> constant_elements, int literal_index, int flags) { |
size_t constant_elements_entry = GetConstantPoolEntry(constant_elements); |
- Output(Bytecode::kCreateArrayLiteral, |
- UnsignedOperand(constant_elements_entry), |
- UnsignedOperand(literal_index), UnsignedOperand(flags)); |
+ OutputCreateArrayLiteral(constant_elements_entry, literal_index, flags); |
return *this; |
} |
@@ -523,42 +629,43 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral( |
Handle<FixedArray> constant_properties, int literal_index, int flags, |
Register output) { |
size_t constant_properties_entry = GetConstantPoolEntry(constant_properties); |
- Output(Bytecode::kCreateObjectLiteral, |
- UnsignedOperand(constant_properties_entry), |
- UnsignedOperand(literal_index), UnsignedOperand(flags), |
- RegisterOperand(output)); |
+ OutputCreateObjectLiteral(constant_properties_entry, literal_index, flags, |
+ output); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) { |
- Output(Bytecode::kPushContext, RegisterOperand(context)); |
+ OutputPushContext(context); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { |
- Output(Bytecode::kPopContext, RegisterOperand(context)); |
+ OutputPopContext(context); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToObject( |
Register out) { |
- Output(Bytecode::kToObject, RegisterOperand(out)); |
+ OutputToObject(out); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToName( |
Register out) { |
- Output(Bytecode::kToName, RegisterOperand(out)); |
+ OutputToName(out); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToNumber( |
Register out) { |
- Output(Bytecode::kToNumber, RegisterOperand(out)); |
+ OutputToNumber(out); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) { |
+ // Flush the register optimizer when binding a label to ensure all |
+ // expected registers are valid when jumping to this label. |
+ if (register_optimizer_) register_optimizer_->Flush(); |
pipeline_->BindLabel(label); |
LeaveBasicBlock(); |
return *this; |
@@ -572,42 +679,42 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target, |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) { |
- OutputJump(Bytecode::kJump, label); |
+ OutputJump(label, 0); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(BytecodeLabel* label) { |
// The peephole optimizer attempts to simplify JumpIfToBooleanTrue |
// to JumpIfTrue. |
- OutputJump(Bytecode::kJumpIfToBooleanTrue, label); |
+ OutputJumpIfToBooleanTrue(label, 0); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) { |
- OutputJump(Bytecode::kJumpIfToBooleanFalse, label); |
+ OutputJumpIfToBooleanFalse(label, 0); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) { |
- OutputJump(Bytecode::kJumpIfNull, label); |
+ OutputJumpIfNull(label, 0); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined( |
BytecodeLabel* label) { |
- OutputJump(Bytecode::kJumpIfUndefined, label); |
+ OutputJumpIfUndefined(label, 0); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotHole( |
BytecodeLabel* label) { |
- OutputJump(Bytecode::kJumpIfNotHole, label); |
+ OutputJumpIfNotHole(label, 0); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpLoop(BytecodeLabel* label, |
int loop_depth) { |
- OutputJump(Bytecode::kJumpLoop, UnsignedOperand(loop_depth), label); |
+ OutputJumpLoop(label, 0, loop_depth); |
return *this; |
} |
@@ -625,44 +732,42 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck(int position) { |
// statement's position. |
latest_source_info_.ForceExpressionPosition(position); |
} |
- Output(Bytecode::kStackCheck); |
+ OutputStackCheck(); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() { |
- Output(Bytecode::kThrow); |
+ OutputThrow(); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::ReThrow() { |
- Output(Bytecode::kReThrow); |
+ OutputReThrow(); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::Return() { |
SetReturnPosition(); |
- Output(Bytecode::kReturn); |
+ OutputReturn(); |
return_seen_in_block_ = true; |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::Debugger() { |
- Output(Bytecode::kDebugger); |
+ OutputDebugger(); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare( |
Register receiver, RegisterList cache_info_triple) { |
DCHECK_EQ(3, cache_info_triple.register_count()); |
- Output(Bytecode::kForInPrepare, RegisterOperand(receiver), |
- RegisterOperand(cache_info_triple.first_register())); |
+ OutputForInPrepare(receiver, cache_info_triple); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInContinue( |
Register index, Register cache_length) { |
- Output(Bytecode::kForInContinue, RegisterOperand(index), |
- RegisterOperand(cache_length)); |
+ OutputForInContinue(index, cache_length); |
return *this; |
} |
@@ -670,27 +775,24 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext( |
Register receiver, Register index, RegisterList cache_type_array_pair, |
int feedback_slot) { |
DCHECK_EQ(2, cache_type_array_pair.register_count()); |
- Output(Bytecode::kForInNext, RegisterOperand(receiver), |
- RegisterOperand(index), |
- RegisterOperand(cache_type_array_pair.first_register()), |
- UnsignedOperand(feedback_slot)); |
+ OutputForInNext(receiver, index, cache_type_array_pair, feedback_slot); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) { |
- Output(Bytecode::kForInStep, RegisterOperand(index)); |
+ OutputForInStep(index); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator( |
Register generator) { |
- Output(Bytecode::kSuspendGenerator, RegisterOperand(generator)); |
+ OutputSuspendGenerator(generator); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator( |
Register generator) { |
- Output(Bytecode::kResumeGenerator, RegisterOperand(generator)); |
+ OutputResumeGenerator(generator); |
return *this; |
} |
@@ -724,16 +826,10 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, |
int feedback_slot, |
TailCallMode tail_call_mode) { |
if (tail_call_mode == TailCallMode::kDisallow) { |
- Output(Bytecode::kCall, RegisterOperand(callable), |
- RegisterOperand(args.first_register()), |
- UnsignedOperand(args.register_count()), |
- UnsignedOperand(feedback_slot)); |
+ OutputCall(callable, args, args.register_count(), feedback_slot); |
} else { |
DCHECK(tail_call_mode == TailCallMode::kAllow); |
- Output(Bytecode::kTailCall, RegisterOperand(callable), |
- RegisterOperand(args.first_register()), |
- UnsignedOperand(args.register_count()), |
- UnsignedOperand(feedback_slot)); |
+ OutputTailCall(callable, args, args.register_count(), feedback_slot); |
} |
return *this; |
} |
@@ -741,10 +837,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, |
BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor, |
RegisterList args, |
int feedback_slot_id) { |
- Output(Bytecode::kNew, RegisterOperand(constructor), |
- RegisterOperand(args.first_register()), |
- UnsignedOperand(args.register_count()), |
- UnsignedOperand(feedback_slot_id)); |
+ OutputNew(constructor, args, args.register_count(), feedback_slot_id); |
return *this; |
} |
@@ -752,17 +845,15 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( |
Runtime::FunctionId function_id, RegisterList args) { |
DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size); |
DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort); |
- Bytecode bytecode; |
- uint32_t id; |
if (IntrinsicsHelper::IsSupported(function_id)) { |
- bytecode = Bytecode::kInvokeIntrinsic; |
- id = static_cast<uint32_t>(IntrinsicsHelper::FromRuntimeId(function_id)); |
+ IntrinsicsHelper::IntrinsicId intrinsic_id = |
+ IntrinsicsHelper::FromRuntimeId(function_id); |
+ OutputInvokeIntrinsic(static_cast<int>(intrinsic_id), args, |
+ args.register_count()); |
} else { |
- bytecode = Bytecode::kCallRuntime; |
- id = static_cast<uint32_t>(function_id); |
+ OutputCallRuntime(static_cast<int>(function_id), args, |
+ args.register_count()); |
} |
- Output(bytecode, id, RegisterOperand(args.first_register()), |
- UnsignedOperand(args.register_count())); |
return *this; |
} |
@@ -782,10 +873,8 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair( |
DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size); |
DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort); |
DCHECK_EQ(2, return_pair.register_count()); |
- Output(Bytecode::kCallRuntimeForPair, static_cast<uint16_t>(function_id), |
- RegisterOperand(args.first_register()), |
- UnsignedOperand(args.register_count()), |
- RegisterOperand(return_pair.first_register())); |
+ OutputCallRuntimeForPair(static_cast<uint16_t>(function_id), args, |
+ args.register_count(), return_pair); |
return *this; |
} |
@@ -797,19 +886,17 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair( |
BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime(int context_index, |
RegisterList args) { |
- Output(Bytecode::kCallJSRuntime, UnsignedOperand(context_index), |
- RegisterOperand(args.first_register()), |
- UnsignedOperand(args.register_count())); |
+ OutputCallJSRuntime(context_index, args, args.register_count()); |
return *this; |
} |
BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object, |
LanguageMode language_mode) { |
if (language_mode == SLOPPY) { |
- Output(Bytecode::kDeletePropertySloppy, RegisterOperand(object)); |
+ OutputDeletePropertySloppy(object); |
} else { |
DCHECK_EQ(language_mode, STRICT); |
- Output(Bytecode::kDeletePropertyStrict, RegisterOperand(object)); |
+ OutputDeletePropertyStrict(object); |
} |
return *this; |
} |
@@ -850,88 +937,50 @@ bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const { |
} |
} |
-bool BytecodeArrayBuilder::OperandsAreValid( |
- Bytecode bytecode, int operand_count, uint32_t operand0, uint32_t operand1, |
- uint32_t operand2, uint32_t operand3) const { |
- if (Bytecodes::NumberOfOperands(bytecode) != operand_count) { |
- return false; |
- } |
- |
- uint32_t operands[] = {operand0, operand1, operand2, operand3}; |
- const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode); |
- for (int i = 0; i < operand_count; ++i) { |
- switch (operand_types[i]) { |
- case OperandType::kNone: |
+bool BytecodeArrayBuilder::RegisterListIsValid(RegisterList reg_list) const { |
+ if (reg_list.register_count() == 0) { |
+ return reg_list.first_register() == Register(0); |
+ } else { |
+ int first_reg_index = reg_list.first_register().index(); |
+ for (int i = 0; i < reg_list.register_count(); i++) { |
+ if (!RegisterIsValid(Register(first_reg_index + i))) { |
return false; |
- case OperandType::kFlag8: |
- case OperandType::kIntrinsicId: |
- if (Bytecodes::SizeForUnsignedOperand(operands[i]) > |
- OperandSize::kByte) { |
- return false; |
- } |
- break; |
- case OperandType::kRuntimeId: |
- if (Bytecodes::SizeForUnsignedOperand(operands[i]) > |
- OperandSize::kShort) { |
- return false; |
- } |
- break; |
- case OperandType::kIdx: |
- // TODO(leszeks): Possibly split this up into constant pool indices and |
- // other indices, for checking. |
- break; |
- case OperandType::kUImm: |
- case OperandType::kImm: |
- break; |
- case OperandType::kRegList: { |
- CHECK_LT(i, operand_count - 1); |
- CHECK(operand_types[i + 1] == OperandType::kRegCount); |
- int reg_count = static_cast<int>(operands[i + 1]); |
- if (reg_count == 0) { |
- return Register::FromOperand(operands[i]) == Register(0); |
- } else { |
- Register start = Register::FromOperand(operands[i]); |
- Register end(start.index() + reg_count - 1); |
- if (!RegisterIsValid(start) || !RegisterIsValid(end) || start > end) { |
- return false; |
- } |
- } |
- i++; // Skip past kRegCount operand. |
- break; |
- } |
- case OperandType::kReg: |
- case OperandType::kRegOut: { |
- Register reg = Register::FromOperand(operands[i]); |
- if (!RegisterIsValid(reg)) { |
- return false; |
- } |
- break; |
- } |
- case OperandType::kRegOutPair: |
- case OperandType::kRegPair: { |
- Register reg0 = Register::FromOperand(operands[i]); |
- Register reg1 = Register(reg0.index() + 1); |
- if (!RegisterIsValid(reg0) || !RegisterIsValid(reg1)) { |
- return false; |
- } |
- break; |
- } |
- case OperandType::kRegOutTriple: { |
- Register reg0 = Register::FromOperand(operands[i]); |
- Register reg1 = Register(reg0.index() + 1); |
- Register reg2 = Register(reg0.index() + 2); |
- if (!RegisterIsValid(reg0) || !RegisterIsValid(reg1) || |
- !RegisterIsValid(reg2)) { |
- return false; |
- } |
- break; |
} |
- case OperandType::kRegCount: |
- UNREACHABLE(); // Dealt with in kRegList above. |
} |
+ return true; |
} |
+} |
+ |
+void BytecodeArrayBuilder::PrepareToOutputBytecode(Bytecode bytecode) { |
+ if (register_optimizer_) register_optimizer_->PrepareForBytecode(bytecode); |
+} |
+ |
+uint32_t BytecodeArrayBuilder::GetInputRegisterOperand(Register reg) { |
+ DCHECK(RegisterIsValid(reg)); |
+ if (register_optimizer_) reg = register_optimizer_->GetInputRegister(reg); |
+ return static_cast<uint32_t>(reg.ToOperand()); |
+} |
+ |
+uint32_t BytecodeArrayBuilder::GetOutputRegisterOperand(Register reg) { |
+ DCHECK(RegisterIsValid(reg)); |
+ if (register_optimizer_) register_optimizer_->PrepareOutputRegister(reg); |
+ return static_cast<uint32_t>(reg.ToOperand()); |
+} |
+ |
+uint32_t BytecodeArrayBuilder::GetInputRegisterListOperand( |
+ RegisterList reg_list) { |
+ DCHECK(RegisterListIsValid(reg_list)); |
+ if (register_optimizer_) |
+ reg_list = register_optimizer_->GetInputRegisterList(reg_list); |
+ return static_cast<uint32_t>(reg_list.first_register().ToOperand()); |
+} |
- return true; |
+uint32_t BytecodeArrayBuilder::GetOutputRegisterListOperand( |
+ RegisterList reg_list) { |
+ DCHECK(RegisterListIsValid(reg_list)); |
+ if (register_optimizer_) |
+ register_optimizer_->PrepareOutputRegisterList(reg_list); |
+ return static_cast<uint32_t>(reg_list.first_register().ToOperand()); |
} |
} // namespace interpreter |