OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 22 matching lines...) Expand all Loading... |
33 #include "codegen.h" | 33 #include "codegen.h" |
34 #include "execution.h" | 34 #include "execution.h" |
35 #include "ic-inl.h" | 35 #include "ic-inl.h" |
36 #include "runtime.h" | 36 #include "runtime.h" |
37 #include "stub-cache.h" | 37 #include "stub-cache.h" |
38 | 38 |
39 namespace v8 { | 39 namespace v8 { |
40 namespace internal { | 40 namespace internal { |
41 | 41 |
42 #ifdef DEBUG | 42 #ifdef DEBUG |
43 static char TransitionMarkFromState(IC::State state) { | 43 char IC::TransitionMarkFromState(IC::State state) { |
44 switch (state) { | 44 switch (state) { |
45 case UNINITIALIZED: return '0'; | 45 case UNINITIALIZED: return '0'; |
46 case PREMONOMORPHIC: return 'P'; | 46 case PREMONOMORPHIC: return 'P'; |
47 case MONOMORPHIC: return '1'; | 47 case MONOMORPHIC: return '1'; |
48 case MONOMORPHIC_PROTOTYPE_FAILURE: return '^'; | 48 case MONOMORPHIC_PROTOTYPE_FAILURE: return '^'; |
49 case MEGAMORPHIC: return 'N'; | 49 case MEGAMORPHIC: return IsGeneric() ? 'G' : 'N'; |
50 | 50 |
51 // We never see the debugger states here, because the state is | 51 // We never see the debugger states here, because the state is |
52 // computed from the original code - not the patched code. Let | 52 // computed from the original code - not the patched code. Let |
53 // these cases fall through to the unreachable code below. | 53 // these cases fall through to the unreachable code below. |
54 case DEBUG_BREAK: break; | 54 case DEBUG_BREAK: break; |
55 case DEBUG_PREPARE_STEP_IN: break; | 55 case DEBUG_PREPARE_STEP_IN: break; |
56 } | 56 } |
57 UNREACHABLE(); | 57 UNREACHABLE(); |
58 return 0; | 58 return 0; |
59 } | 59 } |
(...skipping 13 matching lines...) Expand all Loading... |
73 if (raw_frame->is_internal()) { | 73 if (raw_frame->is_internal()) { |
74 Isolate* isolate = new_target->GetIsolate(); | 74 Isolate* isolate = new_target->GetIsolate(); |
75 Code* apply_builtin = isolate->builtins()->builtin( | 75 Code* apply_builtin = isolate->builtins()->builtin( |
76 Builtins::kFunctionApply); | 76 Builtins::kFunctionApply); |
77 if (raw_frame->unchecked_code() == apply_builtin) { | 77 if (raw_frame->unchecked_code() == apply_builtin) { |
78 PrintF("apply from "); | 78 PrintF("apply from "); |
79 it.Advance(); | 79 it.Advance(); |
80 raw_frame = it.frame(); | 80 raw_frame = it.frame(); |
81 } | 81 } |
82 } | 82 } |
83 if (raw_frame->is_java_script()) { | 83 JavaScriptFrame::PrintTop(stdout, false, true); |
84 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); | |
85 Code* js_code = frame->unchecked_code(); | |
86 // Find the function on the stack and both the active code for the | |
87 // function and the original code. | |
88 JSFunction* function = JSFunction::cast(frame->function()); | |
89 function->PrintName(); | |
90 int code_offset = | |
91 static_cast<int>(address() - js_code->instruction_start()); | |
92 PrintF("+%d", code_offset); | |
93 } else { | |
94 PrintF("<unknown>"); | |
95 } | |
96 PrintF(" (%c->%c)", | 84 PrintF(" (%c->%c)", |
97 TransitionMarkFromState(old_state), | 85 TransitionMarkFromState(old_state), |
98 TransitionMarkFromState(new_state)); | 86 TransitionMarkFromState(new_state)); |
99 name->Print(); | 87 name->Print(); |
100 PrintF("]\n"); | 88 PrintF("]\n"); |
101 } | 89 } |
102 } | 90 } |
| 91 |
| 92 #define TRACE_GENERIC_IC(type, reason) \ |
| 93 do { \ |
| 94 if (FLAG_trace_ic) { \ |
| 95 PrintF("[%s patching generic stub in ", type); \ |
| 96 JavaScriptFrame::PrintTop(stdout, false, true); \ |
| 97 PrintF(" (%s)]\n", reason); \ |
| 98 } \ |
| 99 } while (false) |
| 100 |
| 101 #else |
| 102 #define TRACE_GENERIC_IC(type, reason) |
103 #endif // DEBUG | 103 #endif // DEBUG |
104 | 104 |
105 | |
106 #define TRACE_IC(type, name, old_state, new_target) \ | 105 #define TRACE_IC(type, name, old_state, new_target) \ |
107 ASSERT((TraceIC(type, name, old_state, new_target), true)) | 106 ASSERT((TraceIC(type, name, old_state, new_target), true)) |
108 | 107 |
109 | |
110 IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) { | 108 IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) { |
111 ASSERT(isolate == Isolate::Current()); | 109 ASSERT(isolate == Isolate::Current()); |
112 // To improve the performance of the (much used) IC code, we unfold | 110 // To improve the performance of the (much used) IC code, we unfold |
113 // a few levels of the stack frame iteration code. This yields a | 111 // a few levels of the stack frame iteration code. This yields a |
114 // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag. | 112 // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag. |
115 const Address entry = | 113 const Address entry = |
116 Isolate::c_entry_fp(isolate->thread_local_top()); | 114 Isolate::c_entry_fp(isolate->thread_local_top()); |
117 Address* pc_address = | 115 Address* pc_address = |
118 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); | 116 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); |
119 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); | 117 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); |
(...skipping 10 matching lines...) Expand all Loading... |
130 for (int i = 0; i < depth + 1; i++) it.Advance(); | 128 for (int i = 0; i < depth + 1; i++) it.Advance(); |
131 StackFrame* frame = it.frame(); | 129 StackFrame* frame = it.frame(); |
132 ASSERT(fp == frame->fp() && pc_address == frame->pc_address()); | 130 ASSERT(fp == frame->fp() && pc_address == frame->pc_address()); |
133 #endif | 131 #endif |
134 fp_ = fp; | 132 fp_ = fp; |
135 pc_address_ = pc_address; | 133 pc_address_ = pc_address; |
136 } | 134 } |
137 | 135 |
138 | 136 |
139 #ifdef ENABLE_DEBUGGER_SUPPORT | 137 #ifdef ENABLE_DEBUGGER_SUPPORT |
140 Address IC::OriginalCodeAddress() { | 138 Address IC::OriginalCodeAddress() const { |
141 HandleScope scope; | 139 HandleScope scope; |
142 // Compute the JavaScript frame for the frame pointer of this IC | 140 // Compute the JavaScript frame for the frame pointer of this IC |
143 // structure. We need this to be able to find the function | 141 // structure. We need this to be able to find the function |
144 // corresponding to the frame. | 142 // corresponding to the frame. |
145 StackFrameIterator it; | 143 StackFrameIterator it; |
146 while (it.frame()->fp() != this->fp()) it.Advance(); | 144 while (it.frame()->fp() != this->fp()) it.Advance(); |
147 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame()); | 145 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame()); |
148 // Find the function on the stack and both the active code for the | 146 // Find the function on the stack and both the active code for the |
149 // function and the original code. | 147 // function and the original code. |
150 JSFunction* function = JSFunction::cast(frame->function()); | 148 JSFunction* function = JSFunction::cast(frame->function()); |
(...skipping 965 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1116 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1114 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
1117 if (receiver->elements()->map() == | 1115 if (receiver->elements()->map() == |
1118 isolate()->heap()->non_strict_arguments_elements_map()) { | 1116 isolate()->heap()->non_strict_arguments_elements_map()) { |
1119 stub = non_strict_arguments_stub(); | 1117 stub = non_strict_arguments_stub(); |
1120 } else if (receiver->HasIndexedInterceptor()) { | 1118 } else if (receiver->HasIndexedInterceptor()) { |
1121 stub = indexed_interceptor_stub(); | 1119 stub = indexed_interceptor_stub(); |
1122 } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { | 1120 } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { |
1123 stub = ComputeStub(receiver, LOAD, kNonStrictMode, stub); | 1121 stub = ComputeStub(receiver, LOAD, kNonStrictMode, stub); |
1124 } | 1122 } |
1125 } | 1123 } |
| 1124 } else { |
| 1125 TRACE_GENERIC_IC("KeyedLoadIC", "force generic"); |
1126 } | 1126 } |
1127 if (!stub.is_null()) set_target(*stub); | 1127 if (!stub.is_null()) set_target(*stub); |
1128 } | 1128 } |
1129 | 1129 |
1130 TRACE_IC("KeyedLoadIC", key, state, target()); | 1130 TRACE_IC("KeyedLoadIC", key, state, target()); |
1131 | 1131 |
1132 // Get the property. | 1132 // Get the property. |
1133 return Runtime::GetObjectProperty(isolate(), object, key); | 1133 return Runtime::GetObjectProperty(isolate(), object, key); |
1134 } | 1134 } |
1135 | 1135 |
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1466 !IsTransitionStubKind(stub_kind)) { | 1466 !IsTransitionStubKind(stub_kind)) { |
1467 return ComputeMonomorphicStub( | 1467 return ComputeMonomorphicStub( |
1468 receiver, stub_kind, strict_mode, generic_stub); | 1468 receiver, stub_kind, strict_mode, generic_stub); |
1469 } | 1469 } |
1470 ASSERT(target() != *generic_stub); | 1470 ASSERT(target() != *generic_stub); |
1471 | 1471 |
1472 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | 1472 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS |
1473 // via megamorphic stubs, since they don't have a map in their relocation info | 1473 // via megamorphic stubs, since they don't have a map in their relocation info |
1474 // and so the stubs can't be harvested for the object needed for a map check. | 1474 // and so the stubs can't be harvested for the object needed for a map check. |
1475 if (target()->type() != NORMAL) { | 1475 if (target()->type() != NORMAL) { |
| 1476 TRACE_GENERIC_IC("KeyedIC", "non-NORMAL target type"); |
1476 return generic_stub; | 1477 return generic_stub; |
1477 } | 1478 } |
1478 | 1479 |
1479 // Determine the list of receiver maps that this call site has seen, | 1480 // Determine the list of receiver maps that this call site has seen, |
1480 // adding the map that was just encountered. | 1481 // adding the map that was just encountered. |
1481 MapHandleList target_receiver_maps; | 1482 MapHandleList target_receiver_maps; |
1482 Handle<Map> receiver_map(receiver->map()); | 1483 Handle<Map> receiver_map(receiver->map()); |
1483 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { | 1484 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { |
1484 target_receiver_maps.Add(receiver_map); | 1485 target_receiver_maps.Add(receiver_map); |
1485 } else { | 1486 } else { |
1486 GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps); | 1487 GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps); |
1487 } | 1488 } |
1488 bool map_added = | 1489 bool map_added = |
1489 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map); | 1490 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map); |
1490 if (IsTransitionStubKind(stub_kind)) { | 1491 if (IsTransitionStubKind(stub_kind)) { |
1491 Handle<Map> new_map = ComputeTransitionedMap(receiver, stub_kind); | 1492 Handle<Map> new_map = ComputeTransitionedMap(receiver, stub_kind); |
1492 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map); | 1493 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map); |
1493 } | 1494 } |
1494 if (!map_added) { | 1495 if (!map_added) { |
1495 // If the miss wasn't due to an unseen map, a polymorphic stub | 1496 // If the miss wasn't due to an unseen map, a polymorphic stub |
1496 // won't help, use the generic stub. | 1497 // won't help, use the generic stub. |
| 1498 TRACE_GENERIC_IC("KeyedIC", "same map added twice"); |
1497 return generic_stub; | 1499 return generic_stub; |
1498 } | 1500 } |
1499 | 1501 |
1500 // If the maximum number of receiver maps has been exceeded, use the generic | 1502 // If the maximum number of receiver maps has been exceeded, use the generic |
1501 // version of the IC. | 1503 // version of the IC. |
1502 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { | 1504 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { |
| 1505 TRACE_GENERIC_IC("KeyedIC", "max polymorph exceeded"); |
1503 return generic_stub; | 1506 return generic_stub; |
1504 } | 1507 } |
1505 | 1508 |
1506 Handle<PolymorphicCodeCache> cache = | 1509 Handle<PolymorphicCodeCache> cache = |
1507 isolate()->factory()->polymorphic_code_cache(); | 1510 isolate()->factory()->polymorphic_code_cache(); |
1508 Code::Flags flags = Code::ComputeFlags(kind(), MEGAMORPHIC, strict_mode); | 1511 Code::Flags flags = Code::ComputeFlags(kind(), MEGAMORPHIC, strict_mode); |
1509 Handle<Object> probe = cache->Lookup(&target_receiver_maps, flags); | 1512 Handle<Object> probe = cache->Lookup(&target_receiver_maps, flags); |
1510 if (probe->IsCode()) return Handle<Code>::cast(probe); | 1513 if (probe->IsCode()) return Handle<Code>::cast(probe); |
1511 | 1514 |
1512 Handle<Code> stub = | 1515 Handle<Code> stub = |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1678 } else if (value->IsHeapObject()) { | 1681 } else if (value->IsHeapObject()) { |
1679 stub_kind = STORE_TRANSITION_SMI_TO_OBJECT; | 1682 stub_kind = STORE_TRANSITION_SMI_TO_OBJECT; |
1680 } | 1683 } |
1681 } else if (receiver->GetElementsKind() == FAST_DOUBLE_ELEMENTS) { | 1684 } else if (receiver->GetElementsKind() == FAST_DOUBLE_ELEMENTS) { |
1682 if (!value->IsSmi() && !value->IsHeapNumber()) { | 1685 if (!value->IsSmi() && !value->IsHeapNumber()) { |
1683 stub_kind = STORE_TRANSITION_DOUBLE_TO_OBJECT; | 1686 stub_kind = STORE_TRANSITION_DOUBLE_TO_OBJECT; |
1684 } | 1687 } |
1685 } | 1688 } |
1686 stub = ComputeStub(receiver, stub_kind, strict_mode, stub); | 1689 stub = ComputeStub(receiver, stub_kind, strict_mode, stub); |
1687 } | 1690 } |
| 1691 } else { |
| 1692 TRACE_GENERIC_IC("KeyedStoreIC", "force generic"); |
1688 } | 1693 } |
1689 } | 1694 } |
1690 if (!stub.is_null()) set_target(*stub); | 1695 if (!stub.is_null()) set_target(*stub); |
1691 } | 1696 } |
1692 | 1697 |
1693 TRACE_IC("KeyedStoreIC", key, state, target()); | 1698 TRACE_IC("KeyedStoreIC", key, state, target()); |
1694 | 1699 |
1695 // Set the property. | 1700 // Set the property. |
1696 return Runtime::SetObjectProperty( | 1701 return Runtime::SetObjectProperty( |
1697 isolate(), object , key, value, NONE, strict_mode); | 1702 isolate(), object , key, value, NONE, strict_mode); |
(...skipping 690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2388 #undef ADDR | 2393 #undef ADDR |
2389 }; | 2394 }; |
2390 | 2395 |
2391 | 2396 |
2392 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2397 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2393 return IC_utilities[id]; | 2398 return IC_utilities[id]; |
2394 } | 2399 } |
2395 | 2400 |
2396 | 2401 |
2397 } } // namespace v8::internal | 2402 } } // namespace v8::internal |
OLD | NEW |