Commit de9d1d8b authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Move jump processing to bytecode array writer.

This moves processing of jumps out of bytecode array builder and into
bytecode array writer. This simplifies the pipeline by avoiding having
to flush for offset and patch up offsets in bytecode array builder based
on what was emitted by the bytecode array writer.

This also enables future refactorings to add dead code elimination back
into the pipeline, and move processing of scalable operand sizes to the
end of the pipeline (in the bytecode array writer) rather than having to
deal with scalable operand types throughout pipeline.

BUG=v8:4280,chromium:616064

Review-Url: https://codereview.chromium.org/2035813002
Cr-Commit-Position: refs/heads/master@{#36716}
parent a09fb95b
...@@ -1229,6 +1229,7 @@ v8_source_set("v8_base") { ...@@ -1229,6 +1229,7 @@ v8_source_set("v8_base") {
"src/interpreter/bytecode-array-writer.h", "src/interpreter/bytecode-array-writer.h",
"src/interpreter/bytecode-generator.cc", "src/interpreter/bytecode-generator.cc",
"src/interpreter/bytecode-generator.h", "src/interpreter/bytecode-generator.h",
"src/interpreter/bytecode-label.h",
"src/interpreter/bytecode-peephole-optimizer.cc", "src/interpreter/bytecode-peephole-optimizer.cc",
"src/interpreter/bytecode-peephole-optimizer.h", "src/interpreter/bytecode-peephole-optimizer.h",
"src/interpreter/bytecode-pipeline.cc", "src/interpreter/bytecode-pipeline.cc",
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "src/compiler.h" #include "src/compiler.h"
#include "src/interpreter/bytecode-array-writer.h" #include "src/interpreter/bytecode-array-writer.h"
#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/bytecode-peephole-optimizer.h" #include "src/interpreter/bytecode-peephole-optimizer.h"
#include "src/interpreter/bytecode-register-optimizer.h" #include "src/interpreter/bytecode-register-optimizer.h"
#include "src/interpreter/interpreter-intrinsics.h" #include "src/interpreter/interpreter-intrinsics.h"
...@@ -23,14 +24,12 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone, ...@@ -23,14 +24,12 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone,
bytecode_generated_(false), bytecode_generated_(false),
constant_array_builder_(isolate, zone), constant_array_builder_(isolate, zone),
handler_table_builder_(isolate, zone), handler_table_builder_(isolate, zone),
source_position_table_builder_(isolate, zone),
return_seen_in_block_(false), return_seen_in_block_(false),
unbound_jumps_(0),
parameter_count_(parameter_count), parameter_count_(parameter_count),
local_register_count_(locals_count), local_register_count_(locals_count),
context_register_count_(context_count), context_register_count_(context_count),
temporary_allocator_(zone, fixed_register_count()), temporary_allocator_(zone, fixed_register_count()),
bytecode_array_writer_(zone, &source_position_table_builder_), bytecode_array_writer_(isolate, zone, &constant_array_builder_),
pipeline_(&bytecode_array_writer_) { pipeline_(&bytecode_array_writer_) {
DCHECK_GE(parameter_count_, 0); DCHECK_GE(parameter_count_, 0);
DCHECK_GE(context_register_count_, 0); DCHECK_GE(context_register_count_, 0);
...@@ -49,8 +48,6 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone, ...@@ -49,8 +48,6 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone,
return_position_ = return_position_ =
literal ? std::max(literal->start_position(), literal->end_position() - 1) literal ? std::max(literal->start_position(), literal->end_position() - 1)
: RelocInfo::kNoPosition; : RelocInfo::kNoPosition;
LOG_CODE_EVENT(isolate_, CodeStartLinePosInfoRecordEvent(
source_position_table_builder()));
} }
Register BytecodeArrayBuilder::first_context_register() const { Register BytecodeArrayBuilder::first_context_register() const {
...@@ -58,55 +55,28 @@ Register BytecodeArrayBuilder::first_context_register() const { ...@@ -58,55 +55,28 @@ Register BytecodeArrayBuilder::first_context_register() const {
return Register(local_register_count_); return Register(local_register_count_);
} }
Register BytecodeArrayBuilder::last_context_register() const { Register BytecodeArrayBuilder::last_context_register() const {
DCHECK_GT(context_register_count_, 0); DCHECK_GT(context_register_count_, 0);
return Register(local_register_count_ + context_register_count_ - 1); return Register(local_register_count_ + context_register_count_ - 1);
} }
Register BytecodeArrayBuilder::Parameter(int parameter_index) const { Register BytecodeArrayBuilder::Parameter(int parameter_index) const {
DCHECK_GE(parameter_index, 0); DCHECK_GE(parameter_index, 0);
return Register::FromParameterIndex(parameter_index, parameter_count()); return Register::FromParameterIndex(parameter_index, parameter_count());
} }
bool BytecodeArrayBuilder::RegisterIsParameterOrLocal(Register reg) const { bool BytecodeArrayBuilder::RegisterIsParameterOrLocal(Register reg) const {
return reg.is_parameter() || reg.index() < locals_count(); return reg.is_parameter() || reg.index() < locals_count();
} }
Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
DCHECK_EQ(0, unbound_jumps_);
DCHECK_EQ(bytecode_generated_, false);
DCHECK(return_seen_in_block_); DCHECK(return_seen_in_block_);
DCHECK(!bytecode_generated_);
bytecode_generated_ = true;
pipeline()->FlushBasicBlock();
const ZoneVector<uint8_t>* bytecodes = bytecode_array_writer()->bytecodes();
int bytecode_size = static_cast<int>(bytecodes->size());
// All locals need a frame slot for the debugger, but may not be
// present in generated code.
int frame_size_for_locals = fixed_register_count() * kPointerSize;
int frame_size_used = bytecode_array_writer()->GetMaximumFrameSizeUsed();
int frame_size = std::max(frame_size_for_locals, frame_size_used);
Handle<FixedArray> constant_pool = constant_array_builder()->ToFixedArray();
Handle<FixedArray> handler_table = handler_table_builder()->ToHandlerTable(); Handle<FixedArray> handler_table = handler_table_builder()->ToHandlerTable();
Handle<ByteArray> source_position_table = return pipeline_->ToBytecodeArray(fixed_register_count(), parameter_count(),
source_position_table_builder()->ToSourcePositionTable(); handler_table);
Handle<BytecodeArray> bytecode_array = isolate_->factory()->NewBytecodeArray(
bytecode_size, &bytecodes->front(), frame_size, parameter_count(),
constant_pool);
bytecode_array->set_handler_table(*handler_table);
bytecode_array->set_source_position_table(*source_position_table);
void* line_info = source_position_table_builder()->DetachJITHandlerData();
LOG_CODE_EVENT(isolate_, CodeEndLinePosInfoRecordEvent(
AbstractCode::cast(*bytecode_array), line_info));
bytecode_generated_ = true;
return bytecode_array;
} }
void BytecodeArrayBuilder::AttachSourceInfo(BytecodeNode* node) { void BytecodeArrayBuilder::AttachSourceInfo(BytecodeNode* node) {
...@@ -181,7 +151,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op) { ...@@ -181,7 +151,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op) {
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() { BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() {
Output(Bytecode::kToBooleanLogicalNot); Output(Bytecode::kToBooleanLogicalNot);
return *this; return *this;
...@@ -202,7 +171,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(Token::Value op, ...@@ -202,7 +171,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(Token::Value op,
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
v8::internal::Smi* smi) { v8::internal::Smi* smi) {
int32_t raw_smi = smi->value(); int32_t raw_smi = smi->value();
...@@ -217,7 +185,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( ...@@ -217,7 +185,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) { BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) {
size_t entry = GetConstantPoolEntry(object); size_t entry = GetConstantPoolEntry(object);
OperandScale operand_scale = OperandScale operand_scale =
...@@ -226,31 +193,26 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) { ...@@ -226,31 +193,26 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) {
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() { BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() {
Output(Bytecode::kLdaUndefined); Output(Bytecode::kLdaUndefined);
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() { BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() {
Output(Bytecode::kLdaNull); Output(Bytecode::kLdaNull);
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() { BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() {
Output(Bytecode::kLdaTheHole); Output(Bytecode::kLdaTheHole);
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() { BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() {
Output(Bytecode::kLdaTrue); Output(Bytecode::kLdaTrue);
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() { BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() {
Output(Bytecode::kLdaFalse); Output(Bytecode::kLdaFalse);
return *this; return *this;
...@@ -264,7 +226,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister( ...@@ -264,7 +226,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister( BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
Register reg) { Register reg) {
OperandScale operand_scale = OperandScale operand_scale =
...@@ -273,7 +234,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister( ...@@ -273,7 +234,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from, BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from,
Register to) { Register to) {
DCHECK(from != to); DCHECK(from != to);
...@@ -310,7 +270,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal( ...@@ -310,7 +270,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context, BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context,
int slot_index) { int slot_index) {
OperandScale operand_scale = Bytecodes::OperandSizesToScale( OperandScale operand_scale = Bytecodes::OperandSizesToScale(
...@@ -320,7 +279,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context, ...@@ -320,7 +279,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context,
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context, BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context,
int slot_index) { int slot_index) {
OperandScale operand_scale = Bytecodes::OperandSizesToScale( OperandScale operand_scale = Bytecodes::OperandSizesToScale(
...@@ -386,7 +344,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty( ...@@ -386,7 +344,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty( BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
Register object, Register key, int feedback_slot, Register object, Register key, int feedback_slot,
LanguageMode language_mode) { LanguageMode language_mode) {
...@@ -399,7 +356,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty( ...@@ -399,7 +356,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure( BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure(
Handle<SharedFunctionInfo> shared_info, PretenureFlag tenured) { Handle<SharedFunctionInfo> shared_info, PretenureFlag tenured) {
size_t entry = GetConstantPoolEntry(shared_info); size_t entry = GetConstantPoolEntry(shared_info);
...@@ -410,7 +366,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure( ...@@ -410,7 +366,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments( BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments(
CreateArgumentsType type) { CreateArgumentsType type) {
// TODO(rmcilroy): Consider passing the type as a bytecode operand rather // TODO(rmcilroy): Consider passing the type as a bytecode operand rather
...@@ -421,7 +376,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments( ...@@ -421,7 +376,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral( BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral(
Handle<String> pattern, int literal_index, int flags) { Handle<String> pattern, int literal_index, int flags) {
size_t pattern_entry = GetConstantPoolEntry(pattern); size_t pattern_entry = GetConstantPoolEntry(pattern);
...@@ -435,7 +389,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral( ...@@ -435,7 +389,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral( BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral(
Handle<FixedArray> constant_elements, int literal_index, int flags) { Handle<FixedArray> constant_elements, int literal_index, int flags) {
size_t constant_elements_entry = GetConstantPoolEntry(constant_elements); size_t constant_elements_entry = GetConstantPoolEntry(constant_elements);
...@@ -449,7 +402,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral( ...@@ -449,7 +402,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral( BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral(
Handle<FixedArray> constant_properties, int literal_index, int flags) { Handle<FixedArray> constant_properties, int literal_index, int flags) {
size_t constant_properties_entry = GetConstantPoolEntry(constant_properties); size_t constant_properties_entry = GetConstantPoolEntry(constant_properties);
...@@ -463,7 +415,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral( ...@@ -463,7 +415,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) { BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) {
OperandScale operand_scale = OperandScale operand_scale =
Bytecodes::OperandSizesToScale(context.SizeOfOperand()); Bytecodes::OperandSizesToScale(context.SizeOfOperand());
...@@ -471,7 +422,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) { ...@@ -471,7 +422,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) {
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) {
OperandScale operand_scale = OperandScale operand_scale =
Bytecodes::OperandSizesToScale(context.SizeOfOperand()); Bytecodes::OperandSizesToScale(context.SizeOfOperand());
...@@ -479,13 +429,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { ...@@ -479,13 +429,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) {
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() { BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() {
Output(Bytecode::kToObject); Output(Bytecode::kToObject);
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() { BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() {
Output(Bytecode::kToName); Output(Bytecode::kToName);
return *this; return *this;
...@@ -496,204 +444,24 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToNumber() { ...@@ -496,204 +444,24 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToNumber() {
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) { BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) {
size_t current_offset = pipeline()->FlushForOffset(); pipeline_->BindLabel(label);
if (label->is_forward_target()) {
// An earlier jump instruction refers to this label. Update it's location.
PatchJump(current_offset, label->offset());
// Now treat as if the label will only be back referred to.
}
label->bind_to(current_offset);
LeaveBasicBlock(); LeaveBasicBlock();
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target, BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target,
BytecodeLabel* label) { BytecodeLabel* label) {
DCHECK(!label->is_bound()); pipeline_->BindLabel(target, label);
DCHECK(target.is_bound());
// There is no need to flush the pipeline here, it will have been
// flushed when |target| was bound.
if (label->is_forward_target()) {
// An earlier jump instruction refers to this label. Update it's location.
PatchJump(target.offset(), label->offset());
// Now treat as if the label will only be back referred to.
}
label->bind_to(target.offset());
LeaveBasicBlock(); LeaveBasicBlock();
return *this; return *this;
} }
// static
Bytecode BytecodeArrayBuilder::GetJumpWithConstantOperand(
Bytecode jump_bytecode) {
switch (jump_bytecode) {
case Bytecode::kJump:
return Bytecode::kJumpConstant;
case Bytecode::kJumpIfTrue:
return Bytecode::kJumpIfTrueConstant;
case Bytecode::kJumpIfFalse:
return Bytecode::kJumpIfFalseConstant;
case Bytecode::kJumpIfToBooleanTrue:
return Bytecode::kJumpIfToBooleanTrueConstant;
case Bytecode::kJumpIfToBooleanFalse:
return Bytecode::kJumpIfToBooleanFalseConstant;
case Bytecode::kJumpIfNotHole:
return Bytecode::kJumpIfNotHoleConstant;
case Bytecode::kJumpIfNull:
return Bytecode::kJumpIfNullConstant;
case Bytecode::kJumpIfUndefined:
return Bytecode::kJumpIfUndefinedConstant;
default:
UNREACHABLE();
return Bytecode::kIllegal;
}
}
void BytecodeArrayBuilder::PatchJumpWith8BitOperand(
ZoneVector<uint8_t>* bytecodes, size_t jump_location, int delta) {
Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes->at(jump_location));
DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
size_t operand_location = jump_location + 1;
DCHECK_EQ(bytecodes->at(operand_location), 0);
if (Bytecodes::SizeForSignedOperand(delta) == OperandSize::kByte) {
// The jump fits within the range of an Imm operand, so cancel
// the reservation and jump directly.
constant_array_builder()->DiscardReservedEntry(OperandSize::kByte);
bytecodes->at(operand_location) = static_cast<uint8_t>(delta);
} else {
// The jump does not fit within the range of an Imm 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(Bytecodes::SizeForUnsignedOperand(entry) == OperandSize::kByte);
jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
bytecodes->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
bytecodes->at(operand_location) = static_cast<uint8_t>(entry);
}
}
void BytecodeArrayBuilder::PatchJumpWith16BitOperand(
ZoneVector<uint8_t>* bytecodes, size_t jump_location, int delta) {
Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes->at(jump_location));
DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
size_t operand_location = jump_location + 1;
uint8_t operand_bytes[2];
if (Bytecodes::SizeForSignedOperand(delta) <= OperandSize::kShort) {
constant_array_builder()->DiscardReservedEntry(OperandSize::kShort);
WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(delta));
} else {
jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
bytecodes->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
size_t entry = constant_array_builder()->CommitReservedEntry(
OperandSize::kShort, handle(Smi::FromInt(delta), isolate()));
WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry));
}
DCHECK(bytecodes->at(operand_location) == 0 &&
bytecodes->at(operand_location + 1) == 0);
bytecodes->at(operand_location++) = operand_bytes[0];
bytecodes->at(operand_location) = operand_bytes[1];
}
void BytecodeArrayBuilder::PatchJumpWith32BitOperand(
ZoneVector<uint8_t>* bytecodes, size_t jump_location, int delta) {
DCHECK(Bytecodes::IsJumpImmediate(
Bytecodes::FromByte(bytecodes->at(jump_location))));
constant_array_builder()->DiscardReservedEntry(OperandSize::kQuad);
uint8_t operand_bytes[4];
WriteUnalignedUInt32(operand_bytes, static_cast<uint32_t>(delta));
size_t operand_location = jump_location + 1;
DCHECK(bytecodes->at(operand_location) == 0 &&
bytecodes->at(operand_location + 1) == 0 &&
bytecodes->at(operand_location + 2) == 0 &&
bytecodes->at(operand_location + 3) == 0);
bytecodes->at(operand_location++) = operand_bytes[0];
bytecodes->at(operand_location++) = operand_bytes[1];
bytecodes->at(operand_location++) = operand_bytes[2];
bytecodes->at(operand_location) = operand_bytes[3];
}
void BytecodeArrayBuilder::PatchJump(size_t jump_target, size_t jump_location) {
ZoneVector<uint8_t>* bytecodes = bytecode_array_writer()->bytecodes();
Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes->at(jump_location));
int delta = static_cast<int>(jump_target - jump_location);
int prefix_offset = 0;
OperandScale operand_scale = OperandScale::kSingle;
if (Bytecodes::IsPrefixScalingBytecode(jump_bytecode)) {
// If a prefix scaling bytecode is emitted the target offset is one
// less than the case of no prefix scaling bytecode.
delta -= 1;
prefix_offset = 1;
operand_scale = Bytecodes::PrefixBytecodeToOperandScale(jump_bytecode);
jump_bytecode =
Bytecodes::FromByte(bytecodes->at(jump_location + prefix_offset));
}
DCHECK(Bytecodes::IsJump(jump_bytecode));
switch (operand_scale) {
case OperandScale::kSingle:
PatchJumpWith8BitOperand(bytecodes, jump_location, delta);
break;
case OperandScale::kDouble:
PatchJumpWith16BitOperand(bytecodes, jump_location + prefix_offset,
delta);
break;
case OperandScale::kQuadruple:
PatchJumpWith32BitOperand(bytecodes, jump_location + prefix_offset,
delta);
break;
default:
UNREACHABLE();
}
unbound_jumps_--;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode, BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode,
BytecodeLabel* label) { BytecodeLabel* label) {
if (label->is_bound()) { BytecodeNode node(jump_bytecode, 0, OperandScale::kSingle);
// Label has been bound already so this is a backwards jump. AttachSourceInfo(&node);
size_t current_offset = pipeline()->FlushForOffset(); pipeline_->WriteJump(&node, label);
CHECK_GE(current_offset, label->offset());
CHECK_LE(current_offset, static_cast<size_t>(kMaxInt));
size_t abs_delta = current_offset - label->offset();
int delta = -static_cast<int>(abs_delta);
OperandSize operand_size = Bytecodes::SizeForSignedOperand(delta);
if (operand_size > OperandSize::kByte) {
// Adjust for scaling byte prefix for wide jump offset.
DCHECK_LE(delta, 0);
delta -= 1;
}
OutputScaled(jump_bytecode, Bytecodes::OperandSizesToScale(operand_size),
SignedOperand(delta, operand_size));
} else {
// 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.
unbound_jumps_++;
OperandSize reserved_operand_size =
constant_array_builder()->CreateReservedEntry();
OutputScaled(jump_bytecode,
Bytecodes::OperandSizesToScale(reserved_operand_size), 0);
// Calculate the label position by flushing for offset after emitting the
// jump bytecode.
size_t offset = pipeline()->FlushForOffset();
OperandScale operand_scale =
Bytecodes::OperandSizesToScale(reserved_operand_size);
offset -= Bytecodes::Size(jump_bytecode, operand_scale);
if (Bytecodes::OperandScaleRequiresPrefixBytecode(operand_scale)) {
offset -= 1;
}
label->set_referrer(offset);
}
LeaveBasicBlock(); LeaveBasicBlock();
return *this; return *this;
} }
...@@ -723,6 +491,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined( ...@@ -723,6 +491,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined(
return OutputJump(Bytecode::kJumpIfUndefined, label); return OutputJump(Bytecode::kJumpIfUndefined, label);
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotHole(
BytecodeLabel* label) {
return OutputJump(Bytecode::kJumpIfNotHole, label);
}
BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck(int position) { BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck(int position) {
if (position != RelocInfo::kNoPosition) { if (position != RelocInfo::kNoPosition) {
// We need to attach a non-breakable source position to a stack check, // We need to attach a non-breakable source position to a stack check,
...@@ -733,23 +506,16 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck(int position) { ...@@ -733,23 +506,16 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck(int position) {
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotHole(
BytecodeLabel* label) {
return OutputJump(Bytecode::kJumpIfNotHole, label);
}
BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() { BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() {
Output(Bytecode::kThrow); Output(Bytecode::kThrow);
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::ReThrow() { BytecodeArrayBuilder& BytecodeArrayBuilder::ReThrow() {
Output(Bytecode::kReThrow); Output(Bytecode::kReThrow);
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::Return() { BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
Output(Bytecode::kReturn); Output(Bytecode::kReturn);
return_seen_in_block_ = true; return_seen_in_block_ = true;
...@@ -792,7 +558,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext( ...@@ -792,7 +558,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) { BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) {
OperandScale operand_scale = OperandScale operand_scale =
Bytecodes::OperandSizesToScale(index.SizeOfOperand()); Bytecodes::OperandSizesToScale(index.SizeOfOperand());
...@@ -800,7 +565,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) { ...@@ -800,7 +565,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) {
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator( BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator(
Register generator) { Register generator) {
OperandScale operand_scale = OperandScale operand_scale =
...@@ -810,7 +574,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator( ...@@ -810,7 +574,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator( BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator(
Register generator) { Register generator) {
OperandScale operand_scale = OperandScale operand_scale =
...@@ -820,37 +583,31 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator( ...@@ -820,37 +583,31 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::MarkHandler(int handler_id, BytecodeArrayBuilder& BytecodeArrayBuilder::MarkHandler(int handler_id,
bool will_catch) { bool will_catch) {
size_t offset = pipeline()->FlushForOffset(); BytecodeLabel handler;
handler_table_builder()->SetHandlerTarget(handler_id, offset); Bind(&handler);
handler_table_builder()->SetHandlerTarget(handler_id, handler.offset());
handler_table_builder()->SetPrediction(handler_id, will_catch); handler_table_builder()->SetPrediction(handler_id, will_catch);
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryBegin(int handler_id, BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryBegin(int handler_id,
Register context) { Register context) {
size_t offset = pipeline()->FlushForOffset(); BytecodeLabel try_begin;
handler_table_builder()->SetTryRegionStart(handler_id, offset); Bind(&try_begin);
handler_table_builder()->SetTryRegionStart(handler_id, try_begin.offset());
handler_table_builder()->SetContextRegister(handler_id, context); handler_table_builder()->SetContextRegister(handler_id, context);
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryEnd(int handler_id) { BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryEnd(int handler_id) {
size_t offset = pipeline()->FlushForOffset(); BytecodeLabel try_end;
handler_table_builder()->SetTryRegionEnd(handler_id, offset); Bind(&try_end);
handler_table_builder()->SetTryRegionEnd(handler_id, try_end.offset());
return *this; return *this;
} }
void BytecodeArrayBuilder::LeaveBasicBlock() {
pipeline()->FlushBasicBlock();
return_seen_in_block_ = false;
}
void BytecodeArrayBuilder::EnsureReturn() { void BytecodeArrayBuilder::EnsureReturn() {
if (!return_seen_in_block_) { if (!return_seen_in_block_) {
LoadUndefined(); LoadUndefined();
...@@ -892,7 +649,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor, ...@@ -892,7 +649,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor,
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
Runtime::FunctionId function_id, Register first_arg, size_t arg_count) { Runtime::FunctionId function_id, Register first_arg, size_t arg_count) {
DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size); DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size);
...@@ -911,7 +667,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( ...@@ -911,7 +667,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair( BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
Runtime::FunctionId function_id, Register first_arg, size_t arg_count, Runtime::FunctionId function_id, Register first_arg, size_t arg_count,
Register first_return) { Register first_return) {
...@@ -942,7 +697,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime( ...@@ -942,7 +697,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object, BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object,
LanguageMode language_mode) { LanguageMode language_mode) {
OperandScale operand_scale = OperandScale operand_scale =
...@@ -1093,7 +847,6 @@ Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) { ...@@ -1093,7 +847,6 @@ Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) {
} }
} }
// static // static
Bytecode BytecodeArrayBuilder::BytecodeForCountOperation(Token::Value op) { Bytecode BytecodeArrayBuilder::BytecodeForCountOperation(Token::Value op) {
switch (op) { switch (op) {
...@@ -1107,7 +860,6 @@ Bytecode BytecodeArrayBuilder::BytecodeForCountOperation(Token::Value op) { ...@@ -1107,7 +860,6 @@ Bytecode BytecodeArrayBuilder::BytecodeForCountOperation(Token::Value op) {
} }
} }
// static // static
Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) { Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) {
switch (op) { switch (op) {
...@@ -1135,7 +887,6 @@ Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) { ...@@ -1135,7 +887,6 @@ Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) {
} }
} }
// static // static
Bytecode BytecodeArrayBuilder::BytecodeForStoreNamedProperty( Bytecode BytecodeArrayBuilder::BytecodeForStoreNamedProperty(
LanguageMode language_mode) { LanguageMode language_mode) {
...@@ -1150,7 +901,6 @@ Bytecode BytecodeArrayBuilder::BytecodeForStoreNamedProperty( ...@@ -1150,7 +901,6 @@ Bytecode BytecodeArrayBuilder::BytecodeForStoreNamedProperty(
return Bytecode::kIllegal; return Bytecode::kIllegal;
} }
// static // static
Bytecode BytecodeArrayBuilder::BytecodeForStoreKeyedProperty( Bytecode BytecodeArrayBuilder::BytecodeForStoreKeyedProperty(
LanguageMode language_mode) { LanguageMode language_mode) {
...@@ -1165,14 +915,12 @@ Bytecode BytecodeArrayBuilder::BytecodeForStoreKeyedProperty( ...@@ -1165,14 +915,12 @@ Bytecode BytecodeArrayBuilder::BytecodeForStoreKeyedProperty(
return Bytecode::kIllegal; return Bytecode::kIllegal;
} }
// static // static
Bytecode BytecodeArrayBuilder::BytecodeForLoadGlobal(TypeofMode typeof_mode) { Bytecode BytecodeArrayBuilder::BytecodeForLoadGlobal(TypeofMode typeof_mode) {
return typeof_mode == INSIDE_TYPEOF ? Bytecode::kLdaGlobalInsideTypeof return typeof_mode == INSIDE_TYPEOF ? Bytecode::kLdaGlobalInsideTypeof
: Bytecode::kLdaGlobal; : Bytecode::kLdaGlobal;
} }
// static // static
Bytecode BytecodeArrayBuilder::BytecodeForStoreGlobal( Bytecode BytecodeArrayBuilder::BytecodeForStoreGlobal(
LanguageMode language_mode) { LanguageMode language_mode) {
...@@ -1187,7 +935,6 @@ Bytecode BytecodeArrayBuilder::BytecodeForStoreGlobal( ...@@ -1187,7 +935,6 @@ Bytecode BytecodeArrayBuilder::BytecodeForStoreGlobal(
return Bytecode::kIllegal; return Bytecode::kIllegal;
} }
// static // static
Bytecode BytecodeArrayBuilder::BytecodeForStoreLookupSlot( Bytecode BytecodeArrayBuilder::BytecodeForStoreLookupSlot(
LanguageMode language_mode) { LanguageMode language_mode) {
...@@ -1217,7 +964,6 @@ Bytecode BytecodeArrayBuilder::BytecodeForCreateArguments( ...@@ -1217,7 +964,6 @@ Bytecode BytecodeArrayBuilder::BytecodeForCreateArguments(
return Bytecode::kIllegal; return Bytecode::kIllegal;
} }
// static // static
Bytecode BytecodeArrayBuilder::BytecodeForDelete(LanguageMode language_mode) { Bytecode BytecodeArrayBuilder::BytecodeForDelete(LanguageMode language_mode) {
switch (language_mode) { switch (language_mode) {
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "src/interpreter/bytecodes.h" #include "src/interpreter/bytecodes.h"
#include "src/interpreter/constant-array-builder.h" #include "src/interpreter/constant-array-builder.h"
#include "src/interpreter/handler-table-builder.h" #include "src/interpreter/handler-table-builder.h"
#include "src/interpreter/source-position-table.h"
#include "src/zone-containers.h" #include "src/zone-containers.h"
namespace v8 { namespace v8 {
...@@ -297,8 +296,6 @@ class BytecodeArrayBuilder final : public ZoneObject { ...@@ -297,8 +296,6 @@ class BytecodeArrayBuilder final : public ZoneObject {
static Bytecode BytecodeForDelete(LanguageMode language_mode); static Bytecode BytecodeForDelete(LanguageMode language_mode);
static Bytecode BytecodeForCall(TailCallMode tail_call_mode); static Bytecode BytecodeForCall(TailCallMode tail_call_mode);
static Bytecode GetJumpWithConstantOperand(Bytecode jump_smi8_operand);
void Output(Bytecode bytecode); void Output(Bytecode bytecode);
void OutputScaled(Bytecode bytecode, OperandScale operand_scale, void OutputScaled(Bytecode bytecode, OperandScale operand_scale,
uint32_t operand0, uint32_t operand1, uint32_t operand2, uint32_t operand0, uint32_t operand1, uint32_t operand2,
...@@ -312,15 +309,7 @@ class BytecodeArrayBuilder final : public ZoneObject { ...@@ -312,15 +309,7 @@ class BytecodeArrayBuilder final : public ZoneObject {
BytecodeArrayBuilder& OutputJump(Bytecode jump_bytecode, BytecodeArrayBuilder& OutputJump(Bytecode jump_bytecode,
BytecodeLabel* label); BytecodeLabel* label);
void PatchJump(size_t jump_target, size_t jump_location);
void PatchJumpWith8BitOperand(ZoneVector<uint8_t>* bytecodes,
size_t jump_location, int delta);
void PatchJumpWith16BitOperand(ZoneVector<uint8_t>* bytecodes,
size_t jump_location, int delta);
void PatchJumpWith32BitOperand(ZoneVector<uint8_t>* bytecodes,
size_t jump_location, int delta);
void LeaveBasicBlock();
bool OperandIsValid(Bytecode bytecode, OperandScale operand_scale, bool OperandIsValid(Bytecode bytecode, OperandScale operand_scale,
int operand_index, uint32_t operand_value) const; int operand_index, uint32_t operand_value) const;
...@@ -337,6 +326,8 @@ class BytecodeArrayBuilder final : public ZoneObject { ...@@ -337,6 +326,8 @@ class BytecodeArrayBuilder final : public ZoneObject {
// during bytecode generation. // during bytecode generation.
BytecodeArrayBuilder& Illegal(); BytecodeArrayBuilder& Illegal();
void LeaveBasicBlock() { return_seen_in_block_ = false; }
Isolate* isolate() const { return isolate_; } Isolate* isolate() const { return isolate_; }
BytecodeArrayWriter* bytecode_array_writer() { BytecodeArrayWriter* bytecode_array_writer() {
return &bytecode_array_writer_; return &bytecode_array_writer_;
...@@ -351,18 +342,13 @@ class BytecodeArrayBuilder final : public ZoneObject { ...@@ -351,18 +342,13 @@ class BytecodeArrayBuilder final : public ZoneObject {
HandlerTableBuilder* handler_table_builder() { HandlerTableBuilder* handler_table_builder() {
return &handler_table_builder_; return &handler_table_builder_;
} }
SourcePositionTableBuilder* source_position_table_builder() {
return &source_position_table_builder_;
}
Isolate* isolate_; Isolate* isolate_;
Zone* zone_; Zone* zone_;
bool bytecode_generated_; bool bytecode_generated_;
ConstantArrayBuilder constant_array_builder_; ConstantArrayBuilder constant_array_builder_;
HandlerTableBuilder handler_table_builder_; HandlerTableBuilder handler_table_builder_;
SourcePositionTableBuilder source_position_table_builder_;
bool return_seen_in_block_; bool return_seen_in_block_;
int unbound_jumps_;
int parameter_count_; int parameter_count_;
int local_register_count_; int local_register_count_;
int context_register_count_; int context_register_count_;
...@@ -375,47 +361,6 @@ class BytecodeArrayBuilder final : public ZoneObject { ...@@ -375,47 +361,6 @@ class BytecodeArrayBuilder final : public ZoneObject {
DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder); DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
}; };
// A label representing a branch target in a bytecode array. When a
// label is bound, it represents a known position in the bytecode
// array. For labels that are forward references there can be at most
// one reference whilst it is unbound.
class BytecodeLabel final {
public:
BytecodeLabel() : bound_(false), offset_(kInvalidOffset) {}
bool is_bound() const { return bound_; }
size_t offset() const { return offset_; }
private:
static const size_t kInvalidOffset = static_cast<size_t>(-1);
void bind_to(size_t offset) {
DCHECK(!bound_ && offset != kInvalidOffset);
offset_ = offset;
bound_ = true;
}
void set_referrer(size_t offset) {
DCHECK(!bound_ && offset != kInvalidOffset && offset_ == kInvalidOffset);
offset_ = offset;
}
bool is_forward_target() const {
return offset() != kInvalidOffset && !is_bound();
}
// There are three states for a label:
// bound_ offset_
// UNSET false kInvalidOffset
// FORWARD_TARGET false Offset of referring jump
// BACKWARD_TARGET true Offset of label in bytecode array when bound
bool bound_;
size_t offset_;
friend class BytecodeArrayBuilder;
};
} // namespace interpreter } // namespace interpreter
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -4,39 +4,104 @@ ...@@ -4,39 +4,104 @@
#include "src/interpreter/bytecode-array-writer.h" #include "src/interpreter/bytecode-array-writer.h"
#include <iomanip> #include "src/api.h"
#include "src/interpreter/source-position-table.h" #include "src/interpreter/bytecode-label.h"
#include "src/interpreter/constant-array-builder.h"
#include "src/log.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace interpreter { namespace interpreter {
BytecodeArrayWriter::BytecodeArrayWriter( BytecodeArrayWriter::BytecodeArrayWriter(
Zone* zone, SourcePositionTableBuilder* source_position_table_builder) Isolate* isolate, Zone* zone, ConstantArrayBuilder* constant_array_builder)
: bytecodes_(zone), : isolate_(isolate),
bytecodes_(zone),
max_register_count_(0), max_register_count_(0),
source_position_table_builder_(source_position_table_builder) {} unbound_jumps_(0),
source_position_table_builder_(isolate, zone),
constant_array_builder_(constant_array_builder) {
LOG_CODE_EVENT(isolate_, CodeStartLinePosInfoRecordEvent(
source_position_table_builder()));
}
// override // override
BytecodeArrayWriter::~BytecodeArrayWriter() {} BytecodeArrayWriter::~BytecodeArrayWriter() {}
// override // override
size_t BytecodeArrayWriter::FlushForOffset() { return bytecodes()->size(); } Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
int fixed_register_count, int parameter_count,
Handle<FixedArray> handler_table) {
DCHECK_EQ(0, unbound_jumps_);
int bytecode_size = static_cast<int>(bytecodes()->size());
// All locals need a frame slot for the debugger, but may not be
// present in generated code.
int frame_size_for_locals = fixed_register_count * kPointerSize;
int frame_size_used = max_register_count() * kPointerSize;
int frame_size = std::max(frame_size_for_locals, frame_size_used);
Handle<FixedArray> constant_pool = constant_array_builder()->ToFixedArray();
Handle<ByteArray> source_position_table =
source_position_table_builder()->ToSourcePositionTable();
Handle<BytecodeArray> bytecode_array = isolate_->factory()->NewBytecodeArray(
bytecode_size, &bytecodes()->front(), frame_size, parameter_count,
constant_pool);
bytecode_array->set_handler_table(*handler_table);
bytecode_array->set_source_position_table(*source_position_table);
void* line_info = source_position_table_builder()->DetachJITHandlerData();
LOG_CODE_EVENT(isolate_, CodeEndLinePosInfoRecordEvent(
AbstractCode::cast(*bytecode_array), line_info));
return bytecode_array;
}
// override // override
void BytecodeArrayWriter::Write(BytecodeNode* node) { void BytecodeArrayWriter::Write(BytecodeNode* node) {
DCHECK(!Bytecodes::IsJump(node->bytecode()));
UpdateSourcePositionTable(node); UpdateSourcePositionTable(node);
EmitBytecode(node); EmitBytecode(node);
} }
// override
void BytecodeArrayWriter::WriteJump(BytecodeNode* node, BytecodeLabel* label) {
DCHECK(Bytecodes::IsJump(node->bytecode()));
UpdateSourcePositionTable(node);
EmitJump(node, label);
}
// override
void BytecodeArrayWriter::BindLabel(BytecodeLabel* label) {
size_t current_offset = bytecodes()->size();
if (label->is_forward_target()) {
// An earlier jump instruction refers to this label. Update it's location.
PatchJump(current_offset, label->offset());
// Now treat as if the label will only be back referred to.
}
label->bind_to(current_offset);
}
// override
void BytecodeArrayWriter::BindLabel(const BytecodeLabel& target,
BytecodeLabel* label) {
DCHECK(!label->is_bound());
DCHECK(target.is_bound());
if (label->is_forward_target()) {
// An earlier jump instruction refers to this label. Update it's location.
PatchJump(target.offset(), label->offset());
// Now treat as if the label will only be back referred to.
}
label->bind_to(target.offset());
}
void BytecodeArrayWriter::UpdateSourcePositionTable( void BytecodeArrayWriter::UpdateSourcePositionTable(
const BytecodeNode* const node) { const BytecodeNode* const node) {
int bytecode_offset = static_cast<int>(bytecodes()->size()); int bytecode_offset = static_cast<int>(bytecodes()->size());
const BytecodeSourceInfo& source_info = node->source_info(); const BytecodeSourceInfo& source_info = node->source_info();
if (source_info.is_valid()) { if (source_info.is_valid()) {
source_position_table_builder_->AddPosition(bytecode_offset, source_position_table_builder()->AddPosition(bytecode_offset,
source_info.source_position(), source_info.source_position(),
source_info.is_statement()); source_info.is_statement());
} }
} }
...@@ -95,11 +160,180 @@ void BytecodeArrayWriter::EmitBytecode(const BytecodeNode* const node) { ...@@ -95,11 +160,180 @@ void BytecodeArrayWriter::EmitBytecode(const BytecodeNode* const node) {
} }
} }
// override // TODO(rmcilroy): This is the same as SignedOperand in BytecodeArrayBuilder.
void BytecodeArrayWriter::FlushBasicBlock() {} // Once we move the scalable operand processing here remove the SignedOperand
// in BytecodeArrayBuilder.
static uint32_t SignedOperand(int value, OperandSize size) {
switch (size) {
case OperandSize::kByte:
return static_cast<uint8_t>(value & 0xff);
case OperandSize::kShort:
return static_cast<uint16_t>(value & 0xffff);
case OperandSize::kQuad:
return static_cast<uint32_t>(value);
case OperandSize::kNone:
UNREACHABLE();
}
return 0;
}
int BytecodeArrayWriter::GetMaximumFrameSizeUsed() { // static
return max_register_count_ * kPointerSize; Bytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) {
switch (jump_bytecode) {
case Bytecode::kJump:
return Bytecode::kJumpConstant;
case Bytecode::kJumpIfTrue:
return Bytecode::kJumpIfTrueConstant;
case Bytecode::kJumpIfFalse:
return Bytecode::kJumpIfFalseConstant;
case Bytecode::kJumpIfToBooleanTrue:
return Bytecode::kJumpIfToBooleanTrueConstant;
case Bytecode::kJumpIfToBooleanFalse:
return Bytecode::kJumpIfToBooleanFalseConstant;
case Bytecode::kJumpIfNotHole:
return Bytecode::kJumpIfNotHoleConstant;
case Bytecode::kJumpIfNull:
return Bytecode::kJumpIfNullConstant;
case Bytecode::kJumpIfUndefined:
return Bytecode::kJumpIfUndefinedConstant;
default:
UNREACHABLE();
return Bytecode::kIllegal;
}
}
void BytecodeArrayWriter::PatchJumpWith8BitOperand(size_t jump_location,
int delta) {
Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
size_t operand_location = jump_location + 1;
DCHECK_EQ(bytecodes()->at(operand_location), 0);
if (Bytecodes::SizeForSignedOperand(delta) == OperandSize::kByte) {
// The jump fits within the range of an Imm operand, so cancel
// the reservation and jump directly.
constant_array_builder()->DiscardReservedEntry(OperandSize::kByte);
bytecodes()->at(operand_location) = static_cast<uint8_t>(delta);
} else {
// The jump does not fit within the range of an Imm 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(Bytecodes::SizeForUnsignedOperand(entry) == OperandSize::kByte);
jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
bytecodes()->at(operand_location) = static_cast<uint8_t>(entry);
}
}
void BytecodeArrayWriter::PatchJumpWith16BitOperand(size_t jump_location,
int delta) {
Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
size_t operand_location = jump_location + 1;
uint8_t operand_bytes[2];
if (Bytecodes::SizeForSignedOperand(delta) <= OperandSize::kShort) {
constant_array_builder()->DiscardReservedEntry(OperandSize::kShort);
WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(delta));
} else {
jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
size_t entry = constant_array_builder()->CommitReservedEntry(
OperandSize::kShort, handle(Smi::FromInt(delta), isolate()));
WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry));
}
DCHECK(bytecodes()->at(operand_location) == 0 &&
bytecodes()->at(operand_location + 1) == 0);
bytecodes()->at(operand_location++) = operand_bytes[0];
bytecodes()->at(operand_location) = operand_bytes[1];
}
void BytecodeArrayWriter::PatchJumpWith32BitOperand(size_t jump_location,
int delta) {
DCHECK(Bytecodes::IsJumpImmediate(
Bytecodes::FromByte(bytecodes()->at(jump_location))));
constant_array_builder()->DiscardReservedEntry(OperandSize::kQuad);
uint8_t operand_bytes[4];
WriteUnalignedUInt32(operand_bytes, static_cast<uint32_t>(delta));
size_t operand_location = jump_location + 1;
DCHECK(bytecodes()->at(operand_location) == 0 &&
bytecodes()->at(operand_location + 1) == 0 &&
bytecodes()->at(operand_location + 2) == 0 &&
bytecodes()->at(operand_location + 3) == 0);
bytecodes()->at(operand_location++) = operand_bytes[0];
bytecodes()->at(operand_location++) = operand_bytes[1];
bytecodes()->at(operand_location++) = operand_bytes[2];
bytecodes()->at(operand_location) = operand_bytes[3];
}
void BytecodeArrayWriter::PatchJump(size_t jump_target, size_t jump_location) {
Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
int delta = static_cast<int>(jump_target - jump_location);
int prefix_offset = 0;
OperandScale operand_scale = OperandScale::kSingle;
if (Bytecodes::IsPrefixScalingBytecode(jump_bytecode)) {
// If a prefix scaling bytecode is emitted the target offset is one
// less than the case of no prefix scaling bytecode.
delta -= 1;
prefix_offset = 1;
operand_scale = Bytecodes::PrefixBytecodeToOperandScale(jump_bytecode);
jump_bytecode =
Bytecodes::FromByte(bytecodes()->at(jump_location + prefix_offset));
}
DCHECK(Bytecodes::IsJump(jump_bytecode));
switch (operand_scale) {
case OperandScale::kSingle:
PatchJumpWith8BitOperand(jump_location, delta);
break;
case OperandScale::kDouble:
PatchJumpWith16BitOperand(jump_location + prefix_offset, delta);
break;
case OperandScale::kQuadruple:
PatchJumpWith32BitOperand(jump_location + prefix_offset, delta);
break;
default:
UNREACHABLE();
}
unbound_jumps_--;
}
void BytecodeArrayWriter::EmitJump(BytecodeNode* node, BytecodeLabel* label) {
DCHECK(Bytecodes::IsJump(node->bytecode()));
DCHECK_EQ(0, node->operand(0));
size_t current_offset = bytecodes()->size();
if (label->is_bound()) {
CHECK_GE(current_offset, label->offset());
CHECK_LE(current_offset, static_cast<size_t>(kMaxInt));
// Label has been bound already so this is a backwards jump.
size_t abs_delta = current_offset - label->offset();
int delta = -static_cast<int>(abs_delta);
OperandSize operand_size = Bytecodes::SizeForSignedOperand(delta);
if (operand_size > OperandSize::kByte) {
// Adjust for scaling byte prefix for wide jump offset.
DCHECK_LE(delta, 0);
delta -= 1;
}
node->set_bytecode(node->bytecode(), SignedOperand(delta, operand_size),
Bytecodes::OperandSizesToScale(operand_size));
} else {
// 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.
unbound_jumps_++;
label->set_referrer(current_offset);
OperandSize reserved_operand_size =
constant_array_builder()->CreateReservedEntry();
OperandScale operand_scale =
Bytecodes::OperandSizesToScale(reserved_operand_size);
node->set_bytecode(node->bytecode(), 0, operand_scale);
}
EmitBytecode(node);
} }
} // namespace interpreter } // namespace interpreter
......
...@@ -6,40 +6,61 @@ ...@@ -6,40 +6,61 @@
#define V8_INTERPRETER_BYTECODE_ARRAY_WRITER_H_ #define V8_INTERPRETER_BYTECODE_ARRAY_WRITER_H_
#include "src/interpreter/bytecode-pipeline.h" #include "src/interpreter/bytecode-pipeline.h"
#include "src/interpreter/source-position-table.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace interpreter { namespace interpreter {
class BytecodeLabel;
class SourcePositionTableBuilder; class SourcePositionTableBuilder;
class ConstantArrayBuilder;
// Class for emitting bytecode as the final stage of the bytecode // Class for emitting bytecode as the final stage of the bytecode
// generation pipeline. // generation pipeline.
class BytecodeArrayWriter final : public BytecodePipelineStage { class BytecodeArrayWriter final : public BytecodePipelineStage {
public: public:
BytecodeArrayWriter( BytecodeArrayWriter(Isolate* isolate, Zone* zone,
Zone* zone, SourcePositionTableBuilder* source_position_table_builder); ConstantArrayBuilder* constant_array_builder);
virtual ~BytecodeArrayWriter(); virtual ~BytecodeArrayWriter();
// BytecodePipelineStage interface.
void Write(BytecodeNode* node) override; void Write(BytecodeNode* node) override;
size_t FlushForOffset() override; void WriteJump(BytecodeNode* node, BytecodeLabel* label) override;
void FlushBasicBlock() override; void BindLabel(BytecodeLabel* label) override;
void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) override;
// Get the bytecode vector. Handle<BytecodeArray> ToBytecodeArray(
ZoneVector<uint8_t>* bytecodes() { return &bytecodes_; } int fixed_register_count, int parameter_count,
Handle<FixedArray> handler_table) override;
// Returns the size in bytes of the frame associated with the
// bytecode written.
int GetMaximumFrameSizeUsed();
private: private:
void PatchJump(size_t jump_target, size_t jump_location);
void PatchJumpWith8BitOperand(size_t jump_location, int delta);
void PatchJumpWith16BitOperand(size_t jump_location, int delta);
void PatchJumpWith32BitOperand(size_t jump_location, int delta);
void EmitBytecode(const BytecodeNode* const node); void EmitBytecode(const BytecodeNode* const node);
void EmitJump(BytecodeNode* node, BytecodeLabel* label);
void UpdateSourcePositionTable(const BytecodeNode* const node); void UpdateSourcePositionTable(const BytecodeNode* const node);
Isolate* isolate() { return isolate_; }
ZoneVector<uint8_t>* bytecodes() { return &bytecodes_; }
SourcePositionTableBuilder* source_position_table_builder() {
return &source_position_table_builder_;
}
ConstantArrayBuilder* constant_array_builder() {
return constant_array_builder_;
}
int max_register_count() { return max_register_count_; }
Isolate* isolate_;
ZoneVector<uint8_t> bytecodes_; ZoneVector<uint8_t> bytecodes_;
int max_register_count_; int max_register_count_;
SourcePositionTableBuilder* source_position_table_builder_; int unbound_jumps_;
SourcePositionTableBuilder source_position_table_builder_;
ConstantArrayBuilder* constant_array_builder_;
friend class BytecodeArrayWriterUnittest;
DISALLOW_COPY_AND_ASSIGN(BytecodeArrayWriter); DISALLOW_COPY_AND_ASSIGN(BytecodeArrayWriter);
}; };
......
...@@ -17,7 +17,6 @@ namespace v8 { ...@@ -17,7 +17,6 @@ namespace v8 {
namespace internal { namespace internal {
namespace interpreter { namespace interpreter {
// Scoped class tracking context objects created by the visitor. Represents // Scoped class tracking context objects created by the visitor. Represents
// mutations of the context chain within the function body, allowing pushing and // mutations of the context chain within the function body, allowing pushing and
// popping of the current {context_register} during visitation. // popping of the current {context_register} during visitation.
...@@ -88,7 +87,6 @@ class BytecodeGenerator::ContextScope BASE_EMBEDDED { ...@@ -88,7 +87,6 @@ class BytecodeGenerator::ContextScope BASE_EMBEDDED {
bool should_pop_context_; bool should_pop_context_;
}; };
// Scoped class for tracking control statements entered by the // Scoped class for tracking control statements entered by the
// visitor. The pattern derives AstGraphBuilder::ControlScope. // visitor. The pattern derives AstGraphBuilder::ControlScope.
class BytecodeGenerator::ControlScope BASE_EMBEDDED { class BytecodeGenerator::ControlScope BASE_EMBEDDED {
...@@ -124,7 +122,6 @@ class BytecodeGenerator::ControlScope BASE_EMBEDDED { ...@@ -124,7 +122,6 @@ class BytecodeGenerator::ControlScope BASE_EMBEDDED {
DISALLOW_COPY_AND_ASSIGN(ControlScope); DISALLOW_COPY_AND_ASSIGN(ControlScope);
}; };
// Helper class for a try-finally control scope. It can record intercepted // Helper class for a try-finally control scope. It can record intercepted
// control-flow commands that cause entry into a finally-block, and re-apply // control-flow commands that cause entry into a finally-block, and re-apply
// them after again leaving that block. Special tokens are used to identify // them after again leaving that block. Special tokens are used to identify
...@@ -203,7 +200,6 @@ class BytecodeGenerator::ControlScope::DeferredCommands final { ...@@ -203,7 +200,6 @@ class BytecodeGenerator::ControlScope::DeferredCommands final {
Register result_register_; Register result_register_;
}; };
// Scoped class for dealing with control flow reaching the function level. // Scoped class for dealing with control flow reaching the function level.
class BytecodeGenerator::ControlScopeForTopLevel final class BytecodeGenerator::ControlScopeForTopLevel final
: public BytecodeGenerator::ControlScope { : public BytecodeGenerator::ControlScope {
...@@ -229,7 +225,6 @@ class BytecodeGenerator::ControlScopeForTopLevel final ...@@ -229,7 +225,6 @@ class BytecodeGenerator::ControlScopeForTopLevel final
} }
}; };
// Scoped class for enabling break inside blocks and switch blocks. // Scoped class for enabling break inside blocks and switch blocks.
class BytecodeGenerator::ControlScopeForBreakable final class BytecodeGenerator::ControlScopeForBreakable final
: public BytecodeGenerator::ControlScope { : public BytecodeGenerator::ControlScope {
...@@ -261,7 +256,6 @@ class BytecodeGenerator::ControlScopeForBreakable final ...@@ -261,7 +256,6 @@ class BytecodeGenerator::ControlScopeForBreakable final
BreakableControlFlowBuilder* control_builder_; BreakableControlFlowBuilder* control_builder_;
}; };
// Scoped class for enabling 'break' and 'continue' in iteration // Scoped class for enabling 'break' and 'continue' in iteration
// constructs, e.g. do...while, while..., for... // constructs, e.g. do...while, while..., for...
class BytecodeGenerator::ControlScopeForIteration final class BytecodeGenerator::ControlScopeForIteration final
...@@ -296,7 +290,6 @@ class BytecodeGenerator::ControlScopeForIteration final ...@@ -296,7 +290,6 @@ class BytecodeGenerator::ControlScopeForIteration final
LoopBuilder* loop_builder_; LoopBuilder* loop_builder_;
}; };
// Scoped class for enabling 'throw' in try-catch constructs. // Scoped class for enabling 'throw' in try-catch constructs.
class BytecodeGenerator::ControlScopeForTryCatch final class BytecodeGenerator::ControlScopeForTryCatch final
: public BytecodeGenerator::ControlScope { : public BytecodeGenerator::ControlScope {
...@@ -325,7 +318,6 @@ class BytecodeGenerator::ControlScopeForTryCatch final ...@@ -325,7 +318,6 @@ class BytecodeGenerator::ControlScopeForTryCatch final
} }
}; };
// Scoped class for enabling control flow through try-finally constructs. // Scoped class for enabling control flow through try-finally constructs.
class BytecodeGenerator::ControlScopeForTryFinally final class BytecodeGenerator::ControlScopeForTryFinally final
: public BytecodeGenerator::ControlScope { : public BytecodeGenerator::ControlScope {
...@@ -361,7 +353,6 @@ class BytecodeGenerator::ControlScopeForTryFinally final ...@@ -361,7 +353,6 @@ class BytecodeGenerator::ControlScopeForTryFinally final
DeferredCommands* commands_; DeferredCommands* commands_;
}; };
void BytecodeGenerator::ControlScope::PerformCommand(Command command, void BytecodeGenerator::ControlScope::PerformCommand(Command command,
Statement* statement) { Statement* statement) {
ControlScope* current = this; ControlScope* current = this;
...@@ -384,7 +375,6 @@ void BytecodeGenerator::ControlScope::PerformCommand(Command command, ...@@ -384,7 +375,6 @@ void BytecodeGenerator::ControlScope::PerformCommand(Command command,
UNREACHABLE(); UNREACHABLE();
} }
class BytecodeGenerator::RegisterAllocationScope { class BytecodeGenerator::RegisterAllocationScope {
public: public:
explicit RegisterAllocationScope(BytecodeGenerator* generator) explicit RegisterAllocationScope(BytecodeGenerator* generator)
...@@ -442,7 +432,6 @@ class BytecodeGenerator::RegisterAllocationScope { ...@@ -442,7 +432,6 @@ class BytecodeGenerator::RegisterAllocationScope {
DISALLOW_COPY_AND_ASSIGN(RegisterAllocationScope); DISALLOW_COPY_AND_ASSIGN(RegisterAllocationScope);
}; };
// Scoped base class for determining where the result of an expression // Scoped base class for determining where the result of an expression
// is stored. // is stored.
class BytecodeGenerator::ExpressionResultScope { class BytecodeGenerator::ExpressionResultScope {
...@@ -490,7 +479,6 @@ class BytecodeGenerator::ExpressionResultScope { ...@@ -490,7 +479,6 @@ class BytecodeGenerator::ExpressionResultScope {
DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope); DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope);
}; };
// Scoped class used when the result of the current expression is not // Scoped class used when the result of the current expression is not
// expected to produce a result. // expected to produce a result.
class BytecodeGenerator::EffectResultScope final class BytecodeGenerator::EffectResultScope final
...@@ -505,7 +493,6 @@ class BytecodeGenerator::EffectResultScope final ...@@ -505,7 +493,6 @@ class BytecodeGenerator::EffectResultScope final
virtual void SetResultInRegister(Register reg) {} virtual void SetResultInRegister(Register reg) {}
}; };
// Scoped class used when the result of the current expression to be // Scoped class used when the result of the current expression to be
// evaluated should go into the interpreter's accumulator register. // evaluated should go into the interpreter's accumulator register.
class BytecodeGenerator::AccumulatorResultScope final class BytecodeGenerator::AccumulatorResultScope final
...@@ -522,7 +509,6 @@ class BytecodeGenerator::AccumulatorResultScope final ...@@ -522,7 +509,6 @@ class BytecodeGenerator::AccumulatorResultScope final
} }
}; };
// Scoped class used when the result of the current expression to be // Scoped class used when the result of the current expression to be
// evaluated should go into an interpreter register. // evaluated should go into an interpreter register.
class BytecodeGenerator::RegisterResultScope final class BytecodeGenerator::RegisterResultScope final
...@@ -614,7 +600,6 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode() { ...@@ -614,7 +600,6 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode() {
return builder()->ToBytecodeArray(); return builder()->ToBytecodeArray();
} }
void BytecodeGenerator::MakeBytecodeBody() { void BytecodeGenerator::MakeBytecodeBody() {
// Build the arguments object if it is used. // Build the arguments object if it is used.
VisitArgumentsObject(scope()->arguments()); VisitArgumentsObject(scope()->arguments());
...@@ -729,7 +714,6 @@ void BytecodeGenerator::VisitBlock(Block* stmt) { ...@@ -729,7 +714,6 @@ void BytecodeGenerator::VisitBlock(Block* stmt) {
} }
} }
void BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) { void BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) {
BlockBuilder block_builder(builder()); BlockBuilder block_builder(builder());
ControlScopeForBreakable execution_control(this, stmt, &block_builder); ControlScopeForBreakable execution_control(this, stmt, &block_builder);
...@@ -740,7 +724,6 @@ void BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) { ...@@ -740,7 +724,6 @@ void BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) {
if (stmt->labels() != nullptr) block_builder.EndBlock(); if (stmt->labels() != nullptr) block_builder.EndBlock();
} }
void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
Variable* variable = decl->proxy()->var(); Variable* variable = decl->proxy()->var();
VariableMode mode = decl->mode(); VariableMode mode = decl->mode();
...@@ -802,7 +785,6 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { ...@@ -802,7 +785,6 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
} }
} }
void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
Variable* variable = decl->proxy()->var(); Variable* variable = decl->proxy()->var();
switch (variable->location()) { switch (variable->location()) {
...@@ -849,17 +831,14 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { ...@@ -849,17 +831,14 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
} }
} }
void BytecodeGenerator::VisitImportDeclaration(ImportDeclaration* decl) { void BytecodeGenerator::VisitImportDeclaration(ImportDeclaration* decl) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) { void BytecodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitDeclarations( void BytecodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) { ZoneList<Declaration*>* declarations) {
RegisterAllocationScope register_scope(this); RegisterAllocationScope register_scope(this);
...@@ -888,7 +867,6 @@ void BytecodeGenerator::VisitDeclarations( ...@@ -888,7 +867,6 @@ void BytecodeGenerator::VisitDeclarations(
globals()->clear(); globals()->clear();
} }
void BytecodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { void BytecodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
for (int i = 0; i < statements->length(); i++) { for (int i = 0; i < statements->length(); i++) {
// Allocate an outer register allocations scope for the statement. // Allocate an outer register allocations scope for the statement.
...@@ -899,17 +877,14 @@ void BytecodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { ...@@ -899,17 +877,14 @@ void BytecodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
} }
} }
void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
builder()->SetStatementPosition(stmt); builder()->SetStatementPosition(stmt);
VisitForEffect(stmt->expression()); VisitForEffect(stmt->expression());
} }
void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
} }
void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
builder()->SetStatementPosition(stmt); builder()->SetStatementPosition(stmt);
BytecodeLabel else_label, end_label; BytecodeLabel else_label, end_label;
...@@ -939,32 +914,27 @@ void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { ...@@ -939,32 +914,27 @@ void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
} }
} }
void BytecodeGenerator::VisitSloppyBlockFunctionStatement( void BytecodeGenerator::VisitSloppyBlockFunctionStatement(
SloppyBlockFunctionStatement* stmt) { SloppyBlockFunctionStatement* stmt) {
Visit(stmt->statement()); Visit(stmt->statement());
} }
void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
builder()->SetStatementPosition(stmt); builder()->SetStatementPosition(stmt);
execution_control()->Continue(stmt->target()); execution_control()->Continue(stmt->target());
} }
void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
builder()->SetStatementPosition(stmt); builder()->SetStatementPosition(stmt);
execution_control()->Break(stmt->target()); execution_control()->Break(stmt->target());
} }
void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
builder()->SetStatementPosition(stmt); builder()->SetStatementPosition(stmt);
VisitForAccumulatorValue(stmt->expression()); VisitForAccumulatorValue(stmt->expression());
execution_control()->ReturnAccumulator(); execution_control()->ReturnAccumulator();
} }
void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) {
builder()->SetStatementPosition(stmt); builder()->SetStatementPosition(stmt);
VisitForAccumulatorValue(stmt->expression()); VisitForAccumulatorValue(stmt->expression());
...@@ -973,7 +943,6 @@ void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { ...@@ -973,7 +943,6 @@ void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) {
VisitInScope(stmt->statement(), stmt->scope()); VisitInScope(stmt->statement(), stmt->scope());
} }
void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
// We need this scope because we visit for register values. We have to // We need this scope because we visit for register values. We have to
// maintain a execution result scope where registers can be allocated. // maintain a execution result scope where registers can be allocated.
...@@ -1024,7 +993,6 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { ...@@ -1024,7 +993,6 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
switch_builder.SetBreakTarget(done_label); switch_builder.SetBreakTarget(done_label);
} }
void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { void BytecodeGenerator::VisitCaseClause(CaseClause* clause) {
// Handled entirely in VisitSwitchStatement. // Handled entirely in VisitSwitchStatement.
UNREACHABLE(); UNREACHABLE();
...@@ -1073,7 +1041,6 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { ...@@ -1073,7 +1041,6 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
loop_builder.EndLoop(); loop_builder.EndLoop();
} }
void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
if (stmt->init() != nullptr) { if (stmt->init() != nullptr) {
Visit(stmt->init()); Visit(stmt->init());
...@@ -1100,7 +1067,6 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { ...@@ -1100,7 +1067,6 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
loop_builder.EndLoop(); loop_builder.EndLoop();
} }
void BytecodeGenerator::VisitForInAssignment(Expression* expr, void BytecodeGenerator::VisitForInAssignment(Expression* expr,
FeedbackVectorSlot slot) { FeedbackVectorSlot slot) {
DCHECK(expr->IsValidReferenceExpression()); DCHECK(expr->IsValidReferenceExpression());
...@@ -1174,7 +1140,6 @@ void BytecodeGenerator::VisitForInAssignment(Expression* expr, ...@@ -1174,7 +1140,6 @@ void BytecodeGenerator::VisitForInAssignment(Expression* expr,
} }
} }
void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
if (stmt->subject()->IsNullLiteral() || if (stmt->subject()->IsNullLiteral() ||
stmt->subject()->IsUndefinedLiteral()) { stmt->subject()->IsUndefinedLiteral()) {
...@@ -1226,7 +1191,6 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { ...@@ -1226,7 +1191,6 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
builder()->Bind(&subject_undefined_label); builder()->Bind(&subject_undefined_label);
} }
void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
LoopBuilder loop_builder(builder()); LoopBuilder loop_builder(builder());
ControlScopeForIteration control_scope(this, stmt, &loop_builder); ControlScopeForIteration control_scope(this, stmt, &loop_builder);
...@@ -1246,7 +1210,6 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { ...@@ -1246,7 +1210,6 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
loop_builder.EndLoop(); loop_builder.EndLoop();
} }
void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
TryCatchBuilder try_control_builder(builder()); TryCatchBuilder try_control_builder(builder());
Register no_reg; Register no_reg;
...@@ -1283,7 +1246,6 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { ...@@ -1283,7 +1246,6 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
try_control_builder.EndCatch(); try_control_builder.EndCatch();
} }
void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
TryFinallyBuilder try_control_builder(builder(), IsInsideTryCatch()); TryFinallyBuilder try_control_builder(builder(), IsInsideTryCatch());
Register no_reg; Register no_reg;
...@@ -1348,13 +1310,11 @@ void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { ...@@ -1348,13 +1310,11 @@ void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
commands.ApplyDeferredCommands(); commands.ApplyDeferredCommands();
} }
void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
builder()->SetStatementPosition(stmt); builder()->SetStatementPosition(stmt);
builder()->Debugger(); builder()->Debugger();
} }
void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
// Find or build a shared function info. // Find or build a shared function info.
Handle<SharedFunctionInfo> shared_info = Handle<SharedFunctionInfo> shared_info =
...@@ -1367,7 +1327,6 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { ...@@ -1367,7 +1327,6 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) { void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
if (expr->scope()->ContextLocalCount() > 0) { if (expr->scope()->ContextLocalCount() > 0) {
VisitNewLocalBlockContext(expr->scope()); VisitNewLocalBlockContext(expr->scope());
...@@ -1525,13 +1484,11 @@ void BytecodeGenerator::VisitNativeFunctionLiteral( ...@@ -1525,13 +1484,11 @@ void BytecodeGenerator::VisitNativeFunctionLiteral(
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitDoExpression(DoExpression* expr) { void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
VisitBlock(expr->block()); VisitBlock(expr->block());
VisitVariableProxy(expr->result()); VisitVariableProxy(expr->result());
} }
void BytecodeGenerator::VisitConditional(Conditional* expr) { void BytecodeGenerator::VisitConditional(Conditional* expr) {
// TODO(rmcilroy): Spot easy cases where there code would not need to // TODO(rmcilroy): Spot easy cases where there code would not need to
// emit the then block or the else block, e.g. condition is // emit the then block or the else block, e.g. condition is
...@@ -1552,7 +1509,6 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) { ...@@ -1552,7 +1509,6 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitLiteral(Literal* expr) { void BytecodeGenerator::VisitLiteral(Literal* expr) {
if (!execution_result()->IsEffect()) { if (!execution_result()->IsEffect()) {
Handle<Object> value = expr->value(); Handle<Object> value = expr->value();
...@@ -1575,7 +1531,6 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) { ...@@ -1575,7 +1531,6 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) {
} }
} }
void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
// Materialize a regular expression literal. // Materialize a regular expression literal.
builder()->CreateRegExpLiteral(expr->pattern(), expr->literal_index(), builder()->CreateRegExpLiteral(expr->pattern(), expr->literal_index(),
...@@ -1583,7 +1538,6 @@ void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { ...@@ -1583,7 +1538,6 @@ void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
// Copy the literal boilerplate. // Copy the literal boilerplate.
int fast_clone_properties_count = 0; int fast_clone_properties_count = 0;
...@@ -1787,7 +1741,6 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { ...@@ -1787,7 +1741,6 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
execution_result()->SetResultInRegister(literal); execution_result()->SetResultInRegister(literal);
} }
void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
// Deep-copy the literal boilerplate. // Deep-copy the literal boilerplate.
builder()->CreateArrayLiteral(expr->constant_elements(), builder()->CreateArrayLiteral(expr->constant_elements(),
...@@ -1827,7 +1780,6 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ...@@ -1827,7 +1780,6 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
builder()->SetExpressionPosition(proxy); builder()->SetExpressionPosition(proxy);
VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot());
...@@ -2129,7 +2081,6 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, ...@@ -2129,7 +2081,6 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
} }
} }
void BytecodeGenerator::VisitAssignment(Assignment* expr) { void BytecodeGenerator::VisitAssignment(Assignment* expr) {
DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
Register object, key, home_object, value; Register object, key, home_object, value;
...@@ -2357,7 +2308,6 @@ void BytecodeGenerator::VisitThrow(Throw* expr) { ...@@ -2357,7 +2308,6 @@ void BytecodeGenerator::VisitThrow(Throw* expr) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) {
LhsKind property_kind = Property::GetAssignType(expr); LhsKind property_kind = Property::GetAssignType(expr);
FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); FeedbackVectorSlot slot = expr->PropertyFeedbackSlot();
...@@ -2651,7 +2601,6 @@ void BytecodeGenerator::VisitCallNew(CallNew* expr) { ...@@ -2651,7 +2601,6 @@ void BytecodeGenerator::VisitCallNew(CallNew* expr) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
if (expr->is_jsruntime()) { if (expr->is_jsruntime()) {
...@@ -2672,14 +2621,12 @@ void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { ...@@ -2672,14 +2621,12 @@ void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitVoid(UnaryOperation* expr) { void BytecodeGenerator::VisitVoid(UnaryOperation* expr) {
VisitForEffect(expr->expression()); VisitForEffect(expr->expression());
builder()->LoadUndefined(); builder()->LoadUndefined();
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) { void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
if (expr->expression()->IsVariableProxy()) { if (expr->expression()->IsVariableProxy()) {
// Typeof does not throw a reference error on global variables, hence we // Typeof does not throw a reference error on global variables, hence we
...@@ -2694,14 +2641,12 @@ void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) { ...@@ -2694,14 +2641,12 @@ void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitNot(UnaryOperation* expr) { void BytecodeGenerator::VisitNot(UnaryOperation* expr) {
VisitForAccumulatorValue(expr->expression()); VisitForAccumulatorValue(expr->expression());
builder()->LogicalNot(); builder()->LogicalNot();
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
switch (expr->op()) { switch (expr->op()) {
case Token::Value::NOT: case Token::Value::NOT:
...@@ -2727,7 +2672,6 @@ void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -2727,7 +2672,6 @@ void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
} }
} }
void BytecodeGenerator::VisitDelete(UnaryOperation* expr) { void BytecodeGenerator::VisitDelete(UnaryOperation* expr) {
if (expr->expression()->IsProperty()) { if (expr->expression()->IsProperty()) {
// Delete of an object property is allowed both in sloppy // Delete of an object property is allowed both in sloppy
...@@ -2789,7 +2733,6 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* expr) { ...@@ -2789,7 +2733,6 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* expr) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
...@@ -2911,7 +2854,6 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -2911,7 +2854,6 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
} }
} }
void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) { void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
switch (binop->op()) { switch (binop->op()) {
case Token::COMMA: case Token::COMMA:
...@@ -2929,7 +2871,6 @@ void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) { ...@@ -2929,7 +2871,6 @@ void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
} }
} }
void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Register lhs = VisitForRegisterValue(expr->left()); Register lhs = VisitForRegisterValue(expr->left());
VisitForAccumulatorValue(expr->right()); VisitForAccumulatorValue(expr->right());
...@@ -2938,7 +2879,6 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { ...@@ -2938,7 +2879,6 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
Register lhs = VisitForRegisterValue(expr->left()); Register lhs = VisitForRegisterValue(expr->left());
VisitForAccumulatorValue(expr->right()); VisitForAccumulatorValue(expr->right());
...@@ -2946,39 +2886,32 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { ...@@ -2946,39 +2886,32 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); }
void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
UNREACHABLE(); UNREACHABLE();
} }
void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) { void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) {
execution_result()->SetResultInRegister(Register::function_closure()); execution_result()->SetResultInRegister(Register::function_closure());
} }
void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) { void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) {
// Handled by VisitCall(). // Handled by VisitCall().
UNREACHABLE(); UNREACHABLE();
} }
void BytecodeGenerator::VisitSuperPropertyReference( void BytecodeGenerator::VisitSuperPropertyReference(
SuperPropertyReference* expr) { SuperPropertyReference* expr) {
builder()->CallRuntime(Runtime::kThrowUnsupportedSuperError, Register(0), 0); builder()->CallRuntime(Runtime::kThrowUnsupportedSuperError, Register(0), 0);
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) { void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) {
VisitForEffect(binop->left()); VisitForEffect(binop->left());
Visit(binop->right()); Visit(binop->right());
} }
void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
Expression* left = binop->left(); Expression* left = binop->left();
Expression* right = binop->right(); Expression* right = binop->right();
...@@ -2997,7 +2930,6 @@ void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { ...@@ -2997,7 +2930,6 @@ void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
Expression* left = binop->left(); Expression* left = binop->left();
Expression* right = binop->right(); Expression* right = binop->right();
...@@ -3016,12 +2948,10 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { ...@@ -3016,12 +2948,10 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) { void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) {
Visit(expr->expression()); Visit(expr->expression());
} }
void BytecodeGenerator::VisitNewLocalFunctionContext() { void BytecodeGenerator::VisitNewLocalFunctionContext() {
AccumulatorResultScope accumulator_execution_result(this); AccumulatorResultScope accumulator_execution_result(this);
Scope* scope = this->scope(); Scope* scope = this->scope();
...@@ -3045,7 +2975,6 @@ void BytecodeGenerator::VisitNewLocalFunctionContext() { ...@@ -3045,7 +2975,6 @@ void BytecodeGenerator::VisitNewLocalFunctionContext() {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitBuildLocalActivationContext() { void BytecodeGenerator::VisitBuildLocalActivationContext() {
Scope* scope = this->scope(); Scope* scope = this->scope();
...@@ -3074,7 +3003,6 @@ void BytecodeGenerator::VisitBuildLocalActivationContext() { ...@@ -3074,7 +3003,6 @@ void BytecodeGenerator::VisitBuildLocalActivationContext() {
} }
} }
void BytecodeGenerator::VisitNewLocalBlockContext(Scope* scope) { void BytecodeGenerator::VisitNewLocalBlockContext(Scope* scope) {
AccumulatorResultScope accumulator_execution_result(this); AccumulatorResultScope accumulator_execution_result(this);
DCHECK(scope->is_block_scope()); DCHECK(scope->is_block_scope());
...@@ -3128,7 +3056,6 @@ void BytecodeGenerator::VisitNewLocalCatchContext(Variable* variable) { ...@@ -3128,7 +3056,6 @@ void BytecodeGenerator::VisitNewLocalCatchContext(Variable* variable) {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
void BytecodeGenerator::VisitObjectLiteralAccessor( void BytecodeGenerator::VisitObjectLiteralAccessor(
Register home_object, ObjectLiteralProperty* property, Register value_out) { Register home_object, ObjectLiteralProperty* property, Register value_out) {
// TODO(rmcilroy): Replace value_out with VisitForRegister(); // TODO(rmcilroy): Replace value_out with VisitForRegister();
...@@ -3154,7 +3081,6 @@ void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object, ...@@ -3154,7 +3081,6 @@ void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object,
} }
} }
void BytecodeGenerator::VisitArgumentsObject(Variable* variable) { void BytecodeGenerator::VisitArgumentsObject(Variable* variable) {
if (variable == nullptr) return; if (variable == nullptr) return;
...@@ -3189,7 +3115,6 @@ void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) { ...@@ -3189,7 +3115,6 @@ void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) {
VisitVariableAssignment(variable, Token::INIT, FeedbackVectorSlot::Invalid()); VisitVariableAssignment(variable, Token::INIT, FeedbackVectorSlot::Invalid());
} }
void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) { void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) {
if (variable == nullptr) return; if (variable == nullptr) return;
...@@ -3198,7 +3123,6 @@ void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) { ...@@ -3198,7 +3123,6 @@ void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) {
VisitVariableAssignment(variable, Token::INIT, FeedbackVectorSlot::Invalid()); VisitVariableAssignment(variable, Token::INIT, FeedbackVectorSlot::Invalid());
} }
void BytecodeGenerator::VisitFunctionClosureForContext() { void BytecodeGenerator::VisitFunctionClosureForContext() {
AccumulatorResultScope accumulator_execution_result(this); AccumulatorResultScope accumulator_execution_result(this);
Scope* closure_scope = execution_context()->scope()->ClosureScope(); Scope* closure_scope = execution_context()->scope()->ClosureScope();
...@@ -3225,7 +3149,6 @@ void BytecodeGenerator::VisitFunctionClosureForContext() { ...@@ -3225,7 +3149,6 @@ void BytecodeGenerator::VisitFunctionClosureForContext() {
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
// Visits the expression |expr| and places the result in the accumulator. // Visits the expression |expr| and places the result in the accumulator.
void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) { void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) {
AccumulatorResultScope accumulator_scope(this); AccumulatorResultScope accumulator_scope(this);
...@@ -3246,7 +3169,6 @@ void BytecodeGenerator::VisitForEffect(Expression* expr) { ...@@ -3246,7 +3169,6 @@ void BytecodeGenerator::VisitForEffect(Expression* expr) {
Visit(expr); Visit(expr);
} }
// Visits the expression |expr| and returns the register containing // Visits the expression |expr| and returns the register containing
// the expression result. // the expression result.
Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) { Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) {
...@@ -3270,12 +3192,10 @@ void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) { ...@@ -3270,12 +3192,10 @@ void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) {
Visit(stmt); Visit(stmt);
} }
LanguageMode BytecodeGenerator::language_mode() const { LanguageMode BytecodeGenerator::language_mode() const {
return execution_context()->scope()->language_mode(); return execution_context()->scope()->language_mode();
} }
int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const {
return TypeFeedbackVector::GetIndex(slot); return TypeFeedbackVector::GetIndex(slot);
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "src/ast/ast.h" #include "src/ast/ast.h"
#include "src/interpreter/bytecode-array-builder.h" #include "src/interpreter/bytecode-array-builder.h"
#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/bytecodes.h" #include "src/interpreter/bytecodes.h"
namespace v8 { namespace v8 {
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTERPRETER_BYTECODE_LABEL_H_
#define V8_INTERPRETER_BYTECODE_LABEL_H_
namespace v8 {
namespace internal {
namespace interpreter {
// A label representing a branch target in a bytecode array. When a
// label is bound, it represents a known position in the bytecode
// array. For labels that are forward references there can be at most
// one reference whilst it is unbound.
class BytecodeLabel final {
public:
BytecodeLabel() : bound_(false), offset_(kInvalidOffset) {}
bool is_bound() const { return bound_; }
size_t offset() const { return offset_; }
private:
static const size_t kInvalidOffset = static_cast<size_t>(-1);
void bind_to(size_t offset) {
DCHECK(!bound_ && offset != kInvalidOffset);
offset_ = offset;
bound_ = true;
}
void set_referrer(size_t offset) {
DCHECK(!bound_ && offset != kInvalidOffset && offset_ == kInvalidOffset);
offset_ = offset;
}
bool is_forward_target() const {
return offset() != kInvalidOffset && !is_bound();
}
// There are three states for a label:
// bound_ offset_
// UNSET false kInvalidOffset
// FORWARD_TARGET false Offset of referring jump
// BACKWARD_TARGET true Offset of label in bytecode array when bound
bool bound_;
size_t offset_;
friend class BytecodeArrayWriter;
};
} // namespace interpreter
} // namespace internal
} // namespace v8
#endif // V8_INTERPRETER_BYTECODE_LABEL_H_
...@@ -15,67 +15,67 @@ namespace interpreter { ...@@ -15,67 +15,67 @@ namespace interpreter {
BytecodePeepholeOptimizer::BytecodePeepholeOptimizer( BytecodePeepholeOptimizer::BytecodePeepholeOptimizer(
ConstantArrayBuilder* constant_array_builder, ConstantArrayBuilder* constant_array_builder,
BytecodePipelineStage* next_stage) BytecodePipelineStage* next_stage)
: constant_array_builder_(constant_array_builder), : constant_array_builder_(constant_array_builder), next_stage_(next_stage) {
next_stage_(next_stage),
last_is_discardable_(false) {
InvalidateLast(); InvalidateLast();
} }
void BytecodePeepholeOptimizer::InvalidateLast() { // override
last_.set_bytecode(Bytecode::kIllegal); Handle<BytecodeArray> BytecodePeepholeOptimizer::ToBytecodeArray(
int fixed_register_count, int parameter_count,
Handle<FixedArray> handler_table) {
Flush();
return next_stage_->ToBytecodeArray(fixed_register_count, parameter_count,
handler_table);
} }
bool BytecodePeepholeOptimizer::LastIsValid() const { // override
return last_.bytecode() != Bytecode::kIllegal; void BytecodePeepholeOptimizer::Write(BytecodeNode* node) {
node = OptimizeAndEmitLast(node);
if (node != nullptr) {
SetLast(node);
}
} }
void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) { // override
last_.Clone(node); void BytecodePeepholeOptimizer::WriteJump(BytecodeNode* node,
last_is_discardable_ = true; BytecodeLabel* label) {
node = OptimizeAndEmitLast(node);
next_stage_->WriteJump(node, label);
} }
// override // override
size_t BytecodePeepholeOptimizer::FlushForOffset() { void BytecodePeepholeOptimizer::BindLabel(BytecodeLabel* label) {
size_t buffered_size = next_stage_->FlushForOffset(); Flush();
if (LastIsValid()) { next_stage_->BindLabel(label);
if (last_.bytecode() == Bytecode::kNop &&
!last_.source_info().is_statement()) {
// The Nop can be dropped as it doesn't have a statement
// position for the debugger and doesn't have any effects by
// definition.
InvalidateLast();
} else {
buffered_size += last_.Size();
last_is_discardable_ = false;
}
}
return buffered_size;
} }
// override // override
void BytecodePeepholeOptimizer::FlushBasicBlock() { void BytecodePeepholeOptimizer::BindLabel(const BytecodeLabel& target,
BytecodeLabel* label) {
// There is no need to flush here, it will have been flushed when |target|
// was bound.
next_stage_->BindLabel(target, label);
}
void BytecodePeepholeOptimizer::Flush() {
// TODO(oth/rmcilroy): We could check CanElideLast() here to potentially
// eliminate last rather than writing it.
if (LastIsValid()) { if (LastIsValid()) {
next_stage_->Write(&last_); next_stage_->Write(&last_);
InvalidateLast(); InvalidateLast();
} }
next_stage_->FlushBasicBlock();
} }
// override void BytecodePeepholeOptimizer::InvalidateLast() {
void BytecodePeepholeOptimizer::Write(BytecodeNode* node) { last_.set_bytecode(Bytecode::kIllegal);
// Attempt optimization if there is an earlier node to optimize with. }
if (LastIsValid()) {
node = Optimize(node);
// Only output the last node if it wasn't invalidated by the optimization.
if (LastIsValid()) {
next_stage_->Write(&last_);
InvalidateLast();
}
}
if (node != nullptr) { bool BytecodePeepholeOptimizer::LastIsValid() const {
SetLast(node); return last_.bytecode() != Bytecode::kIllegal;
} }
void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) {
last_.Clone(node);
} }
Handle<Object> BytecodePeepholeOptimizer::GetConstantForIndexOperand( Handle<Object> BytecodePeepholeOptimizer::GetConstantForIndexOperand(
...@@ -260,10 +260,6 @@ bool BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes( ...@@ -260,10 +260,6 @@ bool BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes(
bool BytecodePeepholeOptimizer::CanElideLast( bool BytecodePeepholeOptimizer::CanElideLast(
const BytecodeNode* const current) const { const BytecodeNode* const current) const {
if (!last_is_discardable_) {
return false;
}
if (last_.bytecode() == Bytecode::kNop) { if (last_.bytecode() == Bytecode::kNop) {
// Nop are placeholders for holding source position information. // Nop are placeholders for holding source position information.
return true; return true;
...@@ -311,6 +307,20 @@ BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { ...@@ -311,6 +307,20 @@ BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) {
return current; return current;
} }
BytecodeNode* BytecodePeepholeOptimizer::OptimizeAndEmitLast(
BytecodeNode* current) {
// Attempt optimization if there is an earlier node to optimize with.
if (LastIsValid()) {
current = Optimize(current);
// Only output the last node if it wasn't invalidated by the optimization.
if (LastIsValid()) {
next_stage_->Write(&last_);
InvalidateLast();
}
}
return current;
}
} // namespace interpreter } // namespace interpreter
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -24,11 +24,17 @@ class BytecodePeepholeOptimizer final : public BytecodePipelineStage, ...@@ -24,11 +24,17 @@ class BytecodePeepholeOptimizer final : public BytecodePipelineStage,
// BytecodePipelineStage interface. // BytecodePipelineStage interface.
void Write(BytecodeNode* node) override; void Write(BytecodeNode* node) override;
size_t FlushForOffset() override; void WriteJump(BytecodeNode* node, BytecodeLabel* label) override;
void FlushBasicBlock() override; void BindLabel(BytecodeLabel* label) override;
void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) override;
Handle<BytecodeArray> ToBytecodeArray(
int fixed_register_count, int parameter_count,
Handle<FixedArray> handler_table) override;
private: private:
BytecodeNode* OptimizeAndEmitLast(BytecodeNode* current);
BytecodeNode* Optimize(BytecodeNode* current); BytecodeNode* Optimize(BytecodeNode* current);
void Flush();
void TryToRemoveLastExpressionPosition(const BytecodeNode* const current); void TryToRemoveLastExpressionPosition(const BytecodeNode* const current);
bool TransformLastAndCurrentBytecodes(BytecodeNode* const current); bool TransformLastAndCurrentBytecodes(BytecodeNode* const current);
...@@ -54,7 +60,6 @@ class BytecodePeepholeOptimizer final : public BytecodePipelineStage, ...@@ -54,7 +60,6 @@ class BytecodePeepholeOptimizer final : public BytecodePipelineStage,
ConstantArrayBuilder* constant_array_builder_; ConstantArrayBuilder* constant_array_builder_;
BytecodePipelineStage* next_stage_; BytecodePipelineStage* next_stage_;
BytecodeNode last_; BytecodeNode last_;
bool last_is_discardable_;
DISALLOW_COPY_AND_ASSIGN(BytecodePeepholeOptimizer); DISALLOW_COPY_AND_ASSIGN(BytecodePeepholeOptimizer);
}; };
......
...@@ -13,6 +13,7 @@ namespace v8 { ...@@ -13,6 +13,7 @@ namespace v8 {
namespace internal { namespace internal {
namespace interpreter { namespace interpreter {
class BytecodeLabel;
class BytecodeNode; class BytecodeNode;
class BytecodeSourceInfo; class BytecodeSourceInfo;
...@@ -26,12 +27,26 @@ class BytecodePipelineStage { ...@@ -26,12 +27,26 @@ class BytecodePipelineStage {
// deferring Write() to the next stage. // deferring Write() to the next stage.
virtual void Write(BytecodeNode* node) = 0; virtual void Write(BytecodeNode* node) = 0;
// Flush state for bytecode array offset calculation. Returns the // Write jump bytecode node |node| which jumps to |label| into pipeline.
// current size of bytecode array. // The node and label are only valid for the duration of the call. This call
virtual size_t FlushForOffset() = 0; // implicitly ends the current basic block so should always write to the next
// stage.
// Flush state to terminate basic block. virtual void WriteJump(BytecodeNode* node, BytecodeLabel* label) = 0;
virtual void FlushBasicBlock() = 0;
// Binds |label| to the current bytecode location. This call implicitly
// ends the current basic block and so any deferred bytecodes should be
// written to the next stage.
virtual void BindLabel(BytecodeLabel* label) = 0;
// Binds |label| to the location of |target|. This call implicitly
// ends the current basic block and so any deferred bytecodes should be
// written to the next stage.
virtual void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) = 0;
// Flush the pipeline and generate a bytecode array.
virtual Handle<BytecodeArray> ToBytecodeArray(
int fixed_register_count, int parameter_count,
Handle<FixedArray> handler_table) = 0;
}; };
// Source code position information. // Source code position information.
......
...@@ -198,44 +198,13 @@ BytecodeRegisterOptimizer::BytecodeRegisterOptimizer( ...@@ -198,44 +198,13 @@ BytecodeRegisterOptimizer::BytecodeRegisterOptimizer(
DCHECK(accumulator_info_->register_value() == accumulator_); DCHECK(accumulator_info_->register_value() == accumulator_);
} }
void BytecodeRegisterOptimizer::FlushState() {
if (flushed_) {
return;
}
// Materialize all live registers.
size_t count = register_info_table_.size();
for (size_t i = 0; i < count; ++i) {
RegisterInfo* reg_info = register_info_table_[i];
if (!reg_info->IsOnlyMemberOfEquivalenceSet() &&
!reg_info->materialized()) {
DCHECK(RegisterIsTemporary(reg_info->register_value()) ||
reg_info->register_value() == accumulator_);
Materialize(reg_info);
}
}
// Break all existing equivalences.
for (size_t i = 0; i < count; ++i) {
RegisterInfo* reg_info = register_info_table_[i];
if (!reg_info->IsOnlyMemberOfEquivalenceSet()) {
reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
}
}
flushed_ = true;
}
// override
void BytecodeRegisterOptimizer::FlushBasicBlock() {
FlushState();
next_stage_->FlushBasicBlock();
}
// override // override
size_t BytecodeRegisterOptimizer::FlushForOffset() { Handle<BytecodeArray> BytecodeRegisterOptimizer::ToBytecodeArray(
int fixed_register_count, int parameter_count,
Handle<FixedArray> handler_table) {
FlushState(); FlushState();
return next_stage_->FlushForOffset(); return next_stage_->ToBytecodeArray(fixed_register_count, parameter_count,
handler_table);
} }
// override // override
...@@ -283,6 +252,55 @@ void BytecodeRegisterOptimizer::Write(BytecodeNode* node) { ...@@ -283,6 +252,55 @@ void BytecodeRegisterOptimizer::Write(BytecodeNode* node) {
WriteToNextStage(node); WriteToNextStage(node);
} }
// override
void BytecodeRegisterOptimizer::WriteJump(BytecodeNode* node,
BytecodeLabel* label) {
FlushState();
next_stage_->WriteJump(node, label);
}
// override
void BytecodeRegisterOptimizer::BindLabel(BytecodeLabel* label) {
FlushState();
next_stage_->BindLabel(label);
}
// override
void BytecodeRegisterOptimizer::BindLabel(const BytecodeLabel& target,
BytecodeLabel* label) {
// There is no need to flush here, it will have been flushed when |target|
// was bound.
next_stage_->BindLabel(target, label);
}
void BytecodeRegisterOptimizer::FlushState() {
if (flushed_) {
return;
}
// Materialize all live registers.
size_t count = register_info_table_.size();
for (size_t i = 0; i < count; ++i) {
RegisterInfo* reg_info = register_info_table_[i];
if (!reg_info->IsOnlyMemberOfEquivalenceSet() &&
!reg_info->materialized()) {
DCHECK(RegisterIsTemporary(reg_info->register_value()) ||
reg_info->register_value() == accumulator_);
Materialize(reg_info);
}
}
// Break all existing equivalences.
for (size_t i = 0; i < count; ++i) {
RegisterInfo* reg_info = register_info_table_[i];
if (!reg_info->IsOnlyMemberOfEquivalenceSet()) {
reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
}
}
flushed_ = true;
}
void BytecodeRegisterOptimizer::WriteToNextStage(BytecodeNode* node) const { void BytecodeRegisterOptimizer::WriteToNextStage(BytecodeNode* node) const {
next_stage_->Write(node); next_stage_->Write(node);
} }
......
...@@ -26,9 +26,13 @@ class BytecodeRegisterOptimizer final : public BytecodePipelineStage, ...@@ -26,9 +26,13 @@ class BytecodeRegisterOptimizer final : public BytecodePipelineStage,
virtual ~BytecodeRegisterOptimizer() {} virtual ~BytecodeRegisterOptimizer() {}
// BytecodePipelineStage interface. // BytecodePipelineStage interface.
size_t FlushForOffset() override;
void FlushBasicBlock() override;
void Write(BytecodeNode* node) override; void Write(BytecodeNode* node) override;
void WriteJump(BytecodeNode* node, BytecodeLabel* label) override;
void BindLabel(BytecodeLabel* label) override;
void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) override;
Handle<BytecodeArray> ToBytecodeArray(
int fixed_register_count, int parameter_count,
Handle<FixedArray> handler_table) override;
private: private:
static const uint32_t kInvalidEquivalenceId = kMaxUInt32; static const uint32_t kInvalidEquivalenceId = kMaxUInt32;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "src/interpreter/bytecode-array-builder.h" #include "src/interpreter/bytecode-array-builder.h"
#include "src/interpreter/bytecode-label.h"
#include "src/zone-containers.h" #include "src/zone-containers.h"
namespace v8 { namespace v8 {
......
...@@ -902,6 +902,7 @@ ...@@ -902,6 +902,7 @@
'interpreter/bytecode-array-iterator.h', 'interpreter/bytecode-array-iterator.h',
'interpreter/bytecode-array-writer.cc', 'interpreter/bytecode-array-writer.cc',
'interpreter/bytecode-array-writer.h', 'interpreter/bytecode-array-writer.h',
'interpreter/bytecode-label.h',
'interpreter/bytecode-peephole-optimizer.cc', 'interpreter/bytecode-peephole-optimizer.cc',
'interpreter/bytecode-peephole-optimizer.h', 'interpreter/bytecode-peephole-optimizer.h',
'interpreter/bytecode-pipeline.cc', 'interpreter/bytecode-pipeline.cc',
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/handles.h" #include "src/handles.h"
#include "src/interpreter/bytecode-array-builder.h" #include "src/interpreter/bytecode-array-builder.h"
#include "src/interpreter/bytecode-array-iterator.h" #include "src/interpreter/bytecode-array-iterator.h"
#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/interpreter.h" #include "src/interpreter/interpreter.h"
#include "test/cctest/cctest.h" #include "test/cctest/cctest.h"
#include "test/cctest/interpreter/interpreter-tester.h" #include "test/cctest/interpreter/interpreter-tester.h"
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "src/interpreter/bytecode-array-builder.h" #include "src/interpreter/bytecode-array-builder.h"
#include "src/interpreter/bytecode-array-iterator.h" #include "src/interpreter/bytecode-array-iterator.h"
#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/bytecode-register-allocator.h" #include "src/interpreter/bytecode-register-allocator.h"
#include "test/unittests/test-utils.h" #include "test/unittests/test-utils.h"
...@@ -277,6 +278,19 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -277,6 +278,19 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.StoreLookupSlot(wide_name, LanguageMode::SLOPPY) .StoreLookupSlot(wide_name, LanguageMode::SLOPPY)
.StoreLookupSlot(wide_name, LanguageMode::STRICT); .StoreLookupSlot(wide_name, LanguageMode::STRICT);
// Emit loads which will be transformed to Ldr equivalents by the peephole
// optimizer.
builder.LoadNamedProperty(reg, name, 0)
.StoreAccumulatorInRegister(reg)
.LoadKeyedProperty(reg, 0)
.StoreAccumulatorInRegister(reg)
.LoadContextSlot(reg, 1)
.StoreAccumulatorInRegister(reg)
.LoadGlobal(name, 0, TypeofMode::NOT_INSIDE_TYPEOF)
.StoreAccumulatorInRegister(reg)
.LoadUndefined()
.StoreAccumulatorInRegister(reg);
// CreateClosureWide // CreateClosureWide
Handle<SharedFunctionInfo> shared_info2 = factory->NewSharedFunctionInfo( Handle<SharedFunctionInfo> shared_info2 = factory->NewSharedFunctionInfo(
factory->NewStringFromStaticChars("function_b"), MaybeHandle<Code>(), factory->NewStringFromStaticChars("function_b"), MaybeHandle<Code>(),
...@@ -352,12 +366,20 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -352,12 +366,20 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Insert entry for nop bytecode as this often gets optimized out. // Insert entry for nop bytecode as this often gets optimized out.
scorecard[Bytecodes::ToByte(Bytecode::kNop)] = 1; scorecard[Bytecodes::ToByte(Bytecode::kNop)] = 1;
// Insert entries for bytecodes only emiited by peephole optimizer. if (!FLAG_ignition_peephole) {
scorecard[Bytecodes::ToByte(Bytecode::kLdrNamedProperty)] = 1; // Insert entries for bytecodes only emitted by peephole optimizer.
scorecard[Bytecodes::ToByte(Bytecode::kLdrKeyedProperty)] = 1; scorecard[Bytecodes::ToByte(Bytecode::kLdrNamedProperty)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kLdrGlobal)] = 1; scorecard[Bytecodes::ToByte(Bytecode::kLdrKeyedProperty)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kLdrContextSlot)] = 1; scorecard[Bytecodes::ToByte(Bytecode::kLdrGlobal)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kLdrUndefined)] = 1; scorecard[Bytecodes::ToByte(Bytecode::kLdrContextSlot)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kLdrUndefined)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kLogicalNot)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kJump)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kJumpIfTrue)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kJumpIfFalse)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kJumpIfTrueConstant)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kJumpIfFalseConstant)] = 1;
}
// Check return occurs at the end and only once in the BytecodeArray. // Check return occurs at the end and only once in the BytecodeArray.
CHECK_EQ(final_bytecode, Bytecode::kReturn); CHECK_EQ(final_bytecode, Bytecode::kReturn);
...@@ -470,6 +492,11 @@ TEST_F(BytecodeArrayBuilderTest, Constants) { ...@@ -470,6 +492,11 @@ TEST_F(BytecodeArrayBuilderTest, Constants) {
CHECK_EQ(array->constant_pool()->length(), 3); CHECK_EQ(array->constant_pool()->length(), 3);
} }
static Bytecode PeepholeToBoolean(Bytecode jump_bytecode) {
return FLAG_ignition_peephole
? Bytecodes::GetJumpWithoutToBoolean(jump_bytecode)
: jump_bytecode;
}
TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
static const int kFarJumpDistance = 256; static const int kFarJumpDistance = 256;
...@@ -520,14 +547,16 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { ...@@ -520,14 +547,16 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
// Ignore compare operation. // Ignore compare operation.
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue); CHECK_EQ(iterator.current_bytecode(),
PeepholeToBoolean(Bytecode::kJumpIfToBooleanTrue));
CHECK_EQ(iterator.GetImmediateOperand(0), 14); CHECK_EQ(iterator.GetImmediateOperand(0), 14);
iterator.Advance(); iterator.Advance();
// Ignore compare operation. // Ignore compare operation.
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse); CHECK_EQ(iterator.current_bytecode(),
PeepholeToBoolean(Bytecode::kJumpIfToBooleanFalse));
CHECK_EQ(iterator.GetImmediateOperand(0), 10); CHECK_EQ(iterator.GetImmediateOperand(0), 10);
iterator.Advance(); iterator.Advance();
...@@ -553,7 +582,8 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { ...@@ -553,7 +582,8 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
// Ignore compare operation. // Ignore compare operation.
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant); CHECK_EQ(iterator.current_bytecode(),
PeepholeToBoolean(Bytecode::kJumpIfToBooleanTrueConstant));
CHECK_EQ(*iterator.GetConstantForIndexOperand(0), CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
Smi::FromInt(kFarJumpDistance - 4)); Smi::FromInt(kFarJumpDistance - 4));
iterator.Advance(); iterator.Advance();
...@@ -561,7 +591,8 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { ...@@ -561,7 +591,8 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
// Ignore compare operation. // Ignore compare operation.
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant); CHECK_EQ(iterator.current_bytecode(),
PeepholeToBoolean(Bytecode::kJumpIfToBooleanFalseConstant));
CHECK_EQ(*iterator.GetConstantForIndexOperand(0), CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
Smi::FromInt(kFarJumpDistance - 8)); Smi::FromInt(kFarJumpDistance - 8));
iterator.Advance(); iterator.Advance();
...@@ -628,13 +659,15 @@ TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { ...@@ -628,13 +659,15 @@ TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
iterator.Advance(); iterator.Advance();
// Ignore compare operation. // Ignore compare operation.
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue); CHECK_EQ(iterator.current_bytecode(),
PeepholeToBoolean(Bytecode::kJumpIfToBooleanTrue));
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle); CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK_EQ(iterator.GetImmediateOperand(0), -2); CHECK_EQ(iterator.GetImmediateOperand(0), -2);
iterator.Advance(); iterator.Advance();
// Ignore compare operation. // Ignore compare operation.
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse); CHECK_EQ(iterator.current_bytecode(),
PeepholeToBoolean(Bytecode::kJumpIfToBooleanFalse));
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle); CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK_EQ(iterator.GetImmediateOperand(0), -2); CHECK_EQ(iterator.GetImmediateOperand(0), -2);
iterator.Advance(); iterator.Advance();
...@@ -675,13 +708,15 @@ TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { ...@@ -675,13 +708,15 @@ TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
iterator.Advance(); iterator.Advance();
// Ignore compare operation. // Ignore compare operation.
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse); CHECK_EQ(iterator.current_bytecode(),
PeepholeToBoolean(Bytecode::kJumpIfToBooleanFalse));
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble); CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
CHECK_EQ(iterator.GetImmediateOperand(0), -409); CHECK_EQ(iterator.GetImmediateOperand(0), -409);
iterator.Advance(); iterator.Advance();
// Ignore compare operation. // Ignore compare operation.
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue); CHECK_EQ(iterator.current_bytecode(),
PeepholeToBoolean(Bytecode::kJumpIfToBooleanTrue));
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble); CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
CHECK_EQ(iterator.GetImmediateOperand(0), -419); CHECK_EQ(iterator.GetImmediateOperand(0), -419);
iterator.Advance(); iterator.Advance();
......
...@@ -4,7 +4,11 @@ ...@@ -4,7 +4,11 @@
#include "src/v8.h" #include "src/v8.h"
#include "src/api.h"
#include "src/factory.h"
#include "src/interpreter/bytecode-array-writer.h" #include "src/interpreter/bytecode-array-writer.h"
#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/constant-array-builder.h"
#include "src/interpreter/source-position-table.h" #include "src/interpreter/source-position-table.h"
#include "src/isolate.h" #include "src/isolate.h"
#include "src/utils.h" #include "src/utils.h"
...@@ -18,8 +22,8 @@ namespace interpreter { ...@@ -18,8 +22,8 @@ namespace interpreter {
class BytecodeArrayWriterUnittest : public TestWithIsolateAndZone { class BytecodeArrayWriterUnittest : public TestWithIsolateAndZone {
public: public:
BytecodeArrayWriterUnittest() BytecodeArrayWriterUnittest()
: source_position_builder_(isolate(), zone()), : constant_array_builder_(isolate(), zone()),
bytecode_array_writer_(zone(), &source_position_builder_) {} bytecode_array_writer_(isolate(), zone(), &constant_array_builder_) {}
~BytecodeArrayWriterUnittest() override {} ~BytecodeArrayWriterUnittest() override {}
void Write(BytecodeNode* node, const BytecodeSourceInfo& info); void Write(BytecodeNode* node, const BytecodeSourceInfo& info);
...@@ -37,13 +41,19 @@ class BytecodeArrayWriterUnittest : public TestWithIsolateAndZone { ...@@ -37,13 +41,19 @@ class BytecodeArrayWriterUnittest : public TestWithIsolateAndZone {
uint32_t operand2, uint32_t operand3, OperandScale operand_scale, uint32_t operand2, uint32_t operand3, OperandScale operand_scale,
const BytecodeSourceInfo& info = BytecodeSourceInfo()); const BytecodeSourceInfo& info = BytecodeSourceInfo());
SourcePositionTableBuilder* source_position_builder() { void WriteJump(Bytecode bytecode, BytecodeLabel* label,
return &source_position_builder_; OperandScale operand_scale,
} const BytecodeSourceInfo& info = BytecodeSourceInfo());
BytecodeArrayWriter* writer() { return &bytecode_array_writer_; } BytecodeArrayWriter* writer() { return &bytecode_array_writer_; }
ZoneVector<unsigned char>* bytecodes() { return writer()->bytecodes(); }
SourcePositionTableBuilder* source_position_table_builder() {
return writer()->source_position_table_builder();
}
int max_register_count() { return writer()->max_register_count(); }
private: private:
SourcePositionTableBuilder source_position_builder_; ConstantArrayBuilder constant_array_builder_;
BytecodeArrayWriter bytecode_array_writer_; BytecodeArrayWriter bytecode_array_writer_;
}; };
...@@ -94,40 +104,50 @@ void BytecodeArrayWriterUnittest::Write(Bytecode bytecode, uint32_t operand0, ...@@ -94,40 +104,50 @@ void BytecodeArrayWriterUnittest::Write(Bytecode bytecode, uint32_t operand0,
Write(&node, info); Write(&node, info);
} }
void BytecodeArrayWriterUnittest::WriteJump(Bytecode bytecode,
BytecodeLabel* label,
OperandScale operand_scale,
const BytecodeSourceInfo& info) {
BytecodeNode node(bytecode, 0, operand_scale);
if (info.is_valid()) {
node.source_info().Update(info);
}
writer()->WriteJump(&node, label);
}
TEST_F(BytecodeArrayWriterUnittest, SimpleExample) { TEST_F(BytecodeArrayWriterUnittest, SimpleExample) {
CHECK_EQ(writer()->bytecodes()->size(), 0); CHECK_EQ(bytecodes()->size(), 0);
Write(Bytecode::kStackCheck, {10, false}); Write(Bytecode::kStackCheck, {10, false});
CHECK_EQ(writer()->bytecodes()->size(), 1); CHECK_EQ(bytecodes()->size(), 1);
CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 0); CHECK_EQ(max_register_count(), 0);
Write(Bytecode::kLdaSmi, 0xff, OperandScale::kSingle, {55, true}); Write(Bytecode::kLdaSmi, 0xff, OperandScale::kSingle, {55, true});
CHECK_EQ(writer()->bytecodes()->size(), 3); CHECK_EQ(bytecodes()->size(), 3);
CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 0); CHECK_EQ(max_register_count(), 0);
Write(Bytecode::kLdar, Register(1).ToOperand(), OperandScale::kDouble); Write(Bytecode::kLdar, Register(1).ToOperand(), OperandScale::kDouble);
CHECK_EQ(writer()->bytecodes()->size(), 7); CHECK_EQ(bytecodes()->size(), 7);
CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 2 * kPointerSize); CHECK_EQ(max_register_count(), 2);
Write(Bytecode::kReturn, {70, true}); Write(Bytecode::kReturn, {70, true});
CHECK_EQ(writer()->bytecodes()->size(), 8); CHECK_EQ(bytecodes()->size(), 8);
CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 2 * kPointerSize); CHECK_EQ(max_register_count(), 2);
static const uint8_t bytes[] = {B(StackCheck), B(LdaSmi), U8(0xff), B(Wide), static const uint8_t bytes[] = {B(StackCheck), B(LdaSmi), U8(0xff), B(Wide),
B(Ldar), R16(1), B(Return)}; B(Ldar), R16(1), B(Return)};
CHECK_EQ(writer()->bytecodes()->size(), arraysize(bytes)); CHECK_EQ(bytecodes()->size(), arraysize(bytes));
for (size_t i = 0; i < arraysize(bytes); ++i) { for (size_t i = 0; i < arraysize(bytes); ++i) {
CHECK_EQ(writer()->bytecodes()->at(i), bytes[i]); CHECK_EQ(bytecodes()->at(i), bytes[i]);
} }
CHECK_EQ(writer()->FlushForOffset(), arraysize(bytes)); writer()->ToBytecodeArray(0, 0, factory()->empty_fixed_array());
writer()->FlushBasicBlock(); CHECK_EQ(bytecodes()->size(), arraysize(bytes));
CHECK_EQ(writer()->bytecodes()->size(), arraysize(bytes));
PositionTableEntry expected_positions[] = { PositionTableEntry expected_positions[] = {
{0, 10, false}, {1, 55, true}, {7, 70, true}}; {0, 10, false}, {1, 55, true}, {7, 70, true}};
Handle<ByteArray> source_positions = Handle<ByteArray> source_positions =
source_position_builder()->ToSourcePositionTable(); source_position_table_builder()->ToSourcePositionTable();
SourcePositionTableIterator source_iterator(*source_positions); SourcePositionTableIterator source_iterator(*source_positions);
for (size_t i = 0; i < arraysize(expected_positions); ++i) { for (size_t i = 0; i < arraysize(expected_positions); ++i) {
const PositionTableEntry& expected = expected_positions[i]; const PositionTableEntry& expected = expected_positions[i];
...@@ -173,50 +193,58 @@ TEST_F(BytecodeArrayWriterUnittest, ComplexExample) { ...@@ -173,50 +193,58 @@ TEST_F(BytecodeArrayWriterUnittest, ComplexExample) {
{0, 30, false}, {1, 42, true}, {3, 42, false}, {5, 68, true}, {0, 30, false}, {1, 42, true}, {3, 42, false}, {5, 68, true},
{17, 63, true}, {31, 54, false}, {36, 85, true}, {44, 85, true}}; {17, 63, true}, {31, 54, false}, {36, 85, true}, {44, 85, true}};
BytecodeLabel back_jump, jump_for_in, jump_end_1, jump_end_2, jump_end_3;
#define R(i) static_cast<uint32_t>(Register(i).ToOperand()) #define R(i) static_cast<uint32_t>(Register(i).ToOperand())
Write(Bytecode::kStackCheck, {30, false}); Write(Bytecode::kStackCheck, {30, false});
Write(Bytecode::kLdaConstant, U8(0), OperandScale::kSingle, {42, true}); Write(Bytecode::kLdaConstant, U8(0), OperandScale::kSingle, {42, true});
CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 0 * kPointerSize); CHECK_EQ(max_register_count(), 0);
Write(Bytecode::kStar, R(1), OperandScale::kSingle, {42, false}); Write(Bytecode::kStar, R(1), OperandScale::kSingle, {42, false});
CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 2 * kPointerSize); CHECK_EQ(max_register_count(), 2);
Write(Bytecode::kJumpIfUndefined, U8(38), OperandScale::kSingle, {68, true}); WriteJump(Bytecode::kJumpIfUndefined, &jump_end_1, OperandScale::kSingle,
Write(Bytecode::kJumpIfNull, U8(36), OperandScale::kSingle); {68, true});
WriteJump(Bytecode::kJumpIfNull, &jump_end_2, OperandScale::kSingle);
Write(Bytecode::kToObject); Write(Bytecode::kToObject);
CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 2 * kPointerSize); CHECK_EQ(max_register_count(), 2);
Write(Bytecode::kStar, R(3), OperandScale::kSingle); Write(Bytecode::kStar, R(3), OperandScale::kSingle);
CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 4 * kPointerSize); CHECK_EQ(max_register_count(), 4);
Write(Bytecode::kForInPrepare, R(4), OperandScale::kSingle); Write(Bytecode::kForInPrepare, R(4), OperandScale::kSingle);
CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 7 * kPointerSize); CHECK_EQ(max_register_count(), 7);
Write(Bytecode::kLdaZero); Write(Bytecode::kLdaZero);
CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 7 * kPointerSize); CHECK_EQ(max_register_count(), 7);
Write(Bytecode::kStar, R(7), OperandScale::kSingle); Write(Bytecode::kStar, R(7), OperandScale::kSingle);
CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 8 * kPointerSize); CHECK_EQ(max_register_count(), 8);
writer()->BindLabel(&back_jump);
Write(Bytecode::kForInDone, R(7), R(6), OperandScale::kSingle, {63, true}); Write(Bytecode::kForInDone, R(7), R(6), OperandScale::kSingle, {63, true});
CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 8 * kPointerSize); CHECK_EQ(max_register_count(), 8);
Write(Bytecode::kJumpIfTrue, U8(23), OperandScale::kSingle); WriteJump(Bytecode::kJumpIfTrue, &jump_end_3, OperandScale::kSingle);
Write(Bytecode::kForInNext, R(3), R(7), R(4), U8(1), OperandScale::kSingle); Write(Bytecode::kForInNext, R(3), R(7), R(4), U8(1), OperandScale::kSingle);
Write(Bytecode::kJumpIfUndefined, U8(10), OperandScale::kSingle); WriteJump(Bytecode::kJumpIfUndefined, &jump_for_in, OperandScale::kSingle);
Write(Bytecode::kStar, R(0), OperandScale::kSingle); Write(Bytecode::kStar, R(0), OperandScale::kSingle);
Write(Bytecode::kStackCheck, {54, false}); Write(Bytecode::kStackCheck, {54, false});
Write(Bytecode::kLdar, R(0), OperandScale::kSingle); Write(Bytecode::kLdar, R(0), OperandScale::kSingle);
Write(Bytecode::kStar, R(2), OperandScale::kSingle); Write(Bytecode::kStar, R(2), OperandScale::kSingle);
Write(Bytecode::kReturn, {85, true}); Write(Bytecode::kReturn, {85, true});
writer()->BindLabel(&jump_for_in);
Write(Bytecode::kForInStep, R(7), OperandScale::kSingle); Write(Bytecode::kForInStep, R(7), OperandScale::kSingle);
Write(Bytecode::kStar, R(7), OperandScale::kSingle); Write(Bytecode::kStar, R(7), OperandScale::kSingle);
Write(Bytecode::kJump, U8(-24), OperandScale::kSingle); WriteJump(Bytecode::kJump, &back_jump, OperandScale::kSingle);
writer()->BindLabel(&jump_end_1);
writer()->BindLabel(&jump_end_2);
writer()->BindLabel(&jump_end_3);
Write(Bytecode::kLdaUndefined); Write(Bytecode::kLdaUndefined);
Write(Bytecode::kReturn, {85, true}); Write(Bytecode::kReturn, {85, true});
CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 8 * kPointerSize); CHECK_EQ(max_register_count(), 8);
#undef R #undef R
CHECK_EQ(writer()->bytecodes()->size(), arraysize(expected_bytes)); CHECK_EQ(bytecodes()->size(), arraysize(expected_bytes));
for (size_t i = 0; i < arraysize(expected_bytes); ++i) { for (size_t i = 0; i < arraysize(expected_bytes); ++i) {
CHECK_EQ(static_cast<int>(writer()->bytecodes()->at(i)), CHECK_EQ(static_cast<int>(bytecodes()->at(i)),
static_cast<int>(expected_bytes[i])); static_cast<int>(expected_bytes[i]));
} }
Handle<ByteArray> source_positions = Handle<ByteArray> source_positions =
source_position_builder()->ToSourcePositionTable(); source_position_table_builder()->ToSourcePositionTable();
SourcePositionTableIterator source_iterator(*source_positions); SourcePositionTableIterator source_iterator(*source_positions);
for (size_t i = 0; i < arraysize(expected_positions); ++i) { for (size_t i = 0; i < arraysize(expected_positions); ++i) {
const PositionTableEntry& expected = expected_positions[i]; const PositionTableEntry& expected = expected_positions[i];
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "src/v8.h" #include "src/v8.h"
#include "src/factory.h" #include "src/factory.h"
#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/bytecode-peephole-optimizer.h" #include "src/interpreter/bytecode-peephole-optimizer.h"
#include "src/interpreter/constant-array-builder.h" #include "src/interpreter/constant-array-builder.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
...@@ -23,23 +24,31 @@ class BytecodePeepholeOptimizerTest : public BytecodePipelineStage, ...@@ -23,23 +24,31 @@ class BytecodePeepholeOptimizerTest : public BytecodePipelineStage,
peephole_optimizer_(&constant_array_builder_, this) {} peephole_optimizer_(&constant_array_builder_, this) {}
~BytecodePeepholeOptimizerTest() override {} ~BytecodePeepholeOptimizerTest() override {}
size_t FlushForOffset() override {
flush_for_offset_count_++;
return 0;
};
void FlushBasicBlock() override { flush_basic_block_count_++; }
void Write(BytecodeNode* node) override { void Write(BytecodeNode* node) override {
write_count_++; write_count_++;
last_written_.Clone(node); last_written_.Clone(node);
} }
void WriteJump(BytecodeNode* node, BytecodeLabel* label) override {
write_count_++;
last_written_.Clone(node);
}
void BindLabel(BytecodeLabel* label) override {}
void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) override {}
Handle<BytecodeArray> ToBytecodeArray(
int fixed_register_count, int parameter_count,
Handle<FixedArray> handle_table) override {
return Handle<BytecodeArray>();
}
void Flush() {
optimizer()->ToBytecodeArray(0, 0, factory()->empty_fixed_array());
}
BytecodePeepholeOptimizer* optimizer() { return &peephole_optimizer_; } BytecodePeepholeOptimizer* optimizer() { return &peephole_optimizer_; }
ConstantArrayBuilder* constant_array() { return &constant_array_builder_; } ConstantArrayBuilder* constant_array() { return &constant_array_builder_; }
int flush_for_offset_count() const { return flush_for_offset_count_; }
int flush_basic_block_count() const { return flush_basic_block_count_; }
int write_count() const { return write_count_; } int write_count() const { return write_count_; }
const BytecodeNode& last_written() const { return last_written_; } const BytecodeNode& last_written() const { return last_written_; }
...@@ -47,70 +56,77 @@ class BytecodePeepholeOptimizerTest : public BytecodePipelineStage, ...@@ -47,70 +56,77 @@ class BytecodePeepholeOptimizerTest : public BytecodePipelineStage,
ConstantArrayBuilder constant_array_builder_; ConstantArrayBuilder constant_array_builder_;
BytecodePeepholeOptimizer peephole_optimizer_; BytecodePeepholeOptimizer peephole_optimizer_;
int flush_for_offset_count_ = 0;
int flush_basic_block_count_ = 0;
int write_count_ = 0; int write_count_ = 0;
BytecodeNode last_written_; BytecodeNode last_written_;
}; };
// Sanity tests. // Sanity tests.
TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetPassThrough) { TEST_F(BytecodePeepholeOptimizerTest, FlushOnJump) {
CHECK_EQ(flush_for_offset_count(), 0);
CHECK_EQ(optimizer()->FlushForOffset(), 0);
CHECK_EQ(flush_for_offset_count(), 1);
}
TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetRightSize) {
BytecodeNode node(Bytecode::kAdd, Register(0).ToOperand(),
OperandScale::kQuadruple);
optimizer()->Write(&node);
CHECK_EQ(optimizer()->FlushForOffset(), node.Size());
CHECK_EQ(flush_for_offset_count(), 1);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
}
TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetNop) { BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand(),
BytecodeNode node(Bytecode::kNop); OperandScale::kSingle);
optimizer()->Write(&node); optimizer()->Write(&add);
CHECK_EQ(optimizer()->FlushForOffset(), 0);
CHECK_EQ(flush_for_offset_count(), 1);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
BytecodeLabel target;
BytecodeNode jump(Bytecode::kJump, 0, OperandScale::kSingle);
optimizer()->WriteJump(&jump, &target);
CHECK_EQ(write_count(), 2);
CHECK_EQ(jump, last_written());
} }
TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetNopExpression) { TEST_F(BytecodePeepholeOptimizerTest, FlushOnBind) {
BytecodeNode node(Bytecode::kNop);
node.source_info().Update({3, false});
optimizer()->Write(&node);
CHECK_EQ(optimizer()->FlushForOffset(), 0);
CHECK_EQ(flush_for_offset_count(), 1);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
}
TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetNopStatement) { BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand(),
BytecodeNode node(Bytecode::kNop); OperandScale::kSingle);
node.source_info().Update({3, true}); optimizer()->Write(&add);
optimizer()->Write(&node);
CHECK_EQ(optimizer()->FlushForOffset(), node.Size());
CHECK_EQ(flush_for_offset_count(), 1);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
BytecodeLabel target;
optimizer()->BindLabel(&target);
CHECK_EQ(write_count(), 1);
CHECK_EQ(add, last_written());
} }
TEST_F(BytecodePeepholeOptimizerTest, FlushBasicBlockPassThrough) { // Nop elimination tests.
CHECK_EQ(flush_basic_block_count(), 0);
optimizer()->FlushBasicBlock(); TEST_F(BytecodePeepholeOptimizerTest, ElideEmptyNop) {
CHECK_EQ(flush_basic_block_count(), 1); BytecodeNode nop(Bytecode::kNop);
CHECK_EQ(write_count(), 0); optimizer()->Write(&nop);
BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand(),
OperandScale::kSingle);
optimizer()->Write(&add);
Flush();
CHECK_EQ(write_count(), 1);
CHECK_EQ(add, last_written());
} }
TEST_F(BytecodePeepholeOptimizerTest, WriteOneFlushBasicBlock) { TEST_F(BytecodePeepholeOptimizerTest, ElideExpressionNop) {
BytecodeNode node(Bytecode::kAdd, Register(0).ToOperand(), BytecodeNode nop(Bytecode::kNop);
OperandScale::kQuadruple); nop.source_info().Update({3, false});
optimizer()->Write(&node); optimizer()->Write(&nop);
CHECK_EQ(write_count(), 0); BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand(),
optimizer()->FlushBasicBlock(); OperandScale::kSingle);
optimizer()->Write(&add);
Flush();
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(node, last_written()); CHECK_EQ(add, last_written());
}
TEST_F(BytecodePeepholeOptimizerTest, KeepStatementNop) {
BytecodeNode nop(Bytecode::kNop);
nop.source_info().Update({3, true});
optimizer()->Write(&nop);
BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand(),
OperandScale::kSingle);
add.source_info().Update({3, false});
optimizer()->Write(&add);
Flush();
CHECK_EQ(write_count(), 2);
CHECK_EQ(add, last_written());
} }
// Tests covering BytecodePeepholeOptimizer::UpdateCurrentBytecode(). // Tests covering BytecodePeepholeOptimizer::UpdateCurrentBytecode().
...@@ -123,7 +139,7 @@ TEST_F(BytecodePeepholeOptimizerTest, KeepJumpIfToBooleanTrue) { ...@@ -123,7 +139,7 @@ TEST_F(BytecodePeepholeOptimizerTest, KeepJumpIfToBooleanTrue) {
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first); CHECK_EQ(last_written(), first);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written(), second); CHECK_EQ(last_written(), second);
} }
...@@ -136,7 +152,7 @@ TEST_F(BytecodePeepholeOptimizerTest, ElideJumpIfToBooleanTrue) { ...@@ -136,7 +152,7 @@ TEST_F(BytecodePeepholeOptimizerTest, ElideJumpIfToBooleanTrue) {
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first); CHECK_EQ(last_written(), first);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written().bytecode(), Bytecode::kJumpIfTrue); CHECK_EQ(last_written().bytecode(), Bytecode::kJumpIfTrue);
CHECK_EQ(last_written().operand(0), second.operand(0)); CHECK_EQ(last_written().operand(0), second.operand(0));
...@@ -150,7 +166,7 @@ TEST_F(BytecodePeepholeOptimizerTest, KeepToBooleanLogicalNot) { ...@@ -150,7 +166,7 @@ TEST_F(BytecodePeepholeOptimizerTest, KeepToBooleanLogicalNot) {
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first); CHECK_EQ(last_written(), first);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written(), second); CHECK_EQ(last_written(), second);
} }
...@@ -163,64 +179,63 @@ TEST_F(BytecodePeepholeOptimizerTest, ElideToBooleanLogicalNot) { ...@@ -163,64 +179,63 @@ TEST_F(BytecodePeepholeOptimizerTest, ElideToBooleanLogicalNot) {
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first); CHECK_EQ(last_written(), first);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written().bytecode(), Bytecode::kLogicalNot); CHECK_EQ(last_written().bytecode(), Bytecode::kLogicalNot);
} }
// Tests covering BytecodePeepholeOptimizer::CanElideCurrent(). // Tests covering BytecodePeepholeOptimizer::CanElideCurrent().
TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRy) { TEST_F(BytecodePeepholeOptimizerTest, StarRxLdarRy) {
BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(), BytecodeNode first(Bytecode::kStar, Register(0).ToOperand(),
OperandScale::kSingle); OperandScale::kSingle);
BytecodeNode second(Bytecode::kLdar, Register(1).ToOperand(), BytecodeNode second(Bytecode::kLdar, Register(1).ToOperand(),
OperandScale::kSingle); OperandScale::kSingle);
optimizer()->Write(&first); optimizer()->Write(&first);
optimizer()->FlushForOffset(); // Prevent CanElideLast removing |first|.
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first); CHECK_EQ(last_written(), first);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written(), second); CHECK_EQ(last_written(), second);
} }
TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRx) { TEST_F(BytecodePeepholeOptimizerTest, StarRxLdarRx) {
BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(), BytecodeLabel label;
BytecodeNode first(Bytecode::kStar, Register(0).ToOperand(),
OperandScale::kSingle); OperandScale::kSingle);
BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(), BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(),
OperandScale::kSingle); OperandScale::kSingle);
optimizer()->Write(&first); optimizer()->Write(&first);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
optimizer()->FlushForOffset(); // Prevent CanElideLast removing |first|.
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first); CHECK_EQ(last_written(), first);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
} }
TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRxStatement) { TEST_F(BytecodePeepholeOptimizerTest, StarRxLdarRxStatement) {
BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(), BytecodeNode first(Bytecode::kStar, Register(0).ToOperand(),
OperandScale::kSingle); OperandScale::kSingle);
BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(), BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(),
OperandScale::kSingle); OperandScale::kSingle);
second.source_info().Update({0, true}); second.source_info().Update({0, true});
optimizer()->Write(&first); optimizer()->Write(&first);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
optimizer()->FlushForOffset(); // Prevent CanElideLast removing |first|.
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first); CHECK_EQ(last_written(), first);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written().bytecode(), Bytecode::kNop); CHECK_EQ(last_written().bytecode(), Bytecode::kNop);
CHECK_EQ(last_written().source_info(), second.source_info()); CHECK_EQ(last_written().source_info(), second.source_info());
} }
TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRxStatementStarRy) { TEST_F(BytecodePeepholeOptimizerTest, StarRxLdarRxStatementStarRy) {
BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(), BytecodeLabel label;
BytecodeNode first(Bytecode::kStar, Register(0).ToOperand(),
OperandScale::kSingle); OperandScale::kSingle);
BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(), BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(),
OperandScale::kSingle); OperandScale::kSingle);
...@@ -229,13 +244,12 @@ TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRxStatementStarRy) { ...@@ -229,13 +244,12 @@ TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRxStatementStarRy) {
second.source_info().Update({0, true}); second.source_info().Update({0, true});
optimizer()->Write(&first); optimizer()->Write(&first);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
optimizer()->FlushForOffset(); // Prevent CanElideLast removing |first|.
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first); CHECK_EQ(last_written(), first);
optimizer()->Write(&third); optimizer()->Write(&third);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
// Source position should move |second| to |third| when |second| is elided. // Source position should move |second| to |third| when |second| is elided.
third.source_info().Update(second.source_info()); third.source_info().Update(second.source_info());
...@@ -251,7 +265,7 @@ TEST_F(BytecodePeepholeOptimizerTest, LdarToName) { ...@@ -251,7 +265,7 @@ TEST_F(BytecodePeepholeOptimizerTest, LdarToName) {
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first); CHECK_EQ(last_written(), first);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written(), second); CHECK_EQ(last_written(), second);
} }
...@@ -264,7 +278,7 @@ TEST_F(BytecodePeepholeOptimizerTest, ToNameToName) { ...@@ -264,7 +278,7 @@ TEST_F(BytecodePeepholeOptimizerTest, ToNameToName) {
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first); CHECK_EQ(last_written(), first);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
} }
...@@ -276,7 +290,7 @@ TEST_F(BytecodePeepholeOptimizerTest, TypeOfToName) { ...@@ -276,7 +290,7 @@ TEST_F(BytecodePeepholeOptimizerTest, TypeOfToName) {
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first); CHECK_EQ(last_written(), first);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
} }
...@@ -292,7 +306,7 @@ TEST_F(BytecodePeepholeOptimizerTest, LdaConstantStringToName) { ...@@ -292,7 +306,7 @@ TEST_F(BytecodePeepholeOptimizerTest, LdaConstantStringToName) {
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first); CHECK_EQ(last_written(), first);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
} }
...@@ -307,27 +321,13 @@ TEST_F(BytecodePeepholeOptimizerTest, LdaConstantNumberToName) { ...@@ -307,27 +321,13 @@ TEST_F(BytecodePeepholeOptimizerTest, LdaConstantNumberToName) {
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first); CHECK_EQ(last_written(), first);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written(), second); CHECK_EQ(last_written(), second);
} }
// Tests covering BytecodePeepholeOptimizer::CanElideLast(). // Tests covering BytecodePeepholeOptimizer::CanElideLast().
TEST_F(BytecodePeepholeOptimizerTest, LdaTrueLdaFalseNotDiscardable) {
BytecodeNode first(Bytecode::kLdaTrue);
BytecodeNode second(Bytecode::kLdaFalse);
optimizer()->Write(&first);
optimizer()->FlushForOffset(); // Prevent discarding of |first|.
CHECK_EQ(write_count(), 0);
optimizer()->Write(&second);
CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first);
optimizer()->FlushBasicBlock();
CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written(), second);
}
TEST_F(BytecodePeepholeOptimizerTest, LdaTrueLdaFalse) { TEST_F(BytecodePeepholeOptimizerTest, LdaTrueLdaFalse) {
BytecodeNode first(Bytecode::kLdaTrue); BytecodeNode first(Bytecode::kLdaTrue);
BytecodeNode second(Bytecode::kLdaFalse); BytecodeNode second(Bytecode::kLdaFalse);
...@@ -335,7 +335,7 @@ TEST_F(BytecodePeepholeOptimizerTest, LdaTrueLdaFalse) { ...@@ -335,7 +335,7 @@ TEST_F(BytecodePeepholeOptimizerTest, LdaTrueLdaFalse) {
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), second); CHECK_EQ(last_written(), second);
} }
...@@ -348,7 +348,7 @@ TEST_F(BytecodePeepholeOptimizerTest, LdaTrueStatementLdaFalse) { ...@@ -348,7 +348,7 @@ TEST_F(BytecodePeepholeOptimizerTest, LdaTrueStatementLdaFalse) {
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
second.source_info().Update(first.source_info()); second.source_info().Update(first.source_info());
CHECK_EQ(last_written(), second); CHECK_EQ(last_written(), second);
...@@ -361,7 +361,7 @@ TEST_F(BytecodePeepholeOptimizerTest, NopStackCheck) { ...@@ -361,7 +361,7 @@ TEST_F(BytecodePeepholeOptimizerTest, NopStackCheck) {
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), second); CHECK_EQ(last_written(), second);
} }
...@@ -374,7 +374,7 @@ TEST_F(BytecodePeepholeOptimizerTest, NopStatementStackCheck) { ...@@ -374,7 +374,7 @@ TEST_F(BytecodePeepholeOptimizerTest, NopStatementStackCheck) {
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
optimizer()->Write(&second); optimizer()->Write(&second);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
second.source_info().Update(first.source_info()); second.source_info().Update(first.source_info());
CHECK_EQ(last_written(), second); CHECK_EQ(last_written(), second);
...@@ -406,7 +406,7 @@ TEST_F(BytecodePeepholeOptimizerTest, MergeLoadICStar) { ...@@ -406,7 +406,7 @@ TEST_F(BytecodePeepholeOptimizerTest, MergeLoadICStar) {
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); CHECK_EQ(last_written().bytecode(), Bytecode::kLdar);
CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(last_written().bytecode(), third.bytecode()); CHECK_EQ(last_written().bytecode(), third.bytecode());
} }
...@@ -434,7 +434,7 @@ TEST_F(BytecodePeepholeOptimizerTest, MergeLdaKeyedPropertyStar) { ...@@ -434,7 +434,7 @@ TEST_F(BytecodePeepholeOptimizerTest, MergeLdaKeyedPropertyStar) {
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); CHECK_EQ(last_written().bytecode(), Bytecode::kLdar);
CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(last_written().bytecode(), third.bytecode()); CHECK_EQ(last_written().bytecode(), third.bytecode());
} }
...@@ -461,7 +461,7 @@ TEST_F(BytecodePeepholeOptimizerTest, MergeLdaGlobalStar) { ...@@ -461,7 +461,7 @@ TEST_F(BytecodePeepholeOptimizerTest, MergeLdaGlobalStar) {
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); CHECK_EQ(last_written().bytecode(), Bytecode::kLdar);
CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(last_written().bytecode(), third.bytecode()); CHECK_EQ(last_written().bytecode(), third.bytecode());
} }
...@@ -489,7 +489,7 @@ TEST_F(BytecodePeepholeOptimizerTest, MergeLdaContextSlotStar) { ...@@ -489,7 +489,7 @@ TEST_F(BytecodePeepholeOptimizerTest, MergeLdaContextSlotStar) {
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); CHECK_EQ(last_written().bytecode(), Bytecode::kLdar);
CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(last_written().bytecode(), third.bytecode()); CHECK_EQ(last_written().bytecode(), third.bytecode());
} }
...@@ -515,7 +515,7 @@ TEST_F(BytecodePeepholeOptimizerTest, MergeLdaUndefinedStar) { ...@@ -515,7 +515,7 @@ TEST_F(BytecodePeepholeOptimizerTest, MergeLdaUndefinedStar) {
CHECK_EQ(write_count(), 2); CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written().bytecode(), Bytecode::kLdar); CHECK_EQ(last_written().bytecode(), Bytecode::kLdar);
CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]); CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]);
optimizer()->FlushBasicBlock(); Flush();
CHECK_EQ(last_written().bytecode(), third.bytecode()); CHECK_EQ(last_written().bytecode(), third.bytecode());
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "src/v8.h" #include "src/v8.h"
#include "src/factory.h" #include "src/factory.h"
#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/bytecode-register-optimizer.h" #include "src/interpreter/bytecode-register-optimizer.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/objects.h" #include "src/objects.h"
...@@ -27,14 +28,17 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage, ...@@ -27,14 +28,17 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage,
zone(), register_allocator_, number_of_parameters, this); zone(), register_allocator_, number_of_parameters, this);
} }
size_t FlushForOffset() override {
flush_for_offset_count_++;
return 0;
};
void FlushBasicBlock() override { flush_basic_block_count_++; }
void Write(BytecodeNode* node) override { output_.push_back(*node); } void Write(BytecodeNode* node) override { output_.push_back(*node); }
void WriteJump(BytecodeNode* node, BytecodeLabel* label) override {
output_.push_back(*node);
}
void BindLabel(BytecodeLabel* label) override {}
void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) override {}
Handle<BytecodeArray> ToBytecodeArray(
int fixed_register_count, int parameter_count,
Handle<FixedArray> handle_table) override {
return Handle<BytecodeArray>();
}
TemporaryRegisterAllocator* allocator() { return register_allocator_; } TemporaryRegisterAllocator* allocator() { return register_allocator_; }
BytecodeRegisterOptimizer* optimizer() { return register_optimizer_; } BytecodeRegisterOptimizer* optimizer() { return register_optimizer_; }
...@@ -47,8 +51,6 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage, ...@@ -47,8 +51,6 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage,
allocator()->ReturnTemporaryRegister(reg.index()); allocator()->ReturnTemporaryRegister(reg.index());
} }
int flush_for_offset_count() const { return flush_for_offset_count_; }
int flush_basic_block_count() const { return flush_basic_block_count_; }
size_t write_count() const { return output_.size(); } size_t write_count() const { return output_.size(); }
const BytecodeNode& last_written() const { return output_.back(); } const BytecodeNode& last_written() const { return output_.back(); }
const std::vector<BytecodeNode>* output() { return &output_; } const std::vector<BytecodeNode>* output() { return &output_; }
...@@ -57,76 +59,65 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage, ...@@ -57,76 +59,65 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage,
TemporaryRegisterAllocator* register_allocator_; TemporaryRegisterAllocator* register_allocator_;
BytecodeRegisterOptimizer* register_optimizer_; BytecodeRegisterOptimizer* register_optimizer_;
int flush_for_offset_count_ = 0;
int flush_basic_block_count_ = 0;
std::vector<BytecodeNode> output_; std::vector<BytecodeNode> output_;
}; };
// Sanity tests. // Sanity tests.
TEST_F(BytecodeRegisterOptimizerTest, FlushForOffsetPassThrough) { TEST_F(BytecodeRegisterOptimizerTest, WriteNop) {
Initialize(1, 1);
CHECK_EQ(flush_for_offset_count(), 0);
CHECK_EQ(optimizer()->FlushForOffset(), 0);
CHECK_EQ(flush_for_offset_count(), 1);
}
TEST_F(BytecodeRegisterOptimizerTest, FlushForOffsetRightSize) {
Initialize(1, 1);
BytecodeNode node(Bytecode::kAdd, Register(0).ToOperand(),
OperandScale::kQuadruple);
optimizer()->Write(&node);
CHECK_EQ(optimizer()->FlushForOffset(), 0);
CHECK_EQ(flush_for_offset_count(), 1);
CHECK_EQ(write_count(), 1);
}
TEST_F(BytecodeRegisterOptimizerTest, FlushForOffsetNop) {
Initialize(1, 1); Initialize(1, 1);
BytecodeNode node(Bytecode::kNop); BytecodeNode node(Bytecode::kNop);
optimizer()->Write(&node); optimizer()->Write(&node);
CHECK_EQ(optimizer()->FlushForOffset(), 0);
CHECK_EQ(flush_for_offset_count(), 1);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(node, last_written());
} }
TEST_F(BytecodeRegisterOptimizerTest, FlushForOffsetNopExpression) { TEST_F(BytecodeRegisterOptimizerTest, WriteNopExpression) {
Initialize(1, 1); Initialize(1, 1);
BytecodeNode node(Bytecode::kNop); BytecodeNode node(Bytecode::kNop);
node.source_info().Update({3, false}); node.source_info().Update({3, false});
optimizer()->Write(&node); optimizer()->Write(&node);
CHECK_EQ(optimizer()->FlushForOffset(), 0);
CHECK_EQ(flush_for_offset_count(), 1);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(node, last_written());
} }
TEST_F(BytecodeRegisterOptimizerTest, FlushForOffsetNopStatement) { TEST_F(BytecodeRegisterOptimizerTest, WriteNopStatement) {
Initialize(1, 1); Initialize(1, 1);
BytecodeNode node(Bytecode::kNop); BytecodeNode node(Bytecode::kNop);
node.source_info().Update({3, true}); node.source_info().Update({3, true});
optimizer()->Write(&node); optimizer()->Write(&node);
CHECK_EQ(optimizer()->FlushForOffset(), 0);
CHECK_EQ(flush_for_offset_count(), 1);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
CHECK_EQ(node, last_written());
} }
TEST_F(BytecodeRegisterOptimizerTest, FlushBasicBlockPassThrough) { TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForJump) {
Initialize(1, 1); Initialize(1, 1);
CHECK_EQ(flush_basic_block_count(), 0); Register temp = NewTemporary();
optimizer()->FlushBasicBlock(); BytecodeNode node(Bytecode::kStar, temp.ToOperand(), OperandScale::kSingle);
CHECK_EQ(flush_basic_block_count(), 1); optimizer()->Write(&node);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
BytecodeLabel label;
BytecodeNode jump(Bytecode::kJump, 0, OperandScale::kSingle);
optimizer()->WriteJump(&jump, &label);
CHECK_EQ(write_count(), 2);
CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar);
CHECK_EQ(output()->at(0).operand(0), temp.ToOperand());
CHECK_EQ(output()->at(0).operand_scale(), OperandScale::kSingle);
CHECK_EQ(output()->at(1).bytecode(), Bytecode::kJump);
} }
TEST_F(BytecodeRegisterOptimizerTest, WriteOneFlushBasicBlock) { TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForBind) {
Initialize(1, 1); Initialize(1, 1);
BytecodeNode node(Bytecode::kAdd, Register(0).ToOperand(), Register temp = NewTemporary();
OperandScale::kQuadruple); BytecodeNode node(Bytecode::kStar, temp.ToOperand(), OperandScale::kSingle);
optimizer()->Write(&node); optimizer()->Write(&node);
CHECK_EQ(write_count(), 0);
BytecodeLabel label;
optimizer()->BindLabel(&label);
CHECK_EQ(write_count(), 1); CHECK_EQ(write_count(), 1);
optimizer()->FlushBasicBlock(); CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar);
CHECK_EQ(write_count(), 1); CHECK_EQ(output()->at(0).operand(0), temp.ToOperand());
CHECK_EQ(node, last_written()); CHECK_EQ(output()->at(0).operand_scale(), OperandScale::kSingle);
} }
// Basic Register Optimizations // Basic Register Optimizations
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment