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 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
362 if (code->IsFailure()) return code; | 362 if (code->IsFailure()) return code; |
363 LOG(CodeCreateEvent("KeyedStoreIC", Code::cast(code), name)); | 363 LOG(CodeCreateEvent("KeyedStoreIC", Code::cast(code), name)); |
364 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code)); | 364 Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code)); |
365 if (result->IsFailure()) return result; | 365 if (result->IsFailure()) return result; |
366 } | 366 } |
367 return code; | 367 return code; |
368 } | 368 } |
369 | 369 |
370 | 370 |
371 Object* StubCache::ComputeCallConstant(int argc, | 371 Object* StubCache::ComputeCallConstant(int argc, |
| 372 InlineCacheInLoop in_loop, |
372 String* name, | 373 String* name, |
373 Object* object, | 374 Object* object, |
374 JSObject* holder, | 375 JSObject* holder, |
375 JSFunction* function) { | 376 JSFunction* function) { |
376 // Compute the check type and the map. | 377 // Compute the check type and the map. |
377 Map* map = IC::GetCodeCacheMapForObject(object); | 378 Map* map = IC::GetCodeCacheMapForObject(object); |
378 | 379 |
379 // Compute check type based on receiver/holder. | 380 // Compute check type based on receiver/holder. |
380 StubCompiler::CheckType check = StubCompiler::RECEIVER_MAP_CHECK; | 381 StubCompiler::CheckType check = StubCompiler::RECEIVER_MAP_CHECK; |
381 if (object->IsString()) { | 382 if (object->IsString()) { |
382 check = StubCompiler::STRING_CHECK; | 383 check = StubCompiler::STRING_CHECK; |
383 } else if (object->IsNumber()) { | 384 } else if (object->IsNumber()) { |
384 check = StubCompiler::NUMBER_CHECK; | 385 check = StubCompiler::NUMBER_CHECK; |
385 } else if (object->IsBoolean()) { | 386 } else if (object->IsBoolean()) { |
386 check = StubCompiler::BOOLEAN_CHECK; | 387 check = StubCompiler::BOOLEAN_CHECK; |
387 } | 388 } |
388 | 389 |
389 Code::Flags flags = | 390 Code::Flags flags = |
390 Code::ComputeMonomorphicFlags(Code::CALL_IC, CONSTANT_FUNCTION, argc); | 391 Code::ComputeMonomorphicFlags(Code::CALL_IC, |
| 392 CONSTANT_FUNCTION, |
| 393 in_loop, |
| 394 argc); |
391 Object* code = map->FindInCodeCache(name, flags); | 395 Object* code = map->FindInCodeCache(name, flags); |
392 if (code->IsUndefined()) { | 396 if (code->IsUndefined()) { |
393 if (object->IsJSObject()) { | 397 if (object->IsJSObject()) { |
394 Object* opt = | 398 Object* opt = |
395 Top::LookupSpecialFunction(JSObject::cast(object), holder, function); | 399 Top::LookupSpecialFunction(JSObject::cast(object), holder, function); |
396 if (opt->IsJSFunction()) { | 400 if (opt->IsJSFunction()) { |
397 check = StubCompiler::JSARRAY_HAS_FAST_ELEMENTS_CHECK; | 401 check = StubCompiler::JSARRAY_HAS_FAST_ELEMENTS_CHECK; |
398 function = JSFunction::cast(opt); | 402 function = JSFunction::cast(opt); |
399 } | 403 } |
400 } | 404 } |
401 // If the function hasn't been compiled yet, we cannot do it now | 405 // If the function hasn't been compiled yet, we cannot do it now |
402 // because it may cause GC. To avoid this issue, we return an | 406 // because it may cause GC. To avoid this issue, we return an |
403 // internal error which will make sure we do not update any | 407 // internal error which will make sure we do not update any |
404 // caches. | 408 // caches. |
405 if (!function->is_compiled()) return Failure::InternalError(); | 409 if (!function->is_compiled()) return Failure::InternalError(); |
406 // Compile the stub - only create stubs for fully compiled functions. | 410 // Compile the stub - only create stubs for fully compiled functions. |
407 CallStubCompiler compiler(argc); | 411 CallStubCompiler compiler(argc); |
408 code = compiler.CompileCallConstant(object, holder, function, check); | 412 code = compiler.CompileCallConstant(object, holder, function, check, flags); |
409 if (code->IsFailure()) return code; | 413 if (code->IsFailure()) return code; |
410 LOG(CodeCreateEvent("CallIC", Code::cast(code), name)); | 414 LOG(CodeCreateEvent("CallIC", Code::cast(code), name)); |
411 Object* result = map->UpdateCodeCache(name, Code::cast(code)); | 415 Object* result = map->UpdateCodeCache(name, Code::cast(code)); |
412 if (result->IsFailure()) return result; | 416 if (result->IsFailure()) return result; |
413 } | 417 } |
414 return Set(name, map, Code::cast(code)); | 418 return Set(name, map, Code::cast(code)); |
415 } | 419 } |
416 | 420 |
417 | 421 |
418 Object* StubCache::ComputeCallField(int argc, | 422 Object* StubCache::ComputeCallField(int argc, |
| 423 InlineCacheInLoop in_loop, |
419 String* name, | 424 String* name, |
420 Object* object, | 425 Object* object, |
421 JSObject* holder, | 426 JSObject* holder, |
422 int index) { | 427 int index) { |
423 // Compute the check type and the map. | 428 // Compute the check type and the map. |
424 Map* map = IC::GetCodeCacheMapForObject(object); | 429 Map* map = IC::GetCodeCacheMapForObject(object); |
425 | 430 |
426 // TODO(1233596): We cannot do receiver map check for non-JS objects | 431 // TODO(1233596): We cannot do receiver map check for non-JS objects |
427 // because they may be represented as immediates without a | 432 // because they may be represented as immediates without a |
428 // map. Instead, we check against the map in the holder. | 433 // map. Instead, we check against the map in the holder. |
429 if (object->IsNumber() || object->IsBoolean() || object->IsString()) { | 434 if (object->IsNumber() || object->IsBoolean() || object->IsString()) { |
430 object = holder; | 435 object = holder; |
431 } | 436 } |
432 | 437 |
433 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, FIELD, argc); | 438 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, |
| 439 FIELD, |
| 440 in_loop, |
| 441 argc); |
434 Object* code = map->FindInCodeCache(name, flags); | 442 Object* code = map->FindInCodeCache(name, flags); |
435 if (code->IsUndefined()) { | 443 if (code->IsUndefined()) { |
436 CallStubCompiler compiler(argc); | 444 CallStubCompiler compiler(argc); |
437 code = compiler.CompileCallField(object, holder, index, name); | 445 code = compiler.CompileCallField(object, holder, index, name, flags); |
438 if (code->IsFailure()) return code; | 446 if (code->IsFailure()) return code; |
439 LOG(CodeCreateEvent("CallIC", Code::cast(code), name)); | 447 LOG(CodeCreateEvent("CallIC", Code::cast(code), name)); |
440 Object* result = map->UpdateCodeCache(name, Code::cast(code)); | 448 Object* result = map->UpdateCodeCache(name, Code::cast(code)); |
441 if (result->IsFailure()) return result; | 449 if (result->IsFailure()) return result; |
442 } | 450 } |
443 return Set(name, map, Code::cast(code)); | 451 return Set(name, map, Code::cast(code)); |
444 } | 452 } |
445 | 453 |
446 | 454 |
447 Object* StubCache::ComputeCallInterceptor(int argc, | 455 Object* StubCache::ComputeCallInterceptor(int argc, |
448 String* name, | 456 String* name, |
449 Object* object, | 457 Object* object, |
450 JSObject* holder) { | 458 JSObject* holder) { |
451 // Compute the check type and the map. | 459 // Compute the check type and the map. |
452 // If the object is a value, we use the prototype map for the cache. | 460 // If the object is a value, we use the prototype map for the cache. |
453 Map* map = IC::GetCodeCacheMapForObject(object); | 461 Map* map = IC::GetCodeCacheMapForObject(object); |
454 | 462 |
455 // TODO(1233596): We cannot do receiver map check for non-JS objects | 463 // TODO(1233596): We cannot do receiver map check for non-JS objects |
456 // because they may be represented as immediates without a | 464 // because they may be represented as immediates without a |
457 // map. Instead, we check against the map in the holder. | 465 // map. Instead, we check against the map in the holder. |
458 if (object->IsNumber() || object->IsBoolean() || object->IsString()) { | 466 if (object->IsNumber() || object->IsBoolean() || object->IsString()) { |
459 object = holder; | 467 object = holder; |
460 } | 468 } |
461 | 469 |
462 Code::Flags flags = | 470 Code::Flags flags = |
463 Code::ComputeMonomorphicFlags(Code::CALL_IC, INTERCEPTOR, argc); | 471 Code::ComputeMonomorphicFlags(Code::CALL_IC, |
| 472 INTERCEPTOR, |
| 473 NOT_IN_LOOP, |
| 474 argc); |
464 Object* code = map->FindInCodeCache(name, flags); | 475 Object* code = map->FindInCodeCache(name, flags); |
465 if (code->IsUndefined()) { | 476 if (code->IsUndefined()) { |
466 CallStubCompiler compiler(argc); | 477 CallStubCompiler compiler(argc); |
467 code = compiler.CompileCallInterceptor(object, holder, name); | 478 code = compiler.CompileCallInterceptor(object, holder, name); |
468 if (code->IsFailure()) return code; | 479 if (code->IsFailure()) return code; |
469 LOG(CodeCreateEvent("CallIC", Code::cast(code), name)); | 480 LOG(CodeCreateEvent("CallIC", Code::cast(code), name)); |
470 Object* result = map->UpdateCodeCache(name, Code::cast(code)); | 481 Object* result = map->UpdateCodeCache(name, Code::cast(code)); |
471 if (result->IsFailure()) return result; | 482 if (result->IsFailure()) return result; |
472 } | 483 } |
473 return Set(name, map, Code::cast(code)); | 484 return Set(name, map, Code::cast(code)); |
474 } | 485 } |
475 | 486 |
476 | 487 |
477 Object* StubCache::ComputeCallNormal(int argc, | 488 Object* StubCache::ComputeCallNormal(int argc, |
| 489 InlineCacheInLoop in_loop, |
478 String* name, | 490 String* name, |
479 JSObject* receiver) { | 491 JSObject* receiver) { |
480 Object* code = ComputeCallNormal(argc); | 492 Object* code = ComputeCallNormal(argc, in_loop); |
481 if (code->IsFailure()) return code; | 493 if (code->IsFailure()) return code; |
482 return Set(name, receiver->map(), Code::cast(code)); | 494 return Set(name, receiver->map(), Code::cast(code)); |
483 } | 495 } |
484 | 496 |
485 | 497 |
486 static Object* GetProbeValue(Code::Flags flags) { | 498 static Object* GetProbeValue(Code::Flags flags) { |
487 Dictionary* dictionary = Heap::non_monomorphic_cache(); | 499 Dictionary* dictionary = Heap::non_monomorphic_cache(); |
488 int entry = dictionary->FindNumberEntry(flags); | 500 int entry = dictionary->FindNumberEntry(flags); |
489 if (entry != -1) return dictionary->ValueAt(entry); | 501 if (entry != -1) return dictionary->ValueAt(entry); |
490 return Heap::undefined_value(); | 502 return Heap::undefined_value(); |
(...skipping 24 matching lines...) Expand all Loading... |
515 ASSERT(entry != -1); | 527 ASSERT(entry != -1); |
516 ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) == | 528 ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) == |
517 Heap::undefined_value()); | 529 Heap::undefined_value()); |
518 Heap::non_monomorphic_cache()->ValueAtPut(entry, code); | 530 Heap::non_monomorphic_cache()->ValueAtPut(entry, code); |
519 CHECK(GetProbeValue(Code::cast(code)->flags()) == code); | 531 CHECK(GetProbeValue(Code::cast(code)->flags()) == code); |
520 } | 532 } |
521 return code; | 533 return code; |
522 } | 534 } |
523 | 535 |
524 | 536 |
525 Code* StubCache::FindCallInitialize(int argc) { | 537 Code* StubCache::FindCallInitialize(int argc, InlineCacheInLoop in_loop) { |
526 Code::Flags flags = | 538 Code::Flags flags = |
527 Code::ComputeFlags(Code::CALL_IC, UNINITIALIZED, NORMAL, argc); | 539 Code::ComputeFlags(Code::CALL_IC, in_loop, UNINITIALIZED, NORMAL, argc); |
528 Object* result = ProbeCache(flags); | 540 Object* result = ProbeCache(flags); |
529 ASSERT(!result->IsUndefined()); | 541 ASSERT(!result->IsUndefined()); |
530 // This might be called during the marking phase of the collector | 542 // This might be called during the marking phase of the collector |
531 // hence the unchecked cast. | 543 // hence the unchecked cast. |
532 return reinterpret_cast<Code*>(result); | 544 return reinterpret_cast<Code*>(result); |
533 } | 545 } |
534 | 546 |
535 | 547 |
536 Object* StubCache::ComputeCallInitialize(int argc) { | 548 Object* StubCache::ComputeCallInitialize(int argc, InlineCacheInLoop in_loop) { |
537 Code::Flags flags = | 549 Code::Flags flags = |
538 Code::ComputeFlags(Code::CALL_IC, UNINITIALIZED, NORMAL, argc); | 550 Code::ComputeFlags(Code::CALL_IC, in_loop, UNINITIALIZED, NORMAL, argc); |
539 Object* probe = ProbeCache(flags); | 551 Object* probe = ProbeCache(flags); |
540 if (!probe->IsUndefined()) return probe; | 552 if (!probe->IsUndefined()) return probe; |
541 StubCompiler compiler; | 553 StubCompiler compiler; |
542 return FillCache(compiler.CompileCallInitialize(flags)); | 554 return FillCache(compiler.CompileCallInitialize(flags)); |
543 } | 555 } |
544 | 556 |
545 | 557 |
546 Object* StubCache::ComputeCallInitializeInLoop(int argc) { | 558 Object* StubCache::ComputeCallPreMonomorphic(int argc, |
| 559 InlineCacheInLoop in_loop) { |
547 Code::Flags flags = | 560 Code::Flags flags = |
548 Code::ComputeFlags(Code::CALL_IC, UNINITIALIZED_IN_LOOP, NORMAL, argc); | 561 Code::ComputeFlags(Code::CALL_IC, in_loop, PREMONOMORPHIC, NORMAL, argc); |
549 Object* probe = ProbeCache(flags); | |
550 if (!probe->IsUndefined()) return probe; | |
551 StubCompiler compiler; | |
552 return FillCache(compiler.CompileCallInitialize(flags)); | |
553 } | |
554 | |
555 | |
556 | |
557 Object* StubCache::ComputeCallPreMonomorphic(int argc) { | |
558 Code::Flags flags = | |
559 Code::ComputeFlags(Code::CALL_IC, PREMONOMORPHIC, NORMAL, argc); | |
560 Object* probe = ProbeCache(flags); | 562 Object* probe = ProbeCache(flags); |
561 if (!probe->IsUndefined()) return probe; | 563 if (!probe->IsUndefined()) return probe; |
562 StubCompiler compiler; | 564 StubCompiler compiler; |
563 return FillCache(compiler.CompileCallPreMonomorphic(flags)); | 565 return FillCache(compiler.CompileCallPreMonomorphic(flags)); |
564 } | 566 } |
565 | 567 |
566 | 568 |
567 Object* StubCache::ComputeCallNormal(int argc) { | 569 Object* StubCache::ComputeCallNormal(int argc, InlineCacheInLoop in_loop) { |
568 Code::Flags flags = | 570 Code::Flags flags = |
569 Code::ComputeFlags(Code::CALL_IC, MONOMORPHIC, NORMAL, argc); | 571 Code::ComputeFlags(Code::CALL_IC, in_loop, MONOMORPHIC, NORMAL, argc); |
570 Object* probe = ProbeCache(flags); | 572 Object* probe = ProbeCache(flags); |
571 if (!probe->IsUndefined()) return probe; | 573 if (!probe->IsUndefined()) return probe; |
572 StubCompiler compiler; | 574 StubCompiler compiler; |
573 return FillCache(compiler.CompileCallNormal(flags)); | 575 return FillCache(compiler.CompileCallNormal(flags)); |
574 } | 576 } |
575 | 577 |
576 | 578 |
577 Object* StubCache::ComputeCallMegamorphic(int argc) { | 579 Object* StubCache::ComputeCallMegamorphic(int argc, InlineCacheInLoop in_loop) { |
578 Code::Flags flags = | 580 Code::Flags flags = |
579 Code::ComputeFlags(Code::CALL_IC, MEGAMORPHIC, NORMAL, argc); | 581 Code::ComputeFlags(Code::CALL_IC, in_loop, MEGAMORPHIC, NORMAL, argc); |
580 Object* probe = ProbeCache(flags); | 582 Object* probe = ProbeCache(flags); |
581 if (!probe->IsUndefined()) return probe; | 583 if (!probe->IsUndefined()) return probe; |
582 StubCompiler compiler; | 584 StubCompiler compiler; |
583 return FillCache(compiler.CompileCallMegamorphic(flags)); | 585 return FillCache(compiler.CompileCallMegamorphic(flags)); |
584 } | 586 } |
585 | 587 |
586 | 588 |
587 Object* StubCache::ComputeCallMiss(int argc) { | 589 Object* StubCache::ComputeCallMiss(int argc) { |
588 Code::Flags flags = | 590 Code::Flags flags = |
589 Code::ComputeFlags(Code::STUB, MEGAMORPHIC, NORMAL, argc); | 591 Code::ComputeFlags(Code::STUB, NOT_IN_LOOP, MEGAMORPHIC, NORMAL, argc); |
590 Object* probe = ProbeCache(flags); | 592 Object* probe = ProbeCache(flags); |
591 if (!probe->IsUndefined()) return probe; | 593 if (!probe->IsUndefined()) return probe; |
592 StubCompiler compiler; | 594 StubCompiler compiler; |
593 return FillCache(compiler.CompileCallMiss(flags)); | 595 return FillCache(compiler.CompileCallMiss(flags)); |
594 } | 596 } |
595 | 597 |
596 | 598 |
597 #ifdef ENABLE_DEBUGGER_SUPPORT | 599 #ifdef ENABLE_DEBUGGER_SUPPORT |
598 Object* StubCache::ComputeCallDebugBreak(int argc) { | 600 Object* StubCache::ComputeCallDebugBreak(int argc) { |
599 Code::Flags flags = | 601 Code::Flags flags = |
600 Code::ComputeFlags(Code::CALL_IC, DEBUG_BREAK, NORMAL, argc); | 602 Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, DEBUG_BREAK, NORMAL, argc); |
601 Object* probe = ProbeCache(flags); | 603 Object* probe = ProbeCache(flags); |
602 if (!probe->IsUndefined()) return probe; | 604 if (!probe->IsUndefined()) return probe; |
603 StubCompiler compiler; | 605 StubCompiler compiler; |
604 return FillCache(compiler.CompileCallDebugBreak(flags)); | 606 return FillCache(compiler.CompileCallDebugBreak(flags)); |
605 } | 607 } |
606 | 608 |
607 | 609 |
608 Object* StubCache::ComputeCallDebugPrepareStepIn(int argc) { | 610 Object* StubCache::ComputeCallDebugPrepareStepIn(int argc) { |
609 Code::Flags flags = | 611 Code::Flags flags = |
610 Code::ComputeFlags(Code::CALL_IC, DEBUG_PREPARE_STEP_IN, NORMAL, argc); | 612 Code::ComputeFlags(Code::CALL_IC, |
| 613 NOT_IN_LOOP, |
| 614 DEBUG_PREPARE_STEP_IN, |
| 615 NORMAL, |
| 616 argc); |
611 Object* probe = ProbeCache(flags); | 617 Object* probe = ProbeCache(flags); |
612 if (!probe->IsUndefined()) return probe; | 618 if (!probe->IsUndefined()) return probe; |
613 StubCompiler compiler; | 619 StubCompiler compiler; |
614 return FillCache(compiler.CompileCallDebugPrepareStepIn(flags)); | 620 return FillCache(compiler.CompileCallDebugPrepareStepIn(flags)); |
615 } | 621 } |
616 #endif | 622 #endif |
617 | 623 |
618 | 624 |
619 Object* StubCache::ComputeLazyCompile(int argc) { | 625 Object* StubCache::ComputeLazyCompile(int argc) { |
620 Code::Flags flags = | 626 Code::Flags flags = |
621 Code::ComputeFlags(Code::STUB, UNINITIALIZED, NORMAL, argc); | 627 Code::ComputeFlags(Code::STUB, NOT_IN_LOOP, UNINITIALIZED, NORMAL, argc); |
622 Object* probe = ProbeCache(flags); | 628 Object* probe = ProbeCache(flags); |
623 if (!probe->IsUndefined()) return probe; | 629 if (!probe->IsUndefined()) return probe; |
624 StubCompiler compiler; | 630 StubCompiler compiler; |
625 Object* result = FillCache(compiler.CompileLazyCompile(flags)); | 631 Object* result = FillCache(compiler.CompileLazyCompile(flags)); |
626 if (result->IsCode()) { | 632 if (result->IsCode()) { |
627 Code* code = Code::cast(result); | 633 Code* code = Code::cast(result); |
628 USE(code); | 634 USE(code); |
629 LOG(CodeCreateEvent("LazyCompile", code, code->arguments_count())); | 635 LOG(CodeCreateEvent("LazyCompile", code, code->arguments_count())); |
630 } | 636 } |
631 return result; | 637 return result; |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
910 | 916 |
911 | 917 |
912 Object* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) { | 918 Object* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) { |
913 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type); | 919 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type); |
914 return GetCodeWithFlags(flags, name); | 920 return GetCodeWithFlags(flags, name); |
915 } | 921 } |
916 | 922 |
917 | 923 |
918 Object* CallStubCompiler::GetCode(PropertyType type, String* name) { | 924 Object* CallStubCompiler::GetCode(PropertyType type, String* name) { |
919 int argc = arguments_.immediate(); | 925 int argc = arguments_.immediate(); |
920 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, type, argc); | 926 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, |
| 927 type, |
| 928 NOT_IN_LOOP, |
| 929 argc); |
921 return GetCodeWithFlags(flags, name); | 930 return GetCodeWithFlags(flags, name); |
922 } | 931 } |
923 | 932 |
924 | 933 |
925 } } // namespace v8::internal | 934 } } // namespace v8::internal |
OLD | NEW |