Index: src/ast.cc |
diff --git a/src/ast.cc b/src/ast.cc |
index 9d8624ca1b179b239314388eab61e9d4a8062f74..45fa31ea180e2cbf0d9eda7a150cce921405c8b2 100644 |
--- a/src/ast.cc |
+++ b/src/ast.cc |
@@ -39,6 +39,7 @@ |
#include "scopes.h" |
#include "string-stream.h" |
#include "type-info.h" |
+#include "third_party/loki/TypeManip.h" |
namespace v8 { |
namespace internal { |
@@ -594,6 +595,17 @@ void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { |
} |
+int Call::GetFeedbackSlotCount(Isolate* isolate) { |
+ CallType call_type = GetCallType(isolate); |
+ if (call_type == LOOKUP_SLOT_CALL || call_type == OTHER_CALL) { |
+ // Call only uses a slot in some cases. |
+ return 1; |
+ } |
+ |
+ return 0; |
+} |
+ |
+ |
Call::CallType Call::GetCallType(Isolate* isolate) const { |
VariableProxy* proxy = expression()->AsVariableProxy(); |
if (proxy != NULL) { |
@@ -712,43 +724,52 @@ Handle<JSObject> Call::GetPrototypeForPrimitiveCheck( |
void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle) { |
- is_monomorphic_ = oracle->CallIsMonomorphic(CallFeedbackId()); |
- Property* property = expression()->AsProperty(); |
- if (property == NULL) { |
- // Function call. Specialize for monomorphic calls. |
- if (is_monomorphic_) target_ = oracle->GetCallTarget(CallFeedbackId()); |
- } else if (property->key()->IsPropertyName()) { |
- // Method call. Specialize for the receiver types seen at runtime. |
- Literal* key = property->key()->AsLiteral(); |
- ASSERT(key != NULL && key->value()->IsString()); |
- Handle<String> name = Handle<String>::cast(key->value()); |
- check_type_ = oracle->GetCallCheckType(CallFeedbackId()); |
- receiver_types_.Clear(); |
- if (check_type_ == RECEIVER_MAP_CHECK) { |
- oracle->CallReceiverTypes(CallFeedbackId(), |
- name, arguments()->length(), &receiver_types_); |
- is_monomorphic_ = is_monomorphic_ && receiver_types_.length() > 0; |
- } else { |
- holder_ = GetPrototypeForPrimitiveCheck(check_type_, oracle->isolate()); |
- receiver_types_.Add(handle(holder_->map()), oracle->zone()); |
- } |
+ if (HasCallFeedbackSlot()) { |
+ // We stored feedback in the type vector. |
+ is_monomorphic_ = oracle->CallIsMonomorphic(CallFeedbackSlot()); |
+ ASSERT(expression()->AsProperty() == NULL); |
+ if (is_monomorphic_) target_ = oracle->GetCallTarget(CallFeedbackSlot()); |
+ } else { |
+ // We stored feedback in an IC. |
+ is_monomorphic_ = oracle->CallIsMonomorphic(CallFeedbackId()); |
+ Property* property = expression()->AsProperty(); |
+ if (property != NULL) { |
+ if (property->key()->IsPropertyName()) { |
+ // Method call. Specialize for the receiver types seen at runtime. |
+ Literal* key = property->key()->AsLiteral(); |
+ ASSERT(key != NULL && key->value()->IsString()); |
+ Handle<String> name = Handle<String>::cast(key->value()); |
+ check_type_ = oracle->GetCallCheckType(CallFeedbackId()); |
+ receiver_types_.Clear(); |
+ if (check_type_ == RECEIVER_MAP_CHECK) { |
+ oracle->CallReceiverTypes(CallFeedbackId(), |
+ name, arguments()->length(), |
+ &receiver_types_); |
+ is_monomorphic_ = is_monomorphic_ && receiver_types_.length() > 0; |
+ } else { |
+ holder_ = GetPrototypeForPrimitiveCheck(check_type_, |
+ oracle->isolate()); |
+ receiver_types_.Add(handle(holder_->map()), oracle->zone()); |
+ } |
#ifdef ENABLE_SLOW_ASSERTS |
- if (FLAG_enable_slow_asserts) { |
- int length = receiver_types_.length(); |
- for (int i = 0; i < length; i++) { |
- Handle<Map> map = receiver_types_.at(i); |
- ASSERT(!map.is_null() && *map != NULL); |
- } |
- } |
+ if (FLAG_enable_slow_asserts) { |
+ int length = receiver_types_.length(); |
+ for (int i = 0; i < length; i++) { |
+ Handle<Map> map = receiver_types_.at(i); |
+ ASSERT(!map.is_null() && *map != NULL); |
+ } |
+ } |
#endif |
- if (is_monomorphic_) { |
- Handle<Map> map = receiver_types_.first(); |
- is_monomorphic_ = ComputeTarget(map, name); |
- } |
- } else { |
- if (is_monomorphic_) { |
- keyed_array_call_is_holey_ = |
- oracle->KeyedArrayCallIsHoley(CallFeedbackId()); |
+ if (is_monomorphic_) { |
+ Handle<Map> map = receiver_types_.first(); |
+ is_monomorphic_ = ComputeTarget(map, name); |
+ } |
+ } else { |
+ if (is_monomorphic_) { |
+ keyed_array_call_is_holey_ = |
+ oracle->KeyedArrayCallIsHoley(CallFeedbackId()); |
+ } |
+ } |
} |
} |
} |
@@ -756,10 +777,10 @@ void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle) { |
void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) { |
allocation_site_ = |
- oracle->GetCallNewAllocationSite(CallNewFeedbackId()); |
- is_monomorphic_ = oracle->CallNewIsMonomorphic(CallNewFeedbackId()); |
+ oracle->GetCallNewAllocationSite(CallNewFeedbackSlot()); |
+ is_monomorphic_ = oracle->CallNewIsMonomorphic(CallNewFeedbackSlot()); |
if (is_monomorphic_) { |
- target_ = oracle->GetCallNewTarget(CallNewFeedbackId()); |
+ target_ = oracle->GetCallNewTarget(CallNewFeedbackSlot()); |
if (!allocation_site_.is_null()) { |
elements_kind_ = allocation_site_->GetElementsKind(); |
} |
@@ -1158,13 +1179,43 @@ CaseClause::CaseClause(Zone* zone, |
} |
+// FeedbackSlotUpdater exists to avoid a C-style cast from AstNode subtypes to |
+// FeedbackSlotInterface. With partial template specialization, we allow Loki |
+// to determine whether or not it's safe to cast an AstNode to |
+// FeedbackSlotInterface, then make the cast and call add_slot_node() |
+// in a compile-safe way. |
+template<bool B, class N> |
+class FeedbackSlotUpdater { |
+ public: |
+ static void Update(AstConstructionVisitor* visitor, N* n) { |
+ FeedbackSlotInterface* slot = static_cast<FeedbackSlotInterface*>(n); |
+ visitor->add_slot_node(slot); |
+ } |
+}; |
+ |
+ |
+template<class N> |
+class FeedbackSlotUpdater<false, N> { |
+ public: |
+ static void Update(AstConstructionVisitor* visitor, N* n) {} |
+}; |
+ |
+ |
+#define UPDATE_FEEDBACK_SLOTS(NodeType, node) \ |
+ FeedbackSlotUpdater< \ |
+ Loki::SuperSubclass<FeedbackSlotInterface, NodeType>::value, \ |
+ NodeType>::Update(this, node) |
+ |
+ |
#define REGULAR_NODE(NodeType) \ |
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ |
increase_node_count(); \ |
+ UPDATE_FEEDBACK_SLOTS(NodeType, node); \ |
} |
#define DONT_OPTIMIZE_NODE(NodeType) \ |
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ |
increase_node_count(); \ |
+ UPDATE_FEEDBACK_SLOTS(NodeType, node); \ |
set_dont_optimize_reason(k##NodeType); \ |
add_flag(kDontInline); \ |
add_flag(kDontSelfOptimize); \ |
@@ -1172,11 +1223,13 @@ CaseClause::CaseClause(Zone* zone, |
#define DONT_SELFOPTIMIZE_NODE(NodeType) \ |
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ |
increase_node_count(); \ |
+ UPDATE_FEEDBACK_SLOTS(NodeType, node); \ |
add_flag(kDontSelfOptimize); \ |
} |
#define DONT_CACHE_NODE(NodeType) \ |
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \ |
increase_node_count(); \ |
+ UPDATE_FEEDBACK_SLOTS(NodeType, node); \ |
set_dont_optimize_reason(k##NodeType); \ |
add_flag(kDontInline); \ |
add_flag(kDontSelfOptimize); \ |
@@ -1241,6 +1294,7 @@ DONT_CACHE_NODE(ModuleLiteral) |
void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) { |
increase_node_count(); |
+ UPDATE_FEEDBACK_SLOTS(CallRuntime, node); |
if (node->is_jsruntime()) { |
// Don't try to inline JS runtime calls because we don't (currently) even |
// optimize them. |