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