OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 __ b(ne, miss); | 97 __ b(ne, miss); |
98 | 98 |
99 __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 99 __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
100 __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset)); | 100 __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset)); |
101 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | 101 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
102 __ cmp(t1, ip); | 102 __ cmp(t1, ip); |
103 __ b(ne, miss); | 103 __ b(ne, miss); |
104 } | 104 } |
105 | 105 |
106 | 106 |
107 // Helper function used from LoadIC/CallIC GenerateNormal. | 107 // Helper function used from LoadIC GenerateNormal. |
108 // | 108 // |
109 // elements: Property dictionary. It is not clobbered if a jump to the miss | 109 // elements: Property dictionary. It is not clobbered if a jump to the miss |
110 // label is done. | 110 // label is done. |
111 // name: Property name. It is not clobbered if a jump to the miss label is | 111 // name: Property name. It is not clobbered if a jump to the miss label is |
112 // done | 112 // done |
113 // result: Register for the result. It is only updated if a jump to the miss | 113 // result: Register for the result. It is only updated if a jump to the miss |
114 // label is not done. Can be the same as elements or name clobbering | 114 // label is not done. Can be the same as elements or name clobbering |
115 // one of these in the case of not jumping to the miss label. | 115 // one of these in the case of not jumping to the miss label. |
116 // The two scratch registers need to be different from elements, name and | 116 // The two scratch registers need to be different from elements, name and |
117 // result. | 117 // result. |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 // map: key map | 326 // map: key map |
327 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 327 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
328 STATIC_ASSERT(kInternalizedTag == 0); | 328 STATIC_ASSERT(kInternalizedTag == 0); |
329 __ tst(hash, Operand(kIsNotInternalizedMask)); | 329 __ tst(hash, Operand(kIsNotInternalizedMask)); |
330 __ b(ne, not_unique); | 330 __ b(ne, not_unique); |
331 | 331 |
332 __ bind(&unique); | 332 __ bind(&unique); |
333 } | 333 } |
334 | 334 |
335 | 335 |
336 // Defined in ic.cc. | 336 void LoadIC::GenerateMegamorphic(MacroAssembler* masm, |
337 Object* CallIC_Miss(Arguments args); | 337 ExtraICState extra_state) { |
338 | |
339 // The generated code does not accept smi keys. | |
340 // The generated code falls through if both probes miss. | |
341 void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm, | |
342 int argc, | |
343 Code::Kind kind, | |
344 ExtraICState extra_state) { | |
345 // ----------- S t a t e ------------- | |
346 // -- r1 : receiver | |
347 // -- r2 : name | |
348 // ----------------------------------- | |
349 Label number, non_number, non_string, boolean, probe, miss; | |
350 | |
351 // Probe the stub cache. | |
352 Code::Flags flags = Code::ComputeFlags(kind, | |
353 MONOMORPHIC, | |
354 extra_state, | |
355 Code::NORMAL, | |
356 argc); | |
357 masm->isolate()->stub_cache()->GenerateProbe( | |
358 masm, flags, r1, r2, r3, r4, r5, r6); | |
359 | |
360 // If the stub cache probing failed, the receiver might be a value. | |
361 // For value objects, we use the map of the prototype objects for | |
362 // the corresponding JSValue for the cache and that is what we need | |
363 // to probe. | |
364 // | |
365 // Check for number. | |
366 __ JumpIfSmi(r1, &number); | |
367 __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE); | |
368 __ b(ne, &non_number); | |
369 __ bind(&number); | |
370 StubCompiler::GenerateLoadGlobalFunctionPrototype( | |
371 masm, Context::NUMBER_FUNCTION_INDEX, r1); | |
372 __ b(&probe); | |
373 | |
374 // Check for string. | |
375 __ bind(&non_number); | |
376 __ cmp(r3, Operand(FIRST_NONSTRING_TYPE)); | |
377 __ b(hs, &non_string); | |
378 StubCompiler::GenerateLoadGlobalFunctionPrototype( | |
379 masm, Context::STRING_FUNCTION_INDEX, r1); | |
380 __ b(&probe); | |
381 | |
382 // Check for boolean. | |
383 __ bind(&non_string); | |
384 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | |
385 __ cmp(r1, ip); | |
386 __ b(eq, &boolean); | |
387 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | |
388 __ cmp(r1, ip); | |
389 __ b(ne, &miss); | |
390 __ bind(&boolean); | |
391 StubCompiler::GenerateLoadGlobalFunctionPrototype( | |
392 masm, Context::BOOLEAN_FUNCTION_INDEX, r1); | |
393 | |
394 // Probe the stub cache for the value object. | |
395 __ bind(&probe); | |
396 masm->isolate()->stub_cache()->GenerateProbe( | |
397 masm, flags, r1, r2, r3, r4, r5, r6); | |
398 | |
399 __ bind(&miss); | |
400 } | |
401 | |
402 | |
403 static void GenerateFunctionTailCall(MacroAssembler* masm, | |
404 int argc, | |
405 Label* miss, | |
406 Register scratch) { | |
407 // r1: function | |
408 | |
409 // Check that the value isn't a smi. | |
410 __ JumpIfSmi(r1, miss); | |
411 | |
412 // Check that the value is a JSFunction. | |
413 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE); | |
414 __ b(ne, miss); | |
415 | |
416 // Invoke the function. | |
417 ParameterCount actual(argc); | |
418 __ InvokeFunction(r1, actual, JUMP_FUNCTION, NullCallWrapper()); | |
419 } | |
420 | |
421 | |
422 void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) { | |
423 // ----------- S t a t e ------------- | 338 // ----------- S t a t e ------------- |
424 // -- r2 : name | 339 // -- r2 : name |
425 // -- lr : return address | 340 // -- lr : return address |
426 // ----------------------------------- | |
427 Label miss; | |
428 | |
429 // Get the receiver of the function from the stack into r1. | |
430 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | |
431 | |
432 GenerateNameDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss); | |
433 | |
434 // r0: elements | |
435 // Search the dictionary - put result in register r1. | |
436 GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4); | |
437 | |
438 GenerateFunctionTailCall(masm, argc, &miss, r4); | |
439 | |
440 __ bind(&miss); | |
441 } | |
442 | |
443 | |
444 void CallICBase::GenerateMiss(MacroAssembler* masm, | |
445 int argc, | |
446 IC::UtilityId id, | |
447 ExtraICState extra_state) { | |
448 // ----------- S t a t e ------------- | |
449 // -- r2 : name | |
450 // -- lr : return address | |
451 // ----------------------------------- | |
452 Isolate* isolate = masm->isolate(); | |
453 | |
454 if (id == IC::kCallIC_Miss) { | |
455 __ IncrementCounter(isolate->counters()->call_miss(), 1, r3, r4); | |
456 } else { | |
457 __ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, r3, r4); | |
458 } | |
459 | |
460 // Get the receiver of the function from the stack. | |
461 __ ldr(r3, MemOperand(sp, argc * kPointerSize)); | |
462 | |
463 { | |
464 FrameScope scope(masm, StackFrame::INTERNAL); | |
465 | |
466 // Push the receiver and the name of the function. | |
467 __ Push(r3, r2); | |
468 | |
469 // Call the entry. | |
470 __ mov(r0, Operand(2)); | |
471 __ mov(r1, Operand(ExternalReference(IC_Utility(id), isolate))); | |
472 | |
473 CEntryStub stub(1); | |
474 __ CallStub(&stub); | |
475 | |
476 // Move result to r1 and leave the internal frame. | |
477 __ mov(r1, Operand(r0)); | |
478 } | |
479 | |
480 // Check if the receiver is a global object of some sort. | |
481 // This can happen only for regular CallIC but not KeyedCallIC. | |
482 if (id == IC::kCallIC_Miss) { | |
483 Label invoke, global; | |
484 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver | |
485 __ JumpIfSmi(r2, &invoke); | |
486 __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE); | |
487 __ b(eq, &global); | |
488 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE)); | |
489 __ b(ne, &invoke); | |
490 | |
491 // Patch the receiver on the stack. | |
492 __ bind(&global); | |
493 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); | |
494 __ str(r2, MemOperand(sp, argc * kPointerSize)); | |
495 __ bind(&invoke); | |
496 } | |
497 | |
498 // Invoke the function. | |
499 ParameterCount actual(argc); | |
500 __ InvokeFunction(r1, actual, JUMP_FUNCTION, NullCallWrapper()); | |
501 } | |
502 | |
503 | |
504 void CallIC::GenerateMegamorphic(MacroAssembler* masm, | |
505 int argc, | |
506 ExtraICState extra_ic_state) { | |
507 // ----------- S t a t e ------------- | |
508 // -- r2 : name | |
509 // -- lr : return address | |
510 // ----------------------------------- | |
511 | |
512 // Get the receiver of the function from the stack into r1. | |
513 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | |
514 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state); | |
515 GenerateMiss(masm, argc, extra_ic_state); | |
516 } | |
517 | |
518 | |
519 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { | |
520 // ----------- S t a t e ------------- | |
521 // -- r2 : name | |
522 // -- lr : return address | |
523 // ----------------------------------- | |
524 | |
525 // Get the receiver of the function from the stack into r1. | |
526 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | |
527 | |
528 Label do_call, slow_call, slow_load, slow_reload_receiver; | |
529 Label check_number_dictionary, check_name, lookup_monomorphic_cache; | |
530 Label index_smi, index_name; | |
531 | |
532 // Check that the key is a smi. | |
533 __ JumpIfNotSmi(r2, &check_name); | |
534 __ bind(&index_smi); | |
535 // Now the key is known to be a smi. This place is also jumped to from below | |
536 // where a numeric string is converted to a smi. | |
537 | |
538 GenerateKeyedLoadReceiverCheck( | |
539 masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call); | |
540 | |
541 GenerateFastArrayLoad( | |
542 masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load); | |
543 Counters* counters = masm->isolate()->counters(); | |
544 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, r0, r3); | |
545 | |
546 __ bind(&do_call); | |
547 // receiver in r1 is not used after this point. | |
548 // r2: key | |
549 // r1: function | |
550 GenerateFunctionTailCall(masm, argc, &slow_call, r0); | |
551 | |
552 __ bind(&check_number_dictionary); | |
553 // r2: key | |
554 // r3: elements map | |
555 // r4: elements | |
556 // Check whether the elements is a number dictionary. | |
557 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | |
558 __ cmp(r3, ip); | |
559 __ b(ne, &slow_load); | |
560 __ SmiUntag(r0, r2); | |
561 // r0: untagged index | |
562 __ LoadFromNumberDictionary(&slow_load, r4, r2, r1, r0, r3, r5); | |
563 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, r0, r3); | |
564 __ jmp(&do_call); | |
565 | |
566 __ bind(&slow_load); | |
567 // This branch is taken when calling KeyedCallIC_Miss is neither required | |
568 // nor beneficial. | |
569 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, r0, r3); | |
570 { | |
571 FrameScope scope(masm, StackFrame::INTERNAL); | |
572 __ Push(r2, r1); // save the key and the receiver | |
573 __ push(r2); // pass the receiver and the key | |
574 __ CallRuntime(Runtime::kKeyedGetProperty, 2); | |
575 __ pop(r2); // restore the key | |
576 } | |
577 __ mov(r1, r0); | |
578 __ jmp(&do_call); | |
579 | |
580 __ bind(&check_name); | |
581 GenerateKeyNameCheck(masm, r2, r0, r3, &index_name, &slow_call); | |
582 | |
583 // The key is known to be a unique name. | |
584 // If the receiver is a regular JS object with slow properties then do | |
585 // a quick inline probe of the receiver's dictionary. | |
586 // Otherwise do the monomorphic cache probe. | |
587 GenerateKeyedLoadReceiverCheck( | |
588 masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); | |
589 | |
590 __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset)); | |
591 __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset)); | |
592 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | |
593 __ cmp(r3, ip); | |
594 __ b(ne, &lookup_monomorphic_cache); | |
595 | |
596 GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4); | |
597 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, r0, r3); | |
598 __ jmp(&do_call); | |
599 | |
600 __ bind(&lookup_monomorphic_cache); | |
601 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, r0, r3); | |
602 GenerateMonomorphicCacheProbe(masm, | |
603 argc, | |
604 Code::KEYED_CALL_IC, | |
605 kNoExtraICState); | |
606 // Fall through on miss. | |
607 | |
608 __ bind(&slow_call); | |
609 // This branch is taken if: | |
610 // - the receiver requires boxing or access check, | |
611 // - the key is neither smi nor a unique name, | |
612 // - the value loaded is not a function, | |
613 // - there is hope that the runtime will create a monomorphic call stub | |
614 // that will get fetched next time. | |
615 __ IncrementCounter(counters->keyed_call_generic_slow(), 1, r0, r3); | |
616 GenerateMiss(masm, argc); | |
617 | |
618 __ bind(&index_name); | |
619 __ IndexFromHash(r3, r2); | |
620 // Now jump to the place where smi keys are handled. | |
621 __ jmp(&index_smi); | |
622 } | |
623 | |
624 | |
625 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { | |
626 // ----------- S t a t e ------------- | |
627 // -- r2 : name | |
628 // -- lr : return address | |
629 // ----------------------------------- | |
630 | |
631 // Check if the name is really a name. | |
632 Label miss; | |
633 __ JumpIfSmi(r2, &miss); | |
634 __ IsObjectNameType(r2, r0, &miss); | |
635 | |
636 CallICBase::GenerateNormal(masm, argc); | |
637 __ bind(&miss); | |
638 GenerateMiss(masm, argc); | |
639 } | |
640 | |
641 | |
642 void LoadIC::GenerateMegamorphic(MacroAssembler* masm, ContextualMode mode) { | |
643 // ----------- S t a t e ------------- | |
644 // -- r2 : name | |
645 // -- lr : return address | |
646 // -- r0 : receiver | 341 // -- r0 : receiver |
647 // ----------------------------------- | 342 // ----------------------------------- |
648 | 343 |
649 // Probe the stub cache. | 344 // Probe the stub cache. |
650 ExtraICState extra_ic_state = LoadIC::ComputeExtraICState(mode); | |
651 Code::Flags flags = Code::ComputeFlags( | 345 Code::Flags flags = Code::ComputeFlags( |
652 Code::HANDLER, MONOMORPHIC, extra_ic_state, | 346 Code::HANDLER, MONOMORPHIC, extra_state, |
653 Code::NORMAL, Code::LOAD_IC); | 347 Code::NORMAL, Code::LOAD_IC); |
654 masm->isolate()->stub_cache()->GenerateProbe( | 348 masm->isolate()->stub_cache()->GenerateProbe( |
655 masm, flags, r0, r2, r3, r4, r5, r6); | 349 masm, flags, r0, r2, r3, r4, r5, r6); |
656 | 350 |
657 // Cache miss: Jump to runtime. | 351 // Cache miss: Jump to runtime. |
658 GenerateMiss(masm); | 352 GenerateMiss(masm); |
659 } | 353 } |
660 | 354 |
661 | 355 |
662 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 356 void LoadIC::GenerateNormal(MacroAssembler* masm) { |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
846 __ str(r0, unmapped_location); | 540 __ str(r0, unmapped_location); |
847 __ add(r6, r3, r4); | 541 __ add(r6, r3, r4); |
848 __ mov(r9, r0); | 542 __ mov(r9, r0); |
849 __ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs); | 543 __ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs); |
850 __ Ret(); | 544 __ Ret(); |
851 __ bind(&slow); | 545 __ bind(&slow); |
852 GenerateMiss(masm); | 546 GenerateMiss(masm); |
853 } | 547 } |
854 | 548 |
855 | 549 |
856 void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm, | |
857 int argc) { | |
858 // ----------- S t a t e ------------- | |
859 // -- r2 : name | |
860 // -- lr : return address | |
861 // ----------------------------------- | |
862 Label slow, notin; | |
863 // Load receiver. | |
864 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | |
865 MemOperand mapped_location = | |
866 GenerateMappedArgumentsLookup(masm, r1, r2, r3, r4, r5, ¬in, &slow); | |
867 __ ldr(r1, mapped_location); | |
868 GenerateFunctionTailCall(masm, argc, &slow, r3); | |
869 __ bind(¬in); | |
870 // The unmapped lookup expects that the parameter map is in r3. | |
871 MemOperand unmapped_location = | |
872 GenerateUnmappedArgumentsLookup(masm, r2, r3, r4, &slow); | |
873 __ ldr(r1, unmapped_location); | |
874 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex); | |
875 __ cmp(r1, r3); | |
876 __ b(eq, &slow); | |
877 GenerateFunctionTailCall(masm, argc, &slow, r3); | |
878 __ bind(&slow); | |
879 GenerateMiss(masm, argc); | |
880 } | |
881 | |
882 | |
883 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { | 550 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { |
884 // ---------- S t a t e -------------- | 551 // ---------- S t a t e -------------- |
885 // -- lr : return address | 552 // -- lr : return address |
886 // -- r0 : key | 553 // -- r0 : key |
887 // -- r1 : receiver | 554 // -- r1 : receiver |
888 // ----------------------------------- | 555 // ----------------------------------- |
889 Isolate* isolate = masm->isolate(); | 556 Isolate* isolate = masm->isolate(); |
890 | 557 |
891 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4); | 558 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4); |
892 | 559 |
(...skipping 777 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1670 } else { | 1337 } else { |
1671 ASSERT(Assembler::GetCondition(branch_instr) == ne); | 1338 ASSERT(Assembler::GetCondition(branch_instr) == ne); |
1672 patcher.EmitCondition(eq); | 1339 patcher.EmitCondition(eq); |
1673 } | 1340 } |
1674 } | 1341 } |
1675 | 1342 |
1676 | 1343 |
1677 } } // namespace v8::internal | 1344 } } // namespace v8::internal |
1678 | 1345 |
1679 #endif // V8_TARGET_ARCH_ARM | 1346 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |