"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",
"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",
"+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",
--- /dev/null
+// 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
--- /dev/null
+// 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_
#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"
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();
}
}
--- /dev/null
+// 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
--- /dev/null
+// 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_
}
+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
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);
'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',
--- /dev/null
+// 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()));
+ }
+}
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();
}
--- /dev/null
+// 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
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)
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);
--- /dev/null
+// 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
'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',
'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',
'../../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',
'../../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',