OLD | NEW |
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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 } | 54 } |
55 UNREACHABLE(); | 55 UNREACHABLE(); |
56 return 0; | 56 return 0; |
57 } | 57 } |
58 | 58 |
59 void IC::TraceIC(const char* type, | 59 void IC::TraceIC(const char* type, |
60 Handle<String> name, | 60 Handle<String> name, |
61 State old_state, | 61 State old_state, |
62 Code* new_target) { | 62 Code* new_target) { |
63 if (FLAG_trace_ic) { | 63 if (FLAG_trace_ic) { |
64 State new_state = new_target->ic_state(); | 64 State new_state = StateFrom(new_target, Heap::undefined_value()); |
65 PrintF("[%s (%c->%c) ", type, | 65 PrintF("[%s (%c->%c) ", type, |
66 TransitionMarkFromState(old_state), | 66 TransitionMarkFromState(old_state), |
67 TransitionMarkFromState(new_state)); | 67 TransitionMarkFromState(new_state)); |
68 name->Print(); | 68 name->Print(); |
69 PrintF("]\n"); | 69 PrintF("]\n"); |
70 } | 70 } |
71 } | 71 } |
72 #endif | 72 #endif |
73 | 73 |
74 | 74 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 // normally would be. | 120 // normally would be. |
121 Address addr = pc() - Assembler::kTargetAddrToReturnAddrDist; | 121 Address addr = pc() - Assembler::kTargetAddrToReturnAddrDist; |
122 // Return the address in the original code. This is the place where | 122 // Return the address in the original code. This is the place where |
123 // the call which has been overwriten by the DebugBreakXXX resides | 123 // the call which has been overwriten by the DebugBreakXXX resides |
124 // and the place where the inline cache system should look. | 124 // and the place where the inline cache system should look. |
125 int delta = original_code->instruction_start() - code->instruction_start(); | 125 int delta = original_code->instruction_start() - code->instruction_start(); |
126 return addr + delta; | 126 return addr + delta; |
127 } | 127 } |
128 | 128 |
129 | 129 |
130 IC::State IC::ComputeCacheState(Code* target, Object* receiver, | 130 IC::State IC::StateFrom(Code* target, Object* receiver) { |
131 Object* name, Object** new_target) { | 131 IC::State state = target->ic_state(); |
132 // Get the raw state from the target. | |
133 State target_state = target->ic_state(); | |
134 | 132 |
135 // Assume that no new target exists in the cache. | 133 if (state != MONOMORPHIC) return state; |
136 *new_target = Heap::undefined_value(); | 134 if (receiver->IsUndefined() || receiver->IsNull()) return state; |
137 | |
138 if (target_state != MONOMORPHIC) return target_state; | |
139 if (receiver->IsUndefined() || receiver->IsNull()) return target_state; | |
140 | 135 |
141 Map* map = GetCodeCacheMapForObject(receiver); | 136 Map* map = GetCodeCacheMapForObject(receiver); |
142 | 137 |
143 // Decide whether the inline cache failed because of changes to the | 138 // Decide whether the inline cache failed because of changes to the |
144 // receiver itself or changes to one of its prototypes. | 139 // receiver itself or changes to one of its prototypes. |
145 // | 140 // |
146 // If there are changes to the receiver itself, the map of the | 141 // If there are changes to the receiver itself, the map of the |
147 // receiver will have changed and the current target will not be in | 142 // receiver will have changed and the current target will not be in |
148 // the receiver map's code cache. Therefore, if the current target | 143 // the receiver map's code cache. Therefore, if the current target |
149 // is in the receiver map's code cache, the inline cache failed due | 144 // is in the receiver map's code cache, the inline cache failed due |
150 // to prototype check failure. | 145 // to prototype check failure. |
151 int index = -1; | 146 int index = map->IndexInCodeCache(target); |
152 Object* code = NULL; | 147 if (index >= 0) { |
153 if (name->IsString()) { | |
154 code = map->FindIndexInCodeCache(String::cast(name), | |
155 target->flags(), | |
156 &index); | |
157 } | |
158 if (index >= 0 && code == target) { | |
159 // For keyed load/store, the most likely cause of cache failure is | 148 // For keyed load/store, the most likely cause of cache failure is |
160 // that the key has changed. We do not distinguish between | 149 // that the key has changed. We do not distinguish between |
161 // prototype and non-prototype failures for keyed access. | 150 // prototype and non-prototype failures for keyed access. |
162 Code::Kind kind = target->kind(); | 151 Code::Kind kind = target->kind(); |
163 if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) { | 152 if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) { |
164 return MONOMORPHIC; | 153 return MONOMORPHIC; |
165 } | 154 } |
166 | 155 |
167 // Remove the target from the code cache to avoid hitting the same | 156 // Remove the target from the code cache to avoid hitting the same |
168 // invalid stub again. | 157 // invalid stub again. |
169 map->RemoveFromCodeCache(index); | 158 map->RemoveFromCodeCache(index); |
170 | 159 |
171 return MONOMORPHIC_PROTOTYPE_FAILURE; | 160 return MONOMORPHIC_PROTOTYPE_FAILURE; |
172 } | 161 } |
173 | 162 |
174 // The builtins object is special. It only changes when JavaScript | 163 // The builtins object is special. It only changes when JavaScript |
175 // builtins are loaded lazily. It is important to keep inline | 164 // builtins are loaded lazily. It is important to keep inline |
176 // caches for the builtins object monomorphic. Therefore, if we get | 165 // caches for the builtins object monomorphic. Therefore, if we get |
177 // an inline cache miss for the builtins object after lazily loading | 166 // an inline cache miss for the builtins object after lazily loading |
178 // JavaScript builtins, we clear the code cache and return | 167 // JavaScript builtins, we clear the code cache and return |
179 // uninitialized as the state to force the inline cache back to | 168 // uninitialized as the state to force the inline cache back to |
180 // monomorphic state. | 169 // monomorphic state. |
181 if (receiver->IsJSBuiltinsObject()) { | 170 if (receiver->IsJSBuiltinsObject()) { |
182 map->ClearCodeCache(); | 171 map->ClearCodeCache(); |
183 return UNINITIALIZED; | 172 return UNINITIALIZED; |
184 } | 173 } |
185 | 174 |
186 *new_target = code; | |
187 return MONOMORPHIC; | 175 return MONOMORPHIC; |
188 } | 176 } |
189 | 177 |
190 | 178 |
191 RelocMode IC::ComputeMode() { | 179 RelocMode IC::ComputeMode() { |
192 Address addr = address(); | 180 Address addr = address(); |
193 Code* code = Code::cast(Heap::FindCodeObject(addr)); | 181 Code* code = Code::cast(Heap::FindCodeObject(addr)); |
194 for (RelocIterator it(code, RelocInfo::kCodeTargetMask); | 182 for (RelocIterator it(code, RelocInfo::kCodeTargetMask); |
195 !it.done(); it.next()) { | 183 !it.done(); it.next()) { |
196 RelocInfo* info = it.rinfo(); | 184 RelocInfo* info = it.rinfo(); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 StackFrameLocator locator; | 268 StackFrameLocator locator; |
281 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | 269 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); |
282 int index = frame->ComputeExpressionsCount() - (argc + 1); | 270 int index = frame->ComputeExpressionsCount() - (argc + 1); |
283 frame->SetExpression(index, *target); | 271 frame->SetExpression(index, *target); |
284 } | 272 } |
285 | 273 |
286 return *delegate; | 274 return *delegate; |
287 } | 275 } |
288 | 276 |
289 | 277 |
290 Object* CallIC::LoadFunction(Handle<Object> object, | 278 Object* CallIC::LoadFunction(State state, |
| 279 Handle<Object> object, |
291 Handle<String> name) { | 280 Handle<String> name) { |
292 // If the object is undefined or null it's illegal to try to get any | 281 // If the object is undefined or null it's illegal to try to get any |
293 // of its properties; throw a TypeError in that case. | 282 // of its properties; throw a TypeError in that case. |
294 if (object->IsUndefined() || object->IsNull()) { | 283 if (object->IsUndefined() || object->IsNull()) { |
295 return TypeError("non_object_property_call", object, name); | 284 return TypeError("non_object_property_call", object, name); |
296 } | 285 } |
297 | 286 |
298 Object* result = Heap::the_hole_value(); | 287 Object* result = Heap::the_hole_value(); |
299 | 288 |
300 // Check if the name is trivially convertible to an index and get | 289 // Check if the name is trivially convertible to an index and get |
(...skipping 18 matching lines...) Expand all Loading... |
319 // If the object does not have the requested property, check which | 308 // If the object does not have the requested property, check which |
320 // exception we need to throw. | 309 // exception we need to throw. |
321 if (is_contextual()) { | 310 if (is_contextual()) { |
322 return ReferenceError("not_defined", name); | 311 return ReferenceError("not_defined", name); |
323 } | 312 } |
324 return TypeError("undefined_method", object, name); | 313 return TypeError("undefined_method", object, name); |
325 } | 314 } |
326 | 315 |
327 // Lookup is valid: Update inline cache and stub cache. | 316 // Lookup is valid: Update inline cache and stub cache. |
328 if (FLAG_use_ic && lookup.IsLoaded()) { | 317 if (FLAG_use_ic && lookup.IsLoaded()) { |
329 UpdateCaches(&lookup, object, name); | 318 UpdateCaches(&lookup, state, object, name); |
330 } | 319 } |
331 | 320 |
332 if (lookup.type() == INTERCEPTOR) { | 321 if (lookup.type() == INTERCEPTOR) { |
333 // Get the property. | 322 // Get the property. |
334 PropertyAttributes attr; | 323 PropertyAttributes attr; |
335 result = object->GetProperty(*name, &attr); | 324 result = object->GetProperty(*name, &attr); |
336 if (result->IsFailure()) return result; | 325 if (result->IsFailure()) return result; |
337 // If the object does not have the requested property, check which | 326 // If the object does not have the requested property, check which |
338 // exception we need to throw. | 327 // exception we need to throw. |
339 if (attr == ABSENT) { | 328 if (attr == ABSENT) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 } | 367 } |
379 | 368 |
380 // Try to find a suitable function delegate for the object at hand. | 369 // Try to find a suitable function delegate for the object at hand. |
381 result = TryCallAsFunction(result); | 370 result = TryCallAsFunction(result); |
382 return result->IsJSFunction() ? | 371 return result->IsJSFunction() ? |
383 result : TypeError("property_not_function", object, name); | 372 result : TypeError("property_not_function", object, name); |
384 } | 373 } |
385 | 374 |
386 | 375 |
387 void CallIC::UpdateCaches(LookupResult* lookup, | 376 void CallIC::UpdateCaches(LookupResult* lookup, |
| 377 State state, |
388 Handle<Object> object, | 378 Handle<Object> object, |
389 Handle<String> name) { | 379 Handle<String> name) { |
390 ASSERT(lookup->IsLoaded()); | 380 ASSERT(lookup->IsLoaded()); |
391 // Bail out if we didn't find a result. | 381 // Bail out if we didn't find a result. |
392 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 382 if (!lookup->IsValid() || !lookup->IsCacheable()) return; |
393 | 383 |
394 // Compute the number of arguments. | 384 // Compute the number of arguments. |
395 int argc = target()->arguments_count(); | 385 int argc = target()->arguments_count(); |
| 386 Object* code = NULL; |
396 | 387 |
397 Object* code = Heap::undefined_value(); | 388 if (state == UNINITIALIZED) { |
398 State state = ComputeCacheState(target(), *object, *name, &code); | 389 // This is the first time we execute this inline cache. |
399 | 390 // Set the target to the pre monomorphic stub to delay |
400 switch (state) { | 391 // setting the monomorphic state. |
401 case UNINITIALIZED: | 392 code = StubCache::ComputeCallPreMonomorphic(argc); |
402 code = StubCache::ComputeCallPreMonomorphic(argc); | 393 } else if (state == MONOMORPHIC) { |
403 break; | 394 code = StubCache::ComputeCallMegamorphic(argc); |
404 case MONOMORPHIC: | 395 } else { |
405 if (code->IsUndefined()) code = StubCache::ComputeCallMegamorphic(argc); | 396 // Compute monomorphic stub. |
406 break; | 397 switch (lookup->type()) { |
407 default: | 398 case FIELD: { |
408 // Compute monomorphic stub. | 399 int index = lookup->GetFieldIndex(); |
409 switch (lookup->type()) { | 400 code = StubCache::ComputeCallField(argc, *name, *object, |
410 case FIELD: { | 401 lookup->holder(), index); |
411 int index = lookup->GetFieldIndex(); | 402 break; |
412 code = StubCache::ComputeCallField(argc, *name, *object, | |
413 lookup->holder(), index); | |
414 break; | |
415 } | |
416 case CONSTANT_FUNCTION: { | |
417 // Get the constant function and compute the code stub for this | |
418 // call; used for rewriting to monomorphic state and making sure | |
419 // that the code stub is in the stub cache. | |
420 JSFunction* function = lookup->GetConstantFunction(); | |
421 code = StubCache::ComputeCallConstant(argc, *name, *object, | |
422 lookup->holder(), function); | |
423 break; | |
424 } | |
425 case NORMAL: { | |
426 // There is only one shared stub for calling normalized | |
427 // properties. It does not traverse the prototype chain, so the | |
428 // property must be found in the receiver for the stub to be | |
429 // applicable. | |
430 if (!object->IsJSObject()) return; | |
431 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
432 if (lookup->holder() != *receiver) return; | |
433 code = StubCache::ComputeCallNormal(argc, *name, *receiver); | |
434 break; | |
435 } | |
436 case INTERCEPTOR: { | |
437 code = StubCache::ComputeCallInterceptor(argc, *name, *object, | |
438 lookup->holder()); | |
439 break; | |
440 } | |
441 default: | |
442 return; | |
443 } | 403 } |
444 break; | 404 case CONSTANT_FUNCTION: { |
| 405 // Get the constant function and compute the code stub for this |
| 406 // call; used for rewriting to monomorphic state and making sure |
| 407 // that the code stub is in the stub cache. |
| 408 JSFunction* function = lookup->GetConstantFunction(); |
| 409 code = StubCache::ComputeCallConstant(argc, *name, *object, |
| 410 lookup->holder(), function); |
| 411 break; |
| 412 } |
| 413 case NORMAL: { |
| 414 // There is only one shared stub for calling normalized |
| 415 // properties. It does not traverse the prototype chain, so the |
| 416 // property must be found in the receiver for the stub to be |
| 417 // applicable. |
| 418 if (!object->IsJSObject()) return; |
| 419 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 420 if (lookup->holder() != *receiver) return; |
| 421 code = StubCache::ComputeCallNormal(argc, *name, *receiver); |
| 422 break; |
| 423 } |
| 424 case INTERCEPTOR: { |
| 425 code = StubCache::ComputeCallInterceptor(argc, *name, *object, |
| 426 lookup->holder()); |
| 427 break; |
| 428 } |
| 429 default: |
| 430 return; |
| 431 } |
445 } | 432 } |
446 | 433 |
447 // If we're unable to compute the stub (not enough memory left), we | 434 // If we're unable to compute the stub (not enough memory left), we |
448 // simply avoid updating the caches. | 435 // simply avoid updating the caches. |
449 if (code->IsFailure()) return; | 436 if (code->IsFailure()) return; |
450 | 437 |
451 // Patch the call site depending on the state of the cache. | 438 // Patch the call site depending on the state of the cache. |
452 if (state == UNINITIALIZED || state == PREMONOMORPHIC || | 439 if (state == UNINITIALIZED || state == PREMONOMORPHIC || |
453 state == MONOMORPHIC || state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 440 state == MONOMORPHIC || state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
454 set_target(Code::cast(code)); | 441 set_target(Code::cast(code)); |
455 } | 442 } |
456 | 443 |
457 #ifdef DEBUG | 444 #ifdef DEBUG |
458 TraceIC("CallIC", name, state, target()); | 445 TraceIC("CallIC", name, state, target()); |
459 #endif | 446 #endif |
460 } | 447 } |
461 | 448 |
462 | 449 |
463 Object* LoadIC::Load(Handle<Object> object, Handle<String> name) { | 450 Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) { |
464 // If the object is undefined or null it's illegal to try to get any | 451 // If the object is undefined or null it's illegal to try to get any |
465 // of its properties; throw a TypeError in that case. | 452 // of its properties; throw a TypeError in that case. |
466 if (object->IsUndefined() || object->IsNull()) { | 453 if (object->IsUndefined() || object->IsNull()) { |
467 return TypeError("non_object_property_load", object, name); | 454 return TypeError("non_object_property_load", object, name); |
468 } | 455 } |
469 | 456 |
470 if (FLAG_use_ic) { | 457 if (FLAG_use_ic) { |
471 // Use specialized code for getting the length of strings. | 458 // Use specialized code for getting the length of strings. |
472 if (object->IsString() && name->Equals(Heap::length_symbol())) { | 459 if (object->IsString() && name->Equals(Heap::length_symbol())) { |
473 #ifdef DEBUG | 460 #ifdef DEBUG |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 } | 513 } |
527 String* class_name = object->IsJSObject() | 514 String* class_name = object->IsJSObject() |
528 ? Handle<JSObject>::cast(object)->class_name() | 515 ? Handle<JSObject>::cast(object)->class_name() |
529 : Heap::empty_string(); | 516 : Heap::empty_string(); |
530 LOG(SuspectReadEvent(*name, class_name)); | 517 LOG(SuspectReadEvent(*name, class_name)); |
531 USE(class_name); | 518 USE(class_name); |
532 } | 519 } |
533 | 520 |
534 // Update inline cache and stub cache. | 521 // Update inline cache and stub cache. |
535 if (FLAG_use_ic && lookup.IsLoaded()) { | 522 if (FLAG_use_ic && lookup.IsLoaded()) { |
536 UpdateCaches(&lookup, object, name); | 523 UpdateCaches(&lookup, state, object, name); |
537 } | 524 } |
538 | 525 |
539 PropertyAttributes attr; | 526 PropertyAttributes attr; |
540 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { | 527 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { |
541 // Get the property. | 528 // Get the property. |
542 Object* result = object->GetProperty(*object, &lookup, *name, &attr); | 529 Object* result = object->GetProperty(*object, &lookup, *name, &attr); |
543 if (result->IsFailure()) return result; | 530 if (result->IsFailure()) return result; |
544 // If the property is not present, check if we need to throw an | 531 // If the property is not present, check if we need to throw an |
545 // exception. | 532 // exception. |
546 if (attr == ABSENT && is_contextual()) { | 533 if (attr == ABSENT && is_contextual()) { |
547 return ReferenceError("not_defined", name); | 534 return ReferenceError("not_defined", name); |
548 } | 535 } |
549 return result; | 536 return result; |
550 } | 537 } |
551 | 538 |
552 // Get the property. | 539 // Get the property. |
553 return object->GetProperty(*object, &lookup, *name, &attr); | 540 return object->GetProperty(*object, &lookup, *name, &attr); |
554 } | 541 } |
555 | 542 |
556 | 543 |
557 void LoadIC::UpdateCaches(LookupResult* lookup, | 544 void LoadIC::UpdateCaches(LookupResult* lookup, |
| 545 State state, |
558 Handle<Object> object, | 546 Handle<Object> object, |
559 Handle<String> name) { | 547 Handle<String> name) { |
560 ASSERT(lookup->IsLoaded()); | 548 ASSERT(lookup->IsLoaded()); |
561 // Bail out if we didn't find a result. | 549 // Bail out if we didn't find a result. |
562 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 550 if (!lookup->IsValid() || !lookup->IsCacheable()) return; |
563 | 551 |
564 // Loading properties from values is not common, so don't try to | 552 // Loading properties from values is not common, so don't try to |
565 // deal with non-JS objects here. | 553 // deal with non-JS objects here. |
566 if (!object->IsJSObject()) return; | 554 if (!object->IsJSObject()) return; |
567 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 555 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
568 | 556 |
569 // Compute the code stub for this load. | 557 // Compute the code stub for this load. |
570 Object* code = Heap::undefined_value(); | 558 Object* code = NULL; |
571 State state = ComputeCacheState(target(), *object, *name, &code); | |
572 | |
573 if (state == UNINITIALIZED) { | 559 if (state == UNINITIALIZED) { |
574 // This is the first time we execute this inline cache. | 560 // This is the first time we execute this inline cache. |
575 // Set the target to the pre monomorphic stub to delay | 561 // Set the target to the pre monomorphic stub to delay |
576 // setting the monomorphic state. | 562 // setting the monomorphic state. |
577 code = pre_monomorphic_stub(); | 563 code = pre_monomorphic_stub(); |
578 } else if (state != MONOMORPHIC) { | 564 } else { |
579 // Compute monomorphic stub. | 565 // Compute monomorphic stub. |
580 switch (lookup->type()) { | 566 switch (lookup->type()) { |
581 case FIELD: { | 567 case FIELD: { |
582 code = StubCache::ComputeLoadField(*name, *receiver, | 568 code = StubCache::ComputeLoadField(*name, *receiver, |
583 lookup->holder(), | 569 lookup->holder(), |
584 lookup->GetFieldIndex()); | 570 lookup->GetFieldIndex()); |
585 break; | 571 break; |
586 } | 572 } |
587 case CONSTANT_FUNCTION: { | 573 case CONSTANT_FUNCTION: { |
588 Object* constant = lookup->GetConstantFunction(); | 574 Object* constant = lookup->GetConstantFunction(); |
(...skipping 20 matching lines...) Expand all Loading... |
609 break; | 595 break; |
610 } | 596 } |
611 case INTERCEPTOR: { | 597 case INTERCEPTOR: { |
612 code = StubCache::ComputeLoadInterceptor(*name, *receiver, | 598 code = StubCache::ComputeLoadInterceptor(*name, *receiver, |
613 lookup->holder()); | 599 lookup->holder()); |
614 break; | 600 break; |
615 } | 601 } |
616 default: | 602 default: |
617 return; | 603 return; |
618 } | 604 } |
| 605 } |
619 | 606 |
620 // If we're unable to compute the stub (not enough memory left), we | 607 // If we're unable to compute the stub (not enough memory left), we |
621 // simply avoid updating the caches. | 608 // simply avoid updating the caches. |
622 if (code->IsFailure()) return; | 609 if (code->IsFailure()) return; |
623 } | |
624 | 610 |
625 // Patch the call site depending on the state of the cache. | 611 // Patch the call site depending on the state of the cache. |
626 if (state == UNINITIALIZED || state == PREMONOMORPHIC || | 612 if (state == UNINITIALIZED || state == PREMONOMORPHIC || |
627 state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 613 state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
628 set_target(Code::cast(code)); | 614 set_target(Code::cast(code)); |
629 } else if (state == MONOMORPHIC && code->IsUndefined()) { | 615 } else if (state == MONOMORPHIC) { |
630 set_target(megamorphic_stub()); | 616 set_target(megamorphic_stub()); |
631 } else if (state == MONOMORPHIC) { | |
632 set_target(Code::cast(code)); | |
633 } | 617 } |
634 | 618 |
635 #ifdef DEBUG | 619 #ifdef DEBUG |
636 TraceIC("LoadIC", name, state, target()); | 620 TraceIC("LoadIC", name, state, target()); |
637 #endif | 621 #endif |
638 } | 622 } |
639 | 623 |
640 | 624 |
641 Object* KeyedLoadIC::Load(Handle<Object> object, | 625 Object* KeyedLoadIC::Load(State state, |
| 626 Handle<Object> object, |
642 Handle<Object> key) { | 627 Handle<Object> key) { |
643 if (key->IsSymbol()) { | 628 if (key->IsSymbol()) { |
644 Handle<String> name = Handle<String>::cast(key); | 629 Handle<String> name = Handle<String>::cast(key); |
645 | 630 |
646 // If the object is undefined or null it's illegal to try to get any | 631 // If the object is undefined or null it's illegal to try to get any |
647 // of its properties; throw a TypeError in that case. | 632 // of its properties; throw a TypeError in that case. |
648 if (object->IsUndefined() || object->IsNull()) { | 633 if (object->IsUndefined() || object->IsNull()) { |
649 return TypeError("non_object_property_load", object, name); | 634 return TypeError("non_object_property_load", object, name); |
650 } | 635 } |
651 | 636 |
652 if (FLAG_use_ic) { | 637 if (FLAG_use_ic) { |
653 // Use specialized code for getting the length of strings. | 638 // Use specialized code for getting the length of strings. |
654 if (object->IsString() && name->Equals(Heap::length_symbol())) { | 639 if (object->IsString() && name->Equals(Heap::length_symbol())) { |
655 Handle<String> string = Handle<String>::cast(object); | 640 Handle<String> string = Handle<String>::cast(object); |
656 Object* code = NULL; | 641 Object* code = NULL; |
657 if (string->IsShortString()) { | 642 if (string->IsShortString()) { |
658 code = StubCache::ComputeKeyedLoadShortStringLength(*name, *string); | 643 code = StubCache::ComputeKeyedLoadShortStringLength(*name, *string); |
659 } else if (string->IsMediumString()) { | 644 } else if (string->IsMediumString()) { |
660 code = | 645 code = |
661 StubCache::ComputeKeyedLoadMediumStringLength(*name, *string); | 646 StubCache::ComputeKeyedLoadMediumStringLength(*name, *string); |
662 } else { | 647 } else { |
663 ASSERT(string->IsLongString()); | 648 ASSERT(string->IsLongString()); |
664 code = StubCache::ComputeKeyedLoadLongStringLength(*name, *string); | 649 code = StubCache::ComputeKeyedLoadLongStringLength(*name, *string); |
665 } | 650 } |
666 if (code->IsFailure()) return code; | 651 if (code->IsFailure()) return code; |
667 set_target(Code::cast(code)); | 652 set_target(Code::cast(code)); |
668 #ifdef DEBUG | 653 #ifdef DEBUG |
669 if (FLAG_trace_ic) PrintF("[KeyedLoadIC : +#length /string]\n"); | 654 TraceIC("KeyedLoadIC", name, state, target()); |
670 #endif | 655 #endif |
671 return Smi::FromInt(string->length()); | 656 return Smi::FromInt(string->length()); |
672 } | 657 } |
673 | 658 |
674 // Use specialized code for getting the length of arrays. | 659 // Use specialized code for getting the length of arrays. |
675 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) { | 660 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) { |
676 Handle<JSArray> array = Handle<JSArray>::cast(object); | 661 Handle<JSArray> array = Handle<JSArray>::cast(object); |
677 Object* code = StubCache::ComputeKeyedLoadArrayLength(*name, *array); | 662 Object* code = StubCache::ComputeKeyedLoadArrayLength(*name, *array); |
678 if (code->IsFailure()) return code; | 663 if (code->IsFailure()) return code; |
679 set_target(Code::cast(code)); | 664 set_target(Code::cast(code)); |
680 #ifdef DEBUG | 665 #ifdef DEBUG |
681 if (FLAG_trace_ic) PrintF("[KeyedLoadIC : +#length /array]\n"); | 666 TraceIC("KeyedLoadIC", name, state, target()); |
682 #endif | 667 #endif |
683 return JSArray::cast(*object)->length(); | 668 return JSArray::cast(*object)->length(); |
684 } | 669 } |
685 | 670 |
686 // Use specialized code for getting prototype of functions. | 671 // Use specialized code for getting prototype of functions. |
687 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) { | 672 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) { |
688 Handle<JSFunction> function = Handle<JSFunction>::cast(object); | 673 Handle<JSFunction> function = Handle<JSFunction>::cast(object); |
689 Object* code = | 674 Object* code = |
690 StubCache::ComputeKeyedLoadFunctionPrototype(*name, *function); | 675 StubCache::ComputeKeyedLoadFunctionPrototype(*name, *function); |
691 if (code->IsFailure()) return code; | 676 if (code->IsFailure()) return code; |
692 set_target(Code::cast(code)); | 677 set_target(Code::cast(code)); |
693 #ifdef DEBUG | 678 #ifdef DEBUG |
694 if (FLAG_trace_ic) PrintF("[KeyedLoadIC : +#prototype /function]\n"); | 679 TraceIC("KeyedLoadIC", name, state, target()); |
695 #endif | 680 #endif |
696 return Accessors::FunctionGetPrototype(*object, 0); | 681 return Accessors::FunctionGetPrototype(*object, 0); |
697 } | 682 } |
698 } | 683 } |
699 | 684 |
700 // Check if the name is trivially convertible to an index and get | 685 // Check if the name is trivially convertible to an index and get |
701 // the element or char if so. | 686 // the element or char if so. |
702 uint32_t index = 0; | 687 uint32_t index = 0; |
703 if (name->AsArrayIndex(&index)) { | 688 if (name->AsArrayIndex(&index)) { |
704 HandleScope scope; | 689 HandleScope scope; |
705 // Rewrite to the generic keyed load stub. | 690 // Rewrite to the generic keyed load stub. |
706 if (FLAG_use_ic) set_target(generic_stub()); | 691 if (FLAG_use_ic) set_target(generic_stub()); |
707 return Runtime::GetElementOrCharAt(object, index); | 692 return Runtime::GetElementOrCharAt(object, index); |
708 } | 693 } |
709 | 694 |
710 // Named lookup. | 695 // Named lookup. |
711 LookupResult lookup; | 696 LookupResult lookup; |
712 object->Lookup(*name, &lookup); | 697 object->Lookup(*name, &lookup); |
713 | 698 |
714 // If lookup is invalid, check if we need to throw an exception. | 699 // If lookup is invalid, check if we need to throw an exception. |
715 if (!lookup.IsValid()) { | 700 if (!lookup.IsValid()) { |
716 if (FLAG_strict || is_contextual()) { | 701 if (FLAG_strict || is_contextual()) { |
717 return ReferenceError("not_defined", name); | 702 return ReferenceError("not_defined", name); |
718 } | 703 } |
719 } | 704 } |
720 | 705 |
721 // Update the inline cache. | 706 // Update the inline cache. |
722 if (FLAG_use_ic && lookup.IsLoaded()) { | 707 if (FLAG_use_ic && lookup.IsLoaded()) { |
723 UpdateCaches(&lookup, object, name); | 708 UpdateCaches(&lookup, state, object, name); |
724 } | 709 } |
725 | 710 |
726 PropertyAttributes attr; | 711 PropertyAttributes attr; |
727 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { | 712 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { |
728 // Get the property. | 713 // Get the property. |
729 Object* result = object->GetProperty(*object, &lookup, *name, &attr); | 714 Object* result = object->GetProperty(*object, &lookup, *name, &attr); |
730 if (result->IsFailure()) return result; | 715 if (result->IsFailure()) return result; |
731 // If the property is not present, check if we need to throw an | 716 // If the property is not present, check if we need to throw an |
732 // exception. | 717 // exception. |
733 if (attr == ABSENT && is_contextual()) { | 718 if (attr == ABSENT && is_contextual()) { |
734 return ReferenceError("not_defined", name); | 719 return ReferenceError("not_defined", name); |
735 } | 720 } |
736 return result; | 721 return result; |
737 } | 722 } |
738 | 723 |
739 return object->GetProperty(*object, &lookup, *name, &attr); | 724 return object->GetProperty(*object, &lookup, *name, &attr); |
740 } | 725 } |
741 | 726 |
742 // Do not use ICs for objects that require access checks (including | 727 // Do not use ICs for objects that require access checks (including |
743 // the global object). | 728 // the global object). |
744 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 729 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
745 | 730 |
746 if (use_ic) set_target(generic_stub()); | 731 if (use_ic) set_target(generic_stub()); |
747 | 732 |
748 // Get the property. | 733 // Get the property. |
749 return Runtime::GetObjectProperty(object, key); | 734 return Runtime::GetObjectProperty(object, key); |
750 } | 735 } |
751 | 736 |
752 | 737 |
753 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, | 738 void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, |
754 Handle<Object> object, | 739 Handle<Object> object, Handle<String> name) { |
755 Handle<String> name) { | |
756 ASSERT(lookup->IsLoaded()); | 740 ASSERT(lookup->IsLoaded()); |
757 // Bail out if we didn't find a result. | 741 // Bail out if we didn't find a result. |
758 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 742 if (!lookup->IsValid() || !lookup->IsCacheable()) return; |
759 | 743 |
760 if (!object->IsJSObject()) return; | 744 if (!object->IsJSObject()) return; |
761 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 745 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
762 | 746 |
763 // Compute the state of the current inline cache. | 747 // Compute the code stub for this load. |
764 Object* code = Heap::undefined_value(); | 748 Object* code = NULL; |
765 State state = ComputeCacheState(target(), *object, *name, &code); | |
766 | 749 |
767 // Compute the code stub for this load. | |
768 if (state == UNINITIALIZED) { | 750 if (state == UNINITIALIZED) { |
769 // This is the first time we execute this inline cache. | 751 // This is the first time we execute this inline cache. |
770 // Set the target to the pre monomorphic stub to delay | 752 // Set the target to the pre monomorphic stub to delay |
771 // setting the monomorphic state. | 753 // setting the monomorphic state. |
772 code = pre_monomorphic_stub(); | 754 code = pre_monomorphic_stub(); |
773 } else { | 755 } else { |
774 // Compute a monomorphic stub. | 756 // Compute a monomorphic stub. |
775 switch (lookup->type()) { | 757 switch (lookup->type()) { |
776 case FIELD: { | 758 case FIELD: { |
777 code = StubCache::ComputeKeyedLoadField(*name, *receiver, | 759 code = StubCache::ComputeKeyedLoadField(*name, *receiver, |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
820 } else if (state == MONOMORPHIC) { | 802 } else if (state == MONOMORPHIC) { |
821 set_target(megamorphic_stub()); | 803 set_target(megamorphic_stub()); |
822 } | 804 } |
823 | 805 |
824 #ifdef DEBUG | 806 #ifdef DEBUG |
825 TraceIC("KeyedLoadIC", name, state, target()); | 807 TraceIC("KeyedLoadIC", name, state, target()); |
826 #endif | 808 #endif |
827 } | 809 } |
828 | 810 |
829 | 811 |
830 Object* StoreIC::Store(Handle<Object> object, | 812 Object* StoreIC::Store(State state, |
| 813 Handle<Object> object, |
831 Handle<String> name, | 814 Handle<String> name, |
832 Handle<Object> value) { | 815 Handle<Object> value) { |
833 // If the object is undefined or null it's illegal to try to set any | 816 // If the object is undefined or null it's illegal to try to set any |
834 // properties on it; throw a TypeError in that case. | 817 // properties on it; throw a TypeError in that case. |
835 if (object->IsUndefined() || object->IsNull()) { | 818 if (object->IsUndefined() || object->IsNull()) { |
836 return TypeError("non_object_property_store", object, name); | 819 return TypeError("non_object_property_store", object, name); |
837 } | 820 } |
838 | 821 |
839 // Ignore stores where the receiver is not a JSObject. | 822 // Ignore stores where the receiver is not a JSObject. |
840 if (!object->IsJSObject()) return *value; | 823 if (!object->IsJSObject()) return *value; |
841 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 824 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
842 | 825 |
843 // Check if the given name is an array index. | 826 // Check if the given name is an array index. |
844 uint32_t index; | 827 uint32_t index; |
845 if (name->AsArrayIndex(&index)) { | 828 if (name->AsArrayIndex(&index)) { |
846 HandleScope scope; | 829 HandleScope scope; |
847 Handle<Object> result = SetElement(receiver, index, value); | 830 Handle<Object> result = SetElement(receiver, index, value); |
848 if (result.is_null()) return Failure::Exception(); | 831 if (result.is_null()) return Failure::Exception(); |
849 return *value; | 832 return *value; |
850 } | 833 } |
851 | 834 |
852 // Lookup the property locally in the receiver. | 835 // Lookup the property locally in the receiver. |
853 LookupResult lookup; | 836 LookupResult lookup; |
854 receiver->LocalLookup(*name, &lookup); | 837 receiver->LocalLookup(*name, &lookup); |
855 | 838 |
856 // Update inline cache and stub cache. | 839 // Update inline cache and stub cache. |
857 if (FLAG_use_ic && lookup.IsLoaded()) { | 840 if (FLAG_use_ic && lookup.IsLoaded()) { |
858 UpdateCaches(&lookup, receiver, name, value); | 841 UpdateCaches(&lookup, state, receiver, name, value); |
859 } | 842 } |
860 | 843 |
861 // Set the property. | 844 // Set the property. |
862 return receiver->SetProperty(*name, *value, NONE); | 845 return receiver->SetProperty(*name, *value, NONE); |
863 } | 846 } |
864 | 847 |
865 | 848 |
866 void StoreIC::UpdateCaches(LookupResult* lookup, | 849 void StoreIC::UpdateCaches(LookupResult* lookup, |
| 850 State state, |
867 Handle<JSObject> receiver, | 851 Handle<JSObject> receiver, |
868 Handle<String> name, | 852 Handle<String> name, |
869 Handle<Object> value) { | 853 Handle<Object> value) { |
870 ASSERT(lookup->IsLoaded()); | 854 ASSERT(lookup->IsLoaded()); |
871 // Bail out if we didn't find a result. | 855 // Bail out if we didn't find a result. |
872 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 856 if (!lookup->IsValid() || !lookup->IsCacheable()) return; |
873 | 857 |
874 // If the property is read-only, we leave the IC in its current | 858 // If the property is read-only, we leave the IC in its current |
875 // state. | 859 // state. |
876 if (lookup->IsReadOnly()) return; | 860 if (lookup->IsReadOnly()) return; |
877 | 861 |
878 // If the property has a non-field type allowing map transitions | 862 // If the property has a non-field type allowing map transitions |
879 // where there is extra room in the object, we leave the IC in its | 863 // where there is extra room in the object, we leave the IC in its |
880 // current state. | 864 // current state. |
881 PropertyType type = lookup->type(); | 865 PropertyType type = lookup->type(); |
882 | 866 |
883 // Compute the state of the current inline cache. | |
884 Object* code = Heap::undefined_value(); | |
885 State state = ComputeCacheState(target(), *receiver, *name, &code); | |
886 | |
887 // Compute the code stub for this store; used for rewriting to | 867 // Compute the code stub for this store; used for rewriting to |
888 // monomorphic state and making sure that the code stub is in the | 868 // monomorphic state and making sure that the code stub is in the |
889 // stub cache. | 869 // stub cache. |
| 870 Object* code = NULL; |
890 switch (type) { | 871 switch (type) { |
891 case FIELD: { | 872 case FIELD: { |
892 code = StubCache::ComputeStoreField(*name, *receiver, | 873 code = StubCache::ComputeStoreField(*name, *receiver, |
893 lookup->GetFieldIndex()); | 874 lookup->GetFieldIndex()); |
894 break; | 875 break; |
895 } | 876 } |
896 case MAP_TRANSITION: { | 877 case MAP_TRANSITION: { |
897 if (lookup->GetAttributes() != NONE) return; | 878 if (lookup->GetAttributes() != NONE) return; |
898 if (receiver->map()->unused_property_fields() == 0) return; | 879 if (receiver->map()->unused_property_fields() == 0) return; |
899 HandleScope scope; | 880 HandleScope scope; |
(...skipping 29 matching lines...) Expand all Loading... |
929 } else if (state == MONOMORPHIC) { | 910 } else if (state == MONOMORPHIC) { |
930 set_target(megamorphic_stub()); | 911 set_target(megamorphic_stub()); |
931 } | 912 } |
932 | 913 |
933 #ifdef DEBUG | 914 #ifdef DEBUG |
934 TraceIC("StoreIC", name, state, target()); | 915 TraceIC("StoreIC", name, state, target()); |
935 #endif | 916 #endif |
936 } | 917 } |
937 | 918 |
938 | 919 |
939 Object* KeyedStoreIC::Store(Handle<Object> object, | 920 Object* KeyedStoreIC::Store(State state, |
| 921 Handle<Object> object, |
940 Handle<Object> key, | 922 Handle<Object> key, |
941 Handle<Object> value) { | 923 Handle<Object> value) { |
942 if (key->IsSymbol()) { | 924 if (key->IsSymbol()) { |
943 Handle<String> name = Handle<String>::cast(key); | 925 Handle<String> name = Handle<String>::cast(key); |
944 | 926 |
945 // If the object is undefined or null it's illegal to try to set any | 927 // If the object is undefined or null it's illegal to try to set any |
946 // properties on it; throw a TypeError in that case. | 928 // properties on it; throw a TypeError in that case. |
947 if (object->IsUndefined() || object->IsNull()) { | 929 if (object->IsUndefined() || object->IsNull()) { |
948 return TypeError("non_object_property_store", object, name); | 930 return TypeError("non_object_property_store", object, name); |
949 } | 931 } |
(...skipping 10 matching lines...) Expand all Loading... |
960 if (result.is_null()) return Failure::Exception(); | 942 if (result.is_null()) return Failure::Exception(); |
961 return *value; | 943 return *value; |
962 } | 944 } |
963 | 945 |
964 // Lookup the property locally in the receiver. | 946 // Lookup the property locally in the receiver. |
965 LookupResult lookup; | 947 LookupResult lookup; |
966 receiver->LocalLookup(*name, &lookup); | 948 receiver->LocalLookup(*name, &lookup); |
967 | 949 |
968 // Update inline cache and stub cache. | 950 // Update inline cache and stub cache. |
969 if (FLAG_use_ic && lookup.IsLoaded()) { | 951 if (FLAG_use_ic && lookup.IsLoaded()) { |
970 UpdateCaches(&lookup, receiver, name, value); | 952 UpdateCaches(&lookup, state, receiver, name, value); |
971 } | 953 } |
972 | 954 |
973 // Set the property. | 955 // Set the property. |
974 return receiver->SetProperty(*name, *value, NONE); | 956 return receiver->SetProperty(*name, *value, NONE); |
975 } | 957 } |
976 | 958 |
977 // Do not use ICs for objects that require access checks (including | 959 // Do not use ICs for objects that require access checks (including |
978 // the global object). | 960 // the global object). |
979 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 961 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
980 | 962 |
981 if (use_ic) set_target(generic_stub()); | 963 if (use_ic) set_target(generic_stub()); |
982 | 964 |
983 // Set the property. | 965 // Set the property. |
984 return Runtime::SetObjectProperty(object, key, value, NONE); | 966 return Runtime::SetObjectProperty(object, key, value, NONE); |
985 } | 967 } |
986 | 968 |
987 | 969 |
988 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, | 970 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, |
| 971 State state, |
989 Handle<JSObject> receiver, | 972 Handle<JSObject> receiver, |
990 Handle<String> name, | 973 Handle<String> name, |
991 Handle<Object> value) { | 974 Handle<Object> value) { |
992 ASSERT(lookup->IsLoaded()); | 975 ASSERT(lookup->IsLoaded()); |
993 // Bail out if we didn't find a result. | 976 // Bail out if we didn't find a result. |
994 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | 977 if (!lookup->IsValid() || !lookup->IsCacheable()) return; |
995 | 978 |
996 // If the property is read-only, we leave the IC in its current | 979 // If the property is read-only, we leave the IC in its current |
997 // state. | 980 // state. |
998 if (lookup->IsReadOnly()) return; | 981 if (lookup->IsReadOnly()) return; |
999 | 982 |
1000 // If the property has a non-field type allowing map transitions | 983 // If the property has a non-field type allowing map transitions |
1001 // where there is extra room in the object, we leave the IC in its | 984 // where there is extra room in the object, we leave the IC in its |
1002 // current state. | 985 // current state. |
1003 PropertyType type = lookup->type(); | 986 PropertyType type = lookup->type(); |
1004 | 987 |
1005 // Compute the code stub for this store; used for rewriting to | 988 // Compute the code stub for this store; used for rewriting to |
1006 // monomorphic state and making sure that the code stub is in the | 989 // monomorphic state and making sure that the code stub is in the |
1007 // stub cache. | 990 // stub cache. |
1008 Object* code = Heap::undefined_value(); | 991 Object* code = NULL; |
1009 State state = ComputeCacheState(target(), *receiver, *name, &code); | |
1010 | 992 |
1011 switch (type) { | 993 switch (type) { |
1012 case FIELD: { | 994 case FIELD: { |
1013 code = StubCache::ComputeKeyedStoreField(*name, *receiver, | 995 code = StubCache::ComputeKeyedStoreField(*name, *receiver, |
1014 lookup->GetFieldIndex()); | 996 lookup->GetFieldIndex()); |
1015 break; | 997 break; |
1016 } | 998 } |
1017 case MAP_TRANSITION: { | 999 case MAP_TRANSITION: { |
1018 if (lookup->GetAttributes() == NONE) { | 1000 if (lookup->GetAttributes() == NONE) { |
1019 if (receiver->map()->unused_property_fields() == 0) return; | 1001 if (receiver->map()->unused_property_fields() == 0) return; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1057 | 1039 |
1058 // ---------------------------------------------------------------------------- | 1040 // ---------------------------------------------------------------------------- |
1059 // Static IC stub generators. | 1041 // Static IC stub generators. |
1060 // | 1042 // |
1061 | 1043 |
1062 // Used from ic_<arch>.cc. | 1044 // Used from ic_<arch>.cc. |
1063 Object* CallIC_Miss(Arguments args) { | 1045 Object* CallIC_Miss(Arguments args) { |
1064 NoHandleAllocation na; | 1046 NoHandleAllocation na; |
1065 ASSERT(args.length() == 2); | 1047 ASSERT(args.length() == 2); |
1066 CallIC ic; | 1048 CallIC ic; |
1067 return ic.LoadFunction(args.at<Object>(0), args.at<String>(1)); | 1049 IC::State state = IC::StateFrom(ic.target(), args[0]); |
| 1050 return ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); |
1068 } | 1051 } |
1069 | 1052 |
1070 | 1053 |
1071 void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) { | 1054 void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) { |
1072 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); | 1055 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); |
1073 } | 1056 } |
1074 | 1057 |
1075 | 1058 |
1076 void CallIC::GeneratePreMonomorphic(MacroAssembler* masm, int argc) { | 1059 void CallIC::GeneratePreMonomorphic(MacroAssembler* masm, int argc) { |
1077 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); | 1060 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); |
1078 } | 1061 } |
1079 | 1062 |
1080 | 1063 |
1081 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { | 1064 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { |
1082 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); | 1065 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); |
1083 } | 1066 } |
1084 | 1067 |
1085 | 1068 |
1086 // Used from ic_<arch>.cc. | 1069 // Used from ic_<arch>.cc. |
1087 Object* LoadIC_Miss(Arguments args) { | 1070 Object* LoadIC_Miss(Arguments args) { |
1088 NoHandleAllocation na; | 1071 NoHandleAllocation na; |
1089 ASSERT(args.length() == 2); | 1072 ASSERT(args.length() == 2); |
1090 LoadIC ic; | 1073 LoadIC ic; |
1091 return ic.Load(args.at<Object>(0), args.at<String>(1)); | 1074 IC::State state = IC::StateFrom(ic.target(), args[0]); |
| 1075 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); |
1092 } | 1076 } |
1093 | 1077 |
1094 | 1078 |
1095 void LoadIC::GenerateInitialize(MacroAssembler* masm) { | 1079 void LoadIC::GenerateInitialize(MacroAssembler* masm) { |
1096 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss))); | 1080 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss))); |
1097 } | 1081 } |
1098 | 1082 |
1099 | 1083 |
1100 void LoadIC::GeneratePreMonomorphic(MacroAssembler* masm) { | 1084 void LoadIC::GeneratePreMonomorphic(MacroAssembler* masm) { |
1101 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss))); | 1085 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss))); |
1102 } | 1086 } |
1103 | 1087 |
1104 | 1088 |
1105 // Used from ic_<arch>.cc | 1089 // Used from ic_<arch>.cc |
1106 Object* KeyedLoadIC_Miss(Arguments args) { | 1090 Object* KeyedLoadIC_Miss(Arguments args) { |
1107 NoHandleAllocation na; | 1091 NoHandleAllocation na; |
1108 ASSERT(args.length() == 2); | 1092 ASSERT(args.length() == 2); |
1109 KeyedLoadIC ic; | 1093 KeyedLoadIC ic; |
1110 return ic.Load(args.at<Object>(0), args.at<Object>(1)); | 1094 IC::State state = IC::StateFrom(ic.target(), args[0]); |
| 1095 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); |
1111 } | 1096 } |
1112 | 1097 |
1113 | 1098 |
1114 void KeyedLoadIC::GenerateInitialize(MacroAssembler* masm) { | 1099 void KeyedLoadIC::GenerateInitialize(MacroAssembler* masm) { |
1115 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); | 1100 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); |
1116 } | 1101 } |
1117 | 1102 |
1118 | 1103 |
1119 void KeyedLoadIC::GeneratePreMonomorphic(MacroAssembler* masm) { | 1104 void KeyedLoadIC::GeneratePreMonomorphic(MacroAssembler* masm) { |
1120 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); | 1105 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); |
1121 } | 1106 } |
1122 | 1107 |
1123 | 1108 |
1124 // Used from ic_<arch>.cc. | 1109 // Used from ic_<arch>.cc. |
1125 Object* StoreIC_Miss(Arguments args) { | 1110 Object* StoreIC_Miss(Arguments args) { |
1126 NoHandleAllocation na; | 1111 NoHandleAllocation na; |
1127 ASSERT(args.length() == 3); | 1112 ASSERT(args.length() == 3); |
1128 StoreIC ic; | 1113 StoreIC ic; |
1129 return ic.Store(args.at<Object>(0), args.at<String>(1), args.at<Object>(2)); | 1114 IC::State state = IC::StateFrom(ic.target(), args[0]); |
| 1115 return ic.Store(state, args.at<Object>(0), args.at<String>(1), |
| 1116 args.at<Object>(2)); |
1130 } | 1117 } |
1131 | 1118 |
1132 | 1119 |
1133 void StoreIC::GenerateInitialize(MacroAssembler* masm) { | 1120 void StoreIC::GenerateInitialize(MacroAssembler* masm) { |
1134 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); | 1121 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); |
1135 } | 1122 } |
1136 | 1123 |
1137 | 1124 |
1138 void StoreIC::GenerateMiss(MacroAssembler* masm) { | 1125 void StoreIC::GenerateMiss(MacroAssembler* masm) { |
1139 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); | 1126 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); |
1140 } | 1127 } |
1141 | 1128 |
1142 | 1129 |
1143 // Used from ic_<arch>.cc. | 1130 // Used from ic_<arch>.cc. |
1144 Object* KeyedStoreIC_Miss(Arguments args) { | 1131 Object* KeyedStoreIC_Miss(Arguments args) { |
1145 NoHandleAllocation na; | 1132 NoHandleAllocation na; |
1146 ASSERT(args.length() == 3); | 1133 ASSERT(args.length() == 3); |
1147 KeyedStoreIC ic; | 1134 KeyedStoreIC ic; |
1148 return ic.Store(args.at<Object>(0), args.at<Object>(1), args.at<Object>(2)); | 1135 IC::State state = IC::StateFrom(ic.target(), args[0]); |
| 1136 return ic.Store(state, args.at<Object>(0), args.at<Object>(1), |
| 1137 args.at<Object>(2)); |
1149 } | 1138 } |
1150 | 1139 |
1151 | 1140 |
1152 void KeyedStoreIC::GenerateInitialize(MacroAssembler* masm) { | 1141 void KeyedStoreIC::GenerateInitialize(MacroAssembler* masm) { |
1153 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss))); | 1142 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss))); |
1154 } | 1143 } |
1155 | 1144 |
1156 | 1145 |
1157 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { | 1146 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { |
1158 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss))); | 1147 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss))); |
1159 } | 1148 } |
1160 | 1149 |
1161 | 1150 |
1162 static Address IC_utilities[] = { | 1151 static Address IC_utilities[] = { |
1163 #define ADDR(name) FUNCTION_ADDR(name), | 1152 #define ADDR(name) FUNCTION_ADDR(name), |
1164 IC_UTIL_LIST(ADDR) | 1153 IC_UTIL_LIST(ADDR) |
1165 NULL | 1154 NULL |
1166 #undef ADDR | 1155 #undef ADDR |
1167 }; | 1156 }; |
1168 | 1157 |
1169 | 1158 |
1170 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 1159 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
1171 return IC_utilities[id]; | 1160 return IC_utilities[id]; |
1172 } | 1161 } |
1173 | 1162 |
1174 | 1163 |
1175 } } // namespace v8::internal | 1164 } } // namespace v8::internal |
OLD | NEW |