summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/bytecode-graph-builder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/bytecode-graph-builder.cc')
-rw-r--r--deps/v8/src/compiler/bytecode-graph-builder.cc1401
1 files changed, 1255 insertions, 146 deletions
diff --git a/deps/v8/src/compiler/bytecode-graph-builder.cc b/deps/v8/src/compiler/bytecode-graph-builder.cc
index e113833dc1..cf0b6ab438 100644
--- a/deps/v8/src/compiler/bytecode-graph-builder.cc
+++ b/deps/v8/src/compiler/bytecode-graph-builder.cc
@@ -4,16 +4,78 @@
#include "src/compiler/bytecode-graph-builder.h"
+#include "src/compiler/bytecode-branch-analysis.h"
#include "src/compiler/linkage.h"
#include "src/compiler/operator-properties.h"
-#include "src/interpreter/bytecode-array-iterator.h"
+#include "src/interpreter/bytecodes.h"
namespace v8 {
namespace internal {
namespace compiler {
+// Helper for generating frame states for before and after a bytecode.
+class BytecodeGraphBuilder::FrameStateBeforeAndAfter {
+ public:
+ FrameStateBeforeAndAfter(BytecodeGraphBuilder* builder,
+ const interpreter::BytecodeArrayIterator& iterator)
+ : builder_(builder),
+ id_after_(BailoutId::None()),
+ added_to_node_(false),
+ output_poke_offset_(0),
+ output_poke_count_(0) {
+ BailoutId id_before(iterator.current_offset());
+ frame_state_before_ = builder_->environment()->Checkpoint(
+ id_before, OutputFrameStateCombine::Ignore());
+ id_after_ = BailoutId(id_before.ToInt() + iterator.current_bytecode_size());
+ }
+
+ ~FrameStateBeforeAndAfter() {
+ DCHECK(added_to_node_);
+ DCHECK(builder_->environment()->StateValuesAreUpToDate(output_poke_offset_,
+ output_poke_count_));
+ }
+
+ private:
+ friend class Environment;
+
+ void AddToNode(Node* node, OutputFrameStateCombine combine) {
+ DCHECK(!added_to_node_);
+ int count = OperatorProperties::GetFrameStateInputCount(node->op());
+ DCHECK_LE(count, 2);
+ if (count >= 1) {
+ // Add the frame state for after the operation.
+ DCHECK_EQ(IrOpcode::kDead,
+ NodeProperties::GetFrameStateInput(node, 0)->opcode());
+ Node* frame_state_after =
+ builder_->environment()->Checkpoint(id_after_, combine);
+ NodeProperties::ReplaceFrameStateInput(node, 0, frame_state_after);
+ }
+
+ if (count >= 2) {
+ // Add the frame state for before the operation.
+ DCHECK_EQ(IrOpcode::kDead,
+ NodeProperties::GetFrameStateInput(node, 1)->opcode());
+ NodeProperties::ReplaceFrameStateInput(node, 1, frame_state_before_);
+ }
+
+ if (!combine.IsOutputIgnored()) {
+ output_poke_offset_ = static_cast<int>(combine.GetOffsetToPokeAt());
+ output_poke_count_ = node->op()->ValueOutputCount();
+ }
+ added_to_node_ = true;
+ }
+
+ BytecodeGraphBuilder* builder_;
+ Node* frame_state_before_;
+ BailoutId id_after_;
+
+ bool added_to_node_;
+ int output_poke_offset_;
+ int output_poke_count_;
+};
+
+
// 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,
@@ -27,10 +89,13 @@ BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder,
context_(context),
control_dependency_(control_dependency),
effect_dependency_(control_dependency),
- values_(builder->local_zone()) {
+ values_(builder->local_zone()),
+ parameters_state_values_(nullptr),
+ registers_state_values_(nullptr),
+ accumulator_state_values_(nullptr) {
// The layout of values_ is:
//
- // [receiver] [parameters] [registers]
+ // [receiver] [parameters] [registers] [accumulator]
//
// parameter[0] is the receiver (this), parameters 1..N are the
// parameters supplied to the method (arg0..argN-1). The accumulator
@@ -50,7 +115,26 @@ BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder,
values()->insert(values()->end(), register_count, undefined_constant);
// Accumulator
- accumulator_ = undefined_constant;
+ accumulator_base_ = static_cast<int>(values()->size());
+ values()->push_back(undefined_constant);
+}
+
+
+BytecodeGraphBuilder::Environment::Environment(
+ const BytecodeGraphBuilder::Environment* other)
+ : builder_(other->builder_),
+ register_count_(other->register_count_),
+ parameter_count_(other->parameter_count_),
+ context_(other->context_),
+ control_dependency_(other->control_dependency_),
+ effect_dependency_(other->effect_dependency_),
+ values_(other->zone()),
+ parameters_state_values_(nullptr),
+ registers_state_values_(nullptr),
+ accumulator_state_values_(nullptr),
+ register_base_(other->register_base_),
+ accumulator_base_(other->accumulator_base_) {
+ values_ = other->values_;
}
@@ -64,27 +148,75 @@ int BytecodeGraphBuilder::Environment::RegisterToValuesIndex(
}
-void BytecodeGraphBuilder::Environment::BindRegister(
- interpreter::Register the_register, Node* node) {
- int values_index = RegisterToValuesIndex(the_register);
- values()->at(values_index) = node;
+Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const {
+ return values()->at(accumulator_base_);
}
Node* BytecodeGraphBuilder::Environment::LookupRegister(
interpreter::Register the_register) const {
+ if (the_register.is_function_context()) {
+ return builder()->GetFunctionContext();
+ } else if (the_register.is_function_closure()) {
+ return builder()->GetFunctionClosure();
+ } else if (the_register.is_new_target()) {
+ return builder()->GetNewTarget();
+ } else {
+ int values_index = RegisterToValuesIndex(the_register);
+ return values()->at(values_index);
+ }
+}
+
+
+void BytecodeGraphBuilder::Environment::ExchangeRegisters(
+ interpreter::Register reg0, interpreter::Register reg1) {
+ int reg0_index = RegisterToValuesIndex(reg0);
+ int reg1_index = RegisterToValuesIndex(reg1);
+ Node* saved_reg0_value = values()->at(reg0_index);
+ values()->at(reg0_index) = values()->at(reg1_index);
+ values()->at(reg1_index) = saved_reg0_value;
+}
+
+
+void BytecodeGraphBuilder::Environment::BindAccumulator(
+ Node* node, FrameStateBeforeAndAfter* states) {
+ if (states) {
+ states->AddToNode(node, OutputFrameStateCombine::PokeAt(0));
+ }
+ values()->at(accumulator_base_) = node;
+}
+
+
+void BytecodeGraphBuilder::Environment::BindRegister(
+ interpreter::Register the_register, Node* node,
+ FrameStateBeforeAndAfter* states) {
int values_index = RegisterToValuesIndex(the_register);
- return values()->at(values_index);
+ if (states) {
+ states->AddToNode(node, OutputFrameStateCombine::PokeAt(accumulator_base_ -
+ values_index));
+ }
+ values()->at(values_index) = node;
}
-void BytecodeGraphBuilder::Environment::BindAccumulator(Node* node) {
- accumulator_ = node;
+void BytecodeGraphBuilder::Environment::BindRegistersToProjections(
+ interpreter::Register first_reg, Node* node,
+ FrameStateBeforeAndAfter* states) {
+ int values_index = RegisterToValuesIndex(first_reg);
+ if (states) {
+ states->AddToNode(node, OutputFrameStateCombine::PokeAt(accumulator_base_ -
+ values_index));
+ }
+ for (int i = 0; i < node->op()->ValueOutputCount(); i++) {
+ values()->at(values_index + i) =
+ builder()->NewNode(common()->Projection(i), node);
+ }
}
-Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const {
- return accumulator_;
+void BytecodeGraphBuilder::Environment::RecordAfterState(
+ Node* node, FrameStateBeforeAndAfter* states) {
+ states->AddToNode(node, OutputFrameStateCombine::Ignore());
}
@@ -98,24 +230,188 @@ void BytecodeGraphBuilder::Environment::MarkAsUnreachable() {
}
+BytecodeGraphBuilder::Environment*
+BytecodeGraphBuilder::Environment::CopyForLoop() {
+ PrepareForLoop();
+ return new (zone()) Environment(this);
+}
+
+
+BytecodeGraphBuilder::Environment*
+BytecodeGraphBuilder::Environment::CopyForConditional() const {
+ return new (zone()) Environment(this);
+}
+
+
+void BytecodeGraphBuilder::Environment::Merge(
+ BytecodeGraphBuilder::Environment* other) {
+ // Nothing to do if the other environment is dead.
+ if (other->IsMarkedAsUnreachable()) {
+ return;
+ }
+
+ // Create a merge of the control dependencies of both environments and update
+ // the current environment's control dependency accordingly.
+ Node* control = builder()->MergeControl(GetControlDependency(),
+ other->GetControlDependency());
+ UpdateControlDependency(control);
+
+ // Create a merge of the effect dependencies of both environments and update
+ // the current environment's effect dependency accordingly.
+ Node* effect = builder()->MergeEffect(GetEffectDependency(),
+ other->GetEffectDependency(), control);
+ UpdateEffectDependency(effect);
+
+ // Introduce Phi nodes for values that have differing input at merge points,
+ // potentially extending an existing Phi node if possible.
+ context_ = builder()->MergeValue(context_, other->context_, control);
+ for (size_t i = 0; i < values_.size(); i++) {
+ values_[i] = builder()->MergeValue(values_[i], other->values_[i], control);
+ }
+}
+
+
+void BytecodeGraphBuilder::Environment::PrepareForLoop() {
+ // Create a control node for the loop header.
+ Node* control = builder()->NewLoop();
+
+ // Create a Phi for external effects.
+ Node* effect = builder()->NewEffectPhi(1, GetEffectDependency(), control);
+ UpdateEffectDependency(effect);
+
+ // Assume everything in the loop is updated.
+ context_ = builder()->NewPhi(1, context_, control);
+ int size = static_cast<int>(values()->size());
+ for (int i = 0; i < size; i++) {
+ values()->at(i) = builder()->NewPhi(1, values()->at(i), control);
+ }
+
+ // Connect to the loop end.
+ Node* terminate = builder()->graph()->NewNode(
+ builder()->common()->Terminate(), effect, control);
+ builder()->exit_controls_.push_back(terminate);
+}
+
+
+bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate(
+ Node** state_values, int offset, int count) {
+ if (!builder()->info()->is_deoptimization_enabled()) {
+ return false;
+ }
+ if (*state_values == nullptr) {
+ return true;
+ }
+ DCHECK_EQ((*state_values)->InputCount(), count);
+ DCHECK_LE(static_cast<size_t>(offset + count), values()->size());
+ Node** env_values = (count == 0) ? nullptr : &values()->at(offset);
+ for (int i = 0; i < count; i++) {
+ if ((*state_values)->InputAt(i) != env_values[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values,
+ int offset,
+ int count) {
+ if (StateValuesRequireUpdate(state_values, offset, count)) {
+ const Operator* op = common()->StateValues(count);
+ (*state_values) = graph()->NewNode(op, count, &values()->at(offset));
+ }
+}
+
+
+Node* BytecodeGraphBuilder::Environment::Checkpoint(
+ BailoutId bailout_id, OutputFrameStateCombine combine) {
+ if (!builder()->info()->is_deoptimization_enabled()) {
+ return builder()->jsgraph()->EmptyFrameState();
+ }
+
+ // TODO(rmcilroy): Consider using StateValuesCache for some state values.
+ UpdateStateValues(&parameters_state_values_, 0, parameter_count());
+ UpdateStateValues(&registers_state_values_, register_base(),
+ register_count());
+ UpdateStateValues(&accumulator_state_values_, accumulator_base(), 1);
+
+ const Operator* op = common()->FrameState(
+ bailout_id, combine, builder()->frame_state_function_info());
+ Node* result = graph()->NewNode(
+ op, parameters_state_values_, registers_state_values_,
+ accumulator_state_values_, Context(), builder()->GetFunctionClosure(),
+ builder()->graph()->start());
+
+ return result;
+}
+
+
+bool BytecodeGraphBuilder::Environment::StateValuesAreUpToDate(
+ Node** state_values, int offset, int count, int output_poke_start,
+ int output_poke_end) {
+ DCHECK_LE(static_cast<size_t>(offset + count), values()->size());
+ for (int i = 0; i < count; i++, offset++) {
+ if (offset < output_poke_start || offset >= output_poke_end) {
+ if ((*state_values)->InputAt(i) != values()->at(offset)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+bool BytecodeGraphBuilder::Environment::StateValuesAreUpToDate(
+ int output_poke_offset, int output_poke_count) {
+ // Poke offset is relative to the top of the stack (i.e., the accumulator).
+ int output_poke_start = accumulator_base() - output_poke_offset;
+ int output_poke_end = output_poke_start + output_poke_count;
+ return StateValuesAreUpToDate(&parameters_state_values_, 0, parameter_count(),
+ output_poke_start, output_poke_end) &&
+ StateValuesAreUpToDate(&registers_state_values_, register_base(),
+ register_count(), output_poke_start,
+ output_poke_end) &&
+ StateValuesAreUpToDate(&accumulator_state_values_, accumulator_base(),
+ 1, output_poke_start, output_poke_end);
+}
+
+
BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone,
CompilationInfo* compilation_info,
JSGraph* jsgraph)
: local_zone_(local_zone),
info_(compilation_info),
jsgraph_(jsgraph),
+ bytecode_array_(handle(info()->shared_info()->bytecode_array())),
+ frame_state_function_info_(common()->CreateFrameStateFunctionInfo(
+ FrameStateType::kInterpretedFunction,
+ bytecode_array()->parameter_count(),
+ bytecode_array()->register_count(), info()->shared_info(),
+ CALL_MAINTAINS_NATIVE_CONTEXT)),
+ merge_environments_(local_zone),
+ loop_header_environments_(local_zone),
input_buffer_size_(0),
input_buffer_(nullptr),
- exit_controls_(local_zone) {
- bytecode_array_ = handle(info()->shared_info()->bytecode_array());
+ exit_controls_(local_zone) {}
+
+
+Node* BytecodeGraphBuilder::GetNewTarget() {
+ if (!new_target_.is_set()) {
+ int params = bytecode_array()->parameter_count();
+ int index = Linkage::GetJSCallNewTargetParamIndex(params);
+ const Operator* op = common()->Parameter(index, "%new.target");
+ Node* node = NewNode(op, graph()->start());
+ new_target_.set(node);
+ }
+ return new_target_.get();
}
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");
+ int params = bytecode_array()->parameter_count();
+ int index = Linkage::GetJSCallContextParamIndex(params);
+ const Operator* op = common()->Parameter(index, "%context");
Node* node = NewNode(op, graph()->start());
function_context_.set(node);
}
@@ -123,13 +419,72 @@ Node* BytecodeGraphBuilder::GetFunctionContext() {
}
+Node* BytecodeGraphBuilder::GetFunctionClosure() {
+ if (!function_closure_.is_set()) {
+ int index = Linkage::kJSCallClosureParamIndex;
+ const Operator* op = common()->Parameter(index, "%closure");
+ Node* node = NewNode(op, graph()->start());
+ function_closure_.set(node);
+ }
+ return function_closure_.get();
+}
+
+
+Node* BytecodeGraphBuilder::BuildLoadObjectField(Node* object, int offset) {
+ return NewNode(jsgraph()->machine()->Load(MachineType::AnyTagged()), object,
+ jsgraph()->IntPtrConstant(offset - kHeapObjectTag));
+}
+
+
+Node* BytecodeGraphBuilder::BuildLoadImmutableObjectField(Node* object,
+ int offset) {
+ return graph()->NewNode(jsgraph()->machine()->Load(MachineType::AnyTagged()),
+ object,
+ jsgraph()->IntPtrConstant(offset - kHeapObjectTag),
+ graph()->start(), graph()->start());
+}
+
+
+Node* BytecodeGraphBuilder::BuildLoadNativeContextField(int index) {
+ const Operator* op =
+ javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true);
+ Node* native_context = NewNode(op, environment()->Context());
+ return NewNode(javascript()->LoadContext(0, index, true), native_context);
+}
+
+
+Node* BytecodeGraphBuilder::BuildLoadFeedbackVector() {
+ if (!feedback_vector_.is_set()) {
+ Node* closure = GetFunctionClosure();
+ Node* shared = BuildLoadImmutableObjectField(
+ closure, JSFunction::kSharedFunctionInfoOffset);
+ Node* vector = BuildLoadImmutableObjectField(
+ shared, SharedFunctionInfo::kFeedbackVectorOffset);
+ feedback_vector_.set(vector);
+ }
+ return feedback_vector_.get();
+}
+
+
+VectorSlotPair BytecodeGraphBuilder::CreateVectorSlotPair(int slot_id) {
+ Handle<TypeFeedbackVector> feedback_vector = info()->feedback_vector();
+ FeedbackVectorSlot slot;
+ if (slot_id >= TypeFeedbackVector::kReservedIndexCount) {
+ slot = feedback_vector->ToSlot(slot_id);
+ }
+ return VectorSlotPair(feedback_vector, slot);
+}
+
+
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;
+ // Set up the basic structure of the graph. Outputs for {Start} are the formal
+ // parameters (including the receiver) plus new target, number of arguments,
+ // context and closure.
+ int actual_parameter_count = bytecode_array()->parameter_count() + 4;
graph()->SetStart(graph()->NewNode(common()->Start(actual_parameter_count)));
Environment env(this, bytecode_array()->register_count(),
@@ -137,13 +492,7 @@ bool BytecodeGraphBuilder::CreateGraph(bool stack_check) {
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);
- }
+ CreateGraphBody(stack_check);
// Finish the basic structure of the graph.
DCHECK_NE(0u, exit_controls_.size());
@@ -159,23 +508,41 @@ bool BytecodeGraphBuilder::CreateGraph(bool stack_check) {
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.
+
+ if (stack_check) {
+ Node* node = NewNode(javascript()->StackCheck());
+ PrepareEntryFrameState(node);
+ }
+
VisitBytecodes();
}
void BytecodeGraphBuilder::VisitBytecodes() {
+ BytecodeBranchAnalysis analysis(bytecode_array(), local_zone());
+ analysis.Analyze();
+ set_branch_analysis(&analysis);
interpreter::BytecodeArrayIterator iterator(bytecode_array());
+ set_bytecode_iterator(&iterator);
while (!iterator.done()) {
- switch (iterator.current_bytecode()) {
+ int current_offset = iterator.current_offset();
+ if (analysis.is_reachable(current_offset)) {
+ MergeEnvironmentsOfForwardBranches(current_offset);
+ BuildLoopHeaderForBackwardBranches(current_offset);
+
+ switch (iterator.current_bytecode()) {
#define BYTECODE_CASE(name, ...) \
case interpreter::Bytecode::k##name: \
Visit##name(iterator); \
break;
- BYTECODE_LIST(BYTECODE_CASE)
+ BYTECODE_LIST(BYTECODE_CASE)
#undef BYTECODE_CODE
+ }
}
iterator.Advance();
}
+ set_branch_analysis(nullptr);
+ set_bytecode_iterator(nullptr);
}
@@ -256,547 +623,1093 @@ void BytecodeGraphBuilder::VisitStar(
}
+void BytecodeGraphBuilder::VisitMov(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ Node* value = environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ environment()->BindRegister(iterator.GetRegisterOperand(1), value);
+}
+
+
+void BytecodeGraphBuilder::VisitExchange(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ environment()->ExchangeRegisters(iterator.GetRegisterOperand(0),
+ iterator.GetRegisterOperand(1));
+}
+
+
+void BytecodeGraphBuilder::VisitExchangeWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ environment()->ExchangeRegisters(iterator.GetRegisterOperand(0),
+ iterator.GetRegisterOperand(1));
+}
+
+
+void BytecodeGraphBuilder::BuildLoadGlobal(
+ const interpreter::BytecodeArrayIterator& iterator,
+ TypeofMode typeof_mode) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Handle<Name> name =
+ Handle<Name>::cast(iterator.GetConstantForIndexOperand(0));
+ VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(1));
+
+ const Operator* op = javascript()->LoadGlobal(name, feedback, typeof_mode);
+ Node* node = NewNode(op, BuildLoadFeedbackVector());
+ environment()->BindAccumulator(node, &states);
+}
+
+
void BytecodeGraphBuilder::VisitLdaGlobalSloppy(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_sloppy(language_mode()));
+ BuildLoadGlobal(iterator, TypeofMode::NOT_INSIDE_TYPEOF);
}
void BytecodeGraphBuilder::VisitLdaGlobalStrict(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_strict(language_mode()));
+ BuildLoadGlobal(iterator, TypeofMode::NOT_INSIDE_TYPEOF);
}
void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeofSloppy(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_sloppy(language_mode()));
+ BuildLoadGlobal(iterator, TypeofMode::INSIDE_TYPEOF);
}
void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeofStrict(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_strict(language_mode()));
+ BuildLoadGlobal(iterator, TypeofMode::INSIDE_TYPEOF);
}
void BytecodeGraphBuilder::VisitLdaGlobalSloppyWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_sloppy(language_mode()));
+ BuildLoadGlobal(iterator, TypeofMode::NOT_INSIDE_TYPEOF);
}
void BytecodeGraphBuilder::VisitLdaGlobalStrictWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_strict(language_mode()));
+ BuildLoadGlobal(iterator, TypeofMode::NOT_INSIDE_TYPEOF);
}
void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeofSloppyWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_sloppy(language_mode()));
+ BuildLoadGlobal(iterator, TypeofMode::INSIDE_TYPEOF);
}
void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeofStrictWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_strict(language_mode()));
+ BuildLoadGlobal(iterator, TypeofMode::INSIDE_TYPEOF);
+}
+
+
+void BytecodeGraphBuilder::BuildStoreGlobal(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Handle<Name> name =
+ Handle<Name>::cast(iterator.GetConstantForIndexOperand(0));
+ VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(1));
+ Node* value = environment()->LookupAccumulator();
+
+ const Operator* op =
+ javascript()->StoreGlobal(language_mode(), name, feedback);
+ Node* node = NewNode(op, value, BuildLoadFeedbackVector());
+ environment()->RecordAfterState(node, &states);
}
void BytecodeGraphBuilder::VisitStaGlobalSloppy(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_sloppy(language_mode()));
+ BuildStoreGlobal(iterator);
}
void BytecodeGraphBuilder::VisitStaGlobalStrict(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_strict(language_mode()));
+ BuildStoreGlobal(iterator);
}
void BytecodeGraphBuilder::VisitStaGlobalSloppyWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_sloppy(language_mode()));
+ BuildStoreGlobal(iterator);
}
void BytecodeGraphBuilder::VisitStaGlobalStrictWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_strict(language_mode()));
+ BuildStoreGlobal(iterator);
}
void BytecodeGraphBuilder::VisitLdaContextSlot(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ // TODO(mythria): LoadContextSlots are unrolled by the required depth when
+ // generating bytecode. Hence the value of depth is always 0. Update this
+ // code, when the implementation changes.
+ // TODO(mythria): immutable flag is also set to false. This information is not
+ // available in bytecode array. update this code when the implementation
+ // changes.
+ const Operator* op =
+ javascript()->LoadContext(0, iterator.GetIndexOperand(1), false);
+ Node* context = environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ Node* node = NewNode(op, context);
+ environment()->BindAccumulator(node);
+}
+
+
+void BytecodeGraphBuilder::VisitLdaContextSlotWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ VisitLdaContextSlot(iterator);
}
void BytecodeGraphBuilder::VisitStaContextSlot(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ // TODO(mythria): LoadContextSlots are unrolled by the required depth when
+ // generating bytecode. Hence the value of depth is always 0. Update this
+ // code, when the implementation changes.
+ const Operator* op =
+ javascript()->StoreContext(0, iterator.GetIndexOperand(1));
+ Node* context = environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ Node* value = environment()->LookupAccumulator();
+ NewNode(op, context, value);
}
-void BytecodeGraphBuilder::VisitLoadICSloppy(
+void BytecodeGraphBuilder::VisitStaContextSlotWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ VisitStaContextSlot(iterator);
}
-void BytecodeGraphBuilder::VisitLoadICStrict(
+void BytecodeGraphBuilder::BuildLdaLookupSlot(
+ TypeofMode typeof_mode,
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ FrameStateBeforeAndAfter states(this, iterator);
+ Handle<String> name =
+ Handle<String>::cast(iterator.GetConstantForIndexOperand(0));
+ const Operator* op = javascript()->LoadDynamic(name, typeof_mode);
+ Node* value =
+ NewNode(op, BuildLoadFeedbackVector(), environment()->Context());
+ environment()->BindAccumulator(value, &states);
}
-void BytecodeGraphBuilder::VisitKeyedLoadICSloppy(
+void BytecodeGraphBuilder::VisitLdaLookupSlot(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildLdaLookupSlot(TypeofMode::NOT_INSIDE_TYPEOF, iterator);
}
-void BytecodeGraphBuilder::VisitKeyedLoadICStrict(
+void BytecodeGraphBuilder::VisitLdaLookupSlotInsideTypeof(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ BuildLdaLookupSlot(TypeofMode::INSIDE_TYPEOF, iterator);
+}
+
+
+void BytecodeGraphBuilder::BuildStaLookupSlot(
+ LanguageMode language_mode,
+ const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* value = environment()->LookupAccumulator();
+ Node* name = jsgraph()->Constant(iterator.GetConstantForIndexOperand(0));
+ Node* language = jsgraph()->Constant(language_mode);
+ const Operator* op = javascript()->CallRuntime(Runtime::kStoreLookupSlot, 4);
+ Node* store = NewNode(op, value, environment()->Context(), name, language);
+ environment()->BindAccumulator(store, &states);
+}
+
+
+void BytecodeGraphBuilder::VisitLdaLookupSlotWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ VisitLdaLookupSlot(iterator);
+}
+
+
+void BytecodeGraphBuilder::VisitLdaLookupSlotInsideTypeofWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ VisitLdaLookupSlotInsideTypeof(iterator);
+}
+
+
+void BytecodeGraphBuilder::VisitStaLookupSlotSloppy(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ BuildStaLookupSlot(LanguageMode::SLOPPY, iterator);
+}
+
+
+void BytecodeGraphBuilder::VisitStaLookupSlotStrict(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ BuildStaLookupSlot(LanguageMode::STRICT, iterator);
+}
+
+
+void BytecodeGraphBuilder::VisitStaLookupSlotSloppyWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ VisitStaLookupSlotSloppy(iterator);
+}
+
+
+void BytecodeGraphBuilder::VisitStaLookupSlotStrictWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ VisitStaLookupSlotStrict(iterator);
+}
+
+
+void BytecodeGraphBuilder::BuildNamedLoad(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ Handle<Name> name =
+ Handle<Name>::cast(iterator.GetConstantForIndexOperand(1));
+ VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(2));
+
+ const Operator* op = javascript()->LoadNamed(language_mode(), name, feedback);
+ Node* node = NewNode(op, object, BuildLoadFeedbackVector());
+ environment()->BindAccumulator(node, &states);
+}
+
+
+void BytecodeGraphBuilder::VisitLoadICSloppy(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ DCHECK(is_sloppy(language_mode()));
+ BuildNamedLoad(iterator);
+}
+
+
+void BytecodeGraphBuilder::VisitLoadICStrict(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ DCHECK(is_strict(language_mode()));
+ BuildNamedLoad(iterator);
}
void BytecodeGraphBuilder::VisitLoadICSloppyWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_sloppy(language_mode()));
+ BuildNamedLoad(iterator);
}
void BytecodeGraphBuilder::VisitLoadICStrictWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_strict(language_mode()));
+ BuildNamedLoad(iterator);
+}
+
+
+void BytecodeGraphBuilder::BuildKeyedLoad(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* key = environment()->LookupAccumulator();
+ Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(1));
+
+ const Operator* op = javascript()->LoadProperty(language_mode(), feedback);
+ Node* node = NewNode(op, object, key, BuildLoadFeedbackVector());
+ environment()->BindAccumulator(node, &states);
+}
+
+
+void BytecodeGraphBuilder::VisitKeyedLoadICSloppy(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ DCHECK(is_sloppy(language_mode()));
+ BuildKeyedLoad(iterator);
+}
+
+
+void BytecodeGraphBuilder::VisitKeyedLoadICStrict(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ DCHECK(is_strict(language_mode()));
+ BuildKeyedLoad(iterator);
}
void BytecodeGraphBuilder::VisitKeyedLoadICSloppyWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_sloppy(language_mode()));
+ BuildKeyedLoad(iterator);
}
void BytecodeGraphBuilder::VisitKeyedLoadICStrictWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_strict(language_mode()));
+ BuildKeyedLoad(iterator);
+}
+
+
+void BytecodeGraphBuilder::BuildNamedStore(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* value = environment()->LookupAccumulator();
+ Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ Handle<Name> name =
+ Handle<Name>::cast(iterator.GetConstantForIndexOperand(1));
+ VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(2));
+
+ const Operator* op =
+ javascript()->StoreNamed(language_mode(), name, feedback);
+ Node* node = NewNode(op, object, value, BuildLoadFeedbackVector());
+ environment()->RecordAfterState(node, &states);
}
void BytecodeGraphBuilder::VisitStoreICSloppy(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_sloppy(language_mode()));
+ BuildNamedStore(iterator);
}
void BytecodeGraphBuilder::VisitStoreICStrict(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_strict(language_mode()));
+ BuildNamedStore(iterator);
}
-void BytecodeGraphBuilder::VisitKeyedStoreICSloppy(
+void BytecodeGraphBuilder::VisitStoreICSloppyWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_sloppy(language_mode()));
+ BuildNamedStore(iterator);
}
-void BytecodeGraphBuilder::VisitKeyedStoreICStrict(
+void BytecodeGraphBuilder::VisitStoreICStrictWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_strict(language_mode()));
+ BuildNamedStore(iterator);
}
-void BytecodeGraphBuilder::VisitStoreICSloppyWide(
+void BytecodeGraphBuilder::BuildKeyedStore(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* value = environment()->LookupAccumulator();
+ Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ Node* key = environment()->LookupRegister(iterator.GetRegisterOperand(1));
+ VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(2));
+
+ const Operator* op = javascript()->StoreProperty(language_mode(), feedback);
+ Node* node = NewNode(op, object, key, value, BuildLoadFeedbackVector());
+ environment()->RecordAfterState(node, &states);
}
-void BytecodeGraphBuilder::VisitStoreICStrictWide(
+void BytecodeGraphBuilder::VisitKeyedStoreICSloppy(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_sloppy(language_mode()));
+ BuildKeyedStore(iterator);
+}
+
+
+void BytecodeGraphBuilder::VisitKeyedStoreICStrict(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ DCHECK(is_strict(language_mode()));
+ BuildKeyedStore(iterator);
}
void BytecodeGraphBuilder::VisitKeyedStoreICSloppyWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_sloppy(language_mode()));
+ BuildKeyedStore(iterator);
}
void BytecodeGraphBuilder::VisitKeyedStoreICStrictWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_strict(language_mode()));
+ BuildKeyedStore(iterator);
}
void BytecodeGraphBuilder::VisitPushContext(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ Node* context = environment()->LookupAccumulator();
+ environment()->BindRegister(iterator.GetRegisterOperand(0), context);
+ environment()->SetContext(context);
}
void BytecodeGraphBuilder::VisitPopContext(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ Node* context = environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ environment()->SetContext(context);
}
void BytecodeGraphBuilder::VisitCreateClosure(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ Handle<SharedFunctionInfo> shared_info =
+ Handle<SharedFunctionInfo>::cast(iterator.GetConstantForIndexOperand(0));
+ PretenureFlag tenured =
+ iterator.GetImmediateOperand(1) ? TENURED : NOT_TENURED;
+ const Operator* op = javascript()->CreateClosure(shared_info, tenured);
+ Node* closure = NewNode(op);
+ environment()->BindAccumulator(closure);
+}
+
+
+void BytecodeGraphBuilder::VisitCreateClosureWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ VisitCreateClosure(iterator);
+}
+
+
+void BytecodeGraphBuilder::BuildCreateArguments(
+ CreateArgumentsParameters::Type type,
+ const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ const Operator* op = javascript()->CreateArguments(type, 0);
+ Node* object = NewNode(op, GetFunctionClosure());
+ environment()->BindAccumulator(object, &states);
}
void BytecodeGraphBuilder::VisitCreateMappedArguments(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCreateArguments(CreateArgumentsParameters::kMappedArguments, iterator);
}
void BytecodeGraphBuilder::VisitCreateUnmappedArguments(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCreateArguments(CreateArgumentsParameters::kUnmappedArguments, iterator);
+}
+
+
+void BytecodeGraphBuilder::BuildCreateLiteral(
+ const Operator* op, const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* literal = NewNode(op, GetFunctionClosure());
+ environment()->BindAccumulator(literal, &states);
+}
+
+
+void BytecodeGraphBuilder::BuildCreateRegExpLiteral(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ Handle<String> constant_pattern =
+ Handle<String>::cast(iterator.GetConstantForIndexOperand(0));
+ int literal_index = iterator.GetIndexOperand(1);
+ int literal_flags = iterator.GetImmediateOperand(2);
+ const Operator* op = javascript()->CreateLiteralRegExp(
+ constant_pattern, literal_flags, literal_index);
+ BuildCreateLiteral(op, iterator);
}
void BytecodeGraphBuilder::VisitCreateRegExpLiteral(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCreateRegExpLiteral(iterator);
+}
+
+
+void BytecodeGraphBuilder::VisitCreateRegExpLiteralWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ BuildCreateRegExpLiteral(iterator);
+}
+
+
+void BytecodeGraphBuilder::BuildCreateArrayLiteral(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ Handle<FixedArray> constant_elements =
+ Handle<FixedArray>::cast(iterator.GetConstantForIndexOperand(0));
+ int literal_index = iterator.GetIndexOperand(1);
+ int literal_flags = iterator.GetImmediateOperand(2);
+ const Operator* op = javascript()->CreateLiteralArray(
+ constant_elements, literal_flags, literal_index);
+ BuildCreateLiteral(op, iterator);
}
void BytecodeGraphBuilder::VisitCreateArrayLiteral(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCreateArrayLiteral(iterator);
+}
+
+
+void BytecodeGraphBuilder::VisitCreateArrayLiteralWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ BuildCreateArrayLiteral(iterator);
+}
+
+
+void BytecodeGraphBuilder::BuildCreateObjectLiteral(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ Handle<FixedArray> constant_properties =
+ Handle<FixedArray>::cast(iterator.GetConstantForIndexOperand(0));
+ int literal_index = iterator.GetIndexOperand(1);
+ int literal_flags = iterator.GetImmediateOperand(2);
+ const Operator* op = javascript()->CreateLiteralObject(
+ constant_properties, literal_flags, literal_index);
+ BuildCreateLiteral(op, iterator);
}
void BytecodeGraphBuilder::VisitCreateObjectLiteral(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCreateObjectLiteral(iterator);
+}
+
+
+void BytecodeGraphBuilder::VisitCreateObjectLiteralWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ BuildCreateObjectLiteral(iterator);
+}
+
+
+Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op,
+ Node* callee,
+ interpreter::Register receiver,
+ size_t arity) {
+ Node** all = info()->zone()->NewArray<Node*>(static_cast<int>(arity));
+ all[0] = callee;
+ all[1] = environment()->LookupRegister(receiver);
+ int receiver_index = receiver.index();
+ for (int i = 2; i < static_cast<int>(arity); ++i) {
+ all[i] = environment()->LookupRegister(
+ interpreter::Register(receiver_index + i - 1));
+ }
+ Node* value = MakeNode(call_op, static_cast<int>(arity), all, false);
+ return value;
+}
+
+
+void BytecodeGraphBuilder::BuildCall(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ // TODO(rmcilroy): Set receiver_hint correctly based on whether the receiver
+ // register has been loaded with null / undefined explicitly or we are sure it
+ // is not null / undefined.
+ ConvertReceiverMode receiver_hint = ConvertReceiverMode::kAny;
+ Node* callee = environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ interpreter::Register receiver = iterator.GetRegisterOperand(1);
+ size_t arg_count = iterator.GetCountOperand(2);
+ VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(3));
+
+ const Operator* call = javascript()->CallFunction(
+ arg_count + 2, language_mode(), feedback, receiver_hint);
+ Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 2);
+ environment()->BindAccumulator(value, &states);
}
void BytecodeGraphBuilder::VisitCall(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCall(iterator);
}
-void BytecodeGraphBuilder::VisitCallRuntime(
+void BytecodeGraphBuilder::VisitCallWide(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCall(iterator);
}
void BytecodeGraphBuilder::VisitCallJSRuntime(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* callee = BuildLoadNativeContextField(iterator.GetIndexOperand(0));
+ interpreter::Register receiver = iterator.GetRegisterOperand(1);
+ size_t arg_count = iterator.GetCountOperand(2);
+
+ // Create node to perform the JS runtime call.
+ const Operator* call =
+ javascript()->CallFunction(arg_count + 2, language_mode());
+ Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 2);
+ environment()->BindAccumulator(value, &states);
+}
+
+
+Node* BytecodeGraphBuilder::ProcessCallRuntimeArguments(
+ const Operator* call_runtime_op, interpreter::Register first_arg,
+ size_t arity) {
+ Node** all = info()->zone()->NewArray<Node*>(arity);
+ int first_arg_index = first_arg.index();
+ for (int i = 0; i < static_cast<int>(arity); ++i) {
+ all[i] = environment()->LookupRegister(
+ interpreter::Register(first_arg_index + i));
+ }
+ Node* value = MakeNode(call_runtime_op, static_cast<int>(arity), all, false);
+ return value;
+}
+
+
+void BytecodeGraphBuilder::VisitCallRuntime(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Runtime::FunctionId functionId =
+ static_cast<Runtime::FunctionId>(iterator.GetIndexOperand(0));
+ interpreter::Register first_arg = iterator.GetRegisterOperand(1);
+ size_t arg_count = iterator.GetCountOperand(2);
+
+ // Create node to perform the runtime call.
+ const Operator* call = javascript()->CallRuntime(functionId, arg_count);
+ Node* value = ProcessCallRuntimeArguments(call, first_arg, arg_count);
+ environment()->BindAccumulator(value, &states);
+}
+
+
+void BytecodeGraphBuilder::VisitCallRuntimeForPair(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Runtime::FunctionId functionId =
+ static_cast<Runtime::FunctionId>(iterator.GetIndexOperand(0));
+ interpreter::Register first_arg = iterator.GetRegisterOperand(1);
+ size_t arg_count = iterator.GetCountOperand(2);
+ interpreter::Register first_return = iterator.GetRegisterOperand(3);
+
+ // Create node to perform the runtime call.
+ const Operator* call = javascript()->CallRuntime(functionId, arg_count);
+ Node* return_pair = ProcessCallRuntimeArguments(call, first_arg, arg_count);
+ environment()->BindRegistersToProjections(first_return, return_pair, &states);
+}
+
+
+Node* BytecodeGraphBuilder::ProcessCallNewArguments(
+ const Operator* call_new_op, interpreter::Register callee,
+ interpreter::Register first_arg, size_t arity) {
+ Node** all = info()->zone()->NewArray<Node*>(arity);
+ all[0] = environment()->LookupRegister(callee);
+ int first_arg_index = first_arg.index();
+ for (int i = 1; i < static_cast<int>(arity) - 1; ++i) {
+ all[i] = environment()->LookupRegister(
+ interpreter::Register(first_arg_index + i - 1));
+ }
+ // Original constructor is the same as the callee.
+ all[arity - 1] = environment()->LookupRegister(callee);
+ Node* value = MakeNode(call_new_op, static_cast<int>(arity), all, false);
+ return value;
}
void BytecodeGraphBuilder::VisitNew(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ FrameStateBeforeAndAfter states(this, iterator);
+ interpreter::Register callee = iterator.GetRegisterOperand(0);
+ interpreter::Register first_arg = iterator.GetRegisterOperand(1);
+ size_t arg_count = iterator.GetCountOperand(2);
+
+ // TODO(turbofan): Pass the feedback here.
+ const Operator* call = javascript()->CallConstruct(
+ static_cast<int>(arg_count) + 2, VectorSlotPair());
+ Node* value = ProcessCallNewArguments(call, callee, first_arg, arg_count + 2);
+ environment()->BindAccumulator(value, &states);
}
void BytecodeGraphBuilder::VisitThrow(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* value = environment()->LookupAccumulator();
+ // TODO(mythria): Change to Runtime::kThrow when we have deoptimization
+ // information support in the interpreter.
+ NewNode(javascript()->CallRuntime(Runtime::kReThrow, 1), value);
+ Node* control = NewNode(common()->Throw(), value);
+ environment()->RecordAfterState(control, &states);
+ UpdateControlDependencyToLeaveFunction(control);
}
void BytecodeGraphBuilder::BuildBinaryOp(
const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, 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);
+ environment()->BindAccumulator(node, &states);
}
void BytecodeGraphBuilder::VisitAdd(
const interpreter::BytecodeArrayIterator& iterator) {
- BuildBinaryOp(javascript()->Add(language_mode()), iterator);
+ BinaryOperationHints hints = BinaryOperationHints::Any();
+ BuildBinaryOp(javascript()->Add(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitSub(
const interpreter::BytecodeArrayIterator& iterator) {
- BuildBinaryOp(javascript()->Subtract(language_mode()), iterator);
+ BinaryOperationHints hints = BinaryOperationHints::Any();
+ BuildBinaryOp(javascript()->Subtract(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitMul(
const interpreter::BytecodeArrayIterator& iterator) {
- BuildBinaryOp(javascript()->Multiply(language_mode()), iterator);
+ BinaryOperationHints hints = BinaryOperationHints::Any();
+ BuildBinaryOp(javascript()->Multiply(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitDiv(
const interpreter::BytecodeArrayIterator& iterator) {
- BuildBinaryOp(javascript()->Divide(language_mode()), iterator);
+ BinaryOperationHints hints = BinaryOperationHints::Any();
+ BuildBinaryOp(javascript()->Divide(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitMod(
const interpreter::BytecodeArrayIterator& iterator) {
- BuildBinaryOp(javascript()->Modulus(language_mode()), iterator);
+ BinaryOperationHints hints = BinaryOperationHints::Any();
+ BuildBinaryOp(javascript()->Modulus(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitBitwiseOr(
const interpreter::BytecodeArrayIterator& iterator) {
- BuildBinaryOp(javascript()->BitwiseOr(language_mode()), iterator);
+ BinaryOperationHints hints = BinaryOperationHints::Any();
+ BuildBinaryOp(javascript()->BitwiseOr(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitBitwiseXor(
const interpreter::BytecodeArrayIterator& iterator) {
- BuildBinaryOp(javascript()->BitwiseXor(language_mode()), iterator);
+ BinaryOperationHints hints = BinaryOperationHints::Any();
+ BuildBinaryOp(javascript()->BitwiseXor(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitBitwiseAnd(
const interpreter::BytecodeArrayIterator& iterator) {
- BuildBinaryOp(javascript()->BitwiseAnd(language_mode()), iterator);
+ BinaryOperationHints hints = BinaryOperationHints::Any();
+ BuildBinaryOp(javascript()->BitwiseAnd(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitShiftLeft(
const interpreter::BytecodeArrayIterator& iterator) {
- BuildBinaryOp(javascript()->ShiftLeft(language_mode()), iterator);
+ BinaryOperationHints hints = BinaryOperationHints::Any();
+ BuildBinaryOp(javascript()->ShiftLeft(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitShiftRight(
const interpreter::BytecodeArrayIterator& iterator) {
- BuildBinaryOp(javascript()->ShiftRight(language_mode()), iterator);
+ BinaryOperationHints hints = BinaryOperationHints::Any();
+ BuildBinaryOp(javascript()->ShiftRight(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitShiftRightLogical(
const interpreter::BytecodeArrayIterator& iterator) {
- BuildBinaryOp(javascript()->ShiftRightLogical(language_mode()), iterator);
+ BinaryOperationHints hints = BinaryOperationHints::Any();
+ BuildBinaryOp(javascript()->ShiftRightLogical(language_mode(), hints),
+ iterator);
}
void BytecodeGraphBuilder::VisitInc(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ FrameStateBeforeAndAfter states(this, iterator);
+ const Operator* js_op =
+ javascript()->Add(language_mode(), BinaryOperationHints::Any());
+ Node* node = NewNode(js_op, environment()->LookupAccumulator(),
+ jsgraph()->OneConstant());
+ environment()->BindAccumulator(node, &states);
}
void BytecodeGraphBuilder::VisitDec(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ FrameStateBeforeAndAfter states(this, iterator);
+ const Operator* js_op =
+ javascript()->Subtract(language_mode(), BinaryOperationHints::Any());
+ Node* node = NewNode(js_op, environment()->LookupAccumulator(),
+ jsgraph()->OneConstant());
+ environment()->BindAccumulator(node, &states);
}
void BytecodeGraphBuilder::VisitLogicalNot(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ Node* value = NewNode(javascript()->ToBoolean(ToBooleanHint::kAny),
+ environment()->LookupAccumulator());
+ Node* node = NewNode(common()->Select(MachineRepresentation::kTagged), value,
+ jsgraph()->FalseConstant(), jsgraph()->TrueConstant());
+ environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitTypeOf(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ Node* node =
+ NewNode(javascript()->TypeOf(), environment()->LookupAccumulator());
+ environment()->BindAccumulator(node);
+}
+
+
+void BytecodeGraphBuilder::BuildDelete(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* key = environment()->LookupAccumulator();
+ Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ Node* node =
+ NewNode(javascript()->DeleteProperty(language_mode()), object, key);
+ environment()->BindAccumulator(node, &states);
}
void BytecodeGraphBuilder::VisitDeletePropertyStrict(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_strict(language_mode()));
+ BuildDelete(iterator);
}
void BytecodeGraphBuilder::VisitDeletePropertySloppy(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ DCHECK(is_sloppy(language_mode()));
+ BuildDelete(iterator);
+}
+
+
+void BytecodeGraphBuilder::VisitDeleteLookupSlot(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* name = environment()->LookupAccumulator();
+ const Operator* op = javascript()->CallRuntime(Runtime::kDeleteLookupSlot, 2);
+ Node* result = NewNode(op, environment()->Context(), name);
+ environment()->BindAccumulator(result, &states);
+}
+
+
+void BytecodeGraphBuilder::BuildCompareOp(
+ const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* left = environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ Node* right = environment()->LookupAccumulator();
+ Node* node = NewNode(js_op, left, right);
+ environment()->BindAccumulator(node, &states);
}
void BytecodeGraphBuilder::VisitTestEqual(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCompareOp(javascript()->Equal(), iterator);
}
void BytecodeGraphBuilder::VisitTestNotEqual(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCompareOp(javascript()->NotEqual(), iterator);
}
void BytecodeGraphBuilder::VisitTestEqualStrict(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCompareOp(javascript()->StrictEqual(), iterator);
}
void BytecodeGraphBuilder::VisitTestNotEqualStrict(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCompareOp(javascript()->StrictNotEqual(), iterator);
}
void BytecodeGraphBuilder::VisitTestLessThan(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCompareOp(javascript()->LessThan(language_mode()), iterator);
}
void BytecodeGraphBuilder::VisitTestGreaterThan(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCompareOp(javascript()->GreaterThan(language_mode()), iterator);
}
void BytecodeGraphBuilder::VisitTestLessThanOrEqual(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCompareOp(javascript()->LessThanOrEqual(language_mode()), iterator);
}
void BytecodeGraphBuilder::VisitTestGreaterThanOrEqual(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCompareOp(javascript()->GreaterThanOrEqual(language_mode()), iterator);
}
void BytecodeGraphBuilder::VisitTestIn(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCompareOp(javascript()->HasProperty(), iterator);
}
void BytecodeGraphBuilder::VisitTestInstanceOf(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCompareOp(javascript()->InstanceOf(), iterator);
}
-void BytecodeGraphBuilder::VisitToBoolean(
- const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+void BytecodeGraphBuilder::BuildCastOperator(
+ const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* node = NewNode(js_op, environment()->LookupAccumulator());
+ environment()->BindAccumulator(node, &states);
}
void BytecodeGraphBuilder::VisitToName(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCastOperator(javascript()->ToName(), iterator);
}
-void BytecodeGraphBuilder::VisitToNumber(
+void BytecodeGraphBuilder::VisitToObject(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCastOperator(javascript()->ToObject(), iterator);
}
-void BytecodeGraphBuilder::VisitToObject(
+void BytecodeGraphBuilder::VisitToNumber(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildCastOperator(javascript()->ToNumber(), iterator);
}
void BytecodeGraphBuilder::VisitJump(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJump();
}
void BytecodeGraphBuilder::VisitJumpConstant(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJump();
+}
+
+
+void BytecodeGraphBuilder::VisitJumpConstantWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ BuildJump();
}
void BytecodeGraphBuilder::VisitJumpIfTrue(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJumpIfEqual(jsgraph()->TrueConstant());
}
void BytecodeGraphBuilder::VisitJumpIfTrueConstant(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJumpIfEqual(jsgraph()->TrueConstant());
+}
+
+
+void BytecodeGraphBuilder::VisitJumpIfTrueConstantWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ BuildJumpIfEqual(jsgraph()->TrueConstant());
}
void BytecodeGraphBuilder::VisitJumpIfFalse(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJumpIfEqual(jsgraph()->FalseConstant());
}
void BytecodeGraphBuilder::VisitJumpIfFalseConstant(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJumpIfEqual(jsgraph()->FalseConstant());
+}
+
+
+void BytecodeGraphBuilder::VisitJumpIfFalseConstantWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ BuildJumpIfEqual(jsgraph()->FalseConstant());
}
void BytecodeGraphBuilder::VisitJumpIfToBooleanTrue(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJumpIfToBooleanEqual(jsgraph()->TrueConstant());
}
void BytecodeGraphBuilder::VisitJumpIfToBooleanTrueConstant(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJumpIfToBooleanEqual(jsgraph()->TrueConstant());
+}
+
+
+void BytecodeGraphBuilder::VisitJumpIfToBooleanTrueConstantWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ BuildJumpIfToBooleanEqual(jsgraph()->TrueConstant());
}
void BytecodeGraphBuilder::VisitJumpIfToBooleanFalse(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJumpIfToBooleanEqual(jsgraph()->FalseConstant());
}
void BytecodeGraphBuilder::VisitJumpIfToBooleanFalseConstant(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJumpIfToBooleanEqual(jsgraph()->FalseConstant());
+}
+
+
+void BytecodeGraphBuilder::VisitJumpIfToBooleanFalseConstantWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ BuildJumpIfToBooleanEqual(jsgraph()->FalseConstant());
}
void BytecodeGraphBuilder::VisitJumpIfNull(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJumpIfEqual(jsgraph()->NullConstant());
}
void BytecodeGraphBuilder::VisitJumpIfNullConstant(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJumpIfEqual(jsgraph()->NullConstant());
+}
+
+
+void BytecodeGraphBuilder::VisitJumpIfNullConstantWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ BuildJumpIfEqual(jsgraph()->NullConstant());
}
void BytecodeGraphBuilder::VisitJumpIfUndefined(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJumpIfEqual(jsgraph()->UndefinedConstant());
}
void BytecodeGraphBuilder::VisitJumpIfUndefinedConstant(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ BuildJumpIfEqual(jsgraph()->UndefinedConstant());
+}
+
+
+void BytecodeGraphBuilder::VisitJumpIfUndefinedConstantWide(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ BuildJumpIfEqual(jsgraph()->UndefinedConstant());
}
@@ -805,24 +1718,156 @@ void BytecodeGraphBuilder::VisitReturn(
Node* control =
NewNode(common()->Return(), environment()->LookupAccumulator());
UpdateControlDependencyToLeaveFunction(control);
+ set_environment(nullptr);
}
void BytecodeGraphBuilder::VisitForInPrepare(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ Node* prepare = nullptr;
+ {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* receiver = environment()->LookupAccumulator();
+ prepare = NewNode(javascript()->ForInPrepare(), receiver);
+ environment()->RecordAfterState(prepare, &states);
+ }
+ // Project cache_type, cache_array, cache_length into register
+ // operands 1, 2, 3.
+ for (int i = 0; i < 3; i++) {
+ environment()->BindRegister(iterator.GetRegisterOperand(i),
+ NewNode(common()->Projection(i), prepare));
+ }
}
-void BytecodeGraphBuilder::VisitForInNext(
+void BytecodeGraphBuilder::VisitForInDone(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* index = environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ Node* cache_length =
+ environment()->LookupRegister(iterator.GetRegisterOperand(1));
+ Node* exit_cond = NewNode(javascript()->ForInDone(), index, cache_length);
+ environment()->BindAccumulator(exit_cond, &states);
}
-void BytecodeGraphBuilder::VisitForInDone(
+void BytecodeGraphBuilder::VisitForInNext(
const interpreter::BytecodeArrayIterator& iterator) {
- UNIMPLEMENTED();
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* receiver =
+ environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ Node* cache_type =
+ environment()->LookupRegister(iterator.GetRegisterOperand(1));
+ Node* cache_array =
+ environment()->LookupRegister(iterator.GetRegisterOperand(2));
+ Node* index = environment()->LookupRegister(iterator.GetRegisterOperand(3));
+ Node* value = NewNode(javascript()->ForInNext(), receiver, cache_array,
+ cache_type, index);
+ environment()->BindAccumulator(value, &states);
+}
+
+
+void BytecodeGraphBuilder::VisitForInStep(
+ const interpreter::BytecodeArrayIterator& iterator) {
+ FrameStateBeforeAndAfter states(this, iterator);
+ Node* index = environment()->LookupRegister(iterator.GetRegisterOperand(0));
+ index = NewNode(javascript()->ForInStep(), index);
+ environment()->BindAccumulator(index, &states);
+}
+
+
+void BytecodeGraphBuilder::MergeEnvironmentsOfBackwardBranches(
+ int source_offset, int target_offset) {
+ DCHECK_GE(source_offset, target_offset);
+ const ZoneVector<int>* branch_sites =
+ branch_analysis()->BackwardBranchesTargetting(target_offset);
+ if (branch_sites->back() == source_offset) {
+ // The set of back branches is complete, merge them.
+ DCHECK_GE(branch_sites->at(0), target_offset);
+ Environment* merged = merge_environments_[branch_sites->at(0)];
+ for (size_t i = 1; i < branch_sites->size(); i++) {
+ DCHECK_GE(branch_sites->at(i), target_offset);
+ merged->Merge(merge_environments_[branch_sites->at(i)]);
+ }
+ // And now merge with loop header environment created when loop
+ // header was visited.
+ loop_header_environments_[target_offset]->Merge(merged);
+ }
+}
+
+
+void BytecodeGraphBuilder::MergeEnvironmentsOfForwardBranches(
+ int source_offset) {
+ if (branch_analysis()->forward_branches_target(source_offset)) {
+ // Merge environments of branches that reach this bytecode.
+ auto branch_sites =
+ branch_analysis()->ForwardBranchesTargetting(source_offset);
+ DCHECK_LT(branch_sites->at(0), source_offset);
+ Environment* merged = merge_environments_[branch_sites->at(0)];
+ for (size_t i = 1; i < branch_sites->size(); i++) {
+ DCHECK_LT(branch_sites->at(i), source_offset);
+ merged->Merge(merge_environments_[branch_sites->at(i)]);
+ }
+ if (environment()) {
+ merged->Merge(environment());
+ }
+ set_environment(merged);
+ }
+}
+
+
+void BytecodeGraphBuilder::BuildLoopHeaderForBackwardBranches(
+ int source_offset) {
+ if (branch_analysis()->backward_branches_target(source_offset)) {
+ // Add loop header and store a copy so we can connect merged back
+ // edge inputs to the loop header.
+ loop_header_environments_[source_offset] = environment()->CopyForLoop();
+ }
+}
+
+
+void BytecodeGraphBuilder::BuildJump(int source_offset, int target_offset) {
+ DCHECK_NULL(merge_environments_[source_offset]);
+ merge_environments_[source_offset] = environment();
+ if (source_offset >= target_offset) {
+ MergeEnvironmentsOfBackwardBranches(source_offset, target_offset);
+ }
+ set_environment(nullptr);
+}
+
+
+void BytecodeGraphBuilder::BuildJump() {
+ int source_offset = bytecode_iterator()->current_offset();
+ int target_offset = bytecode_iterator()->GetJumpTargetOffset();
+ BuildJump(source_offset, target_offset);
+}
+
+
+void BytecodeGraphBuilder::BuildConditionalJump(Node* condition) {
+ int source_offset = bytecode_iterator()->current_offset();
+ NewBranch(condition);
+ Environment* if_false_environment = environment()->CopyForConditional();
+ NewIfTrue();
+ BuildJump(source_offset, bytecode_iterator()->GetJumpTargetOffset());
+ set_environment(if_false_environment);
+ NewIfFalse();
+}
+
+
+void BytecodeGraphBuilder::BuildJumpIfEqual(Node* comperand) {
+ Node* accumulator = environment()->LookupAccumulator();
+ Node* condition =
+ NewNode(javascript()->StrictEqual(), accumulator, comperand);
+ BuildConditionalJump(condition);
+}
+
+
+void BytecodeGraphBuilder::BuildJumpIfToBooleanEqual(Node* comperand) {
+ Node* accumulator = environment()->LookupAccumulator();
+ Node* to_boolean =
+ NewNode(javascript()->ToBoolean(ToBooleanHint::kAny), accumulator);
+ Node* condition = NewNode(javascript()->StrictEqual(), to_boolean, comperand);
+ BuildConditionalJump(condition);
}
@@ -836,6 +1881,16 @@ Node** BytecodeGraphBuilder::EnsureInputBufferSize(int size) {
}
+void BytecodeGraphBuilder::PrepareEntryFrameState(Node* node) {
+ DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
+ DCHECK_EQ(IrOpcode::kDead,
+ NodeProperties::GetFrameStateInput(node, 0)->opcode());
+ NodeProperties::ReplaceFrameStateInput(
+ node, 0, environment()->Checkpoint(BailoutId(0),
+ OutputFrameStateCombine::Ignore()));
+}
+
+
Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
Node** value_inputs, bool incomplete) {
DCHECK_EQ(op->ValueInputCount(), value_input_count);
@@ -848,7 +1903,7 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
DCHECK_LT(op->ControlInputCount(), 2);
DCHECK_LT(op->EffectInputCount(), 2);
- Node* result = NULL;
+ Node* result = nullptr;
if (!has_context && frame_state_count == 0 && !has_control && !has_effect) {
result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
} else {
@@ -898,6 +1953,25 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
}
+Node* BytecodeGraphBuilder::NewPhi(int count, Node* input, Node* control) {
+ const Operator* phi_op = common()->Phi(MachineRepresentation::kTagged, count);
+ Node** buffer = EnsureInputBufferSize(count + 1);
+ MemsetPointer(buffer, input, count);
+ buffer[count] = control;
+ return graph()->NewNode(phi_op, count + 1, buffer, true);
+}
+
+
+Node* BytecodeGraphBuilder::NewEffectPhi(int count, Node* input,
+ Node* control) {
+ const Operator* phi_op = common()->EffectPhi(count);
+ Node** buffer = EnsureInputBufferSize(count + 1);
+ MemsetPointer(buffer, input, count);
+ buffer[count] = control;
+ return graph()->NewNode(phi_op, count + 1, buffer, true);
+}
+
+
Node* BytecodeGraphBuilder::MergeControl(Node* control, Node* other) {
int inputs = control->op()->ControlInputCount() + 1;
if (control->opcode() == IrOpcode::kLoop) {
@@ -920,6 +1994,41 @@ Node* BytecodeGraphBuilder::MergeControl(Node* control, Node* other) {
}
+Node* BytecodeGraphBuilder::MergeEffect(Node* value, Node* other,
+ Node* control) {
+ int inputs = control->op()->ControlInputCount();
+ if (value->opcode() == IrOpcode::kEffectPhi &&
+ NodeProperties::GetControlInput(value) == control) {
+ // Phi already exists, add input.
+ value->InsertInput(graph_zone(), inputs - 1, other);
+ NodeProperties::ChangeOp(value, common()->EffectPhi(inputs));
+ } else if (value != other) {
+ // Phi does not exist yet, introduce one.
+ value = NewEffectPhi(inputs, value, control);
+ value->ReplaceInput(inputs - 1, other);
+ }
+ return value;
+}
+
+
+Node* BytecodeGraphBuilder::MergeValue(Node* value, Node* other,
+ Node* control) {
+ int inputs = control->op()->ControlInputCount();
+ if (value->opcode() == IrOpcode::kPhi &&
+ NodeProperties::GetControlInput(value) == control) {
+ // Phi already exists, add input.
+ value->InsertInput(graph_zone(), inputs - 1, other);
+ NodeProperties::ChangeOp(
+ value, common()->Phi(MachineRepresentation::kTagged, inputs));
+ } else if (value != other) {
+ // Phi does not exist yet, introduce one.
+ value = NewPhi(inputs, value, control);
+ value->ReplaceInput(inputs - 1, other);
+ }
+ return value;
+}
+
+
void BytecodeGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) {
if (environment()->IsMarkedAsUnreachable()) return;
environment()->MarkAsUnreachable();