Index: src/interpreter/bytecode-array-builder.cc |
diff --git a/src/interpreter/bytecode-array-builder.cc b/src/interpreter/bytecode-array-builder.cc |
index b901916b60b16df9d5c24db492526e12109ad991..221b52d8a65d5625824d5355d573b63a2585b62e 100644 |
--- a/src/interpreter/bytecode-array-builder.cc |
+++ b/src/interpreter/bytecode-array-builder.cc |
@@ -52,7 +52,8 @@ class BytecodeArrayBuilder::PreviousBytecodeHelper { |
} |
Handle<Object> GetConstantForIndexOperand(int operand_index) const { |
- return array_builder_.constants_.at(GetOperand(operand_index)); |
+ return array_builder_.constant_array_builder()->At( |
+ GetOperand(operand_index)); |
} |
private: |
@@ -68,12 +69,11 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone) |
zone_(zone), |
bytecodes_(zone), |
bytecode_generated_(false), |
+ constant_array_builder_(isolate, zone), |
last_block_end_(0), |
last_bytecode_start_(~0), |
exit_seen_in_block_(false), |
unbound_jumps_(0), |
- constants_map_(isolate->heap(), zone), |
- constants_(zone), |
parameter_count_(-1), |
local_register_count_(-1), |
context_register_count_(-1), |
@@ -144,21 +144,14 @@ bool BytecodeArrayBuilder::RegisterIsTemporary(Register reg) const { |
Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { |
DCHECK_EQ(bytecode_generated_, false); |
- |
EnsureReturn(); |
int bytecode_size = static_cast<int>(bytecodes_.size()); |
int register_count = fixed_register_count() + temporary_register_count_; |
int frame_size = register_count * kPointerSize; |
- |
Factory* factory = isolate_->factory(); |
- int constants_count = static_cast<int>(constants_.size()); |
Handle<FixedArray> constant_pool = |
- factory->NewFixedArray(constants_count, TENURED); |
- for (int i = 0; i < constants_count; i++) { |
- constant_pool->set(i, *constants_[i]); |
- } |
- |
+ constant_array_builder()->ToFixedArray(factory); |
Handle<BytecodeArray> output = |
factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size, |
parameter_count(), constant_pool); |
@@ -767,44 +760,33 @@ Bytecode BytecodeArrayBuilder::GetJumpWithConstantOperand( |
return Bytecode::kJumpIfUndefinedConstant; |
default: |
UNREACHABLE(); |
- return Bytecode::kJumpConstant; |
+ return static_cast<Bytecode>(-1); |
} |
} |
-void BytecodeArrayBuilder::PatchJump( |
- const ZoneVector<uint8_t>::iterator& jump_target, |
- ZoneVector<uint8_t>::iterator jump_location) { |
- Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location); |
- int delta = static_cast<int>(jump_target - jump_location); |
- |
- DCHECK(Bytecodes::IsJump(jump_bytecode)); |
- DCHECK_EQ(Bytecodes::Size(jump_bytecode), 2); |
- DCHECK_NE(delta, 0); |
- |
- if (FitsInImm8Operand(delta)) { |
- // Just update the operand |
- jump_location++; |
- *jump_location = static_cast<uint8_t>(delta); |
- } else { |
- // Update the jump type and operand |
- size_t entry = GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate())); |
- if (FitsInIdx8Operand(entry)) { |
- jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); |
- *jump_location++ = Bytecodes::ToByte(jump_bytecode); |
- *jump_location = static_cast<uint8_t>(entry); |
- } else { |
- // TODO(oth): OutputJump should reserve a constant pool entry |
- // when jump is written. The reservation should be used here if |
- // needed, or cancelled if not. This is due to the patch needing |
- // to match the size of the code it's replacing. In future, |
- // there will probably be a jump with 32-bit operand for cases |
- // when constant pool is full, but that needs to be emitted in |
- // OutputJump too. |
- UNIMPLEMENTED(); |
- } |
+// static |
+Bytecode BytecodeArrayBuilder::GetJumpWithConstantWideOperand( |
+ Bytecode jump_bytecode) { |
+ switch (jump_bytecode) { |
+ case Bytecode::kJump: |
+ return Bytecode::kJumpConstantWide; |
+ case Bytecode::kJumpIfTrue: |
+ return Bytecode::kJumpIfTrueConstantWide; |
+ case Bytecode::kJumpIfFalse: |
+ return Bytecode::kJumpIfFalseConstantWide; |
+ case Bytecode::kJumpIfToBooleanTrue: |
+ return Bytecode::kJumpIfToBooleanTrueConstantWide; |
+ case Bytecode::kJumpIfToBooleanFalse: |
+ return Bytecode::kJumpIfToBooleanFalseConstantWide; |
+ case Bytecode::kJumpIfNull: |
+ return Bytecode::kJumpIfNullConstantWide; |
+ case Bytecode::kJumpIfUndefined: |
+ return Bytecode::kJumpIfUndefinedConstantWide; |
+ default: |
+ UNREACHABLE(); |
+ return static_cast<Bytecode>(-1); |
} |
- unbound_jumps_--; |
} |
@@ -826,6 +808,66 @@ Bytecode BytecodeArrayBuilder::GetJumpWithToBoolean(Bytecode jump_bytecode) { |
} |
+void BytecodeArrayBuilder::PatchIndirectJumpWith8BitOperand( |
+ const ZoneVector<uint8_t>::iterator& jump_location, int delta) { |
+ Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location); |
+ DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode)); |
+ ZoneVector<uint8_t>::iterator operand_location = jump_location + 1; |
+ DCHECK_EQ(*operand_location, 0); |
+ if (FitsInImm8Operand(delta)) { |
+ // The jump fits within the range of an Imm8 operand, so cancel |
+ // the reservation and jump directly. |
+ constant_array_builder()->DiscardReservedEntry(OperandSize::kByte); |
+ *operand_location = static_cast<uint8_t>(delta); |
+ } else { |
+ // The jump does not fit within the range of an Imm8 operand, so |
+ // commit reservation putting the offset into the constant pool, |
+ // and update the jump instruction and operand. |
+ size_t entry = constant_array_builder()->CommitReservedEntry( |
+ OperandSize::kByte, handle(Smi::FromInt(delta), isolate())); |
+ DCHECK(FitsInIdx8Operand(entry)); |
+ jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); |
+ *jump_location = Bytecodes::ToByte(jump_bytecode); |
+ *operand_location = static_cast<uint8_t>(entry); |
+ } |
+} |
+ |
+ |
+void BytecodeArrayBuilder::PatchIndirectJumpWith16BitOperand( |
+ const ZoneVector<uint8_t>::iterator& jump_location, int delta) { |
+ DCHECK(Bytecodes::IsJumpConstantWide(Bytecodes::FromByte(*jump_location))); |
+ ZoneVector<uint8_t>::iterator operand_location = jump_location + 1; |
+ size_t entry = constant_array_builder()->CommitReservedEntry( |
+ OperandSize::kShort, handle(Smi::FromInt(delta), isolate())); |
+ DCHECK(FitsInIdx16Operand(entry)); |
+ uint8_t operand_bytes[2]; |
+ WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry)); |
+ DCHECK(*operand_location == 0 && *(operand_location + 1) == 0); |
+ *operand_location++ = operand_bytes[0]; |
+ *operand_location = operand_bytes[1]; |
+} |
+ |
+ |
+void BytecodeArrayBuilder::PatchJump( |
+ const ZoneVector<uint8_t>::iterator& jump_target, |
+ const ZoneVector<uint8_t>::iterator& jump_location) { |
+ Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location); |
+ int delta = static_cast<int>(jump_target - jump_location); |
+ DCHECK(Bytecodes::IsJump(jump_bytecode)); |
+ switch (Bytecodes::GetOperandSize(jump_bytecode, 0)) { |
+ case OperandSize::kByte: |
+ PatchIndirectJumpWith8BitOperand(jump_location, delta); |
+ break; |
+ case OperandSize::kShort: |
+ PatchIndirectJumpWith16BitOperand(jump_location, delta); |
+ break; |
+ case OperandSize::kNone: |
+ UNREACHABLE(); |
+ } |
+ unbound_jumps_--; |
+} |
+ |
+ |
BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode, |
BytecodeLabel* label) { |
// Don't emit dead code. |
@@ -837,30 +879,48 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode, |
jump_bytecode = GetJumpWithToBoolean(jump_bytecode); |
} |
- int delta; |
if (label->is_bound()) { |
// Label has been bound already so this is a backwards jump. |
CHECK_GE(bytecodes()->size(), label->offset()); |
CHECK_LE(bytecodes()->size(), static_cast<size_t>(kMaxInt)); |
size_t abs_delta = bytecodes()->size() - label->offset(); |
- delta = -static_cast<int>(abs_delta); |
+ int delta = -static_cast<int>(abs_delta); |
+ |
+ if (FitsInImm8Operand(delta)) { |
+ Output(jump_bytecode, static_cast<uint8_t>(delta)); |
+ } else { |
+ size_t entry = |
+ GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate())); |
+ if (FitsInIdx8Operand(entry)) { |
+ Output(GetJumpWithConstantOperand(jump_bytecode), |
+ static_cast<uint8_t>(entry)); |
+ } else if (FitsInIdx16Operand(entry)) { |
+ Output(GetJumpWithConstantWideOperand(jump_bytecode), |
+ static_cast<uint16_t>(entry)); |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ } |
} else { |
- // Label has not yet been bound so this is a forward reference |
- // that will be patched when the label is bound. |
+ // The label has not yet been bound so this is a forward reference |
+ // that will be patched when the label is bound. We create a |
+ // reservation in the constant pool so the jump can be patched |
+ // when the label is bound. The reservation means the maximum size |
+ // of the operand for the constant is known and the jump can |
+ // be emitted into the bytecode stream with space for the operand. |
label->set_referrer(bytecodes()->size()); |
- delta = 0; |
unbound_jumps_++; |
- } |
- |
- if (FitsInImm8Operand(delta)) { |
- Output(jump_bytecode, static_cast<uint8_t>(delta)); |
- } else { |
- size_t entry = GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate())); |
- if (FitsInIdx8Operand(entry)) { |
- Output(GetJumpWithConstantOperand(jump_bytecode), |
- static_cast<uint8_t>(entry)); |
- } else { |
- UNIMPLEMENTED(); |
+ OperandSize reserved_operand_size = |
+ constant_array_builder()->CreateReservedEntry(); |
+ switch (reserved_operand_size) { |
+ case OperandSize::kByte: |
+ Output(jump_bytecode, 0); |
+ break; |
+ case OperandSize::kShort: |
+ Output(GetJumpWithConstantWideOperand(jump_bytecode), 0); |
+ break; |
+ case OperandSize::kNone: |
+ UNREACHABLE(); |
} |
} |
LeaveBasicBlock(); |
@@ -1026,22 +1086,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::DeleteLookupSlot() { |
size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) { |
- // These constants shouldn't be added to the constant pool, the should use |
- // specialzed bytecodes instead. |
- DCHECK(!object.is_identical_to(isolate_->factory()->undefined_value())); |
- DCHECK(!object.is_identical_to(isolate_->factory()->null_value())); |
- DCHECK(!object.is_identical_to(isolate_->factory()->the_hole_value())); |
- DCHECK(!object.is_identical_to(isolate_->factory()->true_value())); |
- DCHECK(!object.is_identical_to(isolate_->factory()->false_value())); |
- |
- size_t* entry = constants_map_.Find(object); |
- if (!entry) { |
- entry = constants_map_.Get(object); |
- *entry = constants_.size(); |
- constants_.push_back(object); |
- } |
- DCHECK(constants_[*entry].is_identical_to(object)); |
- return *entry; |
+ return constant_array_builder()->Insert(object); |
} |