[turbofan] New operator for loads of DYNAMIC_[GLOBAL,LOCAL].
This introduces two new operators for loads of variables bound to Variable::LOOKUP locations. Currently they all still lower to runtime calls, but will allow optimization during typed lowering. R=bmeurer@chromium.org Review URL: https://codereview.chromium.org/1155103004 Cr-Commit-Position: refs/heads/master@{#28713}
This commit is contained in:
parent
4b548dd15a
commit
861c427420
@ -1633,8 +1633,8 @@ void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) {
|
||||
DCHECK_NOT_NULL(expr->class_variable_proxy());
|
||||
Variable* var = expr->class_variable_proxy()->var();
|
||||
FrameStateBeforeAndAfter states(this, BailoutId::None());
|
||||
BuildVariableAssignment(states, var, literal, Token::INIT_CONST,
|
||||
BailoutId::None());
|
||||
BuildVariableAssignment(var, literal, Token::INIT_CONST, BailoutId::None(),
|
||||
states);
|
||||
}
|
||||
|
||||
ast_context()->ProduceValue(literal);
|
||||
@ -1663,7 +1663,7 @@ void AstGraphBuilder::VisitConditional(Conditional* expr) {
|
||||
void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
||||
VectorSlotPair pair = CreateVectorSlotPair(expr->VariableFeedbackSlot());
|
||||
FrameStateBeforeAndAfter states(this, BeforeId(expr));
|
||||
Node* value = BuildVariableLoad(states, expr->var(), expr->id(), pair,
|
||||
Node* value = BuildVariableLoad(expr->var(), expr->id(), states, pair,
|
||||
ast_context()->GetStateCombine());
|
||||
ast_context()->ProduceValue(value);
|
||||
}
|
||||
@ -1975,7 +1975,7 @@ void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value,
|
||||
case VARIABLE: {
|
||||
Variable* var = expr->AsVariableProxy()->var();
|
||||
FrameStateBeforeAndAfter states(this, BailoutId::None());
|
||||
BuildVariableAssignment(states, var, value, Token::ASSIGN, bailout_id);
|
||||
BuildVariableAssignment(var, value, Token::ASSIGN, bailout_id, states);
|
||||
break;
|
||||
}
|
||||
case NAMED_PROPERTY: {
|
||||
@ -2047,7 +2047,7 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
CreateVectorSlotPair(proxy->VariableFeedbackSlot());
|
||||
FrameStateBeforeAndAfter states(this, BeforeId(proxy));
|
||||
old_value =
|
||||
BuildVariableLoad(states, proxy->var(), expr->target()->id(), pair,
|
||||
BuildVariableLoad(proxy->var(), expr->target()->id(), states, pair,
|
||||
OutputFrameStateCombine::Push());
|
||||
break;
|
||||
}
|
||||
@ -2102,8 +2102,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
switch (assign_type) {
|
||||
case VARIABLE: {
|
||||
Variable* variable = expr->target()->AsVariableProxy()->var();
|
||||
BuildVariableAssignment(store_states, variable, value, expr->op(),
|
||||
expr->id(), ast_context()->GetStateCombine());
|
||||
BuildVariableAssignment(variable, value, expr->op(), expr->id(),
|
||||
store_states, ast_context()->GetStateCombine());
|
||||
break;
|
||||
}
|
||||
case NAMED_PROPERTY: {
|
||||
@ -2184,7 +2184,7 @@ void AstGraphBuilder::VisitCall(Call* expr) {
|
||||
VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
|
||||
FrameStateBeforeAndAfter states(this, BeforeId(proxy));
|
||||
callee_value =
|
||||
BuildVariableLoad(states, proxy->var(), expr->expression()->id(),
|
||||
BuildVariableLoad(proxy->var(), expr->expression()->id(), states,
|
||||
pair, OutputFrameStateCombine::Push());
|
||||
receiver_value = jsgraph()->UndefinedConstant();
|
||||
break;
|
||||
@ -2412,7 +2412,7 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
||||
VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
|
||||
FrameStateBeforeAndAfter states(this, BeforeId(proxy));
|
||||
old_value =
|
||||
BuildVariableLoad(states, proxy->var(), expr->expression()->id(),
|
||||
BuildVariableLoad(proxy->var(), expr->expression()->id(), states,
|
||||
pair, OutputFrameStateCombine::Push());
|
||||
stack_depth = 0;
|
||||
break;
|
||||
@ -2476,8 +2476,8 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
||||
case VARIABLE: {
|
||||
Variable* variable = expr->expression()->AsVariableProxy()->var();
|
||||
environment()->Push(value);
|
||||
BuildVariableAssignment(store_states, variable, value, expr->op(),
|
||||
expr->AssignmentId());
|
||||
BuildVariableAssignment(variable, value, expr->op(), expr->AssignmentId(),
|
||||
store_states);
|
||||
environment()->Pop();
|
||||
break;
|
||||
}
|
||||
@ -2680,7 +2680,7 @@ void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) {
|
||||
VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
|
||||
FrameStateBeforeAndAfter states(this, BeforeId(proxy));
|
||||
operand =
|
||||
BuildVariableLoad(states, proxy->var(), expr->expression()->id(), pair,
|
||||
BuildVariableLoad(proxy->var(), expr->expression()->id(), states, pair,
|
||||
OutputFrameStateCombine::Push(), NOT_CONTEXTUAL);
|
||||
} else {
|
||||
VisitForValue(expr->expression());
|
||||
@ -2747,6 +2747,39 @@ VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(
|
||||
}
|
||||
|
||||
|
||||
uint32_t AstGraphBuilder::ComputeBitsetForDynamicGlobal(Variable* variable) {
|
||||
DCHECK_EQ(DYNAMIC_GLOBAL, variable->mode());
|
||||
EnumSet<int, uint32_t> check_depths;
|
||||
for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) {
|
||||
if (s->num_heap_slots() <= 0) continue;
|
||||
// TODO(mstarzinger): Be smarter about which checks to require!
|
||||
int depth = current_scope()->ContextChainLength(s);
|
||||
if (depth > DynamicGlobalAccess::kMaxCheckDepth) {
|
||||
return DynamicGlobalAccess::kFullCheckRequired;
|
||||
}
|
||||
check_depths.Add(depth);
|
||||
}
|
||||
return check_depths.ToIntegral();
|
||||
}
|
||||
|
||||
|
||||
uint32_t AstGraphBuilder::ComputeBitsetForDynamicContext(Variable* variable) {
|
||||
DCHECK_EQ(DYNAMIC_LOCAL, variable->mode());
|
||||
EnumSet<int, uint32_t> check_depths;
|
||||
for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) {
|
||||
if (s->num_heap_slots() <= 0) continue;
|
||||
if (!s->calls_sloppy_eval()) continue;
|
||||
int depth = current_scope()->ContextChainLength(s);
|
||||
if (depth > DynamicContextAccess::kMaxCheckDepth) {
|
||||
return DynamicContextAccess::kFullCheckRequired;
|
||||
}
|
||||
check_depths.Add(depth);
|
||||
if (s == variable->scope()) break;
|
||||
}
|
||||
return check_depths.ToIntegral();
|
||||
}
|
||||
|
||||
|
||||
Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) {
|
||||
DCHECK(environment()->stack_height() >= arity);
|
||||
Node** all = info()->zone()->NewArray<Node*>(arity);
|
||||
@ -2856,8 +2889,8 @@ Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) {
|
||||
DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated());
|
||||
// This should never lazy deopt, so it is fine to send invalid bailout id.
|
||||
FrameStateBeforeAndAfter states(this, BailoutId::None());
|
||||
BuildVariableAssignment(states, arguments, object, Token::ASSIGN,
|
||||
BailoutId::None());
|
||||
BuildVariableAssignment(arguments, object, Token::ASSIGN, BailoutId::None(),
|
||||
states);
|
||||
|
||||
return object;
|
||||
}
|
||||
@ -2874,8 +2907,8 @@ Node* AstGraphBuilder::BuildRestArgumentsArray(Variable* rest, int index) {
|
||||
DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
|
||||
// This should never lazy deopt, so it is fine to send invalid bailout id.
|
||||
FrameStateBeforeAndAfter states(this, BailoutId::None());
|
||||
BuildVariableAssignment(states, rest, object, Token::ASSIGN,
|
||||
BailoutId::None());
|
||||
BuildVariableAssignment(rest, object, Token::ASSIGN, BailoutId::None(),
|
||||
states);
|
||||
|
||||
return object;
|
||||
}
|
||||
@ -2924,9 +2957,9 @@ Node* AstGraphBuilder::BuildThrowIfStaticPrototype(Node* name,
|
||||
}
|
||||
|
||||
|
||||
Node* AstGraphBuilder::BuildVariableLoad(FrameStateBeforeAndAfter& states,
|
||||
Variable* variable,
|
||||
Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
|
||||
BailoutId bailout_id,
|
||||
FrameStateBeforeAndAfter& states,
|
||||
const VectorSlotPair& feedback,
|
||||
OutputFrameStateCombine combine,
|
||||
ContextualMode contextual_mode) {
|
||||
@ -2937,9 +2970,9 @@ Node* AstGraphBuilder::BuildVariableLoad(FrameStateBeforeAndAfter& states,
|
||||
// Global var, const, or let variable.
|
||||
Node* global = BuildLoadGlobalObject();
|
||||
Handle<Name> name = variable->name();
|
||||
Node* node = BuildNamedLoad(global, name, feedback, contextual_mode);
|
||||
states.AddToNode(node, bailout_id, combine);
|
||||
return node;
|
||||
Node* value = BuildNamedLoad(global, name, feedback, contextual_mode);
|
||||
states.AddToNode(value, bailout_id, combine);
|
||||
return value;
|
||||
}
|
||||
case Variable::PARAMETER:
|
||||
case Variable::LOCAL: {
|
||||
@ -2985,15 +3018,30 @@ Node* AstGraphBuilder::BuildVariableLoad(FrameStateBeforeAndAfter& states,
|
||||
}
|
||||
case Variable::LOOKUP: {
|
||||
// Dynamic lookup of context variable (anywhere in the chain).
|
||||
Node* name = jsgraph()->Constant(variable->name());
|
||||
Runtime::FunctionId function_id =
|
||||
(contextual_mode == CONTEXTUAL)
|
||||
? Runtime::kLoadLookupSlot
|
||||
: Runtime::kLoadLookupSlotNoReferenceError;
|
||||
const Operator* op = javascript()->CallRuntime(function_id, 2);
|
||||
Node* pair = NewNode(op, current_context(), name);
|
||||
PrepareFrameState(pair, bailout_id, OutputFrameStateCombine::Push(1));
|
||||
return NewNode(common()->Projection(0), pair);
|
||||
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,
|
||||
contextual_mode);
|
||||
value = NewNode(op, current_context());
|
||||
} else if (mode == DYNAMIC_LOCAL) {
|
||||
Variable* local = variable->local_if_not_shadowed();
|
||||
DCHECK(local->location() == Variable::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());
|
||||
// TODO(mstarzinger): Hole checks are missing here when optimized.
|
||||
} else if (mode == DYNAMIC) {
|
||||
uint32_t check_bitset = DynamicGlobalAccess::kFullCheckRequired;
|
||||
const Operator* op = javascript()->LoadDynamicGlobal(name, check_bitset,
|
||||
contextual_mode);
|
||||
value = NewNode(op, current_context());
|
||||
}
|
||||
PrepareFrameState(value, bailout_id, combine);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
@ -3035,8 +3083,8 @@ Node* AstGraphBuilder::BuildVariableDelete(Variable* variable,
|
||||
|
||||
|
||||
Node* AstGraphBuilder::BuildVariableAssignment(
|
||||
FrameStateBeforeAndAfter& states, Variable* variable, Node* value,
|
||||
Token::Value op, BailoutId bailout_id, OutputFrameStateCombine combine) {
|
||||
Variable* variable, Node* value, Token::Value op, BailoutId bailout_id,
|
||||
FrameStateBeforeAndAfter& states, OutputFrameStateCombine combine) {
|
||||
Node* the_hole = jsgraph()->TheHoleConstant();
|
||||
VariableMode mode = variable->mode();
|
||||
switch (variable->location()) {
|
||||
|
@ -209,9 +209,9 @@ class AstGraphBuilder : public AstVisitor {
|
||||
void UpdateControlDependencyToLeaveFunction(Node* exit);
|
||||
|
||||
// Builds deoptimization for a given node.
|
||||
void PrepareFrameState(
|
||||
Node* node, BailoutId ast_id,
|
||||
OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore());
|
||||
void PrepareFrameState(Node* node, BailoutId ast_id,
|
||||
OutputFrameStateCombine framestate_combine =
|
||||
OutputFrameStateCombine::Ignore());
|
||||
|
||||
BitVector* GetVariablesAssignedInLoop(IterationStatement* stmt);
|
||||
|
||||
@ -234,6 +234,11 @@ class AstGraphBuilder : public AstVisitor {
|
||||
// Named and keyed loads require a VectorSlotPair for successful lowering.
|
||||
VectorSlotPair CreateVectorSlotPair(FeedbackVectorICSlot slot) const;
|
||||
|
||||
// Determine which contexts need to be checked for extension objects that
|
||||
// might shadow the optimistic declaration of dynamic lookup variables.
|
||||
uint32_t ComputeBitsetForDynamicGlobal(Variable* variable);
|
||||
uint32_t ComputeBitsetForDynamicContext(Variable* variable);
|
||||
|
||||
// ===========================================================================
|
||||
// The following build methods all generate graph fragments and return one
|
||||
// resulting node. The operand stack height remains the same, variables and
|
||||
@ -254,15 +259,17 @@ class AstGraphBuilder : public AstVisitor {
|
||||
Node* BuildRestArgumentsArray(Variable* rest, int index);
|
||||
|
||||
// Builders for variable load and assignment.
|
||||
Node* BuildVariableAssignment(
|
||||
FrameStateBeforeAndAfter& states, Variable* var, Node* value,
|
||||
Token::Value op, BailoutId bailout_id,
|
||||
OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore());
|
||||
Node* BuildVariableDelete(Variable* var, BailoutId bailout_id,
|
||||
OutputFrameStateCombine combine);
|
||||
Node* BuildVariableLoad(FrameStateBeforeAndAfter& states, Variable* var,
|
||||
BailoutId bailout_id, const VectorSlotPair& feedback,
|
||||
OutputFrameStateCombine combine,
|
||||
Node* BuildVariableAssignment(Variable* variable, Node* value,
|
||||
Token::Value op, BailoutId bailout_id,
|
||||
FrameStateBeforeAndAfter& states,
|
||||
OutputFrameStateCombine framestate_combine =
|
||||
OutputFrameStateCombine::Ignore());
|
||||
Node* BuildVariableDelete(Variable* variable, BailoutId bailout_id,
|
||||
OutputFrameStateCombine framestate_combine);
|
||||
Node* BuildVariableLoad(Variable* variable, BailoutId bailout_id,
|
||||
FrameStateBeforeAndAfter& states,
|
||||
const VectorSlotPair& feedback,
|
||||
OutputFrameStateCombine framestate_combine,
|
||||
ContextualMode mode = CONTEXTUAL);
|
||||
|
||||
// Builders for property loads and stores.
|
||||
|
@ -447,6 +447,29 @@ void JSGenericLowering::LowerJSStoreContext(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void JSGenericLowering::LowerJSLoadDynamicGlobal(Node* node) {
|
||||
const DynamicGlobalAccess& access = DynamicGlobalAccessOf(node->op());
|
||||
Runtime::FunctionId function_id =
|
||||
(access.mode() == CONTEXTUAL) ? Runtime::kLoadLookupSlot
|
||||
: Runtime::kLoadLookupSlotNoReferenceError;
|
||||
Node* projection = graph()->NewNode(common()->Projection(0), node);
|
||||
NodeProperties::ReplaceWithValue(node, projection, node, node);
|
||||
node->InsertInput(zone(), 1, jsgraph()->Constant(access.name()));
|
||||
ReplaceWithRuntimeCall(node, function_id);
|
||||
projection->ReplaceInput(0, node);
|
||||
}
|
||||
|
||||
|
||||
void JSGenericLowering::LowerJSLoadDynamicContext(Node* node) {
|
||||
const DynamicContextAccess& access = DynamicContextAccessOf(node->op());
|
||||
Node* projection = graph()->NewNode(common()->Projection(0), node);
|
||||
NodeProperties::ReplaceWithValue(node, projection, node, node);
|
||||
node->InsertInput(zone(), 1, jsgraph()->Constant(access.name()));
|
||||
ReplaceWithRuntimeCall(node, Runtime::kLoadLookupSlot);
|
||||
projection->ReplaceInput(0, node);
|
||||
}
|
||||
|
||||
|
||||
void JSGenericLowering::LowerJSCreateClosure(Node* node) {
|
||||
CreateClosureParameters p = CreateClosureParametersOf(node->op());
|
||||
node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.shared_info()));
|
||||
|
@ -91,6 +91,86 @@ ContextAccess const& ContextAccessOf(Operator const* op) {
|
||||
}
|
||||
|
||||
|
||||
DynamicGlobalAccess::DynamicGlobalAccess(const Handle<String>& name,
|
||||
uint32_t check_bitset,
|
||||
ContextualMode mode)
|
||||
: name_(name), check_bitset_(check_bitset), mode_(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.mode();
|
||||
}
|
||||
|
||||
|
||||
DynamicGlobalAccess const& DynamicGlobalAccessOf(Operator const* op) {
|
||||
DCHECK_EQ(IrOpcode::kJSLoadDynamicGlobal, op->opcode());
|
||||
return OpParameter<DynamicGlobalAccess>(op);
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
UNIMPLEMENTED();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool operator!=(DynamicContextAccess const& lhs,
|
||||
DynamicContextAccess const& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
|
||||
size_t hash_value(DynamicContextAccess 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();
|
||||
}
|
||||
|
||||
|
||||
DynamicContextAccess const& DynamicContextAccessOf(Operator const* op) {
|
||||
DCHECK_EQ(IrOpcode::kJSLoadDynamicContext, op->opcode());
|
||||
return OpParameter<DynamicContextAccess>(op);
|
||||
}
|
||||
|
||||
|
||||
bool operator==(VectorSlotPair const& lhs, VectorSlotPair const& rhs) {
|
||||
return lhs.slot().ToInt() == rhs.slot().ToInt() &&
|
||||
lhs.vector().is_identical_to(rhs.vector());
|
||||
@ -440,6 +520,31 @@ const Operator* JSOperatorBuilder::StoreContext(size_t depth, size_t index) {
|
||||
}
|
||||
|
||||
|
||||
const Operator* JSOperatorBuilder::LoadDynamicGlobal(const Handle<String>& name,
|
||||
uint32_t check_bitset,
|
||||
ContextualMode mode) {
|
||||
DynamicGlobalAccess access(name, check_bitset, mode);
|
||||
return new (zone()) Operator1<DynamicGlobalAccess>( // --
|
||||
IrOpcode::kJSLoadDynamicGlobal, Operator::kNoProperties, // opcode
|
||||
"JSLoadDynamicGlobal", // name
|
||||
1, 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::CreateClosure(
|
||||
Handle<SharedFunctionInfo> shared_info, PretenureFlag pretenure) {
|
||||
CreateClosureParameters parameters(shared_info, pretenure);
|
||||
|
@ -112,6 +112,84 @@ 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 {
|
||||
public:
|
||||
DynamicGlobalAccess(const Handle<String>& name, uint32_t check_bitset,
|
||||
ContextualMode mode);
|
||||
|
||||
const Handle<String>& name() const { return name_; }
|
||||
uint32_t check_bitset() const { return check_bitset_; }
|
||||
ContextualMode mode() const { return 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 ContextualMode 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&);
|
||||
|
||||
bool operator==(DynamicContextAccess const&, DynamicContextAccess const&);
|
||||
bool operator!=(DynamicContextAccess const&, DynamicContextAccess const&);
|
||||
|
||||
std::ostream& operator<<(std::ostream&, DynamicContextAccess const&);
|
||||
|
||||
DynamicContextAccess const& DynamicContextAccessOf(Operator const*);
|
||||
|
||||
|
||||
class VectorSlotPair {
|
||||
public:
|
||||
VectorSlotPair(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
|
||||
@ -297,6 +375,12 @@ 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, ContextualMode mode);
|
||||
const Operator* LoadDynamicContext(const Handle<String>& name,
|
||||
uint32_t check_bitset, size_t depth,
|
||||
size_t index);
|
||||
|
||||
const Operator* TypeOf();
|
||||
const Operator* InstanceOf();
|
||||
|
||||
|
@ -123,6 +123,8 @@
|
||||
#define JS_CONTEXT_OP_LIST(V) \
|
||||
V(JSLoadContext) \
|
||||
V(JSStoreContext) \
|
||||
V(JSLoadDynamicGlobal) \
|
||||
V(JSLoadDynamicContext) \
|
||||
V(JSCreateFunctionContext) \
|
||||
V(JSCreateCatchContext) \
|
||||
V(JSCreateWithContext) \
|
||||
|
@ -49,6 +49,8 @@ int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
|
||||
case IrOpcode::kJSCreateLiteralObject:
|
||||
|
||||
// Context operations
|
||||
case IrOpcode::kJSLoadDynamicGlobal:
|
||||
case IrOpcode::kJSLoadDynamicContext:
|
||||
case IrOpcode::kJSCreateScriptContext:
|
||||
case IrOpcode::kJSCreateWithContext:
|
||||
|
||||
|
@ -1506,6 +1506,16 @@ Bounds Typer::Visitor::TypeJSStoreContext(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
Bounds Typer::Visitor::TypeJSLoadDynamicGlobal(Node* node) {
|
||||
return Bounds::Unbounded(zone());
|
||||
}
|
||||
|
||||
|
||||
Bounds Typer::Visitor::TypeJSLoadDynamicContext(Node* node) {
|
||||
return Bounds::Unbounded(zone());
|
||||
}
|
||||
|
||||
|
||||
Bounds Typer::Visitor::WrapContextBoundsForInput(Node* node) {
|
||||
Bounds outer = BoundsOrNone(NodeProperties::GetContextInput(node));
|
||||
if (outer.upper->Is(Type::None())) {
|
||||
|
@ -531,6 +531,8 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
break;
|
||||
|
||||
case IrOpcode::kJSLoadContext:
|
||||
case IrOpcode::kJSLoadDynamicGlobal:
|
||||
case IrOpcode::kJSLoadDynamicContext:
|
||||
// Type can be anything.
|
||||
CheckUpperIs(node, Type::Any());
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user