| 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.
|
|
|