Commit 662a5585 authored by mvstanton's avatar mvstanton Committed by Commit bot

Turbofan: Make type feedback vector a Node.

This improves code generation. Before, it was a constant loaded in a register
every time.

R=mstarzinger@chromium.org
BUG=

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

Cr-Commit-Position: refs/heads/master@{#28874}
parent e3d76269
This diff is collapsed.
......@@ -88,6 +88,7 @@ class AstGraphBuilder : public AstVisitor {
// Nodes representing values in the activation record.
SetOncePointer<Node> function_closure_;
SetOncePointer<Node> function_context_;
SetOncePointer<Node> feedback_vector_;
// Tracks how many try-blocks are currently entered.
int try_catch_nesting_level_;
......@@ -147,6 +148,9 @@ class AstGraphBuilder : public AstVisitor {
// Get or create the node that represents the outer function closure.
Node* GetFunctionClosure();
// Get or create the node that represents the functions type feedback vector.
Node* GetFeedbackVector();
// Node creation helpers.
Node* NewNode(const Operator* op, bool incomplete = false) {
return MakeNode(op, 0, static_cast<Node**>(NULL), incomplete);
......@@ -231,8 +235,9 @@ class AstGraphBuilder : public AstVisitor {
Node** EnsureInputBufferSize(int size);
// Named and keyed loads require a VectorSlotPair for successful lowering.
VectorSlotPair CreateVectorSlotPair(FeedbackVectorICSlot slot) const;
// Named and keyed loads require a ResolvedFeedbackSlot for successful
// lowering.
ResolvedFeedbackSlot ResolveFeedbackSlot(FeedbackVectorICSlot slot) const;
// Determine which contexts need to be checked for extension objects that
// might shadow the optimistic declaration of dynamic lookup variables.
......@@ -271,15 +276,15 @@ class AstGraphBuilder : public AstVisitor {
OutputFrameStateCombine framestate_combine);
Node* BuildVariableLoad(Variable* variable, BailoutId bailout_id,
FrameStateBeforeAndAfter& states,
const VectorSlotPair& feedback,
const ResolvedFeedbackSlot& feedback,
OutputFrameStateCombine framestate_combine,
ContextualMode mode = CONTEXTUAL);
// Builders for property loads and stores.
Node* BuildKeyedLoad(Node* receiver, Node* key,
const VectorSlotPair& feedback);
const ResolvedFeedbackSlot& feedback);
Node* BuildNamedLoad(Node* receiver, Handle<Name> name,
const VectorSlotPair& feedback,
const ResolvedFeedbackSlot& feedback,
ContextualMode mode = NOT_CONTEXTUAL);
Node* BuildKeyedStore(Node* receiver, Node* key, Node* value,
TypeFeedbackId id);
......@@ -292,9 +297,10 @@ class AstGraphBuilder : public AstVisitor {
Node* BuildNamedSuperStore(Node* receiver, Node* home_object,
Handle<Name> name, Node* value, TypeFeedbackId id);
Node* BuildNamedSuperLoad(Node* receiver, Node* home_object,
Handle<Name> name, const VectorSlotPair& feedback);
Handle<Name> name,
const ResolvedFeedbackSlot& feedback);
Node* BuildKeyedSuperLoad(Node* receiver, Node* home_object, Node* key,
const VectorSlotPair& feedback);
const ResolvedFeedbackSlot& feedback);
// Builders for accessing the function context.
Node* BuildLoadBuiltinsObject();
......
......@@ -344,9 +344,7 @@ void JSGenericLowering::LowerJSLoadProperty(Node* node) {
Callable callable =
CodeFactory::KeyedLoadICInOptimizedCode(isolate(), UNINITIALIZED);
node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
node->InsertInput(zone(), 3, jsgraph()->HeapConstant(p.feedback().vector()));
ReplaceWithStubCall(node, callable,
CallDescriptor::kPatchableCallSite | flags);
ReplaceWithStubCall(node, callable, flags);
}
......@@ -357,9 +355,7 @@ void JSGenericLowering::LowerJSLoadNamed(Node* node) {
isolate(), p.contextual_mode(), UNINITIALIZED);
node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
node->InsertInput(zone(), 3, jsgraph()->HeapConstant(p.feedback().vector()));
ReplaceWithStubCall(node, callable,
CallDescriptor::kPatchableCallSite | flags);
ReplaceWithStubCall(node, callable, flags);
}
......@@ -455,6 +451,7 @@ void JSGenericLowering::LowerJSLoadDynamicGlobal(Node* node) {
Node* projection = graph()->NewNode(common()->Projection(0), node);
NodeProperties::ReplaceWithValue(node, projection, 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);
projection->ReplaceInput(0, node);
......
......@@ -93,7 +93,7 @@ ContextAccess const& ContextAccessOf(Operator const* op) {
DynamicGlobalAccess::DynamicGlobalAccess(const Handle<String>& name,
uint32_t check_bitset,
const VectorSlotPair& feedback,
const ResolvedFeedbackSlot& feedback,
ContextualMode mode)
: name_(name),
check_bitset_(check_bitset),
......@@ -175,14 +175,13 @@ DynamicContextAccess const& DynamicContextAccessOf(Operator const* op) {
}
bool operator==(VectorSlotPair const& lhs, VectorSlotPair const& rhs) {
return lhs.slot().ToInt() == rhs.slot().ToInt() &&
lhs.vector().is_identical_to(rhs.vector());
bool operator==(ResolvedFeedbackSlot const& lhs,
ResolvedFeedbackSlot const& rhs) {
return lhs.slot().ToInt() == rhs.slot().ToInt();
}
size_t hash_value(VectorSlotPair const& p) {
// TODO(mvstanton): include the vector in the hash.
size_t hash_value(ResolvedFeedbackSlot const& p) {
base::hash<int> h;
return h(p.slot().ToInt());
}
......@@ -458,25 +457,25 @@ const Operator* JSOperatorBuilder::CallConstruct(int arguments) {
}
const Operator* JSOperatorBuilder::LoadNamed(const Unique<Name>& name,
const VectorSlotPair& feedback,
ContextualMode contextual_mode) {
const Operator* JSOperatorBuilder::LoadNamed(
const Unique<Name>& name, const ResolvedFeedbackSlot& feedback,
ContextualMode contextual_mode) {
LoadNamedParameters parameters(name, feedback, contextual_mode);
return new (zone()) Operator1<LoadNamedParameters>( // --
IrOpcode::kJSLoadNamed, Operator::kNoProperties, // opcode
"JSLoadNamed", // name
1, 1, 1, 1, 1, 2, // counts
2, 1, 1, 1, 1, 2, // counts
parameters); // parameter
}
const Operator* JSOperatorBuilder::LoadProperty(
const VectorSlotPair& feedback) {
const ResolvedFeedbackSlot& feedback) {
LoadPropertyParameters parameters(feedback);
return new (zone()) Operator1<LoadPropertyParameters>( // --
IrOpcode::kJSLoadProperty, Operator::kNoProperties, // opcode
"JSLoadProperty", // name
2, 1, 1, 1, 1, 2, // counts
3, 1, 1, 1, 1, 2, // counts
parameters); // parameter
}
......@@ -526,12 +525,12 @@ 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, ContextualMode mode) {
const ResolvedFeedbackSlot& feedback, ContextualMode mode) {
DynamicGlobalAccess access(name, check_bitset, feedback, mode);
return new (zone()) Operator1<DynamicGlobalAccess>( // --
IrOpcode::kJSLoadDynamicGlobal, Operator::kNoProperties, // opcode
"JSLoadDynamicGlobal", // name
1, 1, 1, 1, 1, 2, // counts
2, 1, 1, 1, 1, 2, // counts
access); // parameter
}
......
......@@ -112,23 +112,28 @@ std::ostream& operator<<(std::ostream&, ContextAccess const&);
ContextAccess const& ContextAccessOf(Operator const*);
class VectorSlotPair {
// A ResolvedFeedbackSlot needs to query the type feedback vector to get it's
// index in the vector.
class ResolvedFeedbackSlot {
public:
VectorSlotPair(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
: vector_(vector), slot_(slot) {}
ResolvedFeedbackSlot(Handle<TypeFeedbackVector> vector,
FeedbackVectorICSlot slot)
: slot_(slot),
index_(slot == FeedbackVectorICSlot::Invalid() ? -1 : vector->GetIndex(
slot)) {}
ResolvedFeedbackSlot() : slot_(FeedbackVectorICSlot::Invalid()), index_(-1) {}
Handle<TypeFeedbackVector> vector() const { return vector_; }
FeedbackVectorICSlot slot() const { return slot_; }
int index() const { return vector_->GetIndex(slot_); }
int index() const { return index_; }
private:
const Handle<TypeFeedbackVector> vector_;
const FeedbackVectorICSlot slot_;
const int index_;
};
bool operator==(VectorSlotPair const& lhs, VectorSlotPair const& rhs);
bool operator==(ResolvedFeedbackSlot const& lhs,
ResolvedFeedbackSlot const& rhs);
// Defines the name for a dynamic variable lookup. The {check_bitset} allows to
......@@ -137,11 +142,12 @@ bool operator==(VectorSlotPair const& lhs, VectorSlotPair const& rhs);
class DynamicGlobalAccess final {
public:
DynamicGlobalAccess(const Handle<String>& name, uint32_t check_bitset,
const VectorSlotPair& feedback, ContextualMode mode);
const ResolvedFeedbackSlot& feedback,
ContextualMode mode);
const Handle<String>& name() const { return name_; }
uint32_t check_bitset() const { return check_bitset_; }
const VectorSlotPair& feedback() const { return feedback_; }
const ResolvedFeedbackSlot& feedback() const { return feedback_; }
ContextualMode mode() const { return mode_; }
// Indicates that an inline check is disabled.
......@@ -158,7 +164,7 @@ class DynamicGlobalAccess final {
private:
const Handle<String> name_;
const uint32_t check_bitset_;
const VectorSlotPair feedback_;
const ResolvedFeedbackSlot feedback_;
const ContextualMode mode_;
};
......@@ -215,18 +221,19 @@ DynamicContextAccess const& DynamicContextAccessOf(Operator const*);
// used as a parameter by JSLoadNamed operators.
class LoadNamedParameters final {
public:
LoadNamedParameters(const Unique<Name>& name, const VectorSlotPair& feedback,
LoadNamedParameters(const Unique<Name>& name,
const ResolvedFeedbackSlot& feedback,
ContextualMode contextual_mode)
: name_(name), feedback_(feedback), contextual_mode_(contextual_mode) {}
const Unique<Name>& name() const { return name_; }
ContextualMode contextual_mode() const { return contextual_mode_; }
const VectorSlotPair& feedback() const { return feedback_; }
const ResolvedFeedbackSlot& feedback() const { return feedback_; }
private:
const Unique<Name> name_;
const VectorSlotPair feedback_;
const ResolvedFeedbackSlot feedback_;
const ContextualMode contextual_mode_;
};
......@@ -244,13 +251,13 @@ const LoadNamedParameters& LoadNamedParametersOf(const Operator* op);
// used as a parameter by JSLoadProperty operators.
class LoadPropertyParameters final {
public:
explicit LoadPropertyParameters(const VectorSlotPair& feedback)
explicit LoadPropertyParameters(const ResolvedFeedbackSlot& feedback)
: feedback_(feedback) {}
const VectorSlotPair& feedback() const { return feedback_; }
const ResolvedFeedbackSlot& feedback() const { return feedback_; }
private:
const VectorSlotPair feedback_;
const ResolvedFeedbackSlot feedback_;
};
bool operator==(LoadPropertyParameters const&, LoadPropertyParameters const&);
......@@ -361,9 +368,9 @@ class JSOperatorBuilder final : public ZoneObject {
const Operator* CallConstruct(int arguments);
const Operator* LoadProperty(const VectorSlotPair& feedback);
const Operator* LoadProperty(const ResolvedFeedbackSlot& feedback);
const Operator* LoadNamed(const Unique<Name>& name,
const VectorSlotPair& feedback,
const ResolvedFeedbackSlot& feedback,
ContextualMode contextual_mode = NOT_CONTEXTUAL);
const Operator* StoreProperty(LanguageMode language_mode);
......@@ -379,7 +386,7 @@ class JSOperatorBuilder final : public ZoneObject {
const Operator* LoadDynamicGlobal(const Handle<String>& name,
uint32_t check_bitset,
const VectorSlotPair& feedback,
const ResolvedFeedbackSlot& feedback,
ContextualMode mode);
const Operator* LoadDynamicContext(const Handle<String>& name,
uint32_t check_bitset, size_t depth,
......
......@@ -936,6 +936,7 @@ 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);
......@@ -971,14 +972,14 @@ Reduction JSTypedLowering::ReduceJSLoadDynamicGlobal(Node* node) {
context, effect);
Node* fast = graph()->NewNode(
javascript()->LoadNamed(name, access.feedback(), access.mode()), global,
context, state1, state2, global, check_true);
vector, context, state1, state2, global, 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.mode()),
context, context, state1, state2, effect, check_false);
vector, context, context, state1, state2, effect, check_false);
// Replace value, effect and control uses accordingly.
Node* new_control =
......
......@@ -77,15 +77,15 @@ class JSTypeFeedbackTest : public TypedGraphTest {
Node* ReturnLoadNamedFromGlobal(
const char* string, Node* effect, Node* control,
JSTypeFeedbackSpecializer::DeoptimizationMode mode) {
VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
FeedbackVectorICSlot::Invalid());
ResolvedFeedbackSlot feedback;
Node* global = Parameter(Type::GlobalObject());
Node* vector = UndefinedConstant();
Node* context = UndefinedConstant();
Unique<Name> name = Unique<Name>::CreateUninitialized(
isolate()->factory()->NewStringFromAsciiChecked(string));
const Operator* op = javascript()->LoadNamed(name, feedback);
Node* load = graph()->NewNode(op, global, context);
Node* load = graph()->NewNode(op, global, vector, context);
if (mode == JSTypeFeedbackSpecializer::kDeoptimizationEnabled) {
for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op);
i++) {
......
......@@ -648,8 +648,7 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
double backing_store[kLength];
Handle<JSArrayBuffer> buffer =
NewArrayBuffer(backing_store, sizeof(backing_store));
VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
FeedbackVectorICSlot::Invalid());
ResolvedFeedbackSlot feedback;
TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
Handle<JSTypedArray> array =
factory()->NewJSTypedArray(type, buffer, 0, kLength);
......@@ -658,12 +657,13 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
Node* key = Parameter(
Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
Node* base = HeapConstant(array);
Node* vector = UndefinedConstant();
Node* context = UndefinedConstant();
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->LoadProperty(feedback),
base, key, context, EmptyFrameState(),
EmptyFrameState(), effect, control));
Reduction r = Reduce(graph()->NewNode(
javascript()->LoadProperty(feedback), base, key, vector, context,
EmptyFrameState(), EmptyFrameState(), effect, control));
Matcher<Node*> offset_matcher =
element_size == 1
......@@ -687,8 +687,7 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) {
double backing_store[kLength];
Handle<JSArrayBuffer> buffer =
NewArrayBuffer(backing_store, sizeof(backing_store));
VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
FeedbackVectorICSlot::Invalid());
ResolvedFeedbackSlot feedback;
TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
Handle<JSTypedArray> array =
factory()->NewJSTypedArray(type, buffer, 0, kLength);
......@@ -699,12 +698,13 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) {
if (min > max) std::swap(min, max);
Node* key = Parameter(Type::Range(min, max, zone()));
Node* base = HeapConstant(array);
Node* vector = UndefinedConstant();
Node* context = UndefinedConstant();
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->LoadProperty(feedback),
base, key, context, EmptyFrameState(),
EmptyFrameState(), effect, control));
Reduction r = Reduce(graph()->NewNode(
javascript()->LoadProperty(feedback), base, key, vector, context,
EmptyFrameState(), EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(
......@@ -878,9 +878,9 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedGlobalConstants) {
IsNumberConstant(IsNaN()) // --
};
VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
FeedbackVectorICSlot::Invalid());
ResolvedFeedbackSlot feedback;
Node* global = Parameter(Type::GlobalObject());
Node* vector = UndefinedConstant();
Node* context = UndefinedConstant();
Node* effect = graph()->start();
Node* control = graph()->start();
......@@ -888,7 +888,7 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedGlobalConstants) {
for (size_t i = 0; i < arraysize(names); i++) {
Unique<Name> name = Unique<Name>::CreateImmovable(names[i]);
Reduction r = Reduce(graph()->NewNode(
javascript()->LoadNamed(name, feedback), global, context,
javascript()->LoadNamed(name, feedback), global, vector, context,
EmptyFrameState(), EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
......@@ -903,17 +903,17 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedGlobalConstants) {
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(Handle<TypeFeedbackVector>::null(),
FeedbackVectorICSlot::Invalid());
ResolvedFeedbackSlot 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_CONTEXTUAL),
context, context, frame_state, frame_state, effect, control));
vector, context, context, frame_state, frame_state, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(
r.replacement(),
......
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