Commit 8df7b4f6 authored by oth's avatar oth Committed by Commit bot

[Interpreter] Skeleton bytecode graph builder

Add skeleton version bytecode-graph-builder.{h,cc} for existing
bytecodes.

BUG=v8:4280
LOG=N

Review URL: https://codereview.chromium.org/1291693004

Cr-Commit-Position: refs/heads/master@{#30687}
parent 752b0308
......@@ -713,6 +713,8 @@ source_set("v8_base") {
"src/compiler/ast-loop-assignment-analyzer.h",
"src/compiler/basic-block-instrumentor.cc",
"src/compiler/basic-block-instrumentor.h",
"src/compiler/bytecode-graph-builder.cc",
"src/compiler/bytecode-graph-builder.h",
"src/compiler/change-lowering.cc",
"src/compiler/change-lowering.h",
"src/compiler/c-linkage.cc",
......@@ -1067,6 +1069,8 @@ source_set("v8_base") {
"src/interpreter/bytecodes.h",
"src/interpreter/bytecode-array-builder.cc",
"src/interpreter/bytecode-array-builder.h",
"src/interpreter/bytecode-array-iterator.cc",
"src/interpreter/bytecode-array-iterator.h",
"src/interpreter/bytecode-generator.cc",
"src/interpreter/bytecode-generator.h",
"src/interpreter/interpreter.cc",
......
......@@ -6,6 +6,7 @@ include_rules = [
"+src/heap/heap.h",
"+src/heap/heap-inl.h",
"-src/interpreter",
"+src/interpreter/bytecode-array-iterator.h",
"+src/interpreter/bytecodes.h",
"+src/interpreter/interpreter.h",
"-src/libplatform",
......
// 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.
#include "src/compiler/bytecode-graph-builder.h"
#include "src/compiler/linkage.h"
#include "src/compiler/operator-properties.h"
#include "src/interpreter/bytecode-array-iterator.h"
namespace v8 {
namespace internal {
namespace compiler {
// Issues:
// - Need to deal with FrameState / FrameStateBeforeAndAfter / StateValue.
// - Scopes - intimately tied to AST. Need to eval what is needed.
// - Need to resolve closure parameter treatment.
BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder,
int register_count,
int parameter_count,
Node* control_dependency,
Node* context)
: builder_(builder),
register_count_(register_count),
parameter_count_(parameter_count),
context_(context),
control_dependency_(control_dependency),
effect_dependency_(control_dependency),
values_(builder->local_zone()) {
// The layout of values_ is:
//
// [receiver] [parameters] [registers]
//
// parameter[0] is the receiver (this), parameters 1..N are the
// parameters supplied to the method (arg0..argN-1). The accumulator
// is stored separately.
// Parameters including the receiver
for (int i = 0; i < parameter_count; i++) {
const char* debug_name = (i == 0) ? "%this" : nullptr;
const Operator* op = common()->Parameter(i, debug_name);
Node* parameter = builder->graph()->NewNode(op, graph()->start());
values()->push_back(parameter);
}
// Registers
register_base_ = static_cast<int>(values()->size());
Node* undefined_constant = builder->jsgraph()->UndefinedConstant();
values()->insert(values()->end(), register_count, undefined_constant);
// Accumulator
accumulator_ = undefined_constant;
}
int BytecodeGraphBuilder::Environment::RegisterToValuesIndex(
interpreter::Register the_register) const {
if (the_register.is_parameter()) {
return the_register.ToParameterIndex(parameter_count());
} else {
return the_register.index() + register_base();
}
}
void BytecodeGraphBuilder::Environment::BindRegister(
interpreter::Register the_register, Node* node) {
int values_index = RegisterToValuesIndex(the_register);
values()->at(values_index) = node;
}
Node* BytecodeGraphBuilder::Environment::LookupRegister(
interpreter::Register the_register) const {
int values_index = RegisterToValuesIndex(the_register);
return values()->at(values_index);
}
void BytecodeGraphBuilder::Environment::BindAccumulator(Node* node) {
accumulator_ = node;
}
Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const {
return accumulator_;
}
bool BytecodeGraphBuilder::Environment::IsMarkedAsUnreachable() const {
return GetControlDependency()->opcode() == IrOpcode::kDead;
}
void BytecodeGraphBuilder::Environment::MarkAsUnreachable() {
UpdateControlDependency(builder()->jsgraph()->Dead());
}
BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone,
CompilationInfo* compilation_info,
JSGraph* jsgraph)
: local_zone_(local_zone),
info_(compilation_info),
jsgraph_(jsgraph),
input_buffer_size_(0),
input_buffer_(nullptr),
exit_controls_(local_zone) {
bytecode_array_ = handle(info()->shared_info()->bytecode_array());
}
Node* BytecodeGraphBuilder::GetFunctionContext() {
if (!function_context_.is_set()) {
// Parameter (arity + 1) is special for the outer context of the function
const Operator* op =
common()->Parameter(bytecode_array()->parameter_count(), "%context");
Node* node = NewNode(op, graph()->start());
function_context_.set(node);
}
return function_context_.get();
}
bool BytecodeGraphBuilder::CreateGraph(bool stack_check) {
// Set up the basic structure of the graph. Outputs for {Start} are
// the formal parameters (including the receiver) plus context and
// closure.
// The additional count items are for the context and closure.
int actual_parameter_count = bytecode_array()->parameter_count() + 2;
graph()->SetStart(graph()->NewNode(common()->Start(actual_parameter_count)));
Environment env(this, bytecode_array()->register_count(),
bytecode_array()->parameter_count(), graph()->start(),
GetFunctionContext());
set_environment(&env);
// Build function context only if there are context allocated variables.
if (info()->num_heap_slots() > 0) {
UNIMPLEMENTED(); // TODO(oth): Write ast-graph-builder equivalent.
} else {
// Simply use the outer function context in building the graph.
CreateGraphBody(stack_check);
}
// Finish the basic structure of the graph.
DCHECK_NE(0u, exit_controls_.size());
int const input_count = static_cast<int>(exit_controls_.size());
Node** const inputs = &exit_controls_.front();
Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs);
graph()->SetEnd(end);
return true;
}
void BytecodeGraphBuilder::CreateGraphBody(bool stack_check) {
// TODO(oth): Review ast-graph-builder equivalent, i.e. arguments
// object setup, this function variable if used, tracing hooks.
VisitBytecodes();
}
void BytecodeGraphBuilder::VisitBytecodes() {
interpreter::BytecodeArrayIterator iterator(bytecode_array());
while (!iterator.done()) {
switch (iterator.current_bytecode()) {
#define BYTECODE_CASE(name, ...) \
case interpreter::Bytecode::k##name: \
Visit##name(iterator); \
break;
BYTECODE_LIST(BYTECODE_CASE)
#undef BYTECODE_CODE
}
iterator.Advance();
}
}
void BytecodeGraphBuilder::VisitLdaZero(
const interpreter::BytecodeArrayIterator& iterator) {
Node* node = jsgraph()->ZeroConstant();
environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitLdaSmi8(
const interpreter::BytecodeArrayIterator& iterator) {
Node* node = jsgraph()->Constant(iterator.GetSmi8Operand(0));
environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitLdaConstant(
const interpreter::BytecodeArrayIterator& iterator) {
Node* node = jsgraph()->Constant(iterator.GetConstantForIndexOperand(0));
environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitLdaUndefined(
const interpreter::BytecodeArrayIterator& iterator) {
Node* node = jsgraph()->UndefinedConstant();
environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitLdaNull(
const interpreter::BytecodeArrayIterator& iterator) {
Node* node = jsgraph()->NullConstant();
environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitLdaTheHole(
const interpreter::BytecodeArrayIterator& iterator) {
Node* node = jsgraph()->TheHoleConstant();
environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitLdaTrue(
const interpreter::BytecodeArrayIterator& iterator) {
Node* node = jsgraph()->TrueConstant();
environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitLdaFalse(
const interpreter::BytecodeArrayIterator& iterator) {
Node* node = jsgraph()->FalseConstant();
environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitLdar(
const interpreter::BytecodeArrayIterator& iterator) {
Node* value = environment()->LookupRegister(iterator.GetRegisterOperand(0));
environment()->BindAccumulator(value);
}
void BytecodeGraphBuilder::VisitStar(
const interpreter::BytecodeArrayIterator& iterator) {
Node* value = environment()->LookupAccumulator();
environment()->BindRegister(iterator.GetRegisterOperand(0), value);
}
void BytecodeGraphBuilder::VisitLoadIC(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitKeyedLoadIC(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitStoreIC(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitKeyedStoreIC(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::BuildBinaryOp(
const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) {
Node* left = environment()->LookupRegister(iterator.GetRegisterOperand(0));
Node* right = environment()->LookupAccumulator();
Node* node = NewNode(js_op, left, right);
// TODO(oth): Real frame state and environment check pointing.
int frame_state_count =
OperatorProperties::GetFrameStateInputCount(node->op());
for (int i = 0; i < frame_state_count; i++) {
NodeProperties::ReplaceFrameStateInput(node, i,
jsgraph()->EmptyFrameState());
}
environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitAdd(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Add(language_mode()), iterator);
}
void BytecodeGraphBuilder::VisitSub(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Subtract(language_mode()), iterator);
}
void BytecodeGraphBuilder::VisitMul(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Multiply(language_mode()), iterator);
}
void BytecodeGraphBuilder::VisitDiv(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Divide(language_mode()), iterator);
}
void BytecodeGraphBuilder::VisitMod(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Modulus(language_mode()), iterator);
}
void BytecodeGraphBuilder::VisitReturn(
const interpreter::BytecodeArrayIterator& iterator) {
Node* control =
NewNode(common()->Return(), environment()->LookupAccumulator());
UpdateControlDependencyToLeaveFunction(control);
}
Node** BytecodeGraphBuilder::EnsureInputBufferSize(int size) {
if (size > input_buffer_size_) {
size = size + kInputBufferSizeIncrement + input_buffer_size_;
input_buffer_ = local_zone()->NewArray<Node*>(size);
input_buffer_size_ = size;
}
return input_buffer_;
}
Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
Node** value_inputs, bool incomplete) {
DCHECK_EQ(op->ValueInputCount(), value_input_count);
bool has_context = OperatorProperties::HasContextInput(op);
int frame_state_count = OperatorProperties::GetFrameStateInputCount(op);
bool has_control = op->ControlInputCount() == 1;
bool has_effect = op->EffectInputCount() == 1;
DCHECK_LT(op->ControlInputCount(), 2);
DCHECK_LT(op->EffectInputCount(), 2);
Node* result = NULL;
if (!has_context && frame_state_count == 0 && !has_control && !has_effect) {
result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
} else {
int input_count_with_deps = value_input_count;
if (has_context) ++input_count_with_deps;
input_count_with_deps += frame_state_count;
if (has_control) ++input_count_with_deps;
if (has_effect) ++input_count_with_deps;
Node** buffer = EnsureInputBufferSize(input_count_with_deps);
memcpy(buffer, value_inputs, kPointerSize * value_input_count);
Node** current_input = buffer + value_input_count;
if (has_context) {
*current_input++ = environment()->Context();
}
for (int i = 0; i < frame_state_count; i++) {
// The frame state will be inserted later. Here we misuse
// the {Dead} node as a sentinel to be later overwritten
// with the real frame state.
*current_input++ = jsgraph()->Dead();
}
if (has_effect) {
*current_input++ = environment()->GetEffectDependency();
}
if (has_control) {
*current_input++ = environment()->GetControlDependency();
}
result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
if (!environment()->IsMarkedAsUnreachable()) {
// Update the current control dependency for control-producing nodes.
if (NodeProperties::IsControl(result)) {
environment()->UpdateControlDependency(result);
}
// Update the current effect dependency for effect-producing nodes.
if (result->op()->EffectOutputCount() > 0) {
environment()->UpdateEffectDependency(result);
}
// Add implicit success continuation for throwing nodes.
if (!result->op()->HasProperty(Operator::kNoThrow)) {
const Operator* op = common()->IfSuccess();
Node* on_success = graph()->NewNode(op, result);
environment_->UpdateControlDependency(on_success);
}
}
}
return result;
}
Node* BytecodeGraphBuilder::MergeControl(Node* control, Node* other) {
int inputs = control->op()->ControlInputCount() + 1;
if (control->opcode() == IrOpcode::kLoop) {
// Control node for loop exists, add input.
const Operator* op = common()->Loop(inputs);
control->AppendInput(graph_zone(), other);
control->set_op(op);
} else if (control->opcode() == IrOpcode::kMerge) {
// Control node for merge exists, add input.
const Operator* op = common()->Merge(inputs);
control->AppendInput(graph_zone(), other);
control->set_op(op);
} else {
// Control node is a singleton, introduce a merge.
const Operator* op = common()->Merge(inputs);
Node* inputs[] = {control, other};
control = graph()->NewNode(op, arraysize(inputs), inputs, true);
}
return control;
}
void BytecodeGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) {
if (environment()->IsMarkedAsUnreachable()) return;
environment()->MarkAsUnreachable();
exit_controls_.push_back(exit);
}
} // namespace compiler
} // namespace internal
} // 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_COMPILER_BYTECODE_GRAPH_BUILDER_H_
#define V8_COMPILER_BYTECODE_GRAPH_BUILDER_H_
#include "src/compiler.h"
#include "src/compiler/js-graph.h"
#include "src/interpreter/bytecode-array-iterator.h"
#include "src/interpreter/bytecodes.h"
namespace v8 {
namespace internal {
namespace compiler {
// The BytecodeGraphBuilder produces a high-level IR graph based on
// interpreter bytecodes.
class BytecodeGraphBuilder {
public:
BytecodeGraphBuilder(Zone* local_zone, CompilationInfo* info,
JSGraph* jsgraph);
// Creates a graph by visiting bytecodes.
bool CreateGraph(bool stack_check = true);
Graph* graph() const { return jsgraph_->graph(); }
private:
class Environment;
void CreateGraphBody(bool stack_check);
void VisitBytecodes();
Node* LoadAccumulator(Node* value);
Node* GetFunctionContext();
void set_environment(Environment* env) { environment_ = env; }
const Environment* environment() const { return environment_; }
Environment* environment() { return environment_; }
// Node creation helpers
Node* NewNode(const Operator* op, bool incomplete = false) {
return MakeNode(op, 0, static_cast<Node**>(NULL), incomplete);
}
Node* NewNode(const Operator* op, Node* n1) {
Node* buffer[] = {n1};
return MakeNode(op, arraysize(buffer), buffer, false);
}
Node* NewNode(const Operator* op, Node* n1, Node* n2) {
Node* buffer[] = {n1, n2};
return MakeNode(op, arraysize(buffer), buffer, false);
}
Node* MakeNode(const Operator* op, int value_input_count, Node** value_inputs,
bool incomplete);
Node* MergeControl(Node* control, Node* other);
Node** EnsureInputBufferSize(int size);
void UpdateControlDependencyToLeaveFunction(Node* exit);
void BuildBinaryOp(const Operator* op,
const interpreter::BytecodeArrayIterator& iterator);
// Growth increment for the temporary buffer used to construct input lists to
// new nodes.
static const int kInputBufferSizeIncrement = 64;
// Field accessors
CommonOperatorBuilder* common() const { return jsgraph_->common(); }
Zone* graph_zone() const { return graph()->zone(); }
CompilationInfo* info() const { return info_; }
JSGraph* jsgraph() const { return jsgraph_; }
JSOperatorBuilder* javascript() const { return jsgraph_->javascript(); }
Zone* local_zone() const { return local_zone_; }
const Handle<BytecodeArray>& bytecode_array() const {
return bytecode_array_;
}
LanguageMode language_mode() const {
// TODO(oth): need to propagate language mode through
return LanguageMode::SLOPPY;
}
#define DECLARE_VISIT_BYTECODE(name, ...) \
void Visit##name(const interpreter::BytecodeArrayIterator& iterator);
BYTECODE_LIST(DECLARE_VISIT_BYTECODE)
#undef DECLARE_VISIT_BYTECODE
Zone* local_zone_;
CompilationInfo* info_;
JSGraph* jsgraph_;
Handle<BytecodeArray> bytecode_array_;
Environment* environment_;
// Temporary storage for building node input lists.
int input_buffer_size_;
Node** input_buffer_;
// Nodes representing values in the activation record.
SetOncePointer<Node> function_context_;
// Control nodes that exit the function body.
ZoneVector<Node*> exit_controls_;
DISALLOW_COPY_AND_ASSIGN(BytecodeGraphBuilder);
};
class BytecodeGraphBuilder::Environment : public ZoneObject {
public:
Environment(BytecodeGraphBuilder* builder, int register_count,
int parameter_count, Node* control_dependency, Node* context);
int parameter_count() const { return parameter_count_; }
int register_count() const { return register_count_; }
void BindRegister(interpreter::Register the_register, Node* node);
Node* LookupRegister(interpreter::Register the_register) const;
void BindAccumulator(Node* node);
Node* LookupAccumulator() const;
bool IsMarkedAsUnreachable() const;
void MarkAsUnreachable();
// Effect dependency tracked by this environment.
Node* GetEffectDependency() { return effect_dependency_; }
void UpdateEffectDependency(Node* dependency) {
effect_dependency_ = dependency;
}
// Control dependency tracked by this environment.
Node* GetControlDependency() const { return control_dependency_; }
void UpdateControlDependency(Node* dependency) {
control_dependency_ = dependency;
}
Node* Context() const { return context_; }
private:
int RegisterToValuesIndex(interpreter::Register the_register) const;
Zone* zone() const { return builder_->local_zone(); }
Graph* graph() const { return builder_->graph(); }
CommonOperatorBuilder* common() const { return builder_->common(); }
BytecodeGraphBuilder* builder() const { return builder_; }
const NodeVector* values() const { return &values_; }
NodeVector* values() { return &values_; }
Node* accumulator() { return accumulator_; }
int register_base() const { return register_base_; }
BytecodeGraphBuilder* builder_;
int register_count_;
int parameter_count_;
Node* accumulator_;
Node* context_;
Node* control_dependency_;
Node* effect_dependency_;
NodeVector values_;
int register_base_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_BYTECODE_GRAPH_BUILDER_H_
......@@ -12,6 +12,7 @@
#include "src/compiler/ast-graph-builder.h"
#include "src/compiler/ast-loop-assignment-analyzer.h"
#include "src/compiler/basic-block-instrumentor.h"
#include "src/compiler/bytecode-graph-builder.h"
#include "src/compiler/change-lowering.h"
#include "src/compiler/code-generator.h"
#include "src/compiler/common-operator-reducer.h"
......@@ -472,11 +473,21 @@ struct GraphBuilderPhase {
static const char* phase_name() { return "graph builder"; }
void Run(PipelineData* data, Zone* temp_zone) {
AstGraphBuilderWithPositions graph_builder(
temp_zone, data->info(), data->jsgraph(), data->loop_assignment(),
data->js_type_feedback(), data->source_positions());
bool stack_check = !data->info()->IsStub();
if (!graph_builder.CreateGraph(stack_check)) {
bool succeeded = false;
if (data->info()->shared_info()->HasBytecodeArray()) {
BytecodeGraphBuilder graph_builder(temp_zone, data->info(),
data->jsgraph());
succeeded = graph_builder.CreateGraph(stack_check);
} else {
AstGraphBuilderWithPositions graph_builder(
temp_zone, data->info(), data->jsgraph(), data->loop_assignment(),
data->js_type_feedback(), data->source_positions());
succeeded = graph_builder.CreateGraph(stack_check);
}
if (!succeeded) {
data->set_compilation_failed();
}
}
......
// 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.
#include "src/interpreter/bytecode-array-iterator.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {
namespace interpreter {
BytecodeArrayIterator::BytecodeArrayIterator(
Handle<BytecodeArray> bytecode_array)
: bytecode_array_(bytecode_array), bytecode_offset_(0) {}
void BytecodeArrayIterator::Advance() {
bytecode_offset_ += Bytecodes::Size(current_bytecode());
}
bool BytecodeArrayIterator::done() const {
return bytecode_offset_ >= bytecode_array()->length();
}
Bytecode BytecodeArrayIterator::current_bytecode() const {
DCHECK(!done());
uint8_t current_byte = bytecode_array()->get(bytecode_offset_);
return interpreter::Bytecodes::FromByte(current_byte);
}
uint8_t BytecodeArrayIterator::GetOperand(int operand_index,
OperandType operand_type) const {
DCHECK_GE(operand_index, 0);
DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
DCHECK_EQ(operand_type,
Bytecodes::GetOperandType(current_bytecode(), operand_index));
int operands_start = bytecode_offset_ + 1;
return bytecode_array()->get(operands_start + operand_index);
}
int8_t BytecodeArrayIterator::GetSmi8Operand(int operand_index) const {
uint8_t operand = GetOperand(operand_index, OperandType::kImm8);
return static_cast<int8_t>(operand);
}
int BytecodeArrayIterator::GetIndexOperand(int operand_index) const {
uint8_t operand = GetOperand(operand_index, OperandType::kIdx);
return static_cast<int>(operand);
}
Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const {
uint8_t operand = GetOperand(operand_index, OperandType::kReg);
return Register::FromOperand(operand);
}
Handle<Object> BytecodeArrayIterator::GetConstantForIndexOperand(
int operand_index) const {
Handle<FixedArray> constants = handle(bytecode_array()->constant_pool());
return FixedArray::get(constants, GetIndexOperand(operand_index));
}
} // namespace interpreter
} // namespace internal
} // 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_ARRAY_ITERATOR_H_
#define V8_INTERPRETER_BYTECODE_ARRAY_ITERATOR_H_
#include "src/handles.h"
#include "src/interpreter/bytecodes.h"
#include "src/objects.h"
namespace v8 {
namespace internal {
namespace interpreter {
class BytecodeArrayIterator {
public:
explicit BytecodeArrayIterator(Handle<BytecodeArray> bytecode_array);
void Advance();
bool done() const;
Bytecode current_bytecode() const;
const Handle<BytecodeArray>& bytecode_array() const {
return bytecode_array_;
}
int8_t GetSmi8Operand(int operand_index) const;
int GetIndexOperand(int operand_index) const;
Register GetRegisterOperand(int operand_index) const;
Handle<Object> GetConstantForIndexOperand(int operand_index) const;
private:
uint8_t GetOperand(int operand_index, OperandType operand_type) const;
Handle<BytecodeArray> bytecode_array_;
int bytecode_offset_;
DISALLOW_COPY_AND_ASSIGN(BytecodeArrayIterator);
};
} // namespace interpreter
} // namespace internal
} // namespace v8
#endif // V8_INTERPRETER_BYTECODE_GRAPH_ITERATOR_H_
......@@ -4091,6 +4091,11 @@ int BytecodeArray::frame_size() const {
}
int BytecodeArray::register_count() const {
return frame_size() / kPointerSize;
}
void BytecodeArray::set_parameter_count(int number_of_parameters) {
DCHECK_GE(number_of_parameters, 0);
// Parameter count is stored as the size on stack of the parameters to allow
......
......@@ -4211,6 +4211,9 @@ class BytecodeArray : public FixedArrayBase {
inline int frame_size() const;
inline void set_frame_size(int frame_size);
// Accessor for register count (derived from frame_size).
inline int register_count() const;
// Accessors for parameter count (including implicit 'this' receiver).
inline int parameter_count() const;
inline void set_parameter_count(int number_of_parameters);
......
......@@ -68,6 +68,7 @@
'compiler/test-osr.cc',
'compiler/test-pipeline.cc',
'compiler/test-representation-change.cc',
'compiler/test-run-bytecode-graph-builder.cc',
'compiler/test-run-deopt.cc',
'compiler/test-run-inlining.cc',
'compiler/test-run-intrinsics.cc',
......
// 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.
#include <utility>
#include "src/v8.h"
#include "src/compiler/pipeline.h"
#include "src/execution.h"
#include "src/handles.h"
#include "src/interpreter/bytecode-array-builder.h"
#include "src/interpreter/interpreter.h"
#include "src/parser.h"
#include "test/cctest/cctest.h"
namespace v8 {
namespace internal {
namespace compiler {
static const char kFunctionName[] = "f";
static MaybeHandle<Object> CallFunction(Isolate* isolate,
Handle<JSFunction> function) {
return Execution::Call(isolate, function,
isolate->factory()->undefined_value(), 0, nullptr,
false);
}
template <class... A>
static MaybeHandle<Object> CallFunction(Isolate* isolate,
Handle<JSFunction> function,
A... args) {
Handle<Object> argv[] = {args...};
return Execution::Call(isolate, function,
isolate->factory()->undefined_value(), sizeof...(args),
argv, false);
}
template <class... A>
class BytecodeGraphCallable {
public:
BytecodeGraphCallable(Isolate* isolate, Handle<JSFunction> function)
: isolate_(isolate), function_(function) {}
virtual ~BytecodeGraphCallable() {}
MaybeHandle<Object> operator()(A... args) {
return CallFunction(isolate_, function_, args...);
}
private:
Isolate* isolate_;
Handle<JSFunction> function_;
};
class BytecodeGraphTester {
public:
BytecodeGraphTester(Isolate* isolate, Zone* zone, const char* script)
: isolate_(isolate), zone_(zone), script_(script) {
i::FLAG_ignition = true;
i::FLAG_always_opt = false;
i::FLAG_vector_stores = true;
// Set ignition filter flag via SetFlagsFromString to avoid double-free
// (or potential leak with StrDup() based on ownership confusion).
ScopedVector<char> ignition_filter(64);
SNPrintF(ignition_filter, "--ignition-filter=%s", kFunctionName);
FlagList::SetFlagsFromString(ignition_filter.start(),
ignition_filter.length());
// Ensure handler table is generated.
isolate->interpreter()->Initialize();
}
virtual ~BytecodeGraphTester() {}
template <class... A>
BytecodeGraphCallable<A...> GetCallable() {
return BytecodeGraphCallable<A...>(isolate_, GetFunction());
}
private:
Isolate* isolate_;
Zone* zone_;
const char* script_;
Handle<JSFunction> GetFunction() {
CompileRun(script_);
Local<Function> api_function =
Local<Function>::Cast(CcTest::global()->Get(v8_str(kFunctionName)));
Handle<JSFunction> function = v8::Utils::OpenHandle(*api_function);
CHECK(function->shared()->HasBytecodeArray());
ParseInfo parse_info(zone_, function);
CompilationInfo compilation_info(&parse_info);
compilation_info.SetOptimizing(BailoutId::None(), Handle<Code>());
Parser parser(&parse_info);
CHECK(parser.Parse(&parse_info));
compiler::Pipeline pipeline(&compilation_info);
Handle<Code> code = pipeline.GenerateCode();
function->ReplaceCode(*code);
return function;
}
DISALLOW_COPY_AND_ASSIGN(BytecodeGraphTester);
};
} // namespace compiler
} // namespace internal
} // namespace v8
using namespace v8::internal;
using namespace v8::internal::compiler;
template <int N>
struct ExpectedSnippet {
const char* code_snippet;
Handle<Object> return_value_and_parameters[N + 1];
inline Handle<Object> return_value() const {
return return_value_and_parameters[0];
}
inline Handle<Object> parameter(int i) const {
return return_value_and_parameters[1 + i];
}
};
TEST(BytecodeGraphBuilderReturnStatements) {
HandleAndZoneScope scope;
Isolate* isolate = scope.main_isolate();
Zone* zone = scope.main_zone();
Factory* factory = isolate->factory();
ExpectedSnippet<0> snippets[] = {
{"return;", {factory->undefined_value()}},
{"return null;", {factory->null_value()}},
{"return true;", {factory->true_value()}},
{"return false;", {factory->false_value()}},
{"return 0;", {factory->NewNumberFromInt(0)}},
{"return +1;", {factory->NewNumberFromInt(1)}},
{"return -1;", {factory->NewNumberFromInt(-1)}},
{"return +127;", {factory->NewNumberFromInt(127)}},
{"return -128;", {factory->NewNumberFromInt(-128)}},
{"return 0.001;", {factory->NewNumber(0.001)}},
{"return 3.7e-60;", {factory->NewNumber(3.7e-60)}},
{"return -3.7e60;", {factory->NewNumber(-3.7e60)}},
{"return '';", {factory->NewStringFromStaticChars("")}},
{"return 'catfood';", {factory->NewStringFromStaticChars("catfood")}}
// TODO(oth): {"return NaN;", {factory->NewNumber(NAN)}}
};
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) {
ScopedVector<char> script(1024);
SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
snippets[i].code_snippet, kFunctionName);
BytecodeGraphTester tester(isolate, zone, script.start());
auto callable = tester.GetCallable<>();
Handle<Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*snippets[i].return_value()));
}
}
TEST(BytecodeGraphBuilderPrimitiveExpressions) {
HandleAndZoneScope scope;
Isolate* isolate = scope.main_isolate();
Zone* zone = scope.main_zone();
Factory* factory = isolate->factory();
ExpectedSnippet<0> snippets[] = {
{"return 1 + 1;", {factory->NewNumberFromInt(2)}},
{"return 20 - 30;", {factory->NewNumberFromInt(-10)}},
{"return 4 * 100;", {factory->NewNumberFromInt(400)}},
{"return 100 / 5;", {factory->NewNumberFromInt(20)}},
{"return 25 % 7;", {factory->NewNumberFromInt(4)}},
};
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) {
ScopedVector<char> script(1024);
SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
snippets[i].code_snippet, kFunctionName);
BytecodeGraphTester tester(isolate, zone, script.start());
auto callable = tester.GetCallable<>();
Handle<Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*snippets[i].return_value()));
}
}
TEST(BytecodeGraphBuilderTwoParameterTests) {
HandleAndZoneScope scope;
Isolate* isolate = scope.main_isolate();
Zone* zone = scope.main_zone();
Factory* factory = isolate->factory();
ExpectedSnippet<2> snippets[] = {
// Integers
{"return p1 + p2;",
{factory->NewNumberFromInt(-70), factory->NewNumberFromInt(3),
factory->NewNumberFromInt(-73)}},
{"return p1 + p2 + 3;",
{factory->NewNumberFromInt(1139044), factory->NewNumberFromInt(300),
factory->NewNumberFromInt(1138741)}},
{"return p1 - p2;",
{factory->NewNumberFromInt(1100), factory->NewNumberFromInt(1000),
factory->NewNumberFromInt(-100)}},
{"return p1 * p2;",
{factory->NewNumberFromInt(-100000), factory->NewNumberFromInt(1000),
factory->NewNumberFromInt(-100)}},
{"return p1 / p2;",
{factory->NewNumberFromInt(-10), factory->NewNumberFromInt(1000),
factory->NewNumberFromInt(-100)}},
{"return p1 % p2;",
{factory->NewNumberFromInt(5), factory->NewNumberFromInt(373),
factory->NewNumberFromInt(16)}},
// Doubles
{"return p1 + p2;",
{factory->NewHeapNumber(9.999), factory->NewHeapNumber(3.333),
factory->NewHeapNumber(6.666)}},
{"return p1 - p2;",
{factory->NewHeapNumber(-3.333), factory->NewHeapNumber(3.333),
factory->NewHeapNumber(6.666)}},
{"return p1 * p2;",
{factory->NewHeapNumber(3.333 * 6.666), factory->NewHeapNumber(3.333),
factory->NewHeapNumber(6.666)}},
{"return p1 / p2;",
{factory->NewHeapNumber(2.25), factory->NewHeapNumber(9),
factory->NewHeapNumber(4)}},
// Strings
{"return p1 + p2;",
{factory->NewStringFromStaticChars("abcdef"),
factory->NewStringFromStaticChars("abc"),
factory->NewStringFromStaticChars("def")}}};
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) {
ScopedVector<char> script(1024);
SNPrintF(script, "function %s(p1, p2) { %s }\n%s(0, 0);", kFunctionName,
snippets[i].code_snippet, kFunctionName);
BytecodeGraphTester tester(isolate, zone, script.start());
auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>();
Handle<Object> return_value =
callable(snippets[i].parameter(0), snippets[i].parameter(1))
.ToHandleChecked();
CHECK(return_value->SameValue(*snippets[i].return_value()));
}
}
......@@ -23,7 +23,8 @@ class BytecodeGeneratorHelper {
BytecodeGeneratorHelper() {
i::FLAG_vector_stores = true;
i::FLAG_ignition = true;
i::FLAG_ignition_filter = kFunctionName;
i::FLAG_ignition_filter = StrDup(kFunctionName);
i::FLAG_always_opt = false;
CcTest::i_isolate()->interpreter()->Initialize();
}
......
// 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.
#include <iostream>
#include "src/compiler/bytecode-graph-builder.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/graph-visualizer.h"
#include "src/compiler/instruction.h"
#include "src/compiler/instruction-selector.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/js-operator.h"
#include "src/interpreter/bytecode-array-builder.h"
#include "src/parser.h"
#include "test/unittests/compiler/compiler-test-utils.h"
#include "test/unittests/compiler/graph-unittest.h"
#include "test/unittests/compiler/node-test-utils.h"
#include "test/unittests/test-utils.h"
using ::testing::_;
namespace v8 {
namespace internal {
namespace compiler {
class BytecodeGraphBuilderTest : public TestWithIsolateAndZone {
public:
BytecodeGraphBuilderTest() : array_builder_(isolate(), zone()) {}
Graph* GetCompletedGraph();
Matcher<Node*> IsUndefinedConstant();
Matcher<Node*> IsNullConstant();
Matcher<Node*> IsTheHoleConstant();
Matcher<Node*> IsFalseConstant();
Matcher<Node*> IsTrueConstant();
interpreter::BytecodeArrayBuilder* array_builder() { return &array_builder_; }
private:
interpreter::BytecodeArrayBuilder array_builder_;
DISALLOW_COPY_AND_ASSIGN(BytecodeGraphBuilderTest);
};
Graph* BytecodeGraphBuilderTest::GetCompletedGraph() {
MachineOperatorBuilder* machine = new (zone()) MachineOperatorBuilder(
zone(), kMachPtr, InstructionSelector::SupportedMachineOperatorFlags());
CommonOperatorBuilder* common = new (zone()) CommonOperatorBuilder(zone());
JSOperatorBuilder* javascript = new (zone()) JSOperatorBuilder(zone());
Graph* graph = new (zone()) Graph(zone());
JSGraph* jsgraph =
new (zone()) JSGraph(isolate(), graph, common, javascript, machine);
Handle<String> name = factory()->NewStringFromStaticChars("test");
Handle<String> script = factory()->NewStringFromStaticChars("test() {}");
Handle<SharedFunctionInfo> shared_info =
factory()->NewSharedFunctionInfo(name, MaybeHandle<Code>());
shared_info->set_script(*factory()->NewScript(script));
ParseInfo parse_info(zone(), shared_info);
CompilationInfo info(&parse_info);
Handle<BytecodeArray> bytecode_array = array_builder()->ToBytecodeArray();
info.shared_info()->set_function_data(*bytecode_array);
BytecodeGraphBuilder graph_builder(zone(), &info, jsgraph);
graph_builder.CreateGraph();
return graph;
}
Matcher<Node*> BytecodeGraphBuilderTest::IsUndefinedConstant() {
return IsHeapConstant(factory()->undefined_value());
}
Matcher<Node*> BytecodeGraphBuilderTest::IsNullConstant() {
return IsHeapConstant(factory()->null_value());
}
Matcher<Node*> BytecodeGraphBuilderTest::IsTheHoleConstant() {
return IsHeapConstant(factory()->the_hole_value());
}
Matcher<Node*> BytecodeGraphBuilderTest::IsFalseConstant() {
return IsHeapConstant(factory()->false_value());
}
Matcher<Node*> BytecodeGraphBuilderTest::IsTrueConstant() {
return IsHeapConstant(factory()->true_value());
}
TEST_F(BytecodeGraphBuilderTest, ReturnUndefined) {
array_builder()->set_locals_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadUndefined().Return();
Graph* graph = GetCompletedGraph();
Node* end = graph->end();
EXPECT_EQ(1, end->InputCount());
Node* ret = end->InputAt(0);
Node* effect = graph->start();
Node* control = graph->start();
EXPECT_THAT(ret, IsReturn(IsUndefinedConstant(), effect, control));
}
TEST_F(BytecodeGraphBuilderTest, ReturnNull) {
array_builder()->set_locals_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadNull().Return();
Graph* graph = GetCompletedGraph();
Node* end = graph->end();
EXPECT_EQ(1, end->InputCount());
Node* ret = end->InputAt(0);
EXPECT_THAT(ret, IsReturn(IsNullConstant(), graph->start(), graph->start()));
}
TEST_F(BytecodeGraphBuilderTest, ReturnTheHole) {
array_builder()->set_locals_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadTheHole().Return();
Graph* graph = GetCompletedGraph();
Node* end = graph->end();
EXPECT_EQ(1, end->InputCount());
Node* ret = end->InputAt(0);
Node* effect = graph->start();
Node* control = graph->start();
EXPECT_THAT(ret, IsReturn(IsTheHoleConstant(), effect, control));
}
TEST_F(BytecodeGraphBuilderTest, ReturnTrue) {
array_builder()->set_locals_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadTrue().Return();
Graph* graph = GetCompletedGraph();
Node* end = graph->end();
EXPECT_EQ(1, end->InputCount());
Node* ret = end->InputAt(0);
Node* effect = graph->start();
Node* control = graph->start();
EXPECT_THAT(ret, IsReturn(IsTrueConstant(), effect, control));
}
TEST_F(BytecodeGraphBuilderTest, ReturnFalse) {
array_builder()->set_locals_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadFalse().Return();
Graph* graph = GetCompletedGraph();
Node* end = graph->end();
EXPECT_EQ(1, end->InputCount());
Node* ret = end->InputAt(0);
Node* effect = graph->start();
Node* control = graph->start();
EXPECT_THAT(ret, IsReturn(IsFalseConstant(), effect, control));
}
TEST_F(BytecodeGraphBuilderTest, ReturnInt8) {
static const int kValue = 3;
array_builder()->set_locals_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadLiteral(Smi::FromInt(kValue)).Return();
Graph* graph = GetCompletedGraph();
Node* end = graph->end();
EXPECT_EQ(1, end->InputCount());
Node* ret = end->InputAt(0);
Node* effect = graph->start();
Node* control = graph->start();
EXPECT_THAT(ret, IsReturn(IsNumberConstant(kValue), effect, control));
}
TEST_F(BytecodeGraphBuilderTest, ReturnDouble) {
const double kValue = 0.123456789;
array_builder()->set_locals_count(0);
array_builder()->set_parameter_count(1);
array_builder()->LoadLiteral(factory()->NewHeapNumber(kValue));
array_builder()->Return();
Graph* graph = GetCompletedGraph();
Node* end = graph->end();
EXPECT_EQ(1, end->InputCount());
Node* ret = end->InputAt(0);
Node* effect = graph->start();
Node* control = graph->start();
EXPECT_THAT(ret, IsReturn(IsNumberConstant(kValue), effect, control));
}
TEST_F(BytecodeGraphBuilderTest, SimpleExpressionWithParameters) {
array_builder()->set_locals_count(1);
array_builder()->set_parameter_count(3);
array_builder()
->LoadAccumulatorWithRegister(array_builder()->Parameter(1))
.BinaryOperation(Token::Value::ADD, array_builder()->Parameter(2))
.StoreAccumulatorInRegister(interpreter::Register(0))
.Return();
Graph* graph = GetCompletedGraph();
Node* end = graph->end();
EXPECT_EQ(1, end->InputCount());
Node* ret = end->InputAt(0);
// NB binary operation is <reg> <op> <acc>. The register represents
// the left-hand side, which is why parameters appear in opposite
// order to construction via the builder.
EXPECT_THAT(ret, IsReturn(IsJSAdd(IsParameter(2), IsParameter(1)), _, _));
}
TEST_F(BytecodeGraphBuilderTest, SimpleExpressionWithRegister) {
static const int kLeft = -655371;
static const int kRight = +2000000;
array_builder()->set_locals_count(1);
array_builder()->set_parameter_count(1);
array_builder()
->LoadLiteral(Smi::FromInt(kLeft))
.StoreAccumulatorInRegister(interpreter::Register(0))
.LoadLiteral(Smi::FromInt(kRight))
.BinaryOperation(Token::Value::ADD, interpreter::Register(0))
.Return();
Graph* graph = GetCompletedGraph();
Node* end = graph->end();
EXPECT_EQ(1, end->InputCount());
Node* ret = end->InputAt(0);
EXPECT_THAT(
ret, IsReturn(IsJSAdd(IsNumberConstant(kLeft), IsNumberConstant(kRight)),
_, _));
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -2008,6 +2008,7 @@ IS_BINOP_MATCHER(Uint32LessThan)
IS_BINOP_MATCHER(Uint32LessThanOrEqual)
IS_BINOP_MATCHER(Int64Add)
IS_BINOP_MATCHER(Int64Sub)
IS_BINOP_MATCHER(JSAdd)
IS_BINOP_MATCHER(Float32Max)
IS_BINOP_MATCHER(Float32Min)
IS_BINOP_MATCHER(Float32Equal)
......
......@@ -295,6 +295,8 @@ Matcher<Node*> IsInt64Add(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsInt64Sub(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsJSAdd(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsChangeFloat64ToInt32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsChangeFloat64ToUint32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsChangeInt32ToFloat64(const Matcher<Node*>& input_matcher);
......
// 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.
#include "src/v8.h"
#include "src/interpreter/bytecode-array-builder.h"
#include "src/interpreter/bytecode-array-iterator.h"
#include "test/unittests/test-utils.h"
namespace v8 {
namespace internal {
namespace interpreter {
class BytecodeArrayIteratorTest : public TestWithIsolateAndZone {
public:
BytecodeArrayIteratorTest() {}
~BytecodeArrayIteratorTest() override {}
};
TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
// Use a builder to create an array with containing multiple bytecodes
// with 0, 1 and 2 operands.
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(3);
builder.set_locals_count(2);
Factory* factory = isolate()->factory();
Handle<HeapObject> heap_num_0 = factory->NewHeapNumber(2.718);
Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(2147483647);
Smi* zero = Smi::FromInt(0);
Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536);
Register reg_0(0);
Register reg_1(1);
Register reg_2 = Register::FromParameterIndex(2, builder.parameter_count());
int feedback_slot = 97;
builder.LoadLiteral(heap_num_0)
.LoadLiteral(heap_num_1)
.LoadLiteral(zero)
.LoadLiteral(smi_0)
.LoadLiteral(smi_1)
.LoadAccumulatorWithRegister(reg_0)
.LoadNamedProperty(reg_1, feedback_slot, LanguageMode::SLOPPY)
.StoreAccumulatorInRegister(reg_2)
.Return();
// Test iterator sees the expected output from the builder.
BytecodeArrayIterator iterator(builder.ToBytecodeArray());
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant);
CHECK(iterator.GetConstantForIndexOperand(0).is_identical_to(heap_num_0));
CHECK(!iterator.done());
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant);
CHECK(iterator.GetConstantForIndexOperand(0).is_identical_to(heap_num_1));
CHECK(!iterator.done());
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaZero);
CHECK(!iterator.done());
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi8);
CHECK_EQ(Smi::FromInt(iterator.GetSmi8Operand(0)), smi_0);
CHECK(!iterator.done());
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant);
CHECK_EQ(*iterator.GetConstantForIndexOperand(0), smi_1);
CHECK(!iterator.done());
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdar);
CHECK_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index());
CHECK(!iterator.done());
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLoadIC);
CHECK_EQ(iterator.GetRegisterOperand(0).index(), reg_1.index());
CHECK_EQ(iterator.GetIndexOperand(1), feedback_slot);
CHECK(!iterator.done());
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kStar);
CHECK_EQ(iterator.GetRegisterOperand(0).index(), reg_2.index());
CHECK(!iterator.done());
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
CHECK(!iterator.done());
iterator.Advance();
CHECK(iterator.done());
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -43,6 +43,7 @@
'base/sys-info-unittest.cc',
'base/utils/random-number-generator-unittest.cc',
'char-predicates-unittest.cc',
'compiler/bytecode-graph-builder-unittest.cc',
'compiler/change-lowering-unittest.cc',
'compiler/coalesced-live-ranges-unittest.cc',
'compiler/common-operator-reducer-unittest.cc',
......@@ -98,6 +99,7 @@
'counters-unittest.cc',
'interpreter/bytecodes-unittest.cc',
'interpreter/bytecode-array-builder-unittest.cc',
'interpreter/bytecode-array-iterator-unittest.cc',
'libplatform/default-platform-unittest.cc',
'libplatform/task-queue-unittest.cc',
'libplatform/worker-thread-unittest.cc',
......
......@@ -454,6 +454,8 @@
'../../src/compiler/ast-loop-assignment-analyzer.h',
'../../src/compiler/basic-block-instrumentor.cc',
'../../src/compiler/basic-block-instrumentor.h',
'../../src/compiler/bytecode-graph-builder.cc',
'../../src/compiler/bytecode-graph-builder.h',
'../../src/compiler/change-lowering.cc',
'../../src/compiler/change-lowering.h',
'../../src/compiler/c-linkage.cc',
......@@ -810,6 +812,8 @@
'../../src/interpreter/bytecode-generator.h',
'../../src/interpreter/bytecode-array-builder.cc',
'../../src/interpreter/bytecode-array-builder.h',
'../../src/interpreter/bytecode-array-iterator.cc',
'../../src/interpreter/bytecode-array-iterator.h',
'../../src/interpreter/interpreter.cc',
'../../src/interpreter/interpreter.h',
'../../src/isolate-inl.h',
......
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