1 // Copyright 2015 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/compiler/type-hint-analyzer.h" 6 7 #include "src/assembler.h" 8 #include "src/code-stubs.h" 9 #include "src/compiler/type-hints.h" 10 #include "src/ic/ic-state.h" 11 12 namespace v8 { 13 namespace internal { 14 namespace compiler { 15 16 namespace { 17 18 // TODO(bmeurer): This detour via types is ugly. 19 BinaryOperationHints::Hint ToBinaryOperationHint(Type* type) { 20 if (type->Is(Type::None())) return BinaryOperationHints::kNone; 21 if (type->Is(Type::SignedSmall())) return BinaryOperationHints::kSignedSmall; 22 if (type->Is(Type::Signed32())) return BinaryOperationHints::kSigned32; 23 if (type->Is(Type::Number())) return BinaryOperationHints::kNumberOrUndefined; 24 if (type->Is(Type::String())) return BinaryOperationHints::kString; 25 return BinaryOperationHints::kAny; 26 } 27 28 CompareOperationHints::Hint ToCompareOperationHint( 29 CompareICState::State state) { 30 switch (state) { 31 case CompareICState::UNINITIALIZED: 32 return CompareOperationHints::kNone; 33 case CompareICState::BOOLEAN: 34 return CompareOperationHints::kBoolean; 35 case CompareICState::SMI: 36 return CompareOperationHints::kSignedSmall; 37 case CompareICState::NUMBER: 38 return CompareOperationHints::kNumber; 39 case CompareICState::STRING: 40 return CompareOperationHints::kString; 41 case CompareICState::INTERNALIZED_STRING: 42 return CompareOperationHints::kInternalizedString; 43 case CompareICState::UNIQUE_NAME: 44 return CompareOperationHints::kUniqueName; 45 case CompareICState::RECEIVER: 46 case CompareICState::KNOWN_RECEIVER: 47 return CompareOperationHints::kReceiver; 48 case CompareICState::GENERIC: 49 return CompareOperationHints::kAny; 50 } 51 UNREACHABLE(); 52 return CompareOperationHints::kAny; 53 } 54 55 } // namespace 56 57 bool TypeHintAnalysis::GetBinaryOperationHints( 58 TypeFeedbackId id, BinaryOperationHints* hints) const { 59 auto i = infos_.find(id); 60 if (i == infos_.end()) return false; 61 Handle<Code> code = i->second; 62 DCHECK_EQ(Code::BINARY_OP_IC, code->kind()); 63 BinaryOpICState state(code->GetIsolate(), code->extra_ic_state()); 64 *hints = BinaryOperationHints(ToBinaryOperationHint(state.GetLeftType()), 65 ToBinaryOperationHint(state.GetRightType()), 66 ToBinaryOperationHint(state.GetResultType())); 67 return true; 68 } 69 70 bool TypeHintAnalysis::GetCompareOperationHints( 71 TypeFeedbackId id, CompareOperationHints* hints) const { 72 auto i = infos_.find(id); 73 if (i == infos_.end()) return false; 74 Handle<Code> code = i->second; 75 DCHECK_EQ(Code::COMPARE_IC, code->kind()); 76 77 Handle<Map> map; 78 Map* raw_map = code->FindFirstMap(); 79 if (raw_map != nullptr) Map::TryUpdate(handle(raw_map)).ToHandle(&map); 80 81 CompareICStub stub(code->stub_key(), code->GetIsolate()); 82 *hints = CompareOperationHints(ToCompareOperationHint(stub.left()), 83 ToCompareOperationHint(stub.right()), 84 ToCompareOperationHint(stub.state())); 85 return true; 86 } 87 88 bool TypeHintAnalysis::GetToBooleanHints(TypeFeedbackId id, 89 ToBooleanHints* hints) const { 90 auto i = infos_.find(id); 91 if (i == infos_.end()) return false; 92 Handle<Code> code = i->second; 93 DCHECK_EQ(Code::TO_BOOLEAN_IC, code->kind()); 94 ToBooleanICStub stub(code->GetIsolate(), code->extra_ic_state()); 95 // TODO(bmeurer): Replace ToBooleanICStub::Types with ToBooleanHints. 96 #define ASSERT_COMPATIBLE(NAME, Name) \ 97 STATIC_ASSERT(1 << ToBooleanICStub::NAME == \ 98 static_cast<int>(ToBooleanHint::k##Name)) 99 ASSERT_COMPATIBLE(UNDEFINED, Undefined); 100 ASSERT_COMPATIBLE(BOOLEAN, Boolean); 101 ASSERT_COMPATIBLE(NULL_TYPE, Null); 102 ASSERT_COMPATIBLE(SMI, SmallInteger); 103 ASSERT_COMPATIBLE(SPEC_OBJECT, Receiver); 104 ASSERT_COMPATIBLE(STRING, String); 105 ASSERT_COMPATIBLE(SYMBOL, Symbol); 106 ASSERT_COMPATIBLE(HEAP_NUMBER, HeapNumber); 107 ASSERT_COMPATIBLE(SIMD_VALUE, SimdValue); 108 #undef ASSERT_COMPATIBLE 109 *hints = ToBooleanHints(stub.types().ToIntegral()); 110 return true; 111 } 112 113 TypeHintAnalysis* TypeHintAnalyzer::Analyze(Handle<Code> code) { 114 DisallowHeapAllocation no_gc; 115 TypeHintAnalysis::Infos infos(zone()); 116 Isolate* const isolate = code->GetIsolate(); 117 int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); 118 for (RelocIterator it(*code, mask); !it.done(); it.next()) { 119 RelocInfo* rinfo = it.rinfo(); 120 Address target_address = rinfo->target_address(); 121 Code* target = Code::GetCodeFromTargetAddress(target_address); 122 switch (target->kind()) { 123 case Code::BINARY_OP_IC: 124 case Code::COMPARE_IC: 125 case Code::TO_BOOLEAN_IC: { 126 // Add this feedback to the {infos}. 127 TypeFeedbackId id(static_cast<unsigned>(rinfo->data())); 128 infos.insert(std::make_pair(id, handle(target, isolate))); 129 break; 130 } 131 default: 132 // Ignore the remaining code objects. 133 break; 134 } 135 } 136 return new (zone()) TypeHintAnalysis(infos, zone()); 137 } 138 139 } // namespace compiler 140 } // namespace internal 141 } // namespace v8 142