aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/bytecode-graph-builder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/bytecode-graph-builder.cc')
-rw-r--r--src/compiler/bytecode-graph-builder.cc887
1 files changed, 549 insertions, 338 deletions
diff --git a/src/compiler/bytecode-graph-builder.cc b/src/compiler/bytecode-graph-builder.cc
index 34b50df3..aaeee666 100644
--- a/src/compiler/bytecode-graph-builder.cc
+++ b/src/compiler/bytecode-graph-builder.cc
@@ -7,12 +7,14 @@
#include "src/ast/ast.h"
#include "src/ast/scopes.h"
#include "src/compilation-info.h"
-#include "src/compiler/bytecode-branch-analysis.h"
#include "src/compiler/compiler-source-position-table.h"
+#include "src/compiler/js-type-hint-lowering.h"
#include "src/compiler/linkage.h"
#include "src/compiler/operator-properties.h"
+#include "src/compiler/simplified-operator.h"
#include "src/interpreter/bytecodes.h"
#include "src/objects-inl.h"
+#include "src/objects/literal-objects.h"
namespace v8 {
namespace internal {
@@ -36,7 +38,6 @@ class BytecodeGraphBuilder::Environment : public ZoneObject {
Node* LookupAccumulator() const;
Node* LookupRegister(interpreter::Register the_register) const;
- void MarkAllRegistersLive();
void BindAccumulator(Node* node,
FrameStateAttachmentMode mode = kDontAttachFrameState);
@@ -57,7 +58,8 @@ class BytecodeGraphBuilder::Environment : public ZoneObject {
// Preserve a checkpoint of the environment for the IR graph. Any
// further mutation of the environment will not affect checkpoints.
Node* Checkpoint(BailoutId bytecode_offset, OutputFrameStateCombine combine,
- bool owner_has_exception);
+ bool owner_has_exception,
+ const BytecodeLivenessState* liveness);
// Control dependency tracked by this environment.
Node* GetControlDependency() const { return control_dependency_; }
@@ -68,30 +70,29 @@ class BytecodeGraphBuilder::Environment : public ZoneObject {
Node* Context() const { return context_; }
void SetContext(Node* new_context) { context_ = new_context; }
- Environment* CopyForConditional();
- Environment* CopyForLoop();
- Environment* CopyForOsrEntry();
+ Environment* Copy();
void Merge(Environment* other);
- void PrepareForOsrEntry();
- void PrepareForLoopExit(Node* loop);
+ void PrepareForOsrEntry();
+ void PrepareForLoop(const BytecodeLoopAssignments& assignments);
+ void PrepareForLoopExit(Node* loop,
+ const BytecodeLoopAssignments& assignments);
private:
- Environment(const Environment* copy, LivenessAnalyzerBlock* liveness_block);
- void PrepareForLoop();
+ explicit Environment(const Environment* copy);
- bool StateValuesRequireUpdate(Node** state_values, int offset, int count);
- void UpdateStateValues(Node** state_values, int offset, int count);
+ bool StateValuesRequireUpdate(Node** state_values, Node** values, int count);
+ void UpdateStateValues(Node** state_values, Node** values, int count);
+ void UpdateStateValuesWithCache(Node** state_values, Node** values, int count,
+ const BitVector* liveness,
+ int liveness_offset);
int RegisterToValuesIndex(interpreter::Register the_register) const;
- bool IsLivenessBlockConsistent() 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_; }
- LivenessAnalyzerBlock* liveness_block() const { return liveness_block_; }
const NodeVector* values() const { return &values_; }
NodeVector* values() { return &values_; }
int register_base() const { return register_base_; }
@@ -100,7 +101,6 @@ class BytecodeGraphBuilder::Environment : public ZoneObject {
BytecodeGraphBuilder* builder_;
int register_count_;
int parameter_count_;
- LivenessAnalyzerBlock* liveness_block_;
Node* context_;
Node* control_dependency_;
Node* effect_dependency_;
@@ -124,9 +124,6 @@ BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder,
: builder_(builder),
register_count_(register_count),
parameter_count_(parameter_count),
- liveness_block_(builder->is_liveness_analysis_enabled_
- ? builder_->liveness_analyzer()->NewBlock()
- : nullptr),
context_(context),
control_dependency_(control_dependency),
effect_dependency_(control_dependency),
@@ -161,12 +158,10 @@ BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder,
}
BytecodeGraphBuilder::Environment::Environment(
- const BytecodeGraphBuilder::Environment* other,
- LivenessAnalyzerBlock* liveness_block)
+ const BytecodeGraphBuilder::Environment* other)
: builder_(other->builder_),
register_count_(other->register_count_),
parameter_count_(other->parameter_count_),
- liveness_block_(liveness_block),
context_(other->context_),
control_dependency_(other->control_dependency_),
effect_dependency_(other->effect_dependency_),
@@ -189,16 +184,7 @@ int BytecodeGraphBuilder::Environment::RegisterToValuesIndex(
}
}
-bool BytecodeGraphBuilder::Environment::IsLivenessBlockConsistent() const {
- return !builder_->IsLivenessAnalysisEnabled() ==
- (liveness_block() == nullptr);
-}
-
Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const {
- DCHECK(IsLivenessBlockConsistent());
- if (liveness_block() != nullptr) {
- liveness_block()->LookupAccumulator();
- }
return values()->at(accumulator_base_);
}
@@ -213,32 +199,15 @@ Node* BytecodeGraphBuilder::Environment::LookupRegister(
return builder()->GetNewTarget();
} else {
int values_index = RegisterToValuesIndex(the_register);
- if (liveness_block() != nullptr && !the_register.is_parameter()) {
- DCHECK(IsLivenessBlockConsistent());
- liveness_block()->Lookup(the_register.index());
- }
return values()->at(values_index);
}
}
-void BytecodeGraphBuilder::Environment::MarkAllRegistersLive() {
- DCHECK(IsLivenessBlockConsistent());
- if (liveness_block() != nullptr) {
- for (int i = 0; i < register_count(); ++i) {
- liveness_block()->Lookup(i);
- }
- }
-}
-
void BytecodeGraphBuilder::Environment::BindAccumulator(
Node* node, FrameStateAttachmentMode mode) {
if (mode == FrameStateAttachmentMode::kAttachFrameState) {
builder()->PrepareFrameState(node, OutputFrameStateCombine::PokeAt(0));
}
- DCHECK(IsLivenessBlockConsistent());
- if (liveness_block() != nullptr) {
- liveness_block()->BindAccumulator();
- }
values()->at(accumulator_base_) = node;
}
@@ -251,10 +220,6 @@ void BytecodeGraphBuilder::Environment::BindRegister(
accumulator_base_ - values_index));
}
values()->at(values_index) = node;
- if (liveness_block() != nullptr && !the_register.is_parameter()) {
- DCHECK(IsLivenessBlockConsistent());
- liveness_block()->Bind(the_register.index());
- }
}
void BytecodeGraphBuilder::Environment::BindRegistersToProjections(
@@ -278,45 +243,13 @@ void BytecodeGraphBuilder::Environment::RecordAfterState(
}
}
-
-BytecodeGraphBuilder::Environment*
-BytecodeGraphBuilder::Environment::CopyForLoop() {
- PrepareForLoop();
- if (liveness_block() != nullptr) {
- // Finish the current block before copying.
- liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block());
- }
- return new (zone()) Environment(this, liveness_block());
-}
-
-BytecodeGraphBuilder::Environment*
-BytecodeGraphBuilder::Environment::CopyForOsrEntry() {
- return new (zone())
- Environment(this, builder_->liveness_analyzer()->NewBlock());
-}
-
-BytecodeGraphBuilder::Environment*
-BytecodeGraphBuilder::Environment::CopyForConditional() {
- LivenessAnalyzerBlock* copy_liveness_block = nullptr;
- if (liveness_block() != nullptr) {
- copy_liveness_block =
- builder_->liveness_analyzer()->NewBlock(liveness_block());
- liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block());
- }
- return new (zone()) Environment(this, copy_liveness_block);
+BytecodeGraphBuilder::Environment* BytecodeGraphBuilder::Environment::Copy() {
+ return new (zone()) Environment(this);
}
void BytecodeGraphBuilder::Environment::Merge(
BytecodeGraphBuilder::Environment* other) {
- if (builder_->is_liveness_analysis_enabled_) {
- if (GetControlDependency()->opcode() != IrOpcode::kLoop) {
- liveness_block_ =
- builder()->liveness_analyzer()->NewBlock(liveness_block());
- }
- liveness_block()->AddPredecessor(other->liveness_block());
- }
-
// Create a merge of the control dependencies of both environments and update
// the current environment's control dependency accordingly.
Node* control = builder()->MergeControl(GetControlDependency(),
@@ -337,8 +270,8 @@ void BytecodeGraphBuilder::Environment::Merge(
}
}
-
-void BytecodeGraphBuilder::Environment::PrepareForLoop() {
+void BytecodeGraphBuilder::Environment::PrepareForLoop(
+ const BytecodeLoopAssignments& assignments) {
// Create a control node for the loop header.
Node* control = builder()->NewLoop();
@@ -346,11 +279,23 @@ void BytecodeGraphBuilder::Environment::PrepareForLoop() {
Node* effect = builder()->NewEffectPhi(1, GetEffectDependency(), control);
UpdateEffectDependency(effect);
- // Assume everything in the loop is updated.
+ // Create Phis for any values that may be updated by the end of the loop.
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);
+ for (int i = 0; i < parameter_count(); i++) {
+ if (assignments.ContainsParameter(i)) {
+ values_[i] = builder()->NewPhi(1, values_[i], control);
+ }
+ }
+ for (int i = 0; i < register_count(); i++) {
+ if (assignments.ContainsLocal(i)) {
+ int index = register_base() + i;
+ values_[index] = builder()->NewPhi(1, values_[index], control);
+ }
+ }
+
+ if (assignments.ContainsAccumulator()) {
+ values_[accumulator_base()] =
+ builder()->NewPhi(1, values_[accumulator_base()], control);
}
// Connect to the loop end.
@@ -384,7 +329,7 @@ void BytecodeGraphBuilder::Environment::PrepareForOsrEntry() {
BailoutId loop_id(builder_->bytecode_iterator().current_offset());
Node* frame_state =
- Checkpoint(loop_id, OutputFrameStateCombine::Ignore(), false);
+ Checkpoint(loop_id, OutputFrameStateCombine::Ignore(), false, nullptr);
Node* checkpoint =
graph()->NewNode(common()->Checkpoint(), frame_state, entry, entry);
UpdateEffectDependency(checkpoint);
@@ -402,22 +347,22 @@ void BytecodeGraphBuilder::Environment::PrepareForOsrEntry() {
}
bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate(
- Node** state_values, int offset, int count) {
+ Node** state_values, Node** values, int count) {
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);
+ Node::Inputs inputs = (*state_values)->inputs();
+ if (inputs.count() != count) return true;
for (int i = 0; i < count; i++) {
- if ((*state_values)->InputAt(i) != env_values[i]) {
+ if (inputs[i] != values[i]) {
return true;
}
}
return false;
}
-void BytecodeGraphBuilder::Environment::PrepareForLoopExit(Node* loop) {
+void BytecodeGraphBuilder::Environment::PrepareForLoopExit(
+ Node* loop, const BytecodeLoopAssignments& assignments) {
DCHECK_EQ(loop->opcode(), IrOpcode::kLoop);
Node* control = GetControlDependency();
@@ -431,34 +376,80 @@ void BytecodeGraphBuilder::Environment::PrepareForLoopExit(Node* loop) {
GetEffectDependency(), loop_exit);
UpdateEffectDependency(effect_rename);
- // TODO(jarin) We should also rename context here. However, uncoditional
+ // TODO(jarin) We should also rename context here. However, unconditional
// renaming confuses global object and native context specialization.
// We should only rename if the context is assigned in the loop.
- // Rename the environmnent values.
- for (size_t i = 0; i < values_.size(); i++) {
- Node* rename =
- graph()->NewNode(common()->LoopExitValue(), values_[i], loop_exit);
- values_[i] = rename;
+ // Rename the environment values if they were assigned in the loop.
+ for (int i = 0; i < parameter_count(); i++) {
+ if (assignments.ContainsParameter(i)) {
+ Node* rename =
+ graph()->NewNode(common()->LoopExitValue(), values_[i], loop_exit);
+ values_[i] = rename;
+ }
+ }
+ for (int i = 0; i < register_count(); i++) {
+ if (assignments.ContainsLocal(i)) {
+ Node* rename = graph()->NewNode(common()->LoopExitValue(),
+ values_[register_base() + i], loop_exit);
+ values_[register_base() + i] = rename;
+ }
+ }
+
+ if (assignments.ContainsAccumulator()) {
+ Node* rename = graph()->NewNode(common()->LoopExitValue(),
+ values_[accumulator_base()], loop_exit);
+ values_[accumulator_base()] = rename;
}
}
void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values,
- int offset,
+ Node** values,
int count) {
- if (StateValuesRequireUpdate(state_values, offset, count)) {
- const Operator* op = common()->StateValues(count);
- (*state_values) = graph()->NewNode(op, count, &values()->at(offset));
+ if (StateValuesRequireUpdate(state_values, values, count)) {
+ const Operator* op = common()->StateValues(count, SparseInputMask::Dense());
+ (*state_values) = graph()->NewNode(op, count, values);
}
}
+void BytecodeGraphBuilder::Environment::UpdateStateValuesWithCache(
+ Node** state_values, Node** values, int count, const BitVector* liveness,
+ int liveness_offset) {
+ *state_values = builder_->state_values_cache_.GetNodeForValues(
+ values, static_cast<size_t>(count), liveness, liveness_offset);
+}
+
Node* BytecodeGraphBuilder::Environment::Checkpoint(
BailoutId bailout_id, OutputFrameStateCombine combine,
- bool owner_has_exception) {
- UpdateStateValues(&parameters_state_values_, 0, parameter_count());
- UpdateStateValues(&registers_state_values_, register_base(),
- register_count());
- UpdateStateValues(&accumulator_state_values_, accumulator_base(), 1);
+ bool owner_has_exception, const BytecodeLivenessState* liveness) {
+ if (parameter_count() == register_count()) {
+ // Re-use the state-value cache if the number of local registers happens
+ // to match the parameter count.
+ UpdateStateValuesWithCache(&parameters_state_values_, &values()->at(0),
+ parameter_count(), nullptr, 0);
+ } else {
+ UpdateStateValues(&parameters_state_values_, &values()->at(0),
+ parameter_count());
+ }
+
+ UpdateStateValuesWithCache(&registers_state_values_,
+ &values()->at(register_base()), register_count(),
+ liveness ? &liveness->bit_vector() : nullptr, 0);
+
+ bool accumulator_is_live = !liveness || liveness->AccumulatorIsLive();
+ if (parameter_count() == 1 && accumulator_is_live &&
+ values()->at(accumulator_base()) == values()->at(0)) {
+ // Re-use the parameter state values if there happens to only be one
+ // parameter and the accumulator is live and holds that parameter's value.
+ accumulator_state_values_ = parameters_state_values_;
+ } else {
+ // Otherwise, use the state values cache to hopefully re-use local register
+ // state values (if there is only one local register), or at the very least
+ // re-use previous accumulator state values.
+ UpdateStateValuesWithCache(
+ &accumulator_state_values_, &values()->at(accumulator_base()), 1,
+ liveness ? &liveness->bit_vector() : nullptr, register_count());
+ }
const Operator* op = common()->FrameState(
bailout_id, combine, builder()->frame_state_function_info());
@@ -467,51 +458,40 @@ Node* BytecodeGraphBuilder::Environment::Checkpoint(
accumulator_state_values_, Context(), builder()->GetFunctionClosure(),
builder()->graph()->start());
- if (liveness_block() != nullptr) {
- // If the owning node has an exception, register the checkpoint to the
- // predecessor so that the checkpoint is used for both the normal and the
- // exceptional paths. Yes, this is a terrible hack and we might want
- // to use an explicit frame state for the exceptional path.
- if (owner_has_exception) {
- liveness_block()->GetPredecessor()->Checkpoint(result);
- } else {
- liveness_block()->Checkpoint(result);
- }
- }
-
return result;
}
BytecodeGraphBuilder::BytecodeGraphBuilder(
- Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph,
- float invocation_frequency, SourcePositionTable* source_positions,
- int inlining_id)
+ Zone* local_zone, Handle<SharedFunctionInfo> shared_info,
+ Handle<FeedbackVector> feedback_vector, BailoutId osr_ast_id,
+ JSGraph* jsgraph, float invocation_frequency,
+ SourcePositionTable* source_positions, int inlining_id)
: local_zone_(local_zone),
jsgraph_(jsgraph),
invocation_frequency_(invocation_frequency),
- bytecode_array_(handle(info->shared_info()->bytecode_array())),
+ bytecode_array_(handle(shared_info->bytecode_array())),
exception_handler_table_(
handle(HandlerTable::cast(bytecode_array()->handler_table()))),
- feedback_vector_(handle(info->closure()->feedback_vector())),
+ feedback_vector_(feedback_vector),
frame_state_function_info_(common()->CreateFrameStateFunctionInfo(
FrameStateType::kInterpretedFunction,
bytecode_array()->parameter_count(),
- bytecode_array()->register_count(), info->shared_info())),
- osr_ast_id_(info->osr_ast_id()),
+ bytecode_array()->register_count(), shared_info)),
+ bytecode_iterator_(nullptr),
+ bytecode_analysis_(nullptr),
+ environment_(nullptr),
+ osr_ast_id_(osr_ast_id),
+ osr_loop_offset_(-1),
merge_environments_(local_zone),
exception_handlers_(local_zone),
current_exception_handler_(0),
input_buffer_size_(0),
input_buffer_(nullptr),
+ needs_eager_checkpoint_(true),
exit_controls_(local_zone),
- is_liveness_analysis_enabled_(FLAG_analyze_environment_liveness &&
- info->is_deoptimization_enabled()),
state_values_cache_(jsgraph),
- liveness_analyzer_(
- static_cast<size_t>(bytecode_array()->register_count()), true,
- local_zone),
source_positions_(source_positions),
- start_position_(info->shared_info()->start_position(), inlining_id) {}
+ start_position_(shared_info->start_position(), inlining_id) {}
Node* BytecodeGraphBuilder::GetNewTarget() {
if (!new_target_.is_set()) {
@@ -551,14 +531,16 @@ Node* BytecodeGraphBuilder::GetFunctionClosure() {
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* native_context = NewNode(op);
+ Node* result = NewNode(javascript()->LoadContext(0, index, true));
+ NodeProperties::ReplaceContextInput(result, native_context);
+ return result;
}
VectorSlotPair BytecodeGraphBuilder::CreateVectorSlotPair(int slot_id) {
- FeedbackVectorSlot slot;
- if (slot_id >= TypeFeedbackVector::kReservedIndexCount) {
+ FeedbackSlot slot;
+ if (slot_id >= FeedbackVector::kReservedIndexCount) {
slot = feedback_vector()->ToSlot(slot_id);
}
return VectorSlotPair(feedback_vector(), slot);
@@ -587,24 +569,42 @@ bool BytecodeGraphBuilder::CreateGraph(bool stack_check) {
Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs);
graph()->SetEnd(end);
- ClearNonLiveSlotsInFrameStates();
-
return true;
}
void BytecodeGraphBuilder::PrepareEagerCheckpoint() {
- if (environment()->GetEffectDependency()->opcode() != IrOpcode::kCheckpoint) {
+ if (needs_eager_checkpoint()) {
// Create an explicit checkpoint node for before the operation. This only
// needs to happen if we aren't effect-dominated by a {Checkpoint} already.
+ mark_as_needing_eager_checkpoint(false);
Node* node = NewNode(common()->Checkpoint());
DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
DCHECK_EQ(IrOpcode::kDead,
NodeProperties::GetFrameStateInput(node)->opcode());
BailoutId bailout_id(bytecode_iterator().current_offset());
+
+ const BytecodeLivenessState* liveness_before =
+ bytecode_analysis()->GetInLivenessFor(
+ bytecode_iterator().current_offset());
+
Node* frame_state_before = environment()->Checkpoint(
- bailout_id, OutputFrameStateCombine::Ignore(), false);
+ bailout_id, OutputFrameStateCombine::Ignore(), false, liveness_before);
NodeProperties::ReplaceFrameStateInput(node, frame_state_before);
+#ifdef DEBUG
+ } else {
+ // In case we skipped checkpoint creation above, we must be able to find an
+ // existing checkpoint that effect-dominates the nodes about to be created.
+ // Starting a search from the current effect-dependency has to succeed.
+ Node* effect = environment()->GetEffectDependency();
+ while (effect->opcode() != IrOpcode::kCheckpoint) {
+ DCHECK(effect->op()->HasProperty(Operator::kNoWrite));
+ DCHECK_EQ(1, effect->op()->EffectInputCount());
+ effect = NodeProperties::GetEffectInput(effect);
+ }
+ }
+#else
}
+#endif // DEBUG
}
void BytecodeGraphBuilder::PrepareFrameState(Node* node,
@@ -617,40 +617,36 @@ void BytecodeGraphBuilder::PrepareFrameState(Node* node,
NodeProperties::GetFrameStateInput(node)->opcode());
BailoutId bailout_id(bytecode_iterator().current_offset());
bool has_exception = NodeProperties::IsExceptionalCall(node);
- Node* frame_state_after =
- environment()->Checkpoint(bailout_id, combine, has_exception);
- NodeProperties::ReplaceFrameStateInput(node, frame_state_after);
- }
-}
-void BytecodeGraphBuilder::ClearNonLiveSlotsInFrameStates() {
- if (!IsLivenessAnalysisEnabled()) {
- return;
- }
- NonLiveFrameStateSlotReplacer replacer(
- &state_values_cache_, jsgraph()->OptimizedOutConstant(),
- liveness_analyzer()->local_count(), true, local_zone());
- liveness_analyzer()->Run(&replacer);
- if (FLAG_trace_environment_liveness) {
- OFStream os(stdout);
- liveness_analyzer()->Print(os);
+ const BytecodeLivenessState* liveness_after =
+ bytecode_analysis()->GetOutLivenessFor(
+ bytecode_iterator().current_offset());
+
+ Node* frame_state_after = environment()->Checkpoint(
+ bailout_id, combine, has_exception, liveness_after);
+ NodeProperties::ReplaceFrameStateInput(node, frame_state_after);
}
}
void BytecodeGraphBuilder::VisitBytecodes(bool stack_check) {
- BytecodeBranchAnalysis analysis(bytecode_array(), local_zone());
- BytecodeLoopAnalysis loop_analysis(bytecode_array(), &analysis, local_zone());
- analysis.Analyze();
- loop_analysis.Analyze();
- set_branch_analysis(&analysis);
- set_loop_analysis(&loop_analysis);
+ BytecodeAnalysis bytecode_analysis(bytecode_array(), local_zone(),
+ FLAG_analyze_environment_liveness);
+ bytecode_analysis.Analyze(osr_ast_id_);
+ set_bytecode_analysis(&bytecode_analysis);
interpreter::BytecodeArrayIterator iterator(bytecode_array());
set_bytecode_iterator(&iterator);
SourcePositionTableIterator source_position_iterator(
bytecode_array()->source_position_table());
+ if (FLAG_trace_environment_liveness) {
+ OFStream of(stdout);
+
+ bytecode_analysis.PrintLivenessTo(of);
+ }
+
BuildOSRNormalEntryPoint();
+
for (; !iterator.done(); iterator.Advance()) {
int current_offset = iterator.current_offset();
UpdateCurrentSourcePosition(&source_position_iterator, current_offset);
@@ -658,7 +654,6 @@ void BytecodeGraphBuilder::VisitBytecodes(bool stack_check) {
SwitchToMergeEnvironment(current_offset);
if (environment() != nullptr) {
BuildLoopHeaderEnvironment(current_offset);
- BuildOSRLoopEntryPoint(current_offset);
// Skip the first stack check if stack_check is false
if (!stack_check &&
@@ -677,8 +672,7 @@ void BytecodeGraphBuilder::VisitBytecodes(bool stack_check) {
}
}
}
-
- set_branch_analysis(nullptr);
+ set_bytecode_analysis(nullptr);
set_bytecode_iterator(nullptr);
DCHECK(exception_handlers_.empty());
}
@@ -741,27 +735,32 @@ void BytecodeGraphBuilder::VisitMov() {
environment()->BindRegister(bytecode_iterator().GetRegisterOperand(1), value);
}
-Node* BytecodeGraphBuilder::BuildLoadGlobal(uint32_t feedback_slot_index,
+Node* BytecodeGraphBuilder::BuildLoadGlobal(Handle<Name> name,
+ uint32_t feedback_slot_index,
TypeofMode typeof_mode) {
VectorSlotPair feedback = CreateVectorSlotPair(feedback_slot_index);
- DCHECK_EQ(FeedbackVectorSlotKind::LOAD_GLOBAL_IC,
- feedback_vector()->GetKind(feedback.slot()));
- Handle<Name> name(feedback_vector()->GetName(feedback.slot()));
+ DCHECK(IsLoadGlobalICKind(feedback_vector()->GetKind(feedback.slot())));
const Operator* op = javascript()->LoadGlobal(name, feedback, typeof_mode);
- return NewNode(op, GetFunctionClosure());
+ return NewNode(op);
}
void BytecodeGraphBuilder::VisitLdaGlobal() {
PrepareEagerCheckpoint();
- Node* node = BuildLoadGlobal(bytecode_iterator().GetIndexOperand(0),
- TypeofMode::NOT_INSIDE_TYPEOF);
+ Handle<Name> name =
+ Handle<Name>::cast(bytecode_iterator().GetConstantForIndexOperand(0));
+ uint32_t feedback_slot_index = bytecode_iterator().GetIndexOperand(1);
+ Node* node =
+ BuildLoadGlobal(name, feedback_slot_index, TypeofMode::NOT_INSIDE_TYPEOF);
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeof() {
PrepareEagerCheckpoint();
- Node* node = BuildLoadGlobal(bytecode_iterator().GetIndexOperand(0),
- TypeofMode::INSIDE_TYPEOF);
+ Handle<Name> name =
+ Handle<Name>::cast(bytecode_iterator().GetConstantForIndexOperand(0));
+ uint32_t feedback_slot_index = bytecode_iterator().GetIndexOperand(1);
+ Node* node =
+ BuildLoadGlobal(name, feedback_slot_index, TypeofMode::INSIDE_TYPEOF);
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
@@ -774,7 +773,7 @@ void BytecodeGraphBuilder::BuildStoreGlobal(LanguageMode language_mode) {
Node* value = environment()->LookupAccumulator();
const Operator* op = javascript()->StoreGlobal(language_mode, name, feedback);
- Node* node = NewNode(op, value, GetFunctionClosure());
+ Node* node = NewNode(op, value);
environment()->RecordAfterState(node, Environment::kAttachFrameState);
}
@@ -786,27 +785,56 @@ void BytecodeGraphBuilder::VisitStaGlobalStrict() {
BuildStoreGlobal(LanguageMode::STRICT);
}
+void BytecodeGraphBuilder::VisitStaDataPropertyInLiteral() {
+ PrepareEagerCheckpoint();
+
+ Node* object =
+ environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
+ Node* name =
+ environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
+ Node* value = environment()->LookupAccumulator();
+ int flags = bytecode_iterator().GetFlagOperand(2);
+ VectorSlotPair feedback =
+ CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(3));
+
+ const Operator* op = javascript()->StoreDataPropertyInLiteral(feedback);
+ Node* node = NewNode(op, object, name, value, jsgraph()->Constant(flags));
+ environment()->RecordAfterState(node, Environment::kAttachFrameState);
+}
+
void BytecodeGraphBuilder::VisitLdaContextSlot() {
- // 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(
bytecode_iterator().GetUnsignedImmediateOperand(2),
bytecode_iterator().GetIndexOperand(1), false);
+ Node* node = NewNode(op);
+ Node* context =
+ environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
+ NodeProperties::ReplaceContextInput(node, context);
+ environment()->BindAccumulator(node);
+}
+
+void BytecodeGraphBuilder::VisitLdaImmutableContextSlot() {
+ const Operator* op = javascript()->LoadContext(
+ bytecode_iterator().GetUnsignedImmediateOperand(2),
+ bytecode_iterator().GetIndexOperand(1), true);
+ Node* node = NewNode(op);
Node* context =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
- Node* node = NewNode(op, context);
+ NodeProperties::ReplaceContextInput(node, context);
environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitLdaCurrentContextSlot() {
- // 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, bytecode_iterator().GetIndexOperand(0), false);
- Node* context = environment()->Context();
- Node* node = NewNode(op, context);
+ Node* node = NewNode(op);
+ environment()->BindAccumulator(node);
+}
+
+void BytecodeGraphBuilder::VisitLdaImmutableCurrentContextSlot() {
+ const Operator* op = javascript()->LoadContext(
+ 0, bytecode_iterator().GetIndexOperand(0), true);
+ Node* node = NewNode(op);
environment()->BindAccumulator(node);
}
@@ -814,18 +842,18 @@ void BytecodeGraphBuilder::VisitStaContextSlot() {
const Operator* op = javascript()->StoreContext(
bytecode_iterator().GetUnsignedImmediateOperand(2),
bytecode_iterator().GetIndexOperand(1));
+ Node* value = environment()->LookupAccumulator();
+ Node* node = NewNode(op, value);
Node* context =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
- Node* value = environment()->LookupAccumulator();
- NewNode(op, context, value);
+ NodeProperties::ReplaceContextInput(node, context);
}
void BytecodeGraphBuilder::VisitStaCurrentContextSlot() {
const Operator* op =
javascript()->StoreContext(0, bytecode_iterator().GetIndexOperand(0));
- Node* context = environment()->Context();
Node* value = environment()->LookupAccumulator();
- NewNode(op, context, value);
+ NewNode(op, value);
}
void BytecodeGraphBuilder::BuildLdaLookupSlot(TypeofMode typeof_mode) {
@@ -857,15 +885,14 @@ BytecodeGraphBuilder::Environment* BytecodeGraphBuilder::CheckContextExtensions(
// the same scope as the variable itself has no way of shadowing it.
for (uint32_t d = 0; d < depth; d++) {
Node* extension_slot =
- NewNode(javascript()->LoadContext(d, Context::EXTENSION_INDEX, false),
- environment()->Context());
+ NewNode(javascript()->LoadContext(d, Context::EXTENSION_INDEX, false));
Node* check_no_extension =
- NewNode(javascript()->StrictEqual(CompareOperationHint::kAny),
- extension_slot, jsgraph()->TheHoleConstant());
+ NewNode(simplified()->ReferenceEqual(), extension_slot,
+ jsgraph()->TheHoleConstant());
NewBranch(check_no_extension);
- Environment* true_environment = environment()->CopyForConditional();
+ Environment* true_environment = environment()->Copy();
{
NewIfFalse();
@@ -904,8 +931,7 @@ void BytecodeGraphBuilder::BuildLdaLookupContextSlot(TypeofMode typeof_mode) {
uint32_t slot_index = bytecode_iterator().GetIndexOperand(1);
const Operator* op = javascript()->LoadContext(depth, slot_index, false);
- Node* context = environment()->Context();
- environment()->BindAccumulator(NewNode(op, context));
+ environment()->BindAccumulator(NewNode(op));
}
// Only build the slow path if there were any slow-path checks.
@@ -930,6 +956,7 @@ void BytecodeGraphBuilder::BuildLdaLookupContextSlot(TypeofMode typeof_mode) {
fast_environment->Merge(environment());
set_environment(fast_environment);
+ mark_as_needing_eager_checkpoint(true);
}
}
@@ -950,8 +977,10 @@ void BytecodeGraphBuilder::BuildLdaLookupGlobalSlot(TypeofMode typeof_mode) {
// Fast path, do a global load.
{
PrepareEagerCheckpoint();
- Node* node =
- BuildLoadGlobal(bytecode_iterator().GetIndexOperand(1), typeof_mode);
+ Handle<Name> name =
+ Handle<Name>::cast(bytecode_iterator().GetConstantForIndexOperand(0));
+ uint32_t feedback_slot_index = bytecode_iterator().GetIndexOperand(1);
+ Node* node = BuildLoadGlobal(name, feedback_slot_index, typeof_mode);
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
@@ -977,6 +1006,7 @@ void BytecodeGraphBuilder::BuildLdaLookupGlobalSlot(TypeofMode typeof_mode) {
fast_environment->Merge(environment());
set_environment(fast_environment);
+ mark_as_needing_eager_checkpoint(true);
}
}
@@ -1018,7 +1048,7 @@ void BytecodeGraphBuilder::VisitLdaNamedProperty() {
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2));
const Operator* op = javascript()->LoadNamed(name, feedback);
- Node* node = NewNode(op, object, GetFunctionClosure());
+ Node* node = NewNode(op, object);
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
@@ -1031,11 +1061,12 @@ void BytecodeGraphBuilder::VisitLdaKeyedProperty() {
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(1));
const Operator* op = javascript()->LoadProperty(feedback);
- Node* node = NewNode(op, object, key, GetFunctionClosure());
+ Node* node = NewNode(op, object, key);
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
-void BytecodeGraphBuilder::BuildNamedStore(LanguageMode language_mode) {
+void BytecodeGraphBuilder::BuildNamedStore(LanguageMode language_mode,
+ StoreMode store_mode) {
PrepareEagerCheckpoint();
Node* value = environment()->LookupAccumulator();
Node* object =
@@ -1045,17 +1076,31 @@ void BytecodeGraphBuilder::BuildNamedStore(LanguageMode language_mode) {
VectorSlotPair feedback =
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2));
- const Operator* op = javascript()->StoreNamed(language_mode, name, feedback);
- Node* node = NewNode(op, object, value, GetFunctionClosure());
+ const Operator* op;
+ if (store_mode == StoreMode::kOwn) {
+ DCHECK_EQ(FeedbackSlotKind::kStoreOwnNamed,
+ feedback.vector()->GetKind(feedback.slot()));
+ op = javascript()->StoreNamedOwn(name, feedback);
+ } else {
+ DCHECK(store_mode == StoreMode::kNormal);
+ DCHECK_EQ(feedback.vector()->GetLanguageMode(feedback.slot()),
+ language_mode);
+ op = javascript()->StoreNamed(language_mode, name, feedback);
+ }
+ Node* node = NewNode(op, object, value);
environment()->RecordAfterState(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitStaNamedPropertySloppy() {
- BuildNamedStore(LanguageMode::SLOPPY);
+ BuildNamedStore(LanguageMode::SLOPPY, StoreMode::kNormal);
}
void BytecodeGraphBuilder::VisitStaNamedPropertyStrict() {
- BuildNamedStore(LanguageMode::STRICT);
+ BuildNamedStore(LanguageMode::STRICT, StoreMode::kNormal);
+}
+
+void BytecodeGraphBuilder::VisitStaNamedOwnProperty() {
+ BuildNamedStore(LanguageMode::STRICT, StoreMode::kOwn);
}
void BytecodeGraphBuilder::BuildKeyedStore(LanguageMode language_mode) {
@@ -1068,8 +1113,9 @@ void BytecodeGraphBuilder::BuildKeyedStore(LanguageMode language_mode) {
VectorSlotPair feedback =
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2));
+ DCHECK_EQ(feedback.vector()->GetLanguageMode(feedback.slot()), language_mode);
const Operator* op = javascript()->StoreProperty(language_mode, feedback);
- Node* node = NewNode(op, object, key, value, GetFunctionClosure());
+ Node* node = NewNode(op, object, key, value);
environment()->RecordAfterState(node, Environment::kAttachFrameState);
}
@@ -1085,8 +1131,7 @@ void BytecodeGraphBuilder::VisitLdaModuleVariable() {
int32_t cell_index = bytecode_iterator().GetImmediateOperand(0);
uint32_t depth = bytecode_iterator().GetUnsignedImmediateOperand(1);
Node* module =
- NewNode(javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false),
- environment()->Context());
+ NewNode(javascript()->LoadContext(depth, Context::EXTENSION_INDEX, true));
Node* value = NewNode(javascript()->LoadModule(cell_index), module);
environment()->BindAccumulator(value);
}
@@ -1095,8 +1140,7 @@ void BytecodeGraphBuilder::VisitStaModuleVariable() {
int32_t cell_index = bytecode_iterator().GetImmediateOperand(0);
uint32_t depth = bytecode_iterator().GetUnsignedImmediateOperand(1);
Node* module =
- NewNode(javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false),
- environment()->Context());
+ NewNode(javascript()->LoadContext(depth, Context::EXTENSION_INDEX, true));
Node* value = environment()->LookupAccumulator();
NewNode(javascript()->StoreModule(cell_index), module, value);
}
@@ -1117,12 +1161,14 @@ void BytecodeGraphBuilder::VisitPopContext() {
void BytecodeGraphBuilder::VisitCreateClosure() {
Handle<SharedFunctionInfo> shared_info = Handle<SharedFunctionInfo>::cast(
bytecode_iterator().GetConstantForIndexOperand(0));
+ int const slot_id = bytecode_iterator().GetIndexOperand(1);
+ VectorSlotPair pair = CreateVectorSlotPair(slot_id);
PretenureFlag tenured =
interpreter::CreateClosureFlags::PretenuredBit::decode(
- bytecode_iterator().GetFlagOperand(1))
+ bytecode_iterator().GetFlagOperand(2))
? TENURED
: NOT_TENURED;
- const Operator* op = javascript()->CreateClosure(shared_info, tenured);
+ const Operator* op = javascript()->CreateClosure(shared_info, pair, tenured);
Node* closure = NewNode(op);
environment()->BindAccumulator(closure);
}
@@ -1138,7 +1184,15 @@ void BytecodeGraphBuilder::VisitCreateBlockContext() {
void BytecodeGraphBuilder::VisitCreateFunctionContext() {
uint32_t slots = bytecode_iterator().GetUnsignedImmediateOperand(0);
- const Operator* op = javascript()->CreateFunctionContext(slots);
+ const Operator* op =
+ javascript()->CreateFunctionContext(slots, FUNCTION_SCOPE);
+ Node* context = NewNode(op, GetFunctionClosure());
+ environment()->BindAccumulator(context);
+}
+
+void BytecodeGraphBuilder::VisitCreateEvalContext() {
+ uint32_t slots = bytecode_iterator().GetUnsignedImmediateOperand(0);
+ const Operator* op = javascript()->CreateFunctionContext(slots, EVAL_SCOPE);
Node* context = NewNode(op, GetFunctionClosure());
environment()->BindAccumulator(context);
}
@@ -1198,16 +1252,21 @@ void BytecodeGraphBuilder::VisitCreateRegExpLiteral() {
}
void BytecodeGraphBuilder::VisitCreateArrayLiteral() {
- Handle<FixedArray> constant_elements = Handle<FixedArray>::cast(
- bytecode_iterator().GetConstantForIndexOperand(0));
+ Handle<ConstantElementsPair> constant_elements =
+ Handle<ConstantElementsPair>::cast(
+ bytecode_iterator().GetConstantForIndexOperand(0));
int literal_index = bytecode_iterator().GetIndexOperand(1);
- int literal_flags = bytecode_iterator().GetFlagOperand(2);
+ int bytecode_flags = bytecode_iterator().GetFlagOperand(2);
+ int literal_flags =
+ interpreter::CreateArrayLiteralFlags::FlagsBits::decode(bytecode_flags);
// Disable allocation site mementos. Only unoptimized code will collect
// feedback about allocation site. Once the code is optimized we expect the
// data to converge. So, we disable allocation site mementos in optimized
// code. We can revisit this when we have data to the contrary.
literal_flags |= ArrayLiteral::kDisableMementos;
- int number_of_elements = constant_elements->length();
+ // TODO(mstarzinger): Thread through number of elements. The below number is
+ // only an estimate and does not match {ArrayLiteral::values::length}.
+ int number_of_elements = constant_elements->constant_values()->length();
Node* literal = NewNode(
javascript()->CreateLiteralArray(constant_elements, literal_flags,
literal_index, number_of_elements),
@@ -1216,15 +1275,16 @@ void BytecodeGraphBuilder::VisitCreateArrayLiteral() {
}
void BytecodeGraphBuilder::VisitCreateObjectLiteral() {
- PrepareEagerCheckpoint();
- Handle<FixedArray> constant_properties = Handle<FixedArray>::cast(
- bytecode_iterator().GetConstantForIndexOperand(0));
+ Handle<BoilerplateDescription> constant_properties =
+ Handle<BoilerplateDescription>::cast(
+ bytecode_iterator().GetConstantForIndexOperand(0));
int literal_index = bytecode_iterator().GetIndexOperand(1);
int bytecode_flags = bytecode_iterator().GetFlagOperand(2);
int literal_flags =
interpreter::CreateObjectLiteralFlags::FlagsBits::decode(bytecode_flags);
- // TODO(mstarzinger): Thread through number of properties.
- int number_of_properties = constant_properties->length() / 2;
+ // TODO(mstarzinger): Thread through number of properties. The below number is
+ // only an estimate and does not match {ObjectLiteral::properties_count}.
+ int number_of_properties = constant_properties->size();
Node* literal = NewNode(
javascript()->CreateLiteralObject(constant_properties, literal_flags,
literal_index, number_of_properties),
@@ -1260,13 +1320,13 @@ void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode,
// Slot index of 0 is used indicate no feedback slot is available. Assert
// the assumption that slot index 0 is never a valid feedback slot.
- STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
+ STATIC_ASSERT(FeedbackVector::kReservedIndexCount > 0);
int const slot_id = bytecode_iterator().GetIndexOperand(3);
VectorSlotPair feedback = CreateVectorSlotPair(slot_id);
float const frequency = ComputeCallFrequency(slot_id);
- const Operator* call = javascript()->CallFunction(
- arg_count + 1, frequency, feedback, receiver_hint, tail_call_mode);
+ const Operator* call = javascript()->Call(arg_count + 1, frequency, feedback,
+ receiver_hint, tail_call_mode);
Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 1);
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
@@ -1275,6 +1335,19 @@ void BytecodeGraphBuilder::VisitCall() {
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kAny);
}
+void BytecodeGraphBuilder::VisitCallWithSpread() {
+ PrepareEagerCheckpoint();
+ Node* callee =
+ environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
+ interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
+ size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
+ const Operator* call =
+ javascript()->CallWithSpread(static_cast<int>(arg_count + 1));
+
+ Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 1);
+ environment()->BindAccumulator(value, Environment::kAttachFrameState);
+}
+
void BytecodeGraphBuilder::VisitCallProperty() {
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kNotNullOrUndefined);
}
@@ -1295,7 +1368,7 @@ void BytecodeGraphBuilder::VisitCallJSRuntime() {
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
// Create node to perform the JS runtime call.
- const Operator* call = javascript()->CallFunction(arg_count + 1);
+ const Operator* call = javascript()->Call(arg_count + 1);
Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 1);
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
@@ -1340,6 +1413,37 @@ void BytecodeGraphBuilder::VisitCallRuntimeForPair() {
Environment::kAttachFrameState);
}
+Node* BytecodeGraphBuilder::ProcessConstructWithSpreadArguments(
+ const Operator* op, Node* callee, Node* new_target,
+ interpreter::Register first_arg, size_t arity) {
+ Node** all = local_zone()->NewArray<Node*>(arity);
+ all[0] = 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));
+ }
+ all[arity - 1] = new_target;
+ Node* value = MakeNode(op, static_cast<int>(arity), all, false);
+ return value;
+}
+
+void BytecodeGraphBuilder::VisitConstructWithSpread() {
+ PrepareEagerCheckpoint();
+ interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0);
+ interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
+ size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
+
+ Node* new_target = environment()->LookupAccumulator();
+ Node* callee = environment()->LookupRegister(callee_reg);
+
+ const Operator* op =
+ javascript()->ConstructWithSpread(static_cast<int>(arg_count) + 2);
+ Node* value = ProcessConstructWithSpreadArguments(op, callee, new_target,
+ first_arg, arg_count + 2);
+ environment()->BindAccumulator(value, Environment::kAttachFrameState);
+}
+
void BytecodeGraphBuilder::VisitInvokeIntrinsic() {
PrepareEagerCheckpoint();
Runtime::FunctionId functionId = bytecode_iterator().GetIntrinsicIdOperand(0);
@@ -1353,7 +1457,7 @@ void BytecodeGraphBuilder::VisitInvokeIntrinsic() {
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
-Node* BytecodeGraphBuilder::ProcessCallNewArguments(
+Node* BytecodeGraphBuilder::ProcessConstructArguments(
const Operator* call_new_op, Node* callee, Node* new_target,
interpreter::Register first_arg, size_t arity) {
Node** all = local_zone()->NewArray<Node*>(arity);
@@ -1368,14 +1472,14 @@ Node* BytecodeGraphBuilder::ProcessCallNewArguments(
return value;
}
-void BytecodeGraphBuilder::VisitNew() {
+void BytecodeGraphBuilder::VisitConstruct() {
PrepareEagerCheckpoint();
interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0);
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
// Slot index of 0 is used indicate no feedback slot is available. Assert
// the assumption that slot index 0 is never a valid feedback slot.
- STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
+ STATIC_ASSERT(FeedbackVector::kReservedIndexCount > 0);
int const slot_id = bytecode_iterator().GetIndexOperand(3);
VectorSlotPair feedback = CreateVectorSlotPair(slot_id);
@@ -1383,24 +1487,18 @@ void BytecodeGraphBuilder::VisitNew() {
Node* callee = environment()->LookupRegister(callee_reg);
float const frequency = ComputeCallFrequency(slot_id);
- const Operator* call = javascript()->CallConstruct(
+ const Operator* call = javascript()->Construct(
static_cast<int>(arg_count) + 2, frequency, feedback);
- Node* value = ProcessCallNewArguments(call, callee, new_target, first_arg,
- arg_count + 2);
+ Node* value = ProcessConstructArguments(call, callee, new_target, first_arg,
+ arg_count + 2);
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
-void BytecodeGraphBuilder::BuildThrow() {
- PrepareEagerCheckpoint();
+void BytecodeGraphBuilder::VisitThrow() {
+ BuildLoopExitsForFunctionExit();
Node* value = environment()->LookupAccumulator();
Node* call = NewNode(javascript()->CallRuntime(Runtime::kThrow), value);
environment()->BindAccumulator(call, Environment::kAttachFrameState);
-}
-
-void BytecodeGraphBuilder::VisitThrow() {
- BuildLoopExitsForFunctionExit();
- BuildThrow();
- Node* call = environment()->LookupAccumulator();
Node* control = NewNode(common()->Throw(), call);
MergeControlToLeaveFunction(control);
}
@@ -1413,12 +1511,39 @@ void BytecodeGraphBuilder::VisitReThrow() {
MergeControlToLeaveFunction(control);
}
-void BytecodeGraphBuilder::BuildBinaryOp(const Operator* js_op) {
+Node* BytecodeGraphBuilder::TryBuildSimplifiedBinaryOp(const Operator* op,
+ Node* left, Node* right,
+ FeedbackSlot slot) {
+ Node* effect = environment()->GetEffectDependency();
+ Node* control = environment()->GetControlDependency();
+ JSTypeHintLowering type_hint_lowering(jsgraph(), feedback_vector());
+ Reduction early_reduction = type_hint_lowering.ReduceBinaryOperation(
+ op, left, right, effect, control, slot);
+ if (early_reduction.Changed()) {
+ Node* node = early_reduction.replacement();
+ if (node->op()->EffectOutputCount() > 0) {
+ environment()->UpdateEffectDependency(node);
+ }
+ return node;
+ }
+ return nullptr;
+}
+
+void BytecodeGraphBuilder::BuildBinaryOp(const Operator* op) {
PrepareEagerCheckpoint();
Node* left =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* right = environment()->LookupAccumulator();
- Node* node = NewNode(js_op, left, right);
+
+ Node* node = nullptr;
+ FeedbackSlot slot = feedback_vector()->ToSlot(
+ bytecode_iterator().GetIndexOperand(kBinaryOperationHintIndex));
+ if (Node* simplified = TryBuildSimplifiedBinaryOp(op, left, right, slot)) {
+ node = simplified;
+ } else {
+ node = NewNode(op, left, right);
+ }
+
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
@@ -1426,10 +1551,9 @@ void BytecodeGraphBuilder::BuildBinaryOp(const Operator* js_op) {
// feedback.
BinaryOperationHint BytecodeGraphBuilder::GetBinaryOperationHint(
int operand_index) {
- FeedbackVectorSlot slot = feedback_vector()->ToSlot(
+ FeedbackSlot slot = feedback_vector()->ToSlot(
bytecode_iterator().GetIndexOperand(operand_index));
- DCHECK_EQ(FeedbackVectorSlotKind::INTERPRETER_BINARYOP_IC,
- feedback_vector()->GetKind(slot));
+ DCHECK_EQ(FeedbackSlotKind::kBinaryOp, feedback_vector()->GetKind(slot));
BinaryOpICNexus nexus(feedback_vector(), slot);
return nexus.GetBinaryOperationFeedback();
}
@@ -1441,10 +1565,9 @@ CompareOperationHint BytecodeGraphBuilder::GetCompareOperationHint() {
if (slot_index == 0) {
return CompareOperationHint::kAny;
}
- FeedbackVectorSlot slot =
+ FeedbackSlot slot =
feedback_vector()->ToSlot(bytecode_iterator().GetIndexOperand(1));
- DCHECK_EQ(FeedbackVectorSlotKind::INTERPRETER_COMPARE_IC,
- feedback_vector()->GetKind(slot));
+ DCHECK_EQ(FeedbackSlotKind::kCompareOp, feedback_vector()->GetKind(slot));
CompareICNexus nexus(feedback_vector(), slot);
return nexus.GetCompareOperationFeedback();
}
@@ -1460,61 +1583,58 @@ void BytecodeGraphBuilder::VisitAdd() {
}
void BytecodeGraphBuilder::VisitSub() {
- BuildBinaryOp(javascript()->Subtract(
- GetBinaryOperationHint(kBinaryOperationHintIndex)));
+ BuildBinaryOp(javascript()->Subtract());
}
void BytecodeGraphBuilder::VisitMul() {
- BuildBinaryOp(javascript()->Multiply(
- GetBinaryOperationHint(kBinaryOperationHintIndex)));
+ BuildBinaryOp(javascript()->Multiply());
}
-void BytecodeGraphBuilder::VisitDiv() {
- BuildBinaryOp(
- javascript()->Divide(GetBinaryOperationHint(kBinaryOperationHintIndex)));
-}
+void BytecodeGraphBuilder::VisitDiv() { BuildBinaryOp(javascript()->Divide()); }
void BytecodeGraphBuilder::VisitMod() {
- BuildBinaryOp(
- javascript()->Modulus(GetBinaryOperationHint(kBinaryOperationHintIndex)));
+ BuildBinaryOp(javascript()->Modulus());
}
void BytecodeGraphBuilder::VisitBitwiseOr() {
- BuildBinaryOp(javascript()->BitwiseOr(
- GetBinaryOperationHint(kBinaryOperationHintIndex)));
+ BuildBinaryOp(javascript()->BitwiseOr());
}
void BytecodeGraphBuilder::VisitBitwiseXor() {
- BuildBinaryOp(javascript()->BitwiseXor(
- GetBinaryOperationHint(kBinaryOperationHintIndex)));
+ BuildBinaryOp(javascript()->BitwiseXor());
}
void BytecodeGraphBuilder::VisitBitwiseAnd() {
- BuildBinaryOp(javascript()->BitwiseAnd(
- GetBinaryOperationHint(kBinaryOperationHintIndex)));
+ BuildBinaryOp(javascript()->BitwiseAnd());
}
void BytecodeGraphBuilder::VisitShiftLeft() {
- BuildBinaryOp(javascript()->ShiftLeft(
- GetBinaryOperationHint(kBinaryOperationHintIndex)));
+ BuildBinaryOp(javascript()->ShiftLeft());
}
void BytecodeGraphBuilder::VisitShiftRight() {
- BuildBinaryOp(javascript()->ShiftRight(
- GetBinaryOperationHint(kBinaryOperationHintIndex)));
+ BuildBinaryOp(javascript()->ShiftRight());
}
void BytecodeGraphBuilder::VisitShiftRightLogical() {
- BuildBinaryOp(javascript()->ShiftRightLogical(
- GetBinaryOperationHint(kBinaryOperationHintIndex)));
+ BuildBinaryOp(javascript()->ShiftRightLogical());
}
-void BytecodeGraphBuilder::BuildBinaryOpWithImmediate(const Operator* js_op) {
+void BytecodeGraphBuilder::BuildBinaryOpWithImmediate(const Operator* op) {
PrepareEagerCheckpoint();
Node* left =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
Node* right = jsgraph()->Constant(bytecode_iterator().GetImmediateOperand(0));
- Node* node = NewNode(js_op, left, right);
+
+ Node* node = nullptr;
+ FeedbackSlot slot = feedback_vector()->ToSlot(
+ bytecode_iterator().GetIndexOperand(kBinaryOperationSmiHintIndex));
+ if (Node* simplified = TryBuildSimplifiedBinaryOp(op, left, right, slot)) {
+ node = simplified;
+ } else {
+ node = NewNode(op, left, right);
+ }
+
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
@@ -1524,62 +1644,73 @@ void BytecodeGraphBuilder::VisitAddSmi() {
}
void BytecodeGraphBuilder::VisitSubSmi() {
- BuildBinaryOpWithImmediate(javascript()->Subtract(
- GetBinaryOperationHint(kBinaryOperationSmiHintIndex)));
+ BuildBinaryOpWithImmediate(javascript()->Subtract());
}
void BytecodeGraphBuilder::VisitBitwiseOrSmi() {
- BuildBinaryOpWithImmediate(javascript()->BitwiseOr(
- GetBinaryOperationHint(kBinaryOperationSmiHintIndex)));
+ BuildBinaryOpWithImmediate(javascript()->BitwiseOr());
}
void BytecodeGraphBuilder::VisitBitwiseAndSmi() {
- BuildBinaryOpWithImmediate(javascript()->BitwiseAnd(
- GetBinaryOperationHint(kBinaryOperationSmiHintIndex)));
+ BuildBinaryOpWithImmediate(javascript()->BitwiseAnd());
}
void BytecodeGraphBuilder::VisitShiftLeftSmi() {
- BuildBinaryOpWithImmediate(javascript()->ShiftLeft(
- GetBinaryOperationHint(kBinaryOperationSmiHintIndex)));
+ BuildBinaryOpWithImmediate(javascript()->ShiftLeft());
}
void BytecodeGraphBuilder::VisitShiftRightSmi() {
- BuildBinaryOpWithImmediate(javascript()->ShiftRight(
- GetBinaryOperationHint(kBinaryOperationSmiHintIndex)));
+ BuildBinaryOpWithImmediate(javascript()->ShiftRight());
}
void BytecodeGraphBuilder::VisitInc() {
PrepareEagerCheckpoint();
// Note: Use subtract -1 here instead of add 1 to ensure we always convert to
// a number, not a string.
- const Operator* js_op =
- javascript()->Subtract(GetBinaryOperationHint(kCountOperationHintIndex));
- Node* node = NewNode(js_op, environment()->LookupAccumulator(),
- jsgraph()->Constant(-1));
+ Node* left = environment()->LookupAccumulator();
+ Node* right = jsgraph()->Constant(-1);
+ const Operator* op = javascript()->Subtract();
+
+ Node* node = nullptr;
+ FeedbackSlot slot = feedback_vector()->ToSlot(
+ bytecode_iterator().GetIndexOperand(kCountOperationHintIndex));
+ if (Node* simplified = TryBuildSimplifiedBinaryOp(op, left, right, slot)) {
+ node = simplified;
+ } else {
+ node = NewNode(op, left, right);
+ }
+
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitDec() {
PrepareEagerCheckpoint();
- const Operator* js_op =
- javascript()->Subtract(GetBinaryOperationHint(kCountOperationHintIndex));
- Node* node = NewNode(js_op, environment()->LookupAccumulator(),
- jsgraph()->OneConstant());
+ Node* left = environment()->LookupAccumulator();
+ Node* right = jsgraph()->OneConstant();
+ const Operator* op = javascript()->Subtract();
+
+ Node* node = nullptr;
+ FeedbackSlot slot = feedback_vector()->ToSlot(
+ bytecode_iterator().GetIndexOperand(kCountOperationHintIndex));
+ if (Node* simplified = TryBuildSimplifiedBinaryOp(op, left, right, slot)) {
+ node = simplified;
+ } else {
+ node = NewNode(op, left, right);
+ }
+
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitLogicalNot() {
Node* value = environment()->LookupAccumulator();
- Node* node = NewNode(common()->Select(MachineRepresentation::kTagged), value,
- jsgraph()->FalseConstant(), jsgraph()->TrueConstant());
+ Node* node = NewNode(simplified()->BooleanNot(), value);
environment()->BindAccumulator(node);
}
void BytecodeGraphBuilder::VisitToBooleanLogicalNot() {
Node* value = NewNode(javascript()->ToBoolean(ToBooleanHint::kAny),
environment()->LookupAccumulator());
- Node* node = NewNode(common()->Select(MachineRepresentation::kTagged), value,
- jsgraph()->FalseConstant(), jsgraph()->TrueConstant());
+ Node* node = NewNode(simplified()->BooleanNot(), value);
environment()->BindAccumulator(node);
}
@@ -1607,6 +1738,13 @@ void BytecodeGraphBuilder::VisitDeletePropertySloppy() {
BuildDelete(LanguageMode::SLOPPY);
}
+void BytecodeGraphBuilder::VisitGetSuperConstructor() {
+ Node* node = NewNode(javascript()->GetSuperConstructor(),
+ environment()->LookupAccumulator());
+ environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0), node,
+ Environment::kAttachFrameState);
+}
+
void BytecodeGraphBuilder::BuildCompareOp(const Operator* js_op) {
PrepareEagerCheckpoint();
Node* left =
@@ -1652,8 +1790,30 @@ void BytecodeGraphBuilder::VisitTestInstanceOf() {
BuildCompareOp(javascript()->InstanceOf());
}
+void BytecodeGraphBuilder::VisitTestUndetectable() {
+ Node* object =
+ environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
+ Node* node = NewNode(jsgraph()->simplified()->ObjectIsUndetectable(), object);
+ environment()->BindAccumulator(node);
+}
+
+void BytecodeGraphBuilder::VisitTestNull() {
+ Node* object =
+ environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
+ Node* result = NewNode(simplified()->ReferenceEqual(), object,
+ jsgraph()->NullConstant());
+ environment()->BindAccumulator(result);
+}
+
+void BytecodeGraphBuilder::VisitTestUndefined() {
+ Node* object =
+ environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
+ Node* result = NewNode(simplified()->ReferenceEqual(), object,
+ jsgraph()->UndefinedConstant());
+ environment()->BindAccumulator(result);
+}
+
void BytecodeGraphBuilder::BuildCastOperator(const Operator* js_op) {
- PrepareEagerCheckpoint();
Node* value = NewNode(js_op, environment()->LookupAccumulator());
environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0), value,
Environment::kAttachFrameState);
@@ -1705,6 +1865,12 @@ void BytecodeGraphBuilder::VisitJumpIfNotHoleConstant() {
BuildJumpIfNotHole();
}
+void BytecodeGraphBuilder::VisitJumpIfJSReceiver() { BuildJumpIfJSReceiver(); }
+
+void BytecodeGraphBuilder::VisitJumpIfJSReceiverConstant() {
+ BuildJumpIfJSReceiver();
+}
+
void BytecodeGraphBuilder::VisitJumpIfNull() {
BuildJumpIfEqual(jsgraph()->NullConstant());
}
@@ -1729,6 +1895,12 @@ void BytecodeGraphBuilder::VisitStackCheck() {
environment()->RecordAfterState(node, Environment::kAttachFrameState);
}
+void BytecodeGraphBuilder::VisitSetPendingMessage() {
+ Node* previous_message = NewNode(javascript()->LoadMessage());
+ NewNode(javascript()->StoreMessage(), environment()->LookupAccumulator());
+ environment()->BindAccumulator(previous_message);
+}
+
void BytecodeGraphBuilder::VisitReturn() {
BuildLoopExitsForFunctionExit();
Node* pop_node = jsgraph()->ZeroConstant();
@@ -1739,10 +1911,8 @@ void BytecodeGraphBuilder::VisitReturn() {
void BytecodeGraphBuilder::VisitDebugger() {
PrepareEagerCheckpoint();
- Node* call =
- NewNode(javascript()->CallRuntime(Runtime::kHandleDebuggerStatement));
- environment()->BindAccumulator(call, Environment::kAttachFrameState);
- environment()->MarkAllRegistersLive();
+ Node* call = NewNode(javascript()->Debugger());
+ environment()->RecordAfterState(call, Environment::kAttachFrameState);
}
// We cannot create a graph from the debugger copy of the bytecode array.
@@ -1798,8 +1968,9 @@ void BytecodeGraphBuilder::VisitForInStep() {
PrepareEagerCheckpoint();
Node* index =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
- index = NewNode(javascript()->Add(BinaryOperationHint::kSignedSmall), index,
- jsgraph()->OneConstant());
+ index = NewNode(
+ simplified()->SpeculativeNumberAdd(NumberOperationHint::kSignedSmall),
+ index, jsgraph()->OneConstant());
environment()->BindAccumulator(index, Environment::kAttachFrameState);
}
@@ -1866,33 +2037,45 @@ void BytecodeGraphBuilder::VisitIllegal() {
void BytecodeGraphBuilder::VisitNop() {}
void BytecodeGraphBuilder::SwitchToMergeEnvironment(int current_offset) {
- if (merge_environments_[current_offset] != nullptr) {
+ auto it = merge_environments_.find(current_offset);
+ if (it != merge_environments_.end()) {
+ mark_as_needing_eager_checkpoint(true);
if (environment() != nullptr) {
- merge_environments_[current_offset]->Merge(environment());
+ it->second->Merge(environment());
}
- set_environment(merge_environments_[current_offset]);
+ set_environment(it->second);
}
}
void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) {
- if (branch_analysis()->backward_branches_target(current_offset)) {
- // Add loop header and store a copy so we can connect merged back
- // edge inputs to the loop header.
- merge_environments_[current_offset] = environment()->CopyForLoop();
+ if (bytecode_analysis()->IsLoopHeader(current_offset)) {
+ mark_as_needing_eager_checkpoint(true);
+ const LoopInfo& loop_info =
+ bytecode_analysis()->GetLoopInfoFor(current_offset);
+
+ // Add loop header.
+ environment()->PrepareForLoop(loop_info.assignments());
+
+ BuildOSRLoopEntryPoint(current_offset);
+
+ // Store a copy of the environment so we can connect merged back edge inputs
+ // to the loop header.
+ merge_environments_[current_offset] = environment()->Copy();
}
}
void BytecodeGraphBuilder::MergeIntoSuccessorEnvironment(int target_offset) {
BuildLoopExitsForBranch(target_offset);
- if (merge_environments_[target_offset] == nullptr) {
+ Environment*& merge_environment = merge_environments_[target_offset];
+ if (merge_environment == nullptr) {
// Append merge nodes to the environment. We may merge here with another
// environment. So add a place holder for merge nodes. We may add redundant
// but will be eliminated in a later pass.
// TODO(mstarzinger): Be smarter about this!
NewMerge();
- merge_environments_[target_offset] = environment();
+ merge_environment = environment();
} else {
- merge_environments_[target_offset]->Merge(environment());
+ merge_environment->Merge(environment());
}
set_environment(nullptr);
}
@@ -1903,13 +2086,14 @@ void BytecodeGraphBuilder::MergeControlToLeaveFunction(Node* exit) {
}
void BytecodeGraphBuilder::BuildOSRLoopEntryPoint(int current_offset) {
- if (!osr_ast_id_.IsNone() && osr_ast_id_.ToInt() == current_offset) {
+ DCHECK(bytecode_analysis()->IsLoopHeader(current_offset));
+
+ if (!osr_ast_id_.IsNone() && osr_loop_offset_ == current_offset) {
// For OSR add a special {OsrLoopEntry} node into the current loop header.
// It will be turned into a usable entry by the OSR deconstruction.
- Environment* loop_env = merge_environments_[current_offset];
- Environment* osr_env = loop_env->CopyForOsrEntry();
+ Environment* osr_env = environment()->Copy();
osr_env->PrepareForOsrEntry();
- loop_env->Merge(osr_env);
+ environment()->Merge(osr_env);
}
}
@@ -1918,9 +2102,11 @@ void BytecodeGraphBuilder::BuildOSRNormalEntryPoint() {
// For OSR add an {OsrNormalEntry} as the the top-level environment start.
// It will be replaced with {Dead} by the OSR deconstruction.
NewNode(common()->OsrNormalEntry());
- // Note that the requested OSR entry point must be the target of a backward
- // branch, otherwise there will not be a proper loop header available.
- DCHECK(branch_analysis()->backward_branches_target(osr_ast_id_.ToInt()));
+ // Translate the offset of the jump instruction to the jump target offset of
+ // that instruction so that the derived BailoutId points to the loop header.
+ osr_loop_offset_ =
+ bytecode_analysis()->GetLoopOffsetFor(osr_ast_id_.ToInt());
+ DCHECK(bytecode_analysis()->IsLoopHeader(osr_loop_offset_));
}
}
@@ -1928,17 +2114,20 @@ void BytecodeGraphBuilder::BuildLoopExitsForBranch(int target_offset) {
int origin_offset = bytecode_iterator().current_offset();
// Only build loop exits for forward edges.
if (target_offset > origin_offset) {
- BuildLoopExitsUntilLoop(loop_analysis()->GetLoopOffsetFor(target_offset));
+ BuildLoopExitsUntilLoop(
+ bytecode_analysis()->GetLoopOffsetFor(target_offset));
}
}
void BytecodeGraphBuilder::BuildLoopExitsUntilLoop(int loop_offset) {
int origin_offset = bytecode_iterator().current_offset();
- int current_loop = loop_analysis()->GetLoopOffsetFor(origin_offset);
+ int current_loop = bytecode_analysis()->GetLoopOffsetFor(origin_offset);
while (loop_offset < current_loop) {
Node* loop_node = merge_environments_[current_loop]->GetControlDependency();
- environment()->PrepareForLoopExit(loop_node);
- current_loop = loop_analysis()->GetParentLoopFor(current_loop);
+ const LoopInfo& loop_info =
+ bytecode_analysis()->GetLoopInfoFor(current_loop);
+ environment()->PrepareForLoopExit(loop_node, loop_info.assignments());
+ current_loop = loop_info.parent_offset();
}
}
@@ -1952,7 +2141,7 @@ void BytecodeGraphBuilder::BuildJump() {
void BytecodeGraphBuilder::BuildJumpIf(Node* condition) {
NewBranch(condition);
- Environment* if_false_environment = environment()->CopyForConditional();
+ Environment* if_false_environment = environment()->Copy();
NewIfTrue();
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
set_environment(if_false_environment);
@@ -1961,7 +2150,7 @@ void BytecodeGraphBuilder::BuildJumpIf(Node* condition) {
void BytecodeGraphBuilder::BuildJumpIfNot(Node* condition) {
NewBranch(condition);
- Environment* if_true_environment = environment()->CopyForConditional();
+ Environment* if_true_environment = environment()->Copy();
NewIfFalse();
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
set_environment(if_true_environment);
@@ -1971,17 +2160,30 @@ void BytecodeGraphBuilder::BuildJumpIfNot(Node* condition) {
void BytecodeGraphBuilder::BuildJumpIfEqual(Node* comperand) {
Node* accumulator = environment()->LookupAccumulator();
Node* condition =
- NewNode(javascript()->StrictEqual(CompareOperationHint::kAny),
- accumulator, comperand);
+ NewNode(simplified()->ReferenceEqual(), accumulator, comperand);
BuildJumpIf(condition);
}
void BytecodeGraphBuilder::BuildJumpIfFalse() {
- BuildJumpIfNot(environment()->LookupAccumulator());
+ NewBranch(environment()->LookupAccumulator());
+ Environment* if_true_environment = environment()->Copy();
+ environment()->BindAccumulator(jsgraph()->FalseConstant());
+ NewIfFalse();
+ MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
+ if_true_environment->BindAccumulator(jsgraph()->TrueConstant());
+ set_environment(if_true_environment);
+ NewIfTrue();
}
void BytecodeGraphBuilder::BuildJumpIfTrue() {
- BuildJumpIf(environment()->LookupAccumulator());
+ NewBranch(environment()->LookupAccumulator());
+ Environment* if_false_environment = environment()->Copy();
+ environment()->BindAccumulator(jsgraph()->TrueConstant());
+ NewIfTrue();
+ MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
+ if_false_environment->BindAccumulator(jsgraph()->FalseConstant());
+ set_environment(if_false_environment);
+ NewIfFalse();
}
void BytecodeGraphBuilder::BuildJumpIfToBooleanTrue() {
@@ -2000,12 +2202,17 @@ void BytecodeGraphBuilder::BuildJumpIfToBooleanFalse() {
void BytecodeGraphBuilder::BuildJumpIfNotHole() {
Node* accumulator = environment()->LookupAccumulator();
- Node* condition =
- NewNode(javascript()->StrictEqual(CompareOperationHint::kAny),
- accumulator, jsgraph()->TheHoleConstant());
+ Node* condition = NewNode(simplified()->ReferenceEqual(), accumulator,
+ jsgraph()->TheHoleConstant());
BuildJumpIfNot(condition);
}
+void BytecodeGraphBuilder::BuildJumpIfJSReceiver() {
+ Node* accumulator = environment()->LookupAccumulator();
+ Node* condition = NewNode(simplified()->ObjectIsReceiver(), accumulator);
+ BuildJumpIf(condition);
+}
+
Node** BytecodeGraphBuilder::EnsureInputBufferSize(int size) {
if (size > input_buffer_size_) {
size = size + kInputBufferSizeIncrement + input_buffer_size_;
@@ -2093,7 +2300,7 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
int handler_offset = exception_handlers_.top().handler_offset_;
int context_index = exception_handlers_.top().context_register_;
interpreter::Register context_register(context_index);
- Environment* success_env = environment()->CopyForConditional();
+ Environment* success_env = environment()->Copy();
const Operator* op = common()->IfException();
Node* effect = environment()->GetEffectDependency();
Node* on_exception = graph()->NewNode(op, effect, result);
@@ -2111,6 +2318,10 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
Node* on_success = graph()->NewNode(if_success, result);
environment()->UpdateControlDependency(on_success);
}
+ // Ensure checkpoints are created after operations with side-effects.
+ if (has_effect && !result->op()->HasProperty(Operator::kNoWrite)) {
+ mark_as_needing_eager_checkpoint(true);
+ }
}
return result;