| 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 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 | 64 |
| 65 | 65 |
| 66 void TypeFeedbackOracle::Initialize(Handle<Code> code) { | 66 void TypeFeedbackOracle::Initialize(Handle<Code> code) { |
| 67 ASSERT(map_.is_null()); // Only initialize once. | 67 ASSERT(map_.is_null()); // Only initialize once. |
| 68 map_ = Factory::NewJSObject(Top::object_function()); | 68 map_ = Factory::NewJSObject(Top::object_function()); |
| 69 PopulateMap(code); | 69 PopulateMap(code); |
| 70 } | 70 } |
| 71 | 71 |
| 72 | 72 |
| 73 bool TypeFeedbackOracle::LoadIsMonomorphic(Property* expr) { | 73 bool TypeFeedbackOracle::LoadIsMonomorphic(Property* expr) { |
| 74 return IsMonomorphic(expr->position()); | 74 return IsMonomorphic(expr->id()); |
| 75 } | 75 } |
| 76 | 76 |
| 77 | 77 |
| 78 bool TypeFeedbackOracle:: StoreIsMonomorphic(Assignment* expr) { | 78 bool TypeFeedbackOracle:: StoreIsMonomorphic(Assignment* expr) { |
| 79 return IsMonomorphic(expr->position()); | 79 return IsMonomorphic(expr->id()); |
| 80 } | 80 } |
| 81 | 81 |
| 82 | 82 |
| 83 bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) { | 83 bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) { |
| 84 return IsMonomorphic(expr->position()); | 84 return IsMonomorphic(expr->id()); |
| 85 } | 85 } |
| 86 | 86 |
| 87 | 87 |
| 88 Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) { | 88 Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) { |
| 89 ASSERT(LoadIsMonomorphic(expr)); | 89 ASSERT(LoadIsMonomorphic(expr)); |
| 90 return Handle<Map>::cast(GetElement(map_, expr->position())); | 90 return Handle<Map>::cast(GetElement(map_, expr->id())); |
| 91 } | 91 } |
| 92 | 92 |
| 93 | 93 |
| 94 Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(Assignment* expr) { | 94 Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(Assignment* expr) { |
| 95 ASSERT(StoreIsMonomorphic(expr)); | 95 ASSERT(StoreIsMonomorphic(expr)); |
| 96 return Handle<Map>::cast(GetElement(map_, expr->position())); | 96 return Handle<Map>::cast(GetElement(map_, expr->id())); |
| 97 } | 97 } |
| 98 | 98 |
| 99 | 99 |
| 100 Handle<Map> TypeFeedbackOracle::CallMonomorphicReceiverType(Call* expr) { | 100 Handle<Map> TypeFeedbackOracle::CallMonomorphicReceiverType(Call* expr) { |
| 101 ASSERT(CallIsMonomorphic(expr)); | 101 ASSERT(CallIsMonomorphic(expr)); |
| 102 return Handle<Map>::cast(GetElement(map_, expr->position())); | 102 return Handle<Map>::cast(GetElement(map_, expr->id())); |
| 103 } | 103 } |
| 104 | 104 |
| 105 | 105 |
| 106 ZoneMapList* TypeFeedbackOracle::LoadReceiverTypes(Property* expr, | 106 ZoneMapList* TypeFeedbackOracle::LoadReceiverTypes(Property* expr, |
| 107 Handle<String> name) { | 107 Handle<String> name) { |
| 108 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL); | 108 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL); |
| 109 return CollectReceiverTypes(expr->position(), name, flags); | 109 return CollectReceiverTypes(expr->id(), name, flags); |
| 110 } | 110 } |
| 111 | 111 |
| 112 | 112 |
| 113 ZoneMapList* TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr, | 113 ZoneMapList* TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr, |
| 114 Handle<String> name) { | 114 Handle<String> name) { |
| 115 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL); | 115 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL); |
| 116 return CollectReceiverTypes(expr->position(), name, flags); | 116 return CollectReceiverTypes(expr->id(), name, flags); |
| 117 } | 117 } |
| 118 | 118 |
| 119 | 119 |
| 120 ZoneMapList* TypeFeedbackOracle::CallReceiverTypes(Call* expr, | 120 ZoneMapList* TypeFeedbackOracle::CallReceiverTypes(Call* expr, |
| 121 Handle<String> name) { | 121 Handle<String> name) { |
| 122 int arity = expr->arguments()->length(); | 122 int arity = expr->arguments()->length(); |
| 123 Code::Flags flags = Code::ComputeMonomorphicFlags( | 123 Code::Flags flags = Code::ComputeMonomorphicFlags( |
| 124 Code::CALL_IC, NORMAL, OWN_MAP, NOT_IN_LOOP, arity); | 124 Code::CALL_IC, NORMAL, OWN_MAP, NOT_IN_LOOP, arity); |
| 125 return CollectReceiverTypes(expr->position(), name, flags); | 125 return CollectReceiverTypes(expr->id(), name, flags); |
| 126 } | 126 } |
| 127 | 127 |
| 128 | 128 |
| 129 bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) { | 129 bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) { |
| 130 Handle<Object> object = GetElement(map_, expr->position()); | 130 Handle<Object> object = GetElement(map_, expr->id()); |
| 131 return *object == Builtins::builtin(id); | 131 return *object == Builtins::builtin(id); |
| 132 } | 132 } |
| 133 | 133 |
| 134 | 134 |
| 135 TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr, Side side) { | 135 TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr, Side side) { |
| 136 Handle<Object> object = GetElement(map_, expr->position()); | 136 Handle<Object> object = GetElement(map_, expr->id()); |
| 137 TypeInfo unknown = TypeInfo::Unknown(); | 137 TypeInfo unknown = TypeInfo::Unknown(); |
| 138 if (!object->IsCode()) return unknown; | 138 if (!object->IsCode()) return unknown; |
| 139 Handle<Code> code = Handle<Code>::cast(object); | 139 Handle<Code> code = Handle<Code>::cast(object); |
| 140 if (!code->is_compare_ic_stub()) return unknown; | 140 if (!code->is_compare_ic_stub()) return unknown; |
| 141 | 141 |
| 142 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); | 142 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); |
| 143 switch (state) { | 143 switch (state) { |
| 144 case CompareIC::UNINITIALIZED: | 144 case CompareIC::UNINITIALIZED: |
| 145 case CompareIC::SMIS: | 145 case CompareIC::SMIS: |
| 146 return TypeInfo::Smi(); | 146 return TypeInfo::Smi(); |
| 147 case CompareIC::HEAP_NUMBERS: | 147 case CompareIC::HEAP_NUMBERS: |
| 148 return TypeInfo::Number(); | 148 return TypeInfo::Number(); |
| 149 case CompareIC::OBJECTS: | 149 case CompareIC::OBJECTS: |
| 150 // TODO(kasperl): We really need a type for JS objects here. | 150 // TODO(kasperl): We really need a type for JS objects here. |
| 151 return TypeInfo::NonPrimitive(); | 151 return TypeInfo::NonPrimitive(); |
| 152 case CompareIC::GENERIC: | 152 case CompareIC::GENERIC: |
| 153 default: | 153 default: |
| 154 return unknown; | 154 return unknown; |
| 155 } | 155 } |
| 156 } | 156 } |
| 157 | 157 |
| 158 | 158 |
| 159 TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr, Side side) { | 159 TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr, Side side) { |
| 160 Handle<Object> object = GetElement(map_, expr->position()); | 160 Handle<Object> object = GetElement(map_, expr->id()); |
| 161 TypeInfo unknown = TypeInfo::Unknown(); | 161 TypeInfo unknown = TypeInfo::Unknown(); |
| 162 if (!object->IsCode()) return unknown; | 162 if (!object->IsCode()) return unknown; |
| 163 Handle<Code> code = Handle<Code>::cast(object); | 163 Handle<Code> code = Handle<Code>::cast(object); |
| 164 if (code->is_binary_op_stub()) { | 164 if (code->is_binary_op_stub()) { |
| 165 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>( | 165 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>( |
| 166 code->binary_op_type()); | 166 code->binary_op_type()); |
| 167 switch (type) { | 167 switch (type) { |
| 168 case BinaryOpIC::UNINIT_OR_SMI: | 168 case BinaryOpIC::UNINIT_OR_SMI: |
| 169 return TypeInfo::Smi(); | 169 return TypeInfo::Smi(); |
| 170 case BinaryOpIC::DEFAULT: | 170 case BinaryOpIC::DEFAULT: |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 case TRBinaryOpIC::GENERIC: | 208 case TRBinaryOpIC::GENERIC: |
| 209 return unknown; | 209 return unknown; |
| 210 default: | 210 default: |
| 211 return unknown; | 211 return unknown; |
| 212 } | 212 } |
| 213 } | 213 } |
| 214 return unknown; | 214 return unknown; |
| 215 } | 215 } |
| 216 | 216 |
| 217 TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) { | 217 TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) { |
| 218 Handle<Object> object = GetElement(map_, clause->position()); | 218 Handle<Object> object = GetElement(map_, clause->label()->id()); |
| 219 TypeInfo unknown = TypeInfo::Unknown(); | 219 TypeInfo unknown = TypeInfo::Unknown(); |
| 220 if (!object->IsCode()) return unknown; | 220 if (!object->IsCode()) return unknown; |
| 221 Handle<Code> code = Handle<Code>::cast(object); | 221 Handle<Code> code = Handle<Code>::cast(object); |
| 222 if (!code->is_compare_ic_stub()) return unknown; | 222 if (!code->is_compare_ic_stub()) return unknown; |
| 223 | 223 |
| 224 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); | 224 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); |
| 225 switch (state) { | 225 switch (state) { |
| 226 case CompareIC::UNINITIALIZED: | 226 case CompareIC::UNINITIALIZED: |
| 227 case CompareIC::SMIS: | 227 case CompareIC::SMIS: |
| 228 return TypeInfo::Smi(); | 228 return TypeInfo::Smi(); |
| 229 case CompareIC::HEAP_NUMBERS: | 229 case CompareIC::HEAP_NUMBERS: |
| 230 return TypeInfo::Number(); | 230 return TypeInfo::Number(); |
| 231 case CompareIC::OBJECTS: | 231 case CompareIC::OBJECTS: |
| 232 // TODO(kasperl): We really need a type for JS objects here. | 232 // TODO(kasperl): We really need a type for JS objects here. |
| 233 return TypeInfo::NonPrimitive(); | 233 return TypeInfo::NonPrimitive(); |
| 234 case CompareIC::GENERIC: | 234 case CompareIC::GENERIC: |
| 235 default: | 235 default: |
| 236 return unknown; | 236 return unknown; |
| 237 } | 237 } |
| 238 } | 238 } |
| 239 | 239 |
| 240 | 240 |
| 241 | 241 |
| 242 ZoneMapList* TypeFeedbackOracle::CollectReceiverTypes(int position, | 242 ZoneMapList* TypeFeedbackOracle::CollectReceiverTypes(AstId id, |
| 243 Handle<String> name, | 243 Handle<String> name, |
| 244 Code::Flags flags) { | 244 Code::Flags flags) { |
| 245 Handle<Object> object = GetElement(map_, position); | 245 Handle<Object> object = GetElement(map_, id); |
| 246 if (object->IsUndefined()) return NULL; | 246 if (object->IsUndefined()) return NULL; |
| 247 | 247 |
| 248 if (*object == Builtins::builtin(Builtins::StoreIC_GlobalProxy)) { | 248 if (*object == Builtins::builtin(Builtins::StoreIC_GlobalProxy)) { |
| 249 // TODO(fschneider): We could collect the maps and signal that | 249 // TODO(fschneider): We could collect the maps and signal that |
| 250 // we need a generic store (or load) here. | 250 // we need a generic store (or load) here. |
| 251 ASSERT(Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC); | 251 ASSERT(Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC); |
| 252 return NULL; | 252 return NULL; |
| 253 } else if (object->IsMap()) { | 253 } else if (object->IsMap()) { |
| 254 ZoneMapList* types = new ZoneMapList(1); | 254 ZoneMapList* types = new ZoneMapList(1); |
| 255 types->Add(Handle<Map>::cast(object)); | 255 types->Add(Handle<Map>::cast(object)); |
| 256 return types; | 256 return types; |
| 257 } else if (Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) { | 257 } else if (Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) { |
| 258 ZoneMapList* types = new ZoneMapList(4); | 258 ZoneMapList* types = new ZoneMapList(4); |
| 259 ASSERT(object->IsCode()); | 259 ASSERT(object->IsCode()); |
| 260 StubCache::CollectMatchingMaps(types, *name, flags); | 260 StubCache::CollectMatchingMaps(types, *name, flags); |
| 261 return types->length() > 0 ? types : NULL; | 261 return types->length() > 0 ? types : NULL; |
| 262 } else { | 262 } else { |
| 263 return NULL; | 263 return NULL; |
| 264 } | 264 } |
| 265 } | 265 } |
| 266 | 266 |
| 267 | 267 |
| 268 void TypeFeedbackOracle::PopulateMap(Handle<Code> code) { | 268 void TypeFeedbackOracle::PopulateMap(Handle<Code> code) { |
| 269 HandleScope scope; | 269 HandleScope scope; |
| 270 | 270 |
| 271 const int kInitialCapacity = 16; | 271 const int kInitialCapacity = 16; |
| 272 List<int> code_positions(kInitialCapacity); | 272 List<int> code_positions(kInitialCapacity); |
| 273 List<int> source_positions(kInitialCapacity); | 273 List<AstId> ast_ids(kInitialCapacity); |
| 274 CollectPositions(*code, &code_positions, &source_positions); | 274 CollectIds(*code, &code_positions, &ast_ids); |
| 275 | 275 |
| 276 int length = code_positions.length(); | 276 const int length = code_positions.length(); |
| 277 ASSERT(source_positions.length() == length); | 277 ASSERT(ast_ids.length() == length); |
| 278 for (int i = 0; i < length; i++) { | 278 for (int i = 0; i < length; i++) { |
| 279 RelocInfo info(code->instruction_start() + code_positions[i], | 279 RelocInfo info(code->instruction_start() + code_positions[i], |
| 280 RelocInfo::CODE_TARGET, 0); | 280 RelocInfo::CODE_TARGET, 0); |
| 281 Handle<Code> target(Code::GetCodeFromTargetAddress(info.target_address())); | 281 Handle<Code> target(Code::GetCodeFromTargetAddress(info.target_address())); |
| 282 int position = source_positions[i]; | 282 AstId id = ast_ids[i]; |
| 283 InlineCacheState state = target->ic_state(); | 283 InlineCacheState state = target->ic_state(); |
| 284 Code::Kind kind = target->kind(); | 284 Code::Kind kind = target->kind(); |
| 285 if (kind == Code::BINARY_OP_IC || | 285 if (kind == Code::BINARY_OP_IC || |
| 286 kind == Code::TYPE_RECORDING_BINARY_OP_IC || | 286 kind == Code::TYPE_RECORDING_BINARY_OP_IC || |
| 287 kind == Code::COMPARE_IC) { | 287 kind == Code::COMPARE_IC) { |
| 288 // TODO(kasperl): Avoid having multiple ICs with the same | 288 SetInfo(id, target); |
| 289 // position by making sure that we have position information | |
| 290 // recorded for all binary ICs. | |
| 291 if (GetElement(map_, position)->IsUndefined()) { | |
| 292 SetElement(map_, position, target); | |
| 293 } | |
| 294 } else if (state == MONOMORPHIC) { | 289 } else if (state == MONOMORPHIC) { |
| 295 Handle<Map> map = Handle<Map>(target->FindFirstMap()); | 290 Handle<Map> map = Handle<Map>(target->FindFirstMap()); |
| 296 if (*map == NULL) { | 291 if (*map == NULL) { |
| 297 SetElement(map_, position, target); | 292 SetInfo(id, target); |
| 298 } else { | 293 } else { |
| 299 SetElement(map_, position, map); | 294 SetInfo(id, map); |
| 300 } | 295 } |
| 301 } else if (state == MEGAMORPHIC) { | 296 } else if (state == MEGAMORPHIC) { |
| 302 SetElement(map_, position, target); | 297 SetInfo(id, target); |
| 303 } | 298 } |
| 304 } | 299 } |
| 305 } | 300 } |
| 306 | 301 |
| 307 | 302 |
| 308 void TypeFeedbackOracle::CollectPositions(Code* code, | 303 void TypeFeedbackOracle::CollectIds(Code* code, |
| 309 List<int>* code_positions, | 304 List<int>* code_positions, |
| 310 List<int>* source_positions) { | 305 List<AstId>* ast_ids) { |
| 311 AssertNoAllocation no_allocation; | 306 AssertNoAllocation no_allocation; |
| 312 int position = 0; | 307 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); |
| 313 // Because the ICs we use for global variables access in the full | |
| 314 // code generator do not have any meaningful positions, we avoid | |
| 315 // collecting those by filtering out contextual code targets. | |
| 316 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | | |
| 317 RelocInfo::kPositionMask; | |
| 318 for (RelocIterator it(code, mask); !it.done(); it.next()) { | 308 for (RelocIterator it(code, mask); !it.done(); it.next()) { |
| 319 RelocInfo* info = it.rinfo(); | 309 RelocInfo* info = it.rinfo(); |
| 320 RelocInfo::Mode mode = info->rmode(); | 310 Code* target = Code::GetCodeFromTargetAddress(info->target_address()); |
| 321 if (RelocInfo::IsCodeTarget(mode)) { | 311 if (target->is_inline_cache_stub()) { |
| 322 Code* target = Code::GetCodeFromTargetAddress(info->target_address()); | 312 InlineCacheState state = target->ic_state(); |
| 323 if (target->is_inline_cache_stub()) { | 313 Code::Kind kind = target->kind(); |
| 324 InlineCacheState state = target->ic_state(); | 314 if (kind == Code::BINARY_OP_IC) { |
| 325 Code::Kind kind = target->kind(); | 315 if (target->binary_op_type() == BinaryOpIC::GENERIC) continue; |
| 326 if (kind == Code::BINARY_OP_IC) { | 316 } else if (kind == Code::TYPE_RECORDING_BINARY_OP_IC) { |
| 327 if (target->binary_op_type() == BinaryOpIC::GENERIC) continue; | 317 if (target->type_recording_binary_op_type() == |
| 328 } else if (kind == Code::TYPE_RECORDING_BINARY_OP_IC) { | 318 TRBinaryOpIC::GENERIC) { |
| 329 if (target->type_recording_binary_op_type() == | 319 continue; |
| 330 TRBinaryOpIC::GENERIC) { | |
| 331 continue; | |
| 332 } | |
| 333 } else if (kind == Code::COMPARE_IC) { | |
| 334 if (target->compare_state() == CompareIC::GENERIC) continue; | |
| 335 } else { | |
| 336 if (kind == Code::CALL_IC && state == MONOMORPHIC && | |
| 337 target->check_type() != RECEIVER_MAP_CHECK) continue; | |
| 338 if (state != MONOMORPHIC && state != MEGAMORPHIC) continue; | |
| 339 } | 320 } |
| 340 code_positions->Add( | 321 } else if (kind == Code::COMPARE_IC) { |
| 341 static_cast<int>(info->pc() - code->instruction_start())); | 322 if (target->compare_state() == CompareIC::GENERIC) continue; |
| 342 source_positions->Add(position); | 323 } else { |
| 324 if (kind == Code::CALL_IC && state == MONOMORPHIC && |
| 325 target->check_type() != RECEIVER_MAP_CHECK) continue; |
| 326 if (state != MONOMORPHIC && state != MEGAMORPHIC) continue; |
| 343 } | 327 } |
| 344 } else { | 328 code_positions->Add( |
| 345 ASSERT(RelocInfo::IsPosition(mode)); | 329 static_cast<int>(info->pc() - code->instruction_start())); |
| 346 position = static_cast<int>(info->data()); | 330 ast_ids->Add(static_cast<AstId>(info->data())); |
| 347 } | 331 } |
| 348 } | 332 } |
| 349 } | 333 } |
| 350 | 334 |
| 335 |
| 336 void TypeFeedbackOracle::SetInfo(AstId id, Handle<Object> info) { |
| 337 ASSERT(GetElement(map_, id)->IsUndefined()); |
| 338 SetElement(map_, id, info); |
| 339 } |
| 340 |
| 351 } } // namespace v8::internal | 341 } } // namespace v8::internal |
| OLD | NEW |