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 |