Commit 3e73ce49 authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[turbofan] Desugar lookup slot optimization in graph builder.

This moves the optimization for variables loads targeting lookup slots
in DYNAMIC_GLOBAL and DYNAMIC_LOCAL mode into the AstGraphBuilder. This
way we implicitly get all optimizations that target global loads and
context loads for free.

R=bmeurer@chromium.org
BUG=v8:4513
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#31713}
parent 5f4611bc
......@@ -3062,6 +3062,17 @@ VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(
}
namespace {
// Limit of context chain length to which inline check is possible.
const int kMaxCheckDepth = 30;
// Sentinel for {TryLoadDynamicVariable} disabling inline checks.
const uint32_t kFullCheckRequired = -1;
} // namespace
uint32_t AstGraphBuilder::ComputeBitsetForDynamicGlobal(Variable* variable) {
DCHECK_EQ(DYNAMIC_GLOBAL, variable->mode());
bool found_eval_scope = false;
......@@ -3074,9 +3085,7 @@ uint32_t AstGraphBuilder::ComputeBitsetForDynamicGlobal(Variable* variable) {
if (s->is_eval_scope()) found_eval_scope = true;
if (!s->calls_sloppy_eval() && !found_eval_scope) continue;
int depth = current_scope()->ContextChainLength(s);
if (depth > DynamicGlobalAccess::kMaxCheckDepth) {
return DynamicGlobalAccess::kFullCheckRequired;
}
if (depth > kMaxCheckDepth) return kFullCheckRequired;
check_depths |= 1 << depth;
}
return check_depths;
......@@ -3090,9 +3099,7 @@ uint32_t AstGraphBuilder::ComputeBitsetForDynamicContext(Variable* variable) {
if (s->num_heap_slots() <= 0) continue;
if (!s->calls_sloppy_eval() && s != variable->scope()) continue;
int depth = current_scope()->ContextChainLength(s);
if (depth > DynamicContextAccess::kMaxCheckDepth) {
return DynamicContextAccess::kFullCheckRequired;
}
if (depth > kMaxCheckDepth) return kFullCheckRequired;
check_depths |= 1 << depth;
if (s == variable->scope()) break;
}
......@@ -3380,40 +3387,15 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
}
case VariableLocation::LOOKUP: {
// Dynamic lookup of context variable (anywhere in the chain).
Node* value = jsgraph()->TheHoleConstant();
Handle<String> name = variable->name();
if (mode == DYNAMIC_GLOBAL) {
uint32_t check_bitset = ComputeBitsetForDynamicGlobal(variable);
const Operator* op = javascript()->LoadDynamicGlobal(
name, check_bitset, feedback, typeof_mode);
value = NewNode(op, BuildLoadFeedbackVector(), current_context());
states.AddToNode(value, bailout_id, combine);
} else if (mode == DYNAMIC_LOCAL) {
Variable* local = variable->local_if_not_shadowed();
DCHECK(local->location() ==
VariableLocation::CONTEXT); // Must be context.
int depth = current_scope()->ContextChainLength(local->scope());
uint32_t check_bitset = ComputeBitsetForDynamicContext(variable);
const Operator* op = javascript()->LoadDynamicContext(
name, check_bitset, depth, local->index());
value = NewNode(op, current_context());
PrepareFrameState(value, bailout_id, combine);
VariableMode local_mode = local->mode();
if (local_mode == CONST_LEGACY) {
// Perform check for uninitialized legacy const variables.
Node* undefined = jsgraph()->UndefinedConstant();
value = BuildHoleCheckSilent(value, undefined, value);
} else if (local_mode == LET || local_mode == CONST) {
// Perform check for uninitialized let/const variables.
value = BuildHoleCheckThenThrow(value, local, value, bailout_id);
}
} else if (mode == DYNAMIC) {
uint32_t check_bitset = DynamicGlobalAccess::kFullCheckRequired;
const Operator* op = javascript()->LoadDynamicGlobal(
name, check_bitset, feedback, typeof_mode);
value = NewNode(op, BuildLoadFeedbackVector(), current_context());
states.AddToNode(value, bailout_id, combine);
if (Node* node =
TryLoadDynamicVariable(variable, name, bailout_id, states,
feedback, combine, typeof_mode)) {
return node;
}
const Operator* op = javascript()->LoadDynamic(name, typeof_mode);
Node* value = NewNode(op, BuildLoadFeedbackVector(), current_context());
states.AddToNode(value, bailout_id, combine);
return value;
}
}
......@@ -3907,6 +3889,102 @@ Node* AstGraphBuilder::TryLoadGlobalConstant(Handle<Name> name) {
}
Node* AstGraphBuilder::TryLoadDynamicVariable(
Variable* variable, Handle<String> name, BailoutId bailout_id,
FrameStateBeforeAndAfter& states, const VectorSlotPair& feedback,
OutputFrameStateCombine combine, TypeofMode typeof_mode) {
VariableMode mode = variable->mode();
if (mode == DYNAMIC_GLOBAL) {
uint32_t bitset = ComputeBitsetForDynamicGlobal(variable);
if (bitset == kFullCheckRequired) return nullptr;
// We are using two blocks to model fast and slow cases.
BlockBuilder fast_block(this);
BlockBuilder slow_block(this);
environment()->Push(jsgraph()->TheHoleConstant());
slow_block.BeginBlock();
environment()->Pop();
fast_block.BeginBlock();
// Perform checks whether the fast mode applies, by looking for any
// extension object which might shadow the optimistic declaration.
for (int depth = 0; bitset != 0; bitset >>= 1, depth++) {
if ((bitset & 1) == 0) continue;
Node* load = NewNode(
javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false),
current_context());
Node* check =
NewNode(javascript()->CallRuntime(Runtime::kInlineIsSmi, 1), load);
fast_block.BreakUnless(check, BranchHint::kTrue);
}
// Fast case, because variable is not shadowed. Perform global slot load.
Node* fast = BuildGlobalLoad(name, feedback, typeof_mode);
states.AddToNode(fast, bailout_id, combine);
environment()->Push(fast);
slow_block.Break();
environment()->Pop();
fast_block.EndBlock();
// Slow case, because variable potentially shadowed. Perform dynamic lookup.
const Operator* op = javascript()->LoadDynamic(name, typeof_mode);
Node* slow = NewNode(op, BuildLoadFeedbackVector(), current_context());
states.AddToNode(slow, bailout_id, combine);
environment()->Push(slow);
slow_block.EndBlock();
return environment()->Pop();
}
if (mode == DYNAMIC_LOCAL) {
uint32_t bitset = ComputeBitsetForDynamicContext(variable);
if (bitset == kFullCheckRequired) return nullptr;
// We are using two blocks to model fast and slow cases.
BlockBuilder fast_block(this);
BlockBuilder slow_block(this);
environment()->Push(jsgraph()->TheHoleConstant());
slow_block.BeginBlock();
environment()->Pop();
fast_block.BeginBlock();
// Perform checks whether the fast mode applies, by looking for any
// extension object which might shadow the optimistic declaration.
for (int depth = 0; bitset != 0; bitset >>= 1, depth++) {
if ((bitset & 1) == 0) continue;
Node* load = NewNode(
javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false),
current_context());
Node* check =
NewNode(javascript()->CallRuntime(Runtime::kInlineIsSmi, 1), load);
fast_block.BreakUnless(check, BranchHint::kTrue);
}
// Fast case, because variable is not shadowed. Perform context slot load.
Variable* local = variable->local_if_not_shadowed();
DCHECK(local->location() == VariableLocation::CONTEXT); // Must be context.
Node* fast = BuildVariableLoad(local, bailout_id, states, feedback, combine,
typeof_mode);
environment()->Push(fast);
slow_block.Break();
environment()->Pop();
fast_block.EndBlock();
// Slow case, because variable potentially shadowed. Perform dynamic lookup.
const Operator* op = javascript()->LoadDynamic(name, typeof_mode);
Node* slow = NewNode(op, BuildLoadFeedbackVector(), current_context());
states.AddToNode(slow, bailout_id, combine);
environment()->Push(slow);
slow_block.EndBlock();
return environment()->Pop();
}
return nullptr;
}
Node* AstGraphBuilder::TryFastToBoolean(Node* input) {
switch (input->opcode()) {
case IrOpcode::kNumberConstant: {
......
......@@ -363,6 +363,15 @@ class AstGraphBuilder : public AstVisitor {
// Optimization for variable load from global object.
Node* TryLoadGlobalConstant(Handle<Name> name);
// Optimization for variable load of dynamic lookup slot that is most likely
// to resolve to a global slot or context slot (inferred from scope chain).
Node* TryLoadDynamicVariable(Variable* variable, Handle<String> name,
BailoutId bailout_id,
FrameStateBeforeAndAfter& states,
const VectorSlotPair& feedback,
OutputFrameStateCombine combine,
TypeofMode typeof_mode);
// Optimizations for automatic type conversion.
Node* TryFastToBoolean(Node* input);
Node* TryFastToName(Node* input);
......
......@@ -153,6 +153,16 @@ void BlockBuilder::BreakWhen(Node* condition, BranchHint hint) {
}
void BlockBuilder::BreakUnless(Node* condition, BranchHint hint) {
IfBuilder control_if(builder_);
control_if.If(condition, hint);
control_if.Then();
control_if.Else();
Break();
control_if.End();
}
void BlockBuilder::EndBlock() {
break_environment_->Merge(environment());
set_environment(break_environment_);
......
......@@ -133,6 +133,7 @@ class BlockBuilder final : public ControlBuilder {
// Compound control commands for conditional break.
void BreakWhen(Node* condition, BranchHint = BranchHint::kNone);
void BreakUnless(Node* condition, BranchHint hint = BranchHint::kNone);
private:
Environment* break_environment_; // Environment after the block exits.
......
......@@ -441,15 +441,14 @@ void JSGenericLowering::LowerJSStoreContext(Node* node) {
}
void JSGenericLowering::LowerJSLoadDynamicGlobal(Node* node) {
const DynamicGlobalAccess& access = DynamicGlobalAccessOf(node->op());
void JSGenericLowering::LowerJSLoadDynamic(Node* node) {
const DynamicAccess& access = DynamicAccessOf(node->op());
Runtime::FunctionId function_id =
(access.typeof_mode() == NOT_INSIDE_TYPEOF)
? Runtime::kLoadLookupSlot
: Runtime::kLoadLookupSlotNoReferenceError;
Node* projection = graph()->NewNode(common()->Projection(0), node);
NodeProperties::ReplaceUses(node, projection, node, node, node);
node->RemoveInput(NodeProperties::FirstFrameStateIndex(node) + 1);
node->RemoveInput(NodeProperties::FirstValueIndex(node));
node->InsertInput(zone(), 1, jsgraph()->Constant(access.name()));
ReplaceWithRuntimeCall(node, function_id);
......@@ -457,16 +456,6 @@ void JSGenericLowering::LowerJSLoadDynamicGlobal(Node* node) {
}
void JSGenericLowering::LowerJSLoadDynamicContext(Node* node) {
const DynamicContextAccess& access = DynamicContextAccessOf(node->op());
Node* projection = graph()->NewNode(common()->Projection(0), node);
NodeProperties::ReplaceUses(node, projection, node, node, node);
node->InsertInput(zone(), 1, jsgraph()->Constant(access.name()));
ReplaceWithRuntimeCall(node, Runtime::kLoadLookupSlot);
projection->ReplaceInput(0, node);
}
void JSGenericLowering::LowerJSCreate(Node* node) { UNIMPLEMENTED(); }
......
......@@ -146,87 +146,35 @@ ContextAccess const& ContextAccessOf(Operator const* op) {
}
DynamicGlobalAccess::DynamicGlobalAccess(const Handle<String>& name,
uint32_t check_bitset,
const VectorSlotPair& feedback,
TypeofMode typeof_mode)
: name_(name),
check_bitset_(check_bitset),
feedback_(feedback),
typeof_mode_(typeof_mode) {
DCHECK(check_bitset == kFullCheckRequired || check_bitset < 0x80000000U);
}
bool operator==(DynamicGlobalAccess const& lhs,
DynamicGlobalAccess const& rhs) {
UNIMPLEMENTED();
return true;
}
bool operator!=(DynamicGlobalAccess const& lhs,
DynamicGlobalAccess const& rhs) {
return !(lhs == rhs);
}
size_t hash_value(DynamicGlobalAccess const& access) {
UNIMPLEMENTED();
return 0;
}
std::ostream& operator<<(std::ostream& os, DynamicGlobalAccess const& access) {
return os << Brief(*access.name()) << ", " << access.check_bitset() << ", "
<< access.typeof_mode();
}
DynamicGlobalAccess const& DynamicGlobalAccessOf(Operator const* op) {
DCHECK_EQ(IrOpcode::kJSLoadDynamicGlobal, op->opcode());
return OpParameter<DynamicGlobalAccess>(op);
}
DynamicAccess::DynamicAccess(const Handle<String>& name, TypeofMode typeof_mode)
: name_(name), typeof_mode_(typeof_mode) {}
DynamicContextAccess::DynamicContextAccess(const Handle<String>& name,
uint32_t check_bitset,
const ContextAccess& context_access)
: name_(name),
check_bitset_(check_bitset),
context_access_(context_access) {
DCHECK(check_bitset == kFullCheckRequired || check_bitset < 0x80000000U);
}
bool operator==(DynamicContextAccess const& lhs,
DynamicContextAccess const& rhs) {
bool operator==(DynamicAccess const& lhs, DynamicAccess const& rhs) {
UNIMPLEMENTED();
return true;
}
bool operator!=(DynamicContextAccess const& lhs,
DynamicContextAccess const& rhs) {
bool operator!=(DynamicAccess const& lhs, DynamicAccess const& rhs) {
return !(lhs == rhs);
}
size_t hash_value(DynamicContextAccess const& access) {
size_t hash_value(DynamicAccess const& access) {
UNIMPLEMENTED();
return 0;
}
std::ostream& operator<<(std::ostream& os, DynamicContextAccess const& access) {
return os << Brief(*access.name()) << ", " << access.check_bitset() << ", "
<< access.context_access();
std::ostream& operator<<(std::ostream& os, DynamicAccess const& access) {
return os << Brief(*access.name()) << ", " << access.typeof_mode();
}
DynamicContextAccess const& DynamicContextAccessOf(Operator const* op) {
DCHECK_EQ(IrOpcode::kJSLoadDynamicContext, op->opcode());
return OpParameter<DynamicContextAccess>(op);
DynamicAccess const& DynamicAccessOf(Operator const* op) {
DCHECK_EQ(IrOpcode::kJSLoadDynamic, op->opcode());
return OpParameter<DynamicAccess>(op);
}
......@@ -669,28 +617,14 @@ const Operator* JSOperatorBuilder::StoreContext(size_t depth, size_t index) {
}
const Operator* JSOperatorBuilder::LoadDynamicGlobal(
const Handle<String>& name, uint32_t check_bitset,
const VectorSlotPair& feedback, TypeofMode typeof_mode) {
DynamicGlobalAccess access(name, check_bitset, feedback, typeof_mode);
return new (zone()) Operator1<DynamicGlobalAccess>( // --
IrOpcode::kJSLoadDynamicGlobal, Operator::kNoProperties, // opcode
"JSLoadDynamicGlobal", // name
2, 1, 1, 1, 1, 2, // counts
access); // parameter
}
const Operator* JSOperatorBuilder::LoadDynamicContext(
const Handle<String>& name, uint32_t check_bitset, size_t depth,
size_t index) {
ContextAccess context_access(depth, index, false);
DynamicContextAccess access(name, check_bitset, context_access);
return new (zone()) Operator1<DynamicContextAccess>( // --
IrOpcode::kJSLoadDynamicContext, Operator::kNoProperties, // opcode
"JSLoadDynamicContext", // name
1, 1, 1, 1, 1, 2, // counts
access); // parameter
const Operator* JSOperatorBuilder::LoadDynamic(const Handle<String>& name,
TypeofMode typeof_mode) {
DynamicAccess access(name, typeof_mode);
return new (zone()) Operator1<DynamicAccess>( // --
IrOpcode::kJSLoadDynamic, Operator::kNoProperties, // opcode
"JSLoadDynamic", // name
2, 1, 1, 1, 1, 2, // counts
access); // parameter
}
......
......@@ -172,84 +172,28 @@ std::ostream& operator<<(std::ostream&, ContextAccess const&);
ContextAccess const& ContextAccessOf(Operator const*);
// Defines the name for a dynamic variable lookup. The {check_bitset} allows to
// inline checks whether the lookup yields in a global variable. This is used as
// a parameter by JSLoadDynamicGlobal and JSStoreDynamicGlobal operators.
class DynamicGlobalAccess final {
// Defines the name for a dynamic variable lookup. This is used as a parameter
// by JSLoadDynamic and JSStoreDynamic operators.
class DynamicAccess final {
public:
DynamicGlobalAccess(const Handle<String>& name, uint32_t check_bitset,
const VectorSlotPair& feedback, TypeofMode typeof_mode);
DynamicAccess(const Handle<String>& name, TypeofMode typeof_mode);
const Handle<String>& name() const { return name_; }
uint32_t check_bitset() const { return check_bitset_; }
const VectorSlotPair& feedback() const { return feedback_; }
TypeofMode typeof_mode() const { return typeof_mode_; }
// Indicates that an inline check is disabled.
bool RequiresFullCheck() const {
return check_bitset() == kFullCheckRequired;
}
// Limit of context chain length to which inline check is possible.
static const int kMaxCheckDepth = 30;
// Sentinel for {check_bitset} disabling inline checks.
static const uint32_t kFullCheckRequired = -1;
private:
const Handle<String> name_;
const uint32_t check_bitset_;
const VectorSlotPair feedback_;
const TypeofMode typeof_mode_;
};
size_t hash_value(DynamicGlobalAccess const&);
bool operator==(DynamicGlobalAccess const&, DynamicGlobalAccess const&);
bool operator!=(DynamicGlobalAccess const&, DynamicGlobalAccess const&);
std::ostream& operator<<(std::ostream&, DynamicGlobalAccess const&);
DynamicGlobalAccess const& DynamicGlobalAccessOf(Operator const*);
// Defines the name for a dynamic variable lookup. The {check_bitset} allows to
// inline checks whether the lookup yields in a context variable. This is used
// as a parameter by JSLoadDynamicContext and JSStoreDynamicContext operators.
class DynamicContextAccess final {
public:
DynamicContextAccess(const Handle<String>& name, uint32_t check_bitset,
const ContextAccess& context_access);
const Handle<String>& name() const { return name_; }
uint32_t check_bitset() const { return check_bitset_; }
const ContextAccess& context_access() const { return context_access_; }
// Indicates that an inline check is disabled.
bool RequiresFullCheck() const {
return check_bitset() == kFullCheckRequired;
}
// Limit of context chain length to which inline check is possible.
static const int kMaxCheckDepth = 30;
// Sentinel for {check_bitset} disabling inline checks.
static const uint32_t kFullCheckRequired = -1;
private:
const Handle<String> name_;
const uint32_t check_bitset_;
const ContextAccess context_access_;
};
size_t hash_value(DynamicContextAccess const&);
size_t hash_value(DynamicAccess const&);
bool operator==(DynamicContextAccess const&, DynamicContextAccess const&);
bool operator!=(DynamicContextAccess const&, DynamicContextAccess const&);
bool operator==(DynamicAccess const&, DynamicAccess const&);
bool operator!=(DynamicAccess const&, DynamicAccess const&);
std::ostream& operator<<(std::ostream&, DynamicContextAccess const&);
std::ostream& operator<<(std::ostream&, DynamicAccess const&);
DynamicContextAccess const& DynamicContextAccessOf(Operator const*);
DynamicAccess const& DynamicAccessOf(Operator const*);
// Defines the property of an object for a named access. This is
......@@ -495,13 +439,8 @@ class JSOperatorBuilder final : public ZoneObject {
const Operator* LoadContext(size_t depth, size_t index, bool immutable);
const Operator* StoreContext(size_t depth, size_t index);
const Operator* LoadDynamicGlobal(const Handle<String>& name,
uint32_t check_bitset,
const VectorSlotPair& feedback,
TypeofMode typeof_mode);
const Operator* LoadDynamicContext(const Handle<String>& name,
uint32_t check_bitset, size_t depth,
size_t index);
const Operator* LoadDynamic(const Handle<String>& name,
TypeofMode typeof_mode);
const Operator* TypeOf();
const Operator* InstanceOf();
......
......@@ -1110,122 +1110,6 @@ Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
}
Reduction JSTypedLowering::ReduceJSLoadDynamicGlobal(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadDynamicGlobal, node->opcode());
DynamicGlobalAccess const& access = DynamicGlobalAccessOf(node->op());
Node* const vector = NodeProperties::GetValueInput(node, 0);
Node* const context = NodeProperties::GetContextInput(node);
Node* const state1 = NodeProperties::GetFrameStateInput(node, 0);
Node* const state2 = NodeProperties::GetFrameStateInput(node, 1);
Node* const effect = NodeProperties::GetEffectInput(node);
Node* const control = NodeProperties::GetControlInput(node);
if (access.RequiresFullCheck()) return NoChange();
// Perform checks whether the fast mode applies, by looking for any extension
// object which might shadow the optimistic declaration.
uint32_t bitset = access.check_bitset();
Node* check_true = control;
Node* check_false = graph()->NewNode(common()->Merge(0));
for (int depth = 0; bitset != 0; bitset >>= 1, depth++) {
if ((bitset & 1) == 0) continue;
Node* load = graph()->NewNode(
javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false),
context, context, effect);
Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()),
load, jsgraph()->ZeroConstant());
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), check,
check_true);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
check_false->AppendInput(graph()->zone(), if_false);
NodeProperties::ChangeOp(check_false,
common()->Merge(check_false->InputCount()));
check_true = if_true;
}
// Fast case, because variable is not shadowed. Perform global object load.
Node* fast = graph()->NewNode(
javascript()->LoadGlobal(access.name(), access.feedback(),
access.typeof_mode()),
vector, context, state1, state2, effect, check_true);
// Slow case, because variable potentially shadowed. Perform dynamic lookup.
uint32_t check_bitset = DynamicGlobalAccess::kFullCheckRequired;
Node* slow = graph()->NewNode(
javascript()->LoadDynamicGlobal(access.name(), check_bitset,
access.feedback(), access.typeof_mode()),
vector, context, context, state1, state2, effect, check_false);
// Replace value, effect and control uses accordingly.
Node* new_control =
graph()->NewNode(common()->Merge(2), check_true, check_false);
Node* new_effect =
graph()->NewNode(common()->EffectPhi(2), fast, slow, new_control);
Node* new_value = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), fast,
slow, new_control);
ReplaceWithValue(node, new_value, new_effect, new_control);
return Changed(new_value);
}
Reduction JSTypedLowering::ReduceJSLoadDynamicContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadDynamicContext, node->opcode());
DynamicContextAccess const& access = DynamicContextAccessOf(node->op());
ContextAccess const& context_access = access.context_access();
Node* const context = NodeProperties::GetContextInput(node);
Node* const state = NodeProperties::GetFrameStateInput(node, 0);
Node* const effect = NodeProperties::GetEffectInput(node);
Node* const control = NodeProperties::GetControlInput(node);
if (access.RequiresFullCheck()) return NoChange();
// Perform checks whether the fast mode applies, by looking for any extension
// object which might shadow the optimistic declaration.
uint32_t bitset = access.check_bitset();
Node* check_true = control;
Node* check_false = graph()->NewNode(common()->Merge(0));
for (int depth = 0; bitset != 0; bitset >>= 1, depth++) {
if ((bitset & 1) == 0) continue;
Node* load = graph()->NewNode(
javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false),
context, context, effect);
Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()),
load, jsgraph()->ZeroConstant());
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), check,
check_true);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
check_false->AppendInput(graph()->zone(), if_false);
NodeProperties::ChangeOp(check_false,
common()->Merge(check_false->InputCount()));
check_true = if_true;
}
// Fast case, because variable is not shadowed. Perform context slot load.
Node* fast =
graph()->NewNode(javascript()->LoadContext(context_access.depth(),
context_access.index(), false),
context, context, effect);
// Slow case, because variable potentially shadowed. Perform dynamic lookup.
uint32_t check_bitset = DynamicContextAccess::kFullCheckRequired;
Node* slow =
graph()->NewNode(javascript()->LoadDynamicContext(
access.name(), check_bitset, context_access.depth(),
context_access.index()),
context, context, state, effect, check_false);
// Replace value, effect and control uses accordingly.
Node* new_control =
graph()->NewNode(common()->Merge(2), check_true, check_false);
Node* new_effect =
graph()->NewNode(common()->EffectPhi(2), fast, slow, new_control);
Node* new_value = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), fast,
slow, new_control);
ReplaceWithValue(node, new_value, new_effect, new_control);
return Changed(new_value);
}
Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode());
ConvertReceiverMode mode = ConvertReceiverModeOf(node->op());
......@@ -2092,10 +1976,6 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSLoadContext(node);
case IrOpcode::kJSStoreContext:
return ReduceJSStoreContext(node);
case IrOpcode::kJSLoadDynamicGlobal:
return ReduceJSLoadDynamicGlobal(node);
case IrOpcode::kJSLoadDynamicContext:
return ReduceJSLoadDynamicContext(node);
case IrOpcode::kJSConvertReceiver:
return ReduceJSConvertReceiver(node);
case IrOpcode::kJSCreateArguments:
......
......@@ -46,8 +46,6 @@ class JSTypedLowering final : public AdvancedReducer {
Reduction ReduceJSStoreProperty(Node* node);
Reduction ReduceJSLoadContext(Node* node);
Reduction ReduceJSStoreContext(Node* node);
Reduction ReduceJSLoadDynamicGlobal(Node* node);
Reduction ReduceJSLoadDynamicContext(Node* node);
Reduction ReduceJSEqual(Node* node, bool invert);
Reduction ReduceJSStrictEqual(Node* node, bool invert);
Reduction ReduceJSUnaryNot(Node* node);
......
......@@ -127,8 +127,7 @@
#define JS_CONTEXT_OP_LIST(V) \
V(JSLoadContext) \
V(JSStoreContext) \
V(JSLoadDynamicGlobal) \
V(JSLoadDynamicContext) \
V(JSLoadDynamic) \
V(JSCreateFunctionContext) \
V(JSCreateCatchContext) \
V(JSCreateWithContext) \
......
......@@ -54,7 +54,7 @@ int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
case IrOpcode::kJSCreateLiteralObject:
// Context operations
case IrOpcode::kJSLoadDynamicContext:
case IrOpcode::kJSLoadDynamic:
case IrOpcode::kJSCreateScriptContext:
case IrOpcode::kJSCreateWithContext:
......@@ -79,7 +79,6 @@ int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
case IrOpcode::kJSStoreProperty:
case IrOpcode::kJSLoadGlobal:
case IrOpcode::kJSStoreGlobal:
case IrOpcode::kJSLoadDynamicGlobal:
return 2;
// Binary operators that can deopt in the middle the operation (e.g.,
......
......@@ -1319,14 +1319,7 @@ Type* Typer::Visitor::TypeJSStoreContext(Node* node) {
}
Type* Typer::Visitor::TypeJSLoadDynamicGlobal(Node* node) {
return Type::Any();
}
Type* Typer::Visitor::TypeJSLoadDynamicContext(Node* node) {
return Type::Any();
}
Type* Typer::Visitor::TypeJSLoadDynamic(Node* node) { return Type::Any(); }
Type* Typer::Visitor::WrapContextTypeForInput(Node* node) {
......
......@@ -544,8 +544,7 @@ void Verifier::Visitor::Check(Node* node) {
break;
case IrOpcode::kJSLoadContext:
case IrOpcode::kJSLoadDynamicGlobal:
case IrOpcode::kJSLoadDynamicContext:
case IrOpcode::kJSLoadDynamic:
// Type can be anything.
CheckUpperIs(node, Type::Any());
break;
......
......@@ -928,76 +928,6 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedStringLength) {
}
// -----------------------------------------------------------------------------
// JSLoadDynamicGlobal
TEST_F(JSTypedLoweringTest, JSLoadDynamicGlobal) {
Node* const context = Parameter(Type::Any());
Node* const vector = UndefinedConstant();
Node* const frame_state = EmptyFrameState();
Node* const effect = graph()->start();
Node* const control = graph()->start();
Handle<String> name = factory()->object_string();
VectorSlotPair feedback;
for (int i = 0; i < DynamicGlobalAccess::kMaxCheckDepth; ++i) {
uint32_t bitset = 1 << i; // Only single check.
Reduction r = Reduce(graph()->NewNode(
javascript()->LoadDynamicGlobal(name, bitset, feedback,
NOT_INSIDE_TYPEOF),
vector, context, context, frame_state, frame_state, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(
r.replacement(),
IsPhi(kMachAnyTagged, _, _,
IsMerge(
IsIfTrue(IsBranch(
IsReferenceEqual(
Type::Tagged(),
IsLoadContext(
ContextAccess(i, Context::EXTENSION_INDEX, false),
context),
IsNumberConstant(BitEq(0.0))),
control)),
_)));
}
}
// -----------------------------------------------------------------------------
// JSLoadDynamicContext
TEST_F(JSTypedLoweringTest, JSLoadDynamicContext) {
Node* const context = Parameter(Type::Any());
Node* const frame_state = EmptyFrameState();
Node* const effect = graph()->start();
Node* const control = graph()->start();
Handle<String> name = factory()->object_string();
for (int i = 0; i < DynamicContextAccess::kMaxCheckDepth; ++i) {
uint32_t bitset = 1 << i; // Only single check.
Reduction r = Reduce(
graph()->NewNode(javascript()->LoadDynamicContext(name, bitset, 23, 42),
context, context, frame_state, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(
r.replacement(),
IsPhi(kMachAnyTagged,
IsLoadContext(ContextAccess(23, 42, false), context), _,
IsMerge(
IsIfTrue(IsBranch(
IsReferenceEqual(
Type::Tagged(),
IsLoadContext(
ContextAccess(i, Context::EXTENSION_INDEX, false),
context),
IsNumberConstant(BitEq(0.0))),
control)),
_)));
}
}
// -----------------------------------------------------------------------------
// JSAdd
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment