| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. | 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
| 15 // | 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 |
| 30 #include "ast.h" |
| 31 #include "compiler.h" |
| 32 #include "ic.h" |
| 33 #include "macro-assembler.h" |
| 34 #include "stub-cache.h" |
| 29 #include "type-info.h" | 35 #include "type-info.h" |
| 36 |
| 37 #include "ic-inl.h" |
| 30 #include "objects-inl.h" | 38 #include "objects-inl.h" |
| 31 | 39 |
| 32 namespace v8 { | 40 namespace v8 { |
| 33 namespace internal { | 41 namespace internal { |
| 34 | 42 |
| 35 | 43 |
| 36 TypeInfo TypeInfo::TypeFromValue(Handle<Object> value) { | 44 TypeInfo TypeInfo::TypeFromValue(Handle<Object> value) { |
| 37 TypeInfo info; | 45 TypeInfo info; |
| 38 if (value->IsSmi()) { | 46 if (value->IsSmi()) { |
| 39 info = TypeInfo::Smi(); | 47 info = TypeInfo::Smi(); |
| 40 } else if (value->IsHeapNumber()) { | 48 } else if (value->IsHeapNumber()) { |
| 41 info = TypeInfo::IsInt32Double(HeapNumber::cast(*value)->value()) | 49 info = TypeInfo::IsInt32Double(HeapNumber::cast(*value)->value()) |
| 42 ? TypeInfo::Integer32() | 50 ? TypeInfo::Integer32() |
| 43 : TypeInfo::Double(); | 51 : TypeInfo::Double(); |
| 44 } else if (value->IsString()) { | 52 } else if (value->IsString()) { |
| 45 info = TypeInfo::String(); | 53 info = TypeInfo::String(); |
| 46 } else { | 54 } else { |
| 47 info = TypeInfo::Unknown(); | 55 info = TypeInfo::Unknown(); |
| 48 } | 56 } |
| 49 return info; | 57 return info; |
| 50 } | 58 } |
| 51 | 59 |
| 52 | 60 |
| 61 TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code) { |
| 62 Initialize(code); |
| 63 } |
| 64 |
| 65 |
| 66 void TypeFeedbackOracle::Initialize(Handle<Code> code) { |
| 67 Isolate* isolate = Isolate::Current(); |
| 68 ASSERT(map_.is_null()); // Only initialize once. |
| 69 map_ = isolate->factory()->NewJSObject(isolate->object_function()); |
| 70 PopulateMap(code); |
| 71 } |
| 72 |
| 73 |
| 74 bool TypeFeedbackOracle::LoadIsMonomorphic(Property* expr) { |
| 75 return IsMonomorphic(expr->position()); |
| 76 } |
| 77 |
| 78 |
| 79 bool TypeFeedbackOracle:: StoreIsMonomorphic(Assignment* expr) { |
| 80 return IsMonomorphic(expr->position()); |
| 81 } |
| 82 |
| 83 |
| 84 bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) { |
| 85 return IsMonomorphic(expr->position()); |
| 86 } |
| 87 |
| 88 |
| 89 Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) { |
| 90 ASSERT(LoadIsMonomorphic(expr)); |
| 91 return Handle<Map>::cast(GetElement(map_, expr->position())); |
| 92 } |
| 93 |
| 94 |
| 95 Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(Assignment* expr) { |
| 96 ASSERT(StoreIsMonomorphic(expr)); |
| 97 return Handle<Map>::cast(GetElement(map_, expr->position())); |
| 98 } |
| 99 |
| 100 |
| 101 Handle<Map> TypeFeedbackOracle::CallMonomorphicReceiverType(Call* expr) { |
| 102 ASSERT(CallIsMonomorphic(expr)); |
| 103 return Handle<Map>::cast(GetElement(map_, expr->position())); |
| 104 } |
| 105 |
| 106 |
| 107 ZoneMapList* TypeFeedbackOracle::LoadReceiverTypes(Property* expr, |
| 108 Handle<String> name) { |
| 109 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL); |
| 110 return CollectReceiverTypes(expr->position(), name, flags); |
| 111 } |
| 112 |
| 113 |
| 114 ZoneMapList* TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr, |
| 115 Handle<String> name) { |
| 116 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL); |
| 117 return CollectReceiverTypes(expr->position(), name, flags); |
| 118 } |
| 119 |
| 120 |
| 121 ZoneMapList* TypeFeedbackOracle::CallReceiverTypes(Call* expr, |
| 122 Handle<String> name) { |
| 123 int arity = expr->arguments()->length(); |
| 124 Code::Flags flags = Code::ComputeMonomorphicFlags( |
| 125 Code::CALL_IC, NORMAL, OWN_MAP, NOT_IN_LOOP, arity); |
| 126 return CollectReceiverTypes(expr->position(), name, flags); |
| 127 } |
| 128 |
| 129 |
| 130 bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) { |
| 131 Handle<Object> object = GetElement(map_, expr->position()); |
| 132 return *object == Isolate::Current()->builtins()->builtin(id); |
| 133 } |
| 134 |
| 135 |
| 136 TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr, Side side) { |
| 137 Handle<Object> object = GetElement(map_, expr->position()); |
| 138 TypeInfo unknown = TypeInfo::Unknown(); |
| 139 if (!object->IsCode()) return unknown; |
| 140 Handle<Code> code = Handle<Code>::cast(object); |
| 141 if (!code->is_compare_ic_stub()) return unknown; |
| 142 |
| 143 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); |
| 144 switch (state) { |
| 145 case CompareIC::UNINITIALIZED: |
| 146 case CompareIC::SMIS: |
| 147 return TypeInfo::Smi(); |
| 148 case CompareIC::HEAP_NUMBERS: |
| 149 return TypeInfo::Number(); |
| 150 case CompareIC::OBJECTS: |
| 151 // TODO(kasperl): We really need a type for JS objects here. |
| 152 return TypeInfo::NonPrimitive(); |
| 153 case CompareIC::GENERIC: |
| 154 default: |
| 155 return unknown; |
| 156 } |
| 157 } |
| 158 |
| 159 |
| 160 TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr, Side side) { |
| 161 Handle<Object> object = GetElement(map_, expr->position()); |
| 162 TypeInfo unknown = TypeInfo::Unknown(); |
| 163 if (!object->IsCode()) return unknown; |
| 164 Handle<Code> code = Handle<Code>::cast(object); |
| 165 if (code->is_binary_op_stub()) { |
| 166 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>( |
| 167 code->binary_op_type()); |
| 168 switch (type) { |
| 169 case BinaryOpIC::UNINIT_OR_SMI: |
| 170 return TypeInfo::Smi(); |
| 171 case BinaryOpIC::DEFAULT: |
| 172 return (expr->op() == Token::DIV || expr->op() == Token::MUL) |
| 173 ? TypeInfo::Double() |
| 174 : TypeInfo::Integer32(); |
| 175 case BinaryOpIC::HEAP_NUMBERS: |
| 176 return TypeInfo::Double(); |
| 177 default: |
| 178 return unknown; |
| 179 } |
| 180 } else if (code->is_type_recording_binary_op_stub()) { |
| 181 TRBinaryOpIC::TypeInfo type = static_cast<TRBinaryOpIC::TypeInfo>( |
| 182 code->type_recording_binary_op_type()); |
| 183 TRBinaryOpIC::TypeInfo result_type = static_cast<TRBinaryOpIC::TypeInfo>( |
| 184 code->type_recording_binary_op_result_type()); |
| 185 |
| 186 switch (type) { |
| 187 case TRBinaryOpIC::UNINITIALIZED: |
| 188 case TRBinaryOpIC::SMI: |
| 189 switch (result_type) { |
| 190 case TRBinaryOpIC::UNINITIALIZED: |
| 191 case TRBinaryOpIC::SMI: |
| 192 return TypeInfo::Smi(); |
| 193 case TRBinaryOpIC::INT32: |
| 194 return TypeInfo::Integer32(); |
| 195 case TRBinaryOpIC::HEAP_NUMBER: |
| 196 return TypeInfo::Double(); |
| 197 default: |
| 198 return unknown; |
| 199 } |
| 200 case TRBinaryOpIC::INT32: |
| 201 if (expr->op() == Token::DIV || |
| 202 result_type == TRBinaryOpIC::HEAP_NUMBER) { |
| 203 return TypeInfo::Double(); |
| 204 } |
| 205 return TypeInfo::Integer32(); |
| 206 case TRBinaryOpIC::HEAP_NUMBER: |
| 207 return TypeInfo::Double(); |
| 208 case TRBinaryOpIC::STRING: |
| 209 case TRBinaryOpIC::GENERIC: |
| 210 return unknown; |
| 211 default: |
| 212 return unknown; |
| 213 } |
| 214 } |
| 215 return unknown; |
| 216 } |
| 217 |
| 218 TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) { |
| 219 Handle<Object> object = GetElement(map_, clause->position()); |
| 220 TypeInfo unknown = TypeInfo::Unknown(); |
| 221 if (!object->IsCode()) return unknown; |
| 222 Handle<Code> code = Handle<Code>::cast(object); |
| 223 if (!code->is_compare_ic_stub()) return unknown; |
| 224 |
| 225 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); |
| 226 switch (state) { |
| 227 case CompareIC::UNINITIALIZED: |
| 228 case CompareIC::SMIS: |
| 229 return TypeInfo::Smi(); |
| 230 case CompareIC::HEAP_NUMBERS: |
| 231 return TypeInfo::Number(); |
| 232 case CompareIC::OBJECTS: |
| 233 // TODO(kasperl): We really need a type for JS objects here. |
| 234 return TypeInfo::NonPrimitive(); |
| 235 case CompareIC::GENERIC: |
| 236 default: |
| 237 return unknown; |
| 238 } |
| 239 } |
| 240 |
| 241 |
| 242 |
| 243 ZoneMapList* TypeFeedbackOracle::CollectReceiverTypes(int position, |
| 244 Handle<String> name, |
| 245 Code::Flags flags) { |
| 246 Isolate* isolate = Isolate::Current(); |
| 247 Handle<Object> object = GetElement(map_, position); |
| 248 if (object->IsUndefined()) return NULL; |
| 249 |
| 250 if (*object == isolate->builtins()->builtin(Builtins::StoreIC_GlobalProxy)) { |
| 251 // TODO(fschneider): We could collect the maps and signal that |
| 252 // we need a generic store (or load) here. |
| 253 ASSERT(Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC); |
| 254 return NULL; |
| 255 } else if (object->IsMap()) { |
| 256 ZoneMapList* types = new ZoneMapList(1); |
| 257 types->Add(Handle<Map>::cast(object)); |
| 258 return types; |
| 259 } else if (Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) { |
| 260 ZoneMapList* types = new ZoneMapList(4); |
| 261 ASSERT(object->IsCode()); |
| 262 isolate->stub_cache()->CollectMatchingMaps(types, *name, flags); |
| 263 return types->length() > 0 ? types : NULL; |
| 264 } else { |
| 265 return NULL; |
| 266 } |
| 267 } |
| 268 |
| 269 |
| 270 void TypeFeedbackOracle::PopulateMap(Handle<Code> code) { |
| 271 HandleScope scope; |
| 272 |
| 273 const int kInitialCapacity = 16; |
| 274 List<int> code_positions(kInitialCapacity); |
| 275 List<int> source_positions(kInitialCapacity); |
| 276 CollectPositions(*code, &code_positions, &source_positions); |
| 277 |
| 278 int length = code_positions.length(); |
| 279 ASSERT(source_positions.length() == length); |
| 280 for (int i = 0; i < length; i++) { |
| 281 RelocInfo info(code->instruction_start() + code_positions[i], |
| 282 RelocInfo::CODE_TARGET, 0); |
| 283 Handle<Code> target(Code::GetCodeFromTargetAddress(info.target_address())); |
| 284 int position = source_positions[i]; |
| 285 InlineCacheState state = target->ic_state(); |
| 286 Code::Kind kind = target->kind(); |
| 287 if (kind == Code::BINARY_OP_IC || |
| 288 kind == Code::TYPE_RECORDING_BINARY_OP_IC || |
| 289 kind == Code::COMPARE_IC) { |
| 290 // TODO(kasperl): Avoid having multiple ICs with the same |
| 291 // position by making sure that we have position information |
| 292 // recorded for all binary ICs. |
| 293 if (GetElement(map_, position)->IsUndefined()) { |
| 294 SetElement(map_, position, target); |
| 295 } |
| 296 } else if (state == MONOMORPHIC) { |
| 297 Map* map = target->FindFirstMap(); |
| 298 if (map == NULL) { |
| 299 SetElement(map_, position, target); |
| 300 } else { |
| 301 SetElement(map_, position, Handle<Map>(map)); |
| 302 } |
| 303 } else if (state == MEGAMORPHIC) { |
| 304 SetElement(map_, position, target); |
| 305 } |
| 306 } |
| 307 } |
| 308 |
| 309 |
| 310 void TypeFeedbackOracle::CollectPositions(Code* code, |
| 311 List<int>* code_positions, |
| 312 List<int>* source_positions) { |
| 313 AssertNoAllocation no_allocation; |
| 314 int position = 0; |
| 315 // Because the ICs we use for global variables access in the full |
| 316 // code generator do not have any meaningful positions, we avoid |
| 317 // collecting those by filtering out contextual code targets. |
| 318 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | |
| 319 RelocInfo::kPositionMask; |
| 320 for (RelocIterator it(code, mask); !it.done(); it.next()) { |
| 321 RelocInfo* info = it.rinfo(); |
| 322 RelocInfo::Mode mode = info->rmode(); |
| 323 if (RelocInfo::IsCodeTarget(mode)) { |
| 324 Code* target = Code::GetCodeFromTargetAddress(info->target_address()); |
| 325 if (target->is_inline_cache_stub()) { |
| 326 InlineCacheState state = target->ic_state(); |
| 327 Code::Kind kind = target->kind(); |
| 328 if (kind == Code::BINARY_OP_IC) { |
| 329 if (target->binary_op_type() == BinaryOpIC::GENERIC) continue; |
| 330 } else if (kind == Code::TYPE_RECORDING_BINARY_OP_IC) { |
| 331 if (target->type_recording_binary_op_type() == |
| 332 TRBinaryOpIC::GENERIC) { |
| 333 continue; |
| 334 } |
| 335 } else if (kind == Code::COMPARE_IC) { |
| 336 if (target->compare_state() == CompareIC::GENERIC) continue; |
| 337 } else { |
| 338 if (kind == Code::CALL_IC && state == MONOMORPHIC && |
| 339 target->check_type() != RECEIVER_MAP_CHECK) continue; |
| 340 if (state != MONOMORPHIC && state != MEGAMORPHIC) continue; |
| 341 } |
| 342 code_positions->Add(info->pc() - code->instruction_start()); |
| 343 source_positions->Add(position); |
| 344 } |
| 345 } else { |
| 346 ASSERT(RelocInfo::IsPosition(mode)); |
| 347 position = info->data(); |
| 348 } |
| 349 } |
| 350 } |
| 351 |
| 53 } } // namespace v8::internal | 352 } } // namespace v8::internal |
| OLD | NEW |