| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 26 matching lines...) Expand all Loading... |
| 37 | 37 |
| 38 #include "ic-inl.h" | 38 #include "ic-inl.h" |
| 39 #include "objects-inl.h" | 39 #include "objects-inl.h" |
| 40 | 40 |
| 41 namespace v8 { | 41 namespace v8 { |
| 42 namespace internal { | 42 namespace internal { |
| 43 | 43 |
| 44 | 44 |
| 45 TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code, | 45 TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code, |
| 46 Handle<Context> native_context, | 46 Handle<Context> native_context, |
| 47 Isolate* isolate, | |
| 48 Zone* zone) | 47 Zone* zone) |
| 49 : native_context_(native_context), | 48 : native_context_(native_context), |
| 50 isolate_(isolate), | |
| 51 zone_(zone) { | 49 zone_(zone) { |
| 52 BuildDictionary(code); | 50 BuildDictionary(code); |
| 53 ASSERT(dictionary_->IsDictionary()); | 51 ASSERT(dictionary_->IsDictionary()); |
| 54 } | 52 } |
| 55 | 53 |
| 56 | 54 |
| 57 static uint32_t IdToKey(TypeFeedbackId ast_id) { | 55 static uint32_t IdToKey(TypeFeedbackId ast_id) { |
| 58 return static_cast<uint32_t>(ast_id.ToInt()); | 56 return static_cast<uint32_t>(ast_id.ToInt()); |
| 59 } | 57 } |
| 60 | 58 |
| 61 | 59 |
| 62 Handle<Object> TypeFeedbackOracle::GetInfo(TypeFeedbackId ast_id) { | 60 Handle<Object> TypeFeedbackOracle::GetInfo(TypeFeedbackId ast_id) { |
| 63 int entry = dictionary_->FindEntry(IdToKey(ast_id)); | 61 int entry = dictionary_->FindEntry(IdToKey(ast_id)); |
| 64 if (entry != UnseededNumberDictionary::kNotFound) { | 62 if (entry != UnseededNumberDictionary::kNotFound) { |
| 65 Object* value = dictionary_->ValueAt(entry); | 63 Object* value = dictionary_->ValueAt(entry); |
| 66 if (value->IsCell()) { | 64 if (value->IsCell()) { |
| 67 Cell* cell = Cell::cast(value); | 65 Cell* cell = Cell::cast(value); |
| 68 return Handle<Object>(cell->value(), isolate_); | 66 return Handle<Object>(cell->value(), isolate()); |
| 69 } else { | 67 } else { |
| 70 return Handle<Object>(value, isolate_); | 68 return Handle<Object>(value, isolate()); |
| 71 } | 69 } |
| 72 } | 70 } |
| 73 return Handle<Object>::cast(isolate_->factory()->undefined_value()); | 71 return Handle<Object>::cast(isolate()->factory()->undefined_value()); |
| 74 } | 72 } |
| 75 | 73 |
| 76 | 74 |
| 77 Handle<Cell> TypeFeedbackOracle::GetInfoCell( | 75 Handle<Cell> TypeFeedbackOracle::GetInfoCell( |
| 78 TypeFeedbackId ast_id) { | 76 TypeFeedbackId ast_id) { |
| 79 int entry = dictionary_->FindEntry(IdToKey(ast_id)); | 77 int entry = dictionary_->FindEntry(IdToKey(ast_id)); |
| 80 if (entry != UnseededNumberDictionary::kNotFound) { | 78 if (entry != UnseededNumberDictionary::kNotFound) { |
| 81 Cell* cell = Cell::cast(dictionary_->ValueAt(entry)); | 79 Cell* cell = Cell::cast(dictionary_->ValueAt(entry)); |
| 82 return Handle<Cell>(cell, isolate_); | 80 return Handle<Cell>(cell, isolate()); |
| 83 } | 81 } |
| 84 return Handle<Cell>::null(); | 82 return Handle<Cell>::null(); |
| 85 } | 83 } |
| 86 | 84 |
| 87 | 85 |
| 88 bool TypeFeedbackOracle::LoadIsUninitialized(TypeFeedbackId id) { | 86 bool TypeFeedbackOracle::LoadIsUninitialized(TypeFeedbackId id) { |
| 89 Handle<Object> maybe_code = GetInfo(id); | 87 Handle<Object> maybe_code = GetInfo(id); |
| 90 if (maybe_code->IsCode()) { | 88 if (maybe_code->IsCode()) { |
| 91 Handle<Code> code = Handle<Code>::cast(maybe_code); | 89 Handle<Code> code = Handle<Code>::cast(maybe_code); |
| 92 return code->is_inline_cache_stub() && code->ic_state() == UNINITIALIZED; | 90 return code->is_inline_cache_stub() && code->ic_state() == UNINITIALIZED; |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 if (!value->IsSmi()) return RECEIVER_MAP_CHECK; | 197 if (!value->IsSmi()) return RECEIVER_MAP_CHECK; |
| 200 CheckType check = static_cast<CheckType>(Smi::cast(*value)->value()); | 198 CheckType check = static_cast<CheckType>(Smi::cast(*value)->value()); |
| 201 ASSERT(check != RECEIVER_MAP_CHECK); | 199 ASSERT(check != RECEIVER_MAP_CHECK); |
| 202 return check; | 200 return check; |
| 203 } | 201 } |
| 204 | 202 |
| 205 | 203 |
| 206 Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(TypeFeedbackId id) { | 204 Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(TypeFeedbackId id) { |
| 207 Handle<Object> info = GetInfo(id); | 205 Handle<Object> info = GetInfo(id); |
| 208 if (info->IsAllocationSite()) { | 206 if (info->IsAllocationSite()) { |
| 209 return Handle<JSFunction>(isolate_->global_context()->array_function()); | 207 return Handle<JSFunction>(isolate()->global_context()->array_function()); |
| 210 } else { | 208 } else { |
| 211 return Handle<JSFunction>::cast(info); | 209 return Handle<JSFunction>::cast(info); |
| 212 } | 210 } |
| 213 } | 211 } |
| 214 | 212 |
| 215 | 213 |
| 216 Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(TypeFeedbackId id) { | 214 Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(TypeFeedbackId id) { |
| 217 Handle<Object> info = GetInfo(id); | 215 Handle<Object> info = GetInfo(id); |
| 218 if (info->IsAllocationSite()) { | 216 if (info->IsAllocationSite()) { |
| 219 return Handle<JSFunction>(isolate_->global_context()->array_function()); | 217 return Handle<JSFunction>(isolate()->global_context()->array_function()); |
| 220 } else { | 218 } else { |
| 221 return Handle<JSFunction>::cast(info); | 219 return Handle<JSFunction>::cast(info); |
| 222 } | 220 } |
| 223 } | 221 } |
| 224 | 222 |
| 225 | 223 |
| 226 Handle<Cell> TypeFeedbackOracle::GetCallNewAllocationInfoCell( | 224 Handle<Cell> TypeFeedbackOracle::GetCallNewAllocationInfoCell( |
| 227 TypeFeedbackId id) { | 225 TypeFeedbackId id) { |
| 228 return GetInfoCell(id); | 226 return GetInfoCell(id); |
| 229 } | 227 } |
| 230 | 228 |
| 231 | 229 |
| 232 bool TypeFeedbackOracle::LoadIsBuiltin( | 230 bool TypeFeedbackOracle::LoadIsBuiltin( |
| 233 TypeFeedbackId id, Builtins::Name builtin) { | 231 TypeFeedbackId id, Builtins::Name builtin) { |
| 234 return *GetInfo(id) == isolate_->builtins()->builtin(builtin); | 232 return *GetInfo(id) == isolate()->builtins()->builtin(builtin); |
| 235 } | 233 } |
| 236 | 234 |
| 237 | 235 |
| 238 bool TypeFeedbackOracle::LoadIsStub(TypeFeedbackId id, ICStub* stub) { | 236 bool TypeFeedbackOracle::LoadIsStub(TypeFeedbackId id, ICStub* stub) { |
| 239 Handle<Object> object = GetInfo(id); | 237 Handle<Object> object = GetInfo(id); |
| 240 if (!object->IsCode()) return false; | 238 if (!object->IsCode()) return false; |
| 241 Handle<Code> code = Handle<Code>::cast(object); | 239 Handle<Code> code = Handle<Code>::cast(object); |
| 242 if (!code->is_load_stub()) return false; | 240 if (!code->is_load_stub()) return false; |
| 243 if (code->ic_state() != MONOMORPHIC) return false; | 241 if (code->ic_state() != MONOMORPHIC) return false; |
| 244 return stub->Describes(*code); | 242 return stub->Describes(*code); |
| 245 } | 243 } |
| 246 | 244 |
| 247 | 245 |
| 248 void TypeFeedbackOracle::CompareType(TypeFeedbackId id, | 246 void TypeFeedbackOracle::CompareType(TypeFeedbackId id, |
| 249 Handle<Type>* left_type, | 247 Type** left_type, |
| 250 Handle<Type>* right_type, | 248 Type** right_type, |
| 251 Handle<Type>* combined_type) { | 249 Type** combined_type) { |
| 252 Handle<Object> info = GetInfo(id); | 250 Handle<Object> info = GetInfo(id); |
| 253 if (!info->IsCode()) { | 251 if (!info->IsCode()) { |
| 254 // For some comparisons we don't have ICs, e.g. LiteralCompareTypeof. | 252 // For some comparisons we don't have ICs, e.g. LiteralCompareTypeof. |
| 255 *left_type = *right_type = *combined_type = Type::None(isolate_); | 253 *left_type = *right_type = *combined_type = Type::None(zone()); |
| 256 return; | 254 return; |
| 257 } | 255 } |
| 258 Handle<Code> code = Handle<Code>::cast(info); | 256 Handle<Code> code = Handle<Code>::cast(info); |
| 259 | 257 |
| 260 Handle<Map> map; | 258 Handle<Map> map; |
| 261 Map* raw_map = code->FindFirstMap(); | 259 Map* raw_map = code->FindFirstMap(); |
| 262 if (raw_map != NULL) { | 260 if (raw_map != NULL) { |
| 263 map = Map::CurrentMapForDeprecated(handle(raw_map)); | 261 map = Map::CurrentMapForDeprecated(handle(raw_map)); |
| 264 if (!map.is_null() && CanRetainOtherContext(*map, *native_context_)) { | 262 if (!map.is_null() && CanRetainOtherContext(*map, *native_context_)) { |
| 265 map = Handle<Map>::null(); | 263 map = Handle<Map>::null(); |
| 266 } | 264 } |
| 267 } | 265 } |
| 268 | 266 |
| 269 if (code->is_compare_ic_stub()) { | 267 if (code->is_compare_ic_stub()) { |
| 270 int stub_minor_key = code->stub_info(); | 268 int stub_minor_key = code->stub_info(); |
| 271 CompareIC::StubInfoToType( | 269 CompareIC::StubInfoToType( |
| 272 stub_minor_key, left_type, right_type, combined_type, map, isolate()); | 270 stub_minor_key, left_type, right_type, combined_type, map, zone()); |
| 273 } else if (code->is_compare_nil_ic_stub()) { | 271 } else if (code->is_compare_nil_ic_stub()) { |
| 274 CompareNilICStub stub(code->extended_extra_ic_state()); | 272 CompareNilICStub stub(code->extended_extra_ic_state()); |
| 275 *combined_type = stub.GetType(isolate_, map); | 273 *combined_type = stub.GetType(zone(), map); |
| 276 *left_type = *right_type = stub.GetInputType(isolate_, map); | 274 *left_type = *right_type = stub.GetInputType(zone(), map); |
| 277 } | 275 } |
| 278 } | 276 } |
| 279 | 277 |
| 280 | 278 |
| 281 void TypeFeedbackOracle::BinaryType(TypeFeedbackId id, | 279 void TypeFeedbackOracle::BinaryType(TypeFeedbackId id, |
| 282 Handle<Type>* left, | 280 Type** left, |
| 283 Handle<Type>* right, | 281 Type** right, |
| 284 Handle<Type>* result, | 282 Type** result, |
| 285 Maybe<int>* fixed_right_arg, | 283 Maybe<int>* fixed_right_arg, |
| 286 Token::Value op) { | 284 Token::Value op) { |
| 287 Handle<Object> object = GetInfo(id); | 285 Handle<Object> object = GetInfo(id); |
| 288 if (!object->IsCode()) { | 286 if (!object->IsCode()) { |
| 289 // For some binary ops we don't have ICs, e.g. Token::COMMA, but for the | 287 // For some binary ops we don't have ICs, e.g. Token::COMMA, but for the |
| 290 // operations covered by the BinaryOpIC we should always have them. | 288 // operations covered by the BinaryOpIC we should always have them. |
| 291 ASSERT(op < BinaryOpIC::State::FIRST_TOKEN || | 289 ASSERT(op < BinaryOpIC::State::FIRST_TOKEN || |
| 292 op > BinaryOpIC::State::LAST_TOKEN); | 290 op > BinaryOpIC::State::LAST_TOKEN); |
| 293 *left = *right = *result = Type::None(isolate_); | 291 *left = *right = *result = Type::None(zone()); |
| 294 *fixed_right_arg = Maybe<int>(); | 292 *fixed_right_arg = Maybe<int>(); |
| 295 return; | 293 return; |
| 296 } | 294 } |
| 297 Handle<Code> code = Handle<Code>::cast(object); | 295 Handle<Code> code = Handle<Code>::cast(object); |
| 298 ASSERT_EQ(Code::BINARY_OP_IC, code->kind()); | 296 ASSERT_EQ(Code::BINARY_OP_IC, code->kind()); |
| 299 BinaryOpIC::State state(code->extended_extra_ic_state()); | 297 BinaryOpIC::State state(code->extended_extra_ic_state()); |
| 300 ASSERT_EQ(op, state.op()); | 298 ASSERT_EQ(op, state.op()); |
| 301 | 299 |
| 302 *left = state.GetLeftType(isolate()); | 300 *left = state.GetLeftType(zone()); |
| 303 *right = state.GetRightType(isolate()); | 301 *right = state.GetRightType(zone()); |
| 304 *result = state.GetResultType(isolate()); | 302 *result = state.GetResultType(zone()); |
| 305 *fixed_right_arg = state.fixed_right_arg(); | 303 *fixed_right_arg = state.fixed_right_arg(); |
| 306 } | 304 } |
| 307 | 305 |
| 308 | 306 |
| 309 Handle<Type> TypeFeedbackOracle::CountType(TypeFeedbackId id) { | 307 Type* TypeFeedbackOracle::CountType(TypeFeedbackId id) { |
| 310 Handle<Object> object = GetInfo(id); | 308 Handle<Object> object = GetInfo(id); |
| 311 if (!object->IsCode()) return Type::None(isolate_); | 309 if (!object->IsCode()) return Type::None(zone()); |
| 312 Handle<Code> code = Handle<Code>::cast(object); | 310 Handle<Code> code = Handle<Code>::cast(object); |
| 313 ASSERT_EQ(Code::BINARY_OP_IC, code->kind()); | 311 ASSERT_EQ(Code::BINARY_OP_IC, code->kind()); |
| 314 BinaryOpIC::State state(code->extended_extra_ic_state()); | 312 BinaryOpIC::State state(code->extended_extra_ic_state()); |
| 315 return state.GetLeftType(isolate()); | 313 return state.GetLeftType(zone()); |
| 316 } | 314 } |
| 317 | 315 |
| 318 | 316 |
| 319 void TypeFeedbackOracle::PropertyReceiverTypes( | 317 void TypeFeedbackOracle::PropertyReceiverTypes( |
| 320 TypeFeedbackId id, Handle<String> name, | 318 TypeFeedbackId id, Handle<String> name, |
| 321 SmallMapList* receiver_types, bool* is_prototype) { | 319 SmallMapList* receiver_types, bool* is_prototype) { |
| 322 receiver_types->Clear(); | 320 receiver_types->Clear(); |
| 323 FunctionPrototypeStub proto_stub(Code::LOAD_IC); | 321 FunctionPrototypeStub proto_stub(Code::LOAD_IC); |
| 324 *is_prototype = LoadIsStub(id, &proto_stub); | 322 *is_prototype = LoadIsStub(id, &proto_stub); |
| 325 if (!*is_prototype) { | 323 if (!*is_prototype) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 SmallMapList* types) { | 373 SmallMapList* types) { |
| 376 Handle<Object> object = GetInfo(ast_id); | 374 Handle<Object> object = GetInfo(ast_id); |
| 377 if (object->IsUndefined() || object->IsSmi()) return; | 375 if (object->IsUndefined() || object->IsSmi()) return; |
| 378 | 376 |
| 379 ASSERT(object->IsCode()); | 377 ASSERT(object->IsCode()); |
| 380 Handle<Code> code(Handle<Code>::cast(object)); | 378 Handle<Code> code(Handle<Code>::cast(object)); |
| 381 | 379 |
| 382 if (FLAG_collect_megamorphic_maps_from_stub_cache && | 380 if (FLAG_collect_megamorphic_maps_from_stub_cache && |
| 383 code->ic_state() == MEGAMORPHIC) { | 381 code->ic_state() == MEGAMORPHIC) { |
| 384 types->Reserve(4, zone()); | 382 types->Reserve(4, zone()); |
| 385 isolate_->stub_cache()->CollectMatchingMaps( | 383 isolate()->stub_cache()->CollectMatchingMaps( |
| 386 types, name, flags, native_context_, zone()); | 384 types, name, flags, native_context_, zone()); |
| 387 } else { | 385 } else { |
| 388 CollectReceiverTypes(ast_id, types); | 386 CollectReceiverTypes(ast_id, types); |
| 389 } | 387 } |
| 390 } | 388 } |
| 391 | 389 |
| 392 | 390 |
| 393 // Check if a map originates from a given native context. We use this | 391 // Check if a map originates from a given native context. We use this |
| 394 // information to filter out maps from different context to avoid | 392 // information to filter out maps from different context to avoid |
| 395 // retaining objects from different tabs in Chrome via optimized code. | 393 // retaining objects from different tabs in Chrome via optimized code. |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 } | 452 } |
| 455 | 453 |
| 456 | 454 |
| 457 // Things are a bit tricky here: The iterator for the RelocInfos and the infos | 455 // Things are a bit tricky here: The iterator for the RelocInfos and the infos |
| 458 // themselves are not GC-safe, so we first get all infos, then we create the | 456 // themselves are not GC-safe, so we first get all infos, then we create the |
| 459 // dictionary (possibly triggering GC), and finally we relocate the collected | 457 // dictionary (possibly triggering GC), and finally we relocate the collected |
| 460 // infos before we process them. | 458 // infos before we process them. |
| 461 void TypeFeedbackOracle::BuildDictionary(Handle<Code> code) { | 459 void TypeFeedbackOracle::BuildDictionary(Handle<Code> code) { |
| 462 DisallowHeapAllocation no_allocation; | 460 DisallowHeapAllocation no_allocation; |
| 463 ZoneList<RelocInfo> infos(16, zone()); | 461 ZoneList<RelocInfo> infos(16, zone()); |
| 464 HandleScope scope(isolate_); | 462 HandleScope scope(isolate()); |
| 465 GetRelocInfos(code, &infos); | 463 GetRelocInfos(code, &infos); |
| 466 CreateDictionary(code, &infos); | 464 CreateDictionary(code, &infos); |
| 467 ProcessRelocInfos(&infos); | 465 ProcessRelocInfos(&infos); |
| 468 ProcessTypeFeedbackCells(code); | 466 ProcessTypeFeedbackCells(code); |
| 469 // Allocate handle in the parent scope. | 467 // Allocate handle in the parent scope. |
| 470 dictionary_ = scope.CloseAndEscape(dictionary_); | 468 dictionary_ = scope.CloseAndEscape(dictionary_); |
| 471 } | 469 } |
| 472 | 470 |
| 473 | 471 |
| 474 void TypeFeedbackOracle::GetRelocInfos(Handle<Code> code, | 472 void TypeFeedbackOracle::GetRelocInfos(Handle<Code> code, |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 566 #ifdef DEBUG | 564 #ifdef DEBUG |
| 567 Object* result = NULL; | 565 Object* result = NULL; |
| 568 // Dictionary has been allocated with sufficient size for all elements. | 566 // Dictionary has been allocated with sufficient size for all elements. |
| 569 ASSERT(maybe_result->ToObject(&result)); | 567 ASSERT(maybe_result->ToObject(&result)); |
| 570 ASSERT(*dictionary_ == result); | 568 ASSERT(*dictionary_ == result); |
| 571 #endif | 569 #endif |
| 572 } | 570 } |
| 573 | 571 |
| 574 | 572 |
| 575 } } // namespace v8::internal | 573 } } // namespace v8::internal |
| OLD | NEW |