Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/ast.h" | 7 #include "src/ast.h" |
| 8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
| 9 #include "src/compiler.h" | 9 #include "src/compiler.h" |
| 10 #include "src/ic/ic.h" | 10 #include "src/ic/ic.h" |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 45 return Handle<Object>(value, isolate()); | 45 return Handle<Object>(value, isolate()); |
| 46 } | 46 } |
| 47 } | 47 } |
| 48 return Handle<Object>::cast(isolate()->factory()->undefined_value()); | 48 return Handle<Object>::cast(isolate()->factory()->undefined_value()); |
| 49 } | 49 } |
| 50 | 50 |
| 51 | 51 |
| 52 Handle<Object> TypeFeedbackOracle::GetInfo(FeedbackVectorSlot slot) { | 52 Handle<Object> TypeFeedbackOracle::GetInfo(FeedbackVectorSlot slot) { |
| 53 DCHECK(slot.ToInt() >= 0 && slot.ToInt() < feedback_vector_->length()); | 53 DCHECK(slot.ToInt() >= 0 && slot.ToInt() < feedback_vector_->length()); |
| 54 Object* obj = feedback_vector_->Get(slot); | 54 Object* obj = feedback_vector_->Get(slot); |
| 55 if (!obj->IsJSFunction() || | 55 return Handle<Object>(obj, isolate()); |
| 56 !CanRetainOtherContext(JSFunction::cast(obj), *native_context_)) { | |
| 57 DCHECK(!obj->IsMap()); | |
| 58 return Handle<Object>(obj, isolate()); | |
| 59 } | |
| 60 return Handle<Object>::cast(isolate()->factory()->undefined_value()); | |
| 61 } | 56 } |
| 62 | 57 |
| 63 | 58 |
| 64 Handle<Object> TypeFeedbackOracle::GetInfo(FeedbackVectorICSlot slot) { | 59 Handle<Object> TypeFeedbackOracle::GetInfo(FeedbackVectorICSlot slot) { |
| 65 DCHECK(slot.ToInt() >= 0 && slot.ToInt() < feedback_vector_->length()); | 60 DCHECK(slot.ToInt() >= 0 && slot.ToInt() < feedback_vector_->length()); |
| 66 Handle<Object> undefined = | 61 Handle<Object> undefined = |
| 67 Handle<Object>::cast(isolate()->factory()->undefined_value()); | 62 Handle<Object>::cast(isolate()->factory()->undefined_value()); |
| 68 Object* obj = feedback_vector_->Get(slot); | 63 Object* obj = feedback_vector_->Get(slot); |
| 69 | 64 |
| 70 // Vector-based ICs do not embed direct pointers to maps, functions. | 65 // Vector-based ICs do not embed direct pointers to maps, functions. |
| 71 // Instead a WeakCell is always used. | 66 // Instead a WeakCell is always used. |
| 72 if (obj->IsWeakCell()) { | 67 if (obj->IsWeakCell()) { |
| 73 WeakCell* cell = WeakCell::cast(obj); | 68 WeakCell* cell = WeakCell::cast(obj); |
| 74 if (cell->cleared()) return undefined; | 69 if (cell->cleared()) return undefined; |
| 75 obj = cell->value(); | 70 obj = cell->value(); |
| 76 } | 71 } |
| 77 | 72 |
| 78 if ((obj->IsJSFunction() && | 73 if (obj->IsJSFunction() || obj->IsAllocationSite() || obj->IsSymbol()) { |
| 79 !CanRetainOtherContext(JSFunction::cast(obj), *native_context_)) || | |
| 80 obj->IsAllocationSite() || obj->IsSymbol()) { | |
| 81 return Handle<Object>(obj, isolate()); | 74 return Handle<Object>(obj, isolate()); |
| 82 } | 75 } |
| 83 | 76 |
| 84 return undefined; | 77 return undefined; |
| 85 } | 78 } |
| 86 | 79 |
| 87 | 80 |
| 88 bool TypeFeedbackOracle::LoadIsUninitialized(TypeFeedbackId id) { | 81 bool TypeFeedbackOracle::LoadIsUninitialized(TypeFeedbackId id) { |
| 89 Handle<Object> maybe_code = GetInfo(id); | 82 Handle<Object> maybe_code = GetInfo(id); |
| 90 if (maybe_code->IsCode()) { | 83 if (maybe_code->IsCode()) { |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 241 Handle<Object> info = GetInfo(id); | 234 Handle<Object> info = GetInfo(id); |
| 242 if (!info->IsCode()) { | 235 if (!info->IsCode()) { |
| 243 // For some comparisons we don't have ICs, e.g. LiteralCompareTypeof. | 236 // For some comparisons we don't have ICs, e.g. LiteralCompareTypeof. |
| 244 *left_type = *right_type = *combined_type = Type::None(zone()); | 237 *left_type = *right_type = *combined_type = Type::None(zone()); |
| 245 return; | 238 return; |
| 246 } | 239 } |
| 247 Handle<Code> code = Handle<Code>::cast(info); | 240 Handle<Code> code = Handle<Code>::cast(info); |
| 248 | 241 |
| 249 Handle<Map> map; | 242 Handle<Map> map; |
| 250 Map* raw_map = code->FindFirstMap(); | 243 Map* raw_map = code->FindFirstMap(); |
| 251 if (raw_map != NULL) { | 244 if (raw_map != NULL) Map::TryUpdate(handle(raw_map)).ToHandle(&map); |
| 252 if (Map::TryUpdate(handle(raw_map)).ToHandle(&map) && | |
| 253 CanRetainOtherContext(*map, *native_context_)) { | |
| 254 map = Handle<Map>::null(); | |
| 255 } | |
| 256 } | |
| 257 | 245 |
| 258 if (code->is_compare_ic_stub()) { | 246 if (code->is_compare_ic_stub()) { |
| 259 CompareICStub stub(code->stub_key(), isolate()); | 247 CompareICStub stub(code->stub_key(), isolate()); |
| 260 *left_type = CompareICState::StateToType(zone(), stub.left()); | 248 *left_type = CompareICState::StateToType(zone(), stub.left()); |
| 261 *right_type = CompareICState::StateToType(zone(), stub.right()); | 249 *right_type = CompareICState::StateToType(zone(), stub.right()); |
| 262 *combined_type = CompareICState::StateToType(zone(), stub.state(), map); | 250 *combined_type = CompareICState::StateToType(zone(), stub.state(), map); |
| 263 } else if (code->is_compare_nil_ic_stub()) { | 251 } else if (code->is_compare_nil_ic_stub()) { |
| 264 CompareNilICStub stub(isolate(), code->extra_ic_state()); | 252 CompareNilICStub stub(isolate(), code->extra_ic_state()); |
| 265 *combined_type = stub.GetType(zone(), map); | 253 *combined_type = stub.GetType(zone(), map); |
| 266 *left_type = *right_type = stub.GetInputType(zone(), map); | 254 *left_type = *right_type = stub.GetInputType(zone(), map); |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 412 obj->ic_state() == MEGAMORPHIC) { | 400 obj->ic_state() == MEGAMORPHIC) { |
| 413 types->Reserve(4, zone()); | 401 types->Reserve(4, zone()); |
| 414 isolate()->stub_cache()->CollectMatchingMaps( | 402 isolate()->stub_cache()->CollectMatchingMaps( |
| 415 types, name, flags, native_context_, zone()); | 403 types, name, flags, native_context_, zone()); |
| 416 } else { | 404 } else { |
| 417 CollectReceiverTypes<T>(obj, types); | 405 CollectReceiverTypes<T>(obj, types); |
| 418 } | 406 } |
| 419 } | 407 } |
| 420 | 408 |
| 421 | 409 |
| 422 // Check if a map originates from a given native context. We use this | |
| 423 // information to filter out maps from different context to avoid | |
| 424 // retaining objects from different tabs in Chrome via optimized code. | |
| 425 bool TypeFeedbackOracle::CanRetainOtherContext(Map* map, | |
| 426 Context* native_context) { | |
| 427 Object* constructor = NULL; | |
| 428 while (!map->prototype()->IsNull()) { | |
| 429 constructor = map->GetConstructor(); | |
| 430 if (!constructor->IsNull()) { | |
| 431 // If the constructor is not null or a JSFunction, we have to | |
| 432 // conservatively assume that it may retain a native context. | |
| 433 if (!constructor->IsJSFunction()) return true; | |
| 434 // Check if the constructor directly references a foreign context. | |
| 435 if (CanRetainOtherContext(JSFunction::cast(constructor), | |
| 436 native_context)) { | |
| 437 return true; | |
| 438 } | |
| 439 } | |
| 440 map = HeapObject::cast(map->prototype())->map(); | |
| 441 } | |
| 442 constructor = map->GetConstructor(); | |
| 443 if (constructor->IsNull()) return false; | |
| 444 // If the constructor is not null or a JSFunction, we have to conservatively | |
| 445 // assume that it may retain a native context. | |
| 446 if (!constructor->IsJSFunction()) return true; | |
| 447 JSFunction* function = JSFunction::cast(constructor); | |
| 448 return CanRetainOtherContext(function, native_context); | |
| 449 } | |
| 450 | |
| 451 | |
| 452 bool TypeFeedbackOracle::CanRetainOtherContext(JSFunction* function, | |
| 453 Context* native_context) { | |
| 454 return function->context()->global_object() != native_context->global_object() | |
| 455 && function->context()->global_object() != native_context->builtins(); | |
| 456 } | |
| 457 | |
| 458 | |
| 459 void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id, | 410 void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id, |
| 460 SmallMapList* types) { | 411 SmallMapList* types) { |
| 461 Handle<Object> object = GetInfo(ast_id); | 412 Handle<Object> object = GetInfo(ast_id); |
| 462 if (!object->IsCode()) return; | 413 if (!object->IsCode()) return; |
| 463 Handle<Code> code = Handle<Code>::cast(object); | 414 Handle<Code> code = Handle<Code>::cast(object); |
| 464 CollectReceiverTypes<Code>(*code, types); | 415 CollectReceiverTypes<Code>(*code, types); |
| 465 } | 416 } |
| 466 | 417 |
| 467 | 418 |
| 468 template <class T> | 419 template <class T> |
| 469 void TypeFeedbackOracle::CollectReceiverTypes(T* obj, SmallMapList* types) { | 420 void TypeFeedbackOracle::CollectReceiverTypes(T* obj, SmallMapList* types) { |
| 470 MapHandleList maps; | 421 MapHandleList maps; |
| 471 if (obj->ic_state() == MONOMORPHIC) { | 422 if (obj->ic_state() == MONOMORPHIC) { |
| 472 Map* map = obj->FindFirstMap(); | 423 Map* map = obj->FindFirstMap(); |
| 473 if (map != NULL) maps.Add(handle(map)); | 424 if (map != NULL) maps.Add(handle(map)); |
| 474 } else if (obj->ic_state() == POLYMORPHIC) { | 425 } else if (obj->ic_state() == POLYMORPHIC) { |
| 475 obj->FindAllMaps(&maps); | 426 obj->FindAllMaps(&maps); |
| 476 } else { | 427 } else { |
| 477 return; | 428 return; |
| 478 } | 429 } |
| 479 types->Reserve(maps.length(), zone()); | 430 types->Reserve(maps.length(), zone()); |
| 480 for (int i = 0; i < maps.length(); i++) { | 431 for (int i = 0; i < maps.length(); i++) { |
| 481 Handle<Map> map(maps.at(i)); | 432 Handle<Map> map(maps.at(i)); |
|
Erik Corry
2015/03/26 11:20:57
Perhaps you don't need this variable if it's only
| |
| 482 if (!CanRetainOtherContext(*map, *native_context_)) { | 433 if (IsRelevantFeedback(*map, *native_context_)) { |
| 483 types->AddMapIfMissing(map, zone()); | 434 types->AddMapIfMissing(maps.at(i), zone()); |
| 484 } | 435 } |
| 485 } | 436 } |
| 486 } | 437 } |
| 487 | 438 |
| 488 | 439 |
| 489 byte TypeFeedbackOracle::ToBooleanTypes(TypeFeedbackId id) { | 440 byte TypeFeedbackOracle::ToBooleanTypes(TypeFeedbackId id) { |
| 490 Handle<Object> object = GetInfo(id); | 441 Handle<Object> object = GetInfo(id); |
| 491 return object->IsCode() ? Handle<Code>::cast(object)->to_boolean_state() : 0; | 442 return object->IsCode() ? Handle<Code>::cast(object)->to_boolean_state() : 0; |
| 492 } | 443 } |
| 493 | 444 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 569 UnseededNumberDictionary::kNotFound); | 520 UnseededNumberDictionary::kNotFound); |
| 570 // Dictionary has been allocated with sufficient size for all elements. | 521 // Dictionary has been allocated with sufficient size for all elements. |
| 571 DisallowHeapAllocation no_need_to_resize_dictionary; | 522 DisallowHeapAllocation no_need_to_resize_dictionary; |
| 572 HandleScope scope(isolate()); | 523 HandleScope scope(isolate()); |
| 573 USE(UnseededNumberDictionary::AtNumberPut( | 524 USE(UnseededNumberDictionary::AtNumberPut( |
| 574 dictionary_, IdToKey(ast_id), handle(target, isolate()))); | 525 dictionary_, IdToKey(ast_id), handle(target, isolate()))); |
| 575 } | 526 } |
| 576 | 527 |
| 577 | 528 |
| 578 } } // namespace v8::internal | 529 } } // namespace v8::internal |
| OLD | NEW |