Commit 861c4274 authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[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}
parent 4b548dd1
This diff is collapsed.
...@@ -209,9 +209,9 @@ class AstGraphBuilder : public AstVisitor { ...@@ -209,9 +209,9 @@ class AstGraphBuilder : public AstVisitor {
void UpdateControlDependencyToLeaveFunction(Node* exit); void UpdateControlDependencyToLeaveFunction(Node* exit);
// Builds deoptimization for a given node. // Builds deoptimization for a given node.
void PrepareFrameState( void PrepareFrameState(Node* node, BailoutId ast_id,
Node* node, BailoutId ast_id, OutputFrameStateCombine framestate_combine =
OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore()); OutputFrameStateCombine::Ignore());
BitVector* GetVariablesAssignedInLoop(IterationStatement* stmt); BitVector* GetVariablesAssignedInLoop(IterationStatement* stmt);
...@@ -234,6 +234,11 @@ class AstGraphBuilder : public AstVisitor { ...@@ -234,6 +234,11 @@ class AstGraphBuilder : public AstVisitor {
// Named and keyed loads require a VectorSlotPair for successful lowering. // Named and keyed loads require a VectorSlotPair for successful lowering.
VectorSlotPair CreateVectorSlotPair(FeedbackVectorICSlot slot) const; 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 // The following build methods all generate graph fragments and return one
// resulting node. The operand stack height remains the same, variables and // resulting node. The operand stack height remains the same, variables and
...@@ -254,15 +259,17 @@ class AstGraphBuilder : public AstVisitor { ...@@ -254,15 +259,17 @@ class AstGraphBuilder : public AstVisitor {
Node* BuildRestArgumentsArray(Variable* rest, int index); Node* BuildRestArgumentsArray(Variable* rest, int index);
// Builders for variable load and assignment. // Builders for variable load and assignment.
Node* BuildVariableAssignment( Node* BuildVariableAssignment(Variable* variable, Node* value,
FrameStateBeforeAndAfter& states, Variable* var, Node* value,
Token::Value op, BailoutId bailout_id, Token::Value op, BailoutId bailout_id,
OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore()); FrameStateBeforeAndAfter& states,
Node* BuildVariableDelete(Variable* var, BailoutId bailout_id, OutputFrameStateCombine framestate_combine =
OutputFrameStateCombine combine); OutputFrameStateCombine::Ignore());
Node* BuildVariableLoad(FrameStateBeforeAndAfter& states, Variable* var, Node* BuildVariableDelete(Variable* variable, BailoutId bailout_id,
BailoutId bailout_id, const VectorSlotPair& feedback, OutputFrameStateCombine framestate_combine);
OutputFrameStateCombine combine, Node* BuildVariableLoad(Variable* variable, BailoutId bailout_id,
FrameStateBeforeAndAfter& states,
const VectorSlotPair& feedback,
OutputFrameStateCombine framestate_combine,
ContextualMode mode = CONTEXTUAL); ContextualMode mode = CONTEXTUAL);
// Builders for property loads and stores. // Builders for property loads and stores.
......
...@@ -447,6 +447,29 @@ void JSGenericLowering::LowerJSStoreContext(Node* node) { ...@@ -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) { void JSGenericLowering::LowerJSCreateClosure(Node* node) {
CreateClosureParameters p = CreateClosureParametersOf(node->op()); CreateClosureParameters p = CreateClosureParametersOf(node->op());
node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.shared_info())); node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.shared_info()));
......
...@@ -91,6 +91,86 @@ ContextAccess const& ContextAccessOf(Operator const* op) { ...@@ -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) { bool operator==(VectorSlotPair const& lhs, VectorSlotPair const& rhs) {
return lhs.slot().ToInt() == rhs.slot().ToInt() && return lhs.slot().ToInt() == rhs.slot().ToInt() &&
lhs.vector().is_identical_to(rhs.vector()); lhs.vector().is_identical_to(rhs.vector());
...@@ -440,6 +520,31 @@ const Operator* JSOperatorBuilder::StoreContext(size_t depth, size_t index) { ...@@ -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( const Operator* JSOperatorBuilder::CreateClosure(
Handle<SharedFunctionInfo> shared_info, PretenureFlag pretenure) { Handle<SharedFunctionInfo> shared_info, PretenureFlag pretenure) {
CreateClosureParameters parameters(shared_info, pretenure); CreateClosureParameters parameters(shared_info, pretenure);
......
...@@ -112,6 +112,84 @@ std::ostream& operator<<(std::ostream&, ContextAccess const&); ...@@ -112,6 +112,84 @@ std::ostream& operator<<(std::ostream&, ContextAccess const&);
ContextAccess const& ContextAccessOf(Operator 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 { class VectorSlotPair {
public: public:
VectorSlotPair(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot) VectorSlotPair(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
...@@ -297,6 +375,12 @@ class JSOperatorBuilder final : public ZoneObject { ...@@ -297,6 +375,12 @@ class JSOperatorBuilder final : public ZoneObject {
const Operator* LoadContext(size_t depth, size_t index, bool immutable); const Operator* LoadContext(size_t depth, size_t index, bool immutable);
const Operator* StoreContext(size_t depth, size_t index); 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* TypeOf();
const Operator* InstanceOf(); const Operator* InstanceOf();
......
...@@ -123,6 +123,8 @@ ...@@ -123,6 +123,8 @@
#define JS_CONTEXT_OP_LIST(V) \ #define JS_CONTEXT_OP_LIST(V) \
V(JSLoadContext) \ V(JSLoadContext) \
V(JSStoreContext) \ V(JSStoreContext) \
V(JSLoadDynamicGlobal) \
V(JSLoadDynamicContext) \
V(JSCreateFunctionContext) \ V(JSCreateFunctionContext) \
V(JSCreateCatchContext) \ V(JSCreateCatchContext) \
V(JSCreateWithContext) \ V(JSCreateWithContext) \
......
...@@ -49,6 +49,8 @@ int OperatorProperties::GetFrameStateInputCount(const Operator* op) { ...@@ -49,6 +49,8 @@ int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
case IrOpcode::kJSCreateLiteralObject: case IrOpcode::kJSCreateLiteralObject:
// Context operations // Context operations
case IrOpcode::kJSLoadDynamicGlobal:
case IrOpcode::kJSLoadDynamicContext:
case IrOpcode::kJSCreateScriptContext: case IrOpcode::kJSCreateScriptContext:
case IrOpcode::kJSCreateWithContext: case IrOpcode::kJSCreateWithContext:
......
...@@ -1506,6 +1506,16 @@ Bounds Typer::Visitor::TypeJSStoreContext(Node* node) { ...@@ -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 Typer::Visitor::WrapContextBoundsForInput(Node* node) {
Bounds outer = BoundsOrNone(NodeProperties::GetContextInput(node)); Bounds outer = BoundsOrNone(NodeProperties::GetContextInput(node));
if (outer.upper->Is(Type::None())) { if (outer.upper->Is(Type::None())) {
......
...@@ -531,6 +531,8 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -531,6 +531,8 @@ void Verifier::Visitor::Check(Node* node) {
break; break;
case IrOpcode::kJSLoadContext: case IrOpcode::kJSLoadContext:
case IrOpcode::kJSLoadDynamicGlobal:
case IrOpcode::kJSLoadDynamicContext:
// Type can be anything. // Type can be anything.
CheckUpperIs(node, Type::Any()); CheckUpperIs(node, Type::Any());
break; break;
......
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