Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(161)

Side by Side Diff: src/ic.cc

Issue 115744: This patch much improves our tracking of whether function is... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 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 20 matching lines...) Expand all
31 #include "api.h" 31 #include "api.h"
32 #include "arguments.h" 32 #include "arguments.h"
33 #include "execution.h" 33 #include "execution.h"
34 #include "ic-inl.h" 34 #include "ic-inl.h"
35 #include "runtime.h" 35 #include "runtime.h"
36 #include "stub-cache.h" 36 #include "stub-cache.h"
37 37
38 namespace v8 { namespace internal { 38 namespace v8 { namespace internal {
39 39
40 #ifdef DEBUG 40 #ifdef DEBUG
41 static char TransitionMarkFromState(IC::State state) { 41 static const char TransitionMarkFromState(IC::State state) {
42 switch (state) { 42 switch (state) {
43 case UNINITIALIZED: return '0'; 43 case UNINITIALIZED: return '0';
44 case UNINITIALIZED_IN_LOOP: return 'L';
45 case PREMONOMORPHIC: return 'P'; 44 case PREMONOMORPHIC: return 'P';
46 case MONOMORPHIC: return '1'; 45 case MONOMORPHIC: return '1';
47 case MONOMORPHIC_PROTOTYPE_FAILURE: return '^'; 46 case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
48 case MEGAMORPHIC: return 'N'; 47 case MEGAMORPHIC: return 'N';
49 48
50 // We never see the debugger states here, because the state is 49 // We never see the debugger states here, because the state is
51 // computed from the original code - not the patched code. Let 50 // computed from the original code - not the patched code. Let
52 // these cases fall through to the unreachable code below. 51 // these cases fall through to the unreachable code below.
53 case DEBUG_BREAK: break; 52 case DEBUG_BREAK: break;
54 case DEBUG_PREPARE_STEP_IN: break; 53 case DEBUG_PREPARE_STEP_IN: break;
55 } 54 }
56 UNREACHABLE(); 55 UNREACHABLE();
57 return 0; 56 return 0;
58 } 57 }
59 58
60 void IC::TraceIC(const char* type, 59 void IC::TraceIC(const char* type,
61 Handle<String> name, 60 Handle<String> name,
62 State old_state, 61 State old_state,
63 Code* new_target) { 62 Code* new_target,
63 const char* extra_info) {
64 if (FLAG_trace_ic) { 64 if (FLAG_trace_ic) {
65 State new_state = StateFrom(new_target, Heap::undefined_value()); 65 State new_state = StateFrom(new_target, Heap::undefined_value());
66 PrintF("[%s (%c->%c) ", type, 66 PrintF("[%s (%c->%c)%s", type,
67 TransitionMarkFromState(old_state), 67 TransitionMarkFromState(old_state),
68 TransitionMarkFromState(new_state)); 68 TransitionMarkFromState(new_state),
69 extra_info);
69 name->Print(); 70 name->Print();
70 PrintF("]\n"); 71 PrintF("]\n");
71 } 72 }
72 } 73 }
73 #endif 74 #endif
74 75
75 76
76 IC::IC(FrameDepth depth) { 77 IC::IC(FrameDepth depth) {
77 // To improve the performance of the (much used) IC code, we unfold 78 // To improve the performance of the (much used) IC code, we unfold
78 // a few levels of the stack frame iteration code. This yields a 79 // a few levels of the stack frame iteration code. This yields a
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 case Code::STORE_IC: return StoreIC::Clear(address, target); 220 case Code::STORE_IC: return StoreIC::Clear(address, target);
220 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); 221 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target);
221 case Code::CALL_IC: return CallIC::Clear(address, target); 222 case Code::CALL_IC: return CallIC::Clear(address, target);
222 default: UNREACHABLE(); 223 default: UNREACHABLE();
223 } 224 }
224 } 225 }
225 226
226 227
227 void CallIC::Clear(Address address, Code* target) { 228 void CallIC::Clear(Address address, Code* target) {
228 State state = target->ic_state(); 229 State state = target->ic_state();
229 if (state == UNINITIALIZED || state == UNINITIALIZED_IN_LOOP) return; 230 InlineCacheInLoop in_loop = target->ic_in_loop();
230 Code* code = StubCache::FindCallInitialize(target->arguments_count()); 231 if (state == UNINITIALIZED) return;
232 Code* code =
233 StubCache::FindCallInitialize(target->arguments_count(), in_loop);
231 SetTargetAtAddress(address, code); 234 SetTargetAtAddress(address, code);
232 } 235 }
233 236
234 237
235 void KeyedLoadIC::Clear(Address address, Code* target) { 238 void KeyedLoadIC::Clear(Address address, Code* target) {
236 if (target->ic_state() == UNINITIALIZED) return; 239 if (target->ic_state() == UNINITIALIZED) return;
237 // Make sure to also clear the map used in inline fast cases. If we 240 // Make sure to also clear the map used in inline fast cases. If we
238 // do not clear these maps, cached code can keep objects alive 241 // do not clear these maps, cached code can keep objects alive
239 // through the embedded maps. 242 // through the embedded maps.
240 ClearInlinedVersion(address); 243 ClearInlinedVersion(address);
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 void CallIC::UpdateCaches(LookupResult* lookup, 386 void CallIC::UpdateCaches(LookupResult* lookup,
384 State state, 387 State state,
385 Handle<Object> object, 388 Handle<Object> object,
386 Handle<String> name) { 389 Handle<String> name) {
387 ASSERT(lookup->IsLoaded()); 390 ASSERT(lookup->IsLoaded());
388 // Bail out if we didn't find a result. 391 // Bail out if we didn't find a result.
389 if (!lookup->IsValid() || !lookup->IsCacheable()) return; 392 if (!lookup->IsValid() || !lookup->IsCacheable()) return;
390 393
391 // Compute the number of arguments. 394 // Compute the number of arguments.
392 int argc = target()->arguments_count(); 395 int argc = target()->arguments_count();
396 InlineCacheInLoop in_loop = target()->ic_in_loop();
393 Object* code = NULL; 397 Object* code = NULL;
394 398
395 if (state == UNINITIALIZED) { 399 if (state == UNINITIALIZED) {
396 // This is the first time we execute this inline cache. 400 // This is the first time we execute this inline cache.
397 // Set the target to the pre monomorphic stub to delay 401 // Set the target to the pre monomorphic stub to delay
398 // setting the monomorphic state. 402 // setting the monomorphic state.
399 code = StubCache::ComputeCallPreMonomorphic(argc); 403 code = StubCache::ComputeCallPreMonomorphic(argc, in_loop);
400 } else if (state == MONOMORPHIC) { 404 } else if (state == MONOMORPHIC) {
401 code = StubCache::ComputeCallMegamorphic(argc); 405 code = StubCache::ComputeCallMegamorphic(argc, in_loop);
402 } else { 406 } else {
403 // Compute monomorphic stub. 407 // Compute monomorphic stub.
404 switch (lookup->type()) { 408 switch (lookup->type()) {
405 case FIELD: { 409 case FIELD: {
406 int index = lookup->GetFieldIndex(); 410 int index = lookup->GetFieldIndex();
407 code = StubCache::ComputeCallField(argc, *name, *object, 411 code = StubCache::ComputeCallField(argc, in_loop, *name, *object,
408 lookup->holder(), index); 412 lookup->holder(), index);
409 break; 413 break;
410 } 414 }
411 case CONSTANT_FUNCTION: { 415 case CONSTANT_FUNCTION: {
412 // Get the constant function and compute the code stub for this 416 // Get the constant function and compute the code stub for this
413 // call; used for rewriting to monomorphic state and making sure 417 // call; used for rewriting to monomorphic state and making sure
414 // that the code stub is in the stub cache. 418 // that the code stub is in the stub cache.
415 JSFunction* function = lookup->GetConstantFunction(); 419 JSFunction* function = lookup->GetConstantFunction();
416 code = StubCache::ComputeCallConstant(argc, *name, *object, 420 code = StubCache::ComputeCallConstant(argc, in_loop, *name, *object,
417 lookup->holder(), function); 421 lookup->holder(), function);
418 break; 422 break;
419 } 423 }
420 case NORMAL: { 424 case NORMAL: {
421 // There is only one shared stub for calling normalized 425 // There is only one shared stub for calling normalized
422 // properties. It does not traverse the prototype chain, so the 426 // properties. It does not traverse the prototype chain, so the
423 // property must be found in the receiver for the stub to be 427 // property must be found in the receiver for the stub to be
424 // applicable. 428 // applicable.
425 if (!object->IsJSObject()) return; 429 if (!object->IsJSObject()) return;
426 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 430 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
427 if (lookup->holder() != *receiver) return; 431 if (lookup->holder() != *receiver) return;
428 code = StubCache::ComputeCallNormal(argc, *name, *receiver); 432 code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver);
429 break; 433 break;
430 } 434 }
431 case INTERCEPTOR: { 435 case INTERCEPTOR: {
432 code = StubCache::ComputeCallInterceptor(argc, *name, *object, 436 code = StubCache::ComputeCallInterceptor(argc, *name, *object,
433 lookup->holder()); 437 lookup->holder());
434 break; 438 break;
435 } 439 }
436 default: 440 default:
437 return; 441 return;
438 } 442 }
439 } 443 }
440 444
441 // If we're unable to compute the stub (not enough memory left), we 445 // If we're unable to compute the stub (not enough memory left), we
442 // simply avoid updating the caches. 446 // simply avoid updating the caches.
443 if (code->IsFailure()) return; 447 if (code->IsFailure()) return;
444 448
445 // Patch the call site depending on the state of the cache. 449 // Patch the call site depending on the state of the cache.
446 if (state == UNINITIALIZED || state == UNINITIALIZED_IN_LOOP || 450 if (state == UNINITIALIZED ||
447 state == PREMONOMORPHIC || state == MONOMORPHIC || 451 state == PREMONOMORPHIC || state == MONOMORPHIC ||
Kevin Millikin (Chromium) 2009/05/25 11:00:42 One disjunct per line?
448 state == MONOMORPHIC_PROTOTYPE_FAILURE) { 452 state == MONOMORPHIC_PROTOTYPE_FAILURE) {
449 set_target(Code::cast(code)); 453 set_target(Code::cast(code));
450 } 454 }
451 455
452 #ifdef DEBUG 456 #ifdef DEBUG
453 TraceIC("CallIC", name, state, target()); 457 TraceIC("CallIC", name, state, target(), in_loop ? " (in-loop)" : "");
454 #endif 458 #endif
455 } 459 }
456 460
457 461
458 Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) { 462 Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
459 // If the object is undefined or null it's illegal to try to get any 463 // If the object is undefined or null it's illegal to try to get any
460 // of its properties; throw a TypeError in that case. 464 // of its properties; throw a TypeError in that case.
461 if (object->IsUndefined() || object->IsNull()) { 465 if (object->IsUndefined() || object->IsNull()) {
462 return TypeError("non_object_property_load", object, name); 466 return TypeError("non_object_property_load", object, name);
463 } 467 }
(...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after
1081 // 1085 //
1082 1086
1083 // Used from ic_<arch>.cc. 1087 // Used from ic_<arch>.cc.
1084 Object* CallIC_Miss(Arguments args) { 1088 Object* CallIC_Miss(Arguments args) {
1085 NoHandleAllocation na; 1089 NoHandleAllocation na;
1086 ASSERT(args.length() == 2); 1090 ASSERT(args.length() == 2);
1087 CallIC ic; 1091 CallIC ic;
1088 IC::State state = IC::StateFrom(ic.target(), args[0]); 1092 IC::State state = IC::StateFrom(ic.target(), args[0]);
1089 Object* result = 1093 Object* result =
1090 ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); 1094 ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
1091 if (state != UNINITIALIZED_IN_LOOP || !result->IsJSFunction()) 1095
1096 // The first time the inline cache is updated may be the first time the
1097 // function it references gets called. If the function was lazily compiled
1098 // then the first call will trigger a compilation. We check for this case
1099 // and we do the compilation immediately, instead of waiting for the stub
1100 // currently attached to the JSFunction object to trigger compilation. We
1101 // do this in the case where we know that the inline cache is inside a loop,
1102 // because then we know that we want to optimize the function.
1103 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
1092 return result; 1104 return result;
1105 }
1093 1106
1094 // Compile the function with the knowledge that it's called from 1107 // Compile now with optimization.
1095 // within a loop. This enables further optimization of the function.
1096 HandleScope scope; 1108 HandleScope scope;
1097 Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result)); 1109 Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result));
1098 if (!function->is_compiled()) CompileLazyInLoop(function, CLEAR_EXCEPTION); 1110 InlineCacheInLoop in_loop = ic.target()->ic_in_loop();
1111 if (in_loop) {
Kevin Millikin (Chromium) 2009/05/25 11:00:42 if (in_loop == IN_LOOP) ....
1112 CompileLazyInLoop(function, CLEAR_EXCEPTION);
1113 } else {
1114 CompileLazy(function, CLEAR_EXCEPTION);
1115 }
1099 return *function; 1116 return *function;
1100 } 1117 }
1101 1118
1102 1119
1103 void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) { 1120 void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) {
1104 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); 1121 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
1105 } 1122 }
1106 1123
1107 1124
1108 void CallIC::GeneratePreMonomorphic(MacroAssembler* masm, int argc) { 1125 void CallIC::GeneratePreMonomorphic(MacroAssembler* masm, int argc) {
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
1238 #undef ADDR 1255 #undef ADDR
1239 }; 1256 };
1240 1257
1241 1258
1242 Address IC::AddressFromUtilityId(IC::UtilityId id) { 1259 Address IC::AddressFromUtilityId(IC::UtilityId id) {
1243 return IC_utilities[id]; 1260 return IC_utilities[id];
1244 } 1261 }
1245 1262
1246 1263
1247 } } // namespace v8::internal 1264 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698