OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize); | 506 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 1 * kPointerSize); |
507 pop(ebp); | 507 pop(ebp); |
508 pop(edx); // Remove state. | 508 pop(edx); // Remove state. |
509 | 509 |
510 // Before returning we restore the context from the frame pointer if | 510 // Before returning we restore the context from the frame pointer if |
511 // not NULL. The frame pointer is NULL in the exception handler of | 511 // not NULL. The frame pointer is NULL in the exception handler of |
512 // a JS entry frame. | 512 // a JS entry frame. |
513 Set(esi, Immediate(0)); // Tentatively set context pointer to NULL. | 513 Set(esi, Immediate(0)); // Tentatively set context pointer to NULL. |
514 Label skip; | 514 Label skip; |
515 cmp(ebp, 0); | 515 cmp(ebp, 0); |
516 j(equal, &skip, not_taken, Label::kNear); | 516 j(equal, &skip, Label::kNear); |
517 mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 517 mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
518 bind(&skip); | 518 bind(&skip); |
519 | 519 |
520 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); | 520 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); |
521 ret(0); | 521 ret(0); |
522 } | 522 } |
523 | 523 |
524 | 524 |
525 void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, | 525 void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, |
526 Register value) { | 526 Register value) { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
607 push(scratch); | 607 push(scratch); |
608 // Read the first word and compare to global_context_map. | 608 // Read the first word and compare to global_context_map. |
609 mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); | 609 mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
610 cmp(scratch, isolate()->factory()->global_context_map()); | 610 cmp(scratch, isolate()->factory()->global_context_map()); |
611 Check(equal, "JSGlobalObject::global_context should be a global context."); | 611 Check(equal, "JSGlobalObject::global_context should be a global context."); |
612 pop(scratch); | 612 pop(scratch); |
613 } | 613 } |
614 | 614 |
615 // Check if both contexts are the same. | 615 // Check if both contexts are the same. |
616 cmp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset)); | 616 cmp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset)); |
617 j(equal, &same_contexts, taken); | 617 j(equal, &same_contexts); |
618 | 618 |
619 // Compare security tokens, save holder_reg on the stack so we can use it | 619 // Compare security tokens, save holder_reg on the stack so we can use it |
620 // as a temporary register. | 620 // as a temporary register. |
621 // | 621 // |
622 // TODO(119): avoid push(holder_reg)/pop(holder_reg) | 622 // TODO(119): avoid push(holder_reg)/pop(holder_reg) |
623 push(holder_reg); | 623 push(holder_reg); |
624 // Check that the security token in the calling global object is | 624 // Check that the security token in the calling global object is |
625 // compatible with the security token in the receiving global | 625 // compatible with the security token in the receiving global |
626 // object. | 626 // object. |
627 mov(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset)); | 627 mov(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset)); |
628 | 628 |
629 // Check the context is a global context. | 629 // Check the context is a global context. |
630 if (emit_debug_code()) { | 630 if (emit_debug_code()) { |
631 cmp(holder_reg, isolate()->factory()->null_value()); | 631 cmp(holder_reg, isolate()->factory()->null_value()); |
632 Check(not_equal, "JSGlobalProxy::context() should not be null."); | 632 Check(not_equal, "JSGlobalProxy::context() should not be null."); |
633 | 633 |
634 push(holder_reg); | 634 push(holder_reg); |
635 // Read the first word and compare to global_context_map(), | 635 // Read the first word and compare to global_context_map(), |
636 mov(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset)); | 636 mov(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset)); |
637 cmp(holder_reg, isolate()->factory()->global_context_map()); | 637 cmp(holder_reg, isolate()->factory()->global_context_map()); |
638 Check(equal, "JSGlobalObject::global_context should be a global context."); | 638 Check(equal, "JSGlobalObject::global_context should be a global context."); |
639 pop(holder_reg); | 639 pop(holder_reg); |
640 } | 640 } |
641 | 641 |
642 int token_offset = Context::kHeaderSize + | 642 int token_offset = Context::kHeaderSize + |
643 Context::SECURITY_TOKEN_INDEX * kPointerSize; | 643 Context::SECURITY_TOKEN_INDEX * kPointerSize; |
644 mov(scratch, FieldOperand(scratch, token_offset)); | 644 mov(scratch, FieldOperand(scratch, token_offset)); |
645 cmp(scratch, FieldOperand(holder_reg, token_offset)); | 645 cmp(scratch, FieldOperand(holder_reg, token_offset)); |
646 pop(holder_reg); | 646 pop(holder_reg); |
647 j(not_equal, miss, not_taken); | 647 j(not_equal, miss); |
648 | 648 |
649 bind(&same_contexts); | 649 bind(&same_contexts); |
650 } | 650 } |
651 | 651 |
652 | 652 |
653 void MacroAssembler::LoadAllocationTopHelper(Register result, | 653 void MacroAssembler::LoadAllocationTopHelper(Register result, |
654 Register scratch, | 654 Register scratch, |
655 AllocationFlags flags) { | 655 AllocationFlags flags) { |
656 ExternalReference new_space_allocation_top = | 656 ExternalReference new_space_allocation_top = |
657 ExternalReference::new_space_allocation_top_address(isolate()); | 657 ExternalReference::new_space_allocation_top_address(isolate()); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
725 Register top_reg = result_end.is_valid() ? result_end : result; | 725 Register top_reg = result_end.is_valid() ? result_end : result; |
726 | 726 |
727 // Calculate new top and bail out if new space is exhausted. | 727 // Calculate new top and bail out if new space is exhausted. |
728 ExternalReference new_space_allocation_limit = | 728 ExternalReference new_space_allocation_limit = |
729 ExternalReference::new_space_allocation_limit_address(isolate()); | 729 ExternalReference::new_space_allocation_limit_address(isolate()); |
730 | 730 |
731 if (!top_reg.is(result)) { | 731 if (!top_reg.is(result)) { |
732 mov(top_reg, result); | 732 mov(top_reg, result); |
733 } | 733 } |
734 add(Operand(top_reg), Immediate(object_size)); | 734 add(Operand(top_reg), Immediate(object_size)); |
735 j(carry, gc_required, not_taken); | 735 j(carry, gc_required); |
736 cmp(top_reg, Operand::StaticVariable(new_space_allocation_limit)); | 736 cmp(top_reg, Operand::StaticVariable(new_space_allocation_limit)); |
737 j(above, gc_required, not_taken); | 737 j(above, gc_required); |
738 | 738 |
739 // Update allocation top. | 739 // Update allocation top. |
740 UpdateAllocationTopHelper(top_reg, scratch); | 740 UpdateAllocationTopHelper(top_reg, scratch); |
741 | 741 |
742 // Tag result if requested. | 742 // Tag result if requested. |
743 if (top_reg.is(result)) { | 743 if (top_reg.is(result)) { |
744 if ((flags & TAG_OBJECT) != 0) { | 744 if ((flags & TAG_OBJECT) != 0) { |
745 sub(Operand(result), Immediate(object_size - kHeapObjectTag)); | 745 sub(Operand(result), Immediate(object_size - kHeapObjectTag)); |
746 } else { | 746 } else { |
747 sub(Operand(result), Immediate(object_size)); | 747 sub(Operand(result), Immediate(object_size)); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
824 // Load address of new object into result. | 824 // Load address of new object into result. |
825 LoadAllocationTopHelper(result, scratch, flags); | 825 LoadAllocationTopHelper(result, scratch, flags); |
826 | 826 |
827 // Calculate new top and bail out if new space is exhausted. | 827 // Calculate new top and bail out if new space is exhausted. |
828 ExternalReference new_space_allocation_limit = | 828 ExternalReference new_space_allocation_limit = |
829 ExternalReference::new_space_allocation_limit_address(isolate()); | 829 ExternalReference::new_space_allocation_limit_address(isolate()); |
830 if (!object_size.is(result_end)) { | 830 if (!object_size.is(result_end)) { |
831 mov(result_end, object_size); | 831 mov(result_end, object_size); |
832 } | 832 } |
833 add(result_end, Operand(result)); | 833 add(result_end, Operand(result)); |
834 j(carry, gc_required, not_taken); | 834 j(carry, gc_required); |
835 cmp(result_end, Operand::StaticVariable(new_space_allocation_limit)); | 835 cmp(result_end, Operand::StaticVariable(new_space_allocation_limit)); |
836 j(above, gc_required, not_taken); | 836 j(above, gc_required); |
837 | 837 |
838 // Tag result if requested. | 838 // Tag result if requested. |
839 if ((flags & TAG_OBJECT) != 0) { | 839 if ((flags & TAG_OBJECT) != 0) { |
840 lea(result, Operand(result, kHeapObjectTag)); | 840 lea(result, Operand(result, kHeapObjectTag)); |
841 } | 841 } |
842 | 842 |
843 // Update allocation top. | 843 // Update allocation top. |
844 UpdateAllocationTopHelper(result_end, scratch); | 844 UpdateAllocationTopHelper(result_end, scratch); |
845 } | 845 } |
846 | 846 |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1055 | 1055 |
1056 bind(&done); | 1056 bind(&done); |
1057 } | 1057 } |
1058 | 1058 |
1059 | 1059 |
1060 void MacroAssembler::NegativeZeroTest(Register result, | 1060 void MacroAssembler::NegativeZeroTest(Register result, |
1061 Register op, | 1061 Register op, |
1062 Label* then_label) { | 1062 Label* then_label) { |
1063 Label ok; | 1063 Label ok; |
1064 test(result, Operand(result)); | 1064 test(result, Operand(result)); |
1065 j(not_zero, &ok, taken); | 1065 j(not_zero, &ok); |
1066 test(op, Operand(op)); | 1066 test(op, Operand(op)); |
1067 j(sign, then_label, not_taken); | 1067 j(sign, then_label); |
1068 bind(&ok); | 1068 bind(&ok); |
1069 } | 1069 } |
1070 | 1070 |
1071 | 1071 |
1072 void MacroAssembler::NegativeZeroTest(Register result, | 1072 void MacroAssembler::NegativeZeroTest(Register result, |
1073 Register op1, | 1073 Register op1, |
1074 Register op2, | 1074 Register op2, |
1075 Register scratch, | 1075 Register scratch, |
1076 Label* then_label) { | 1076 Label* then_label) { |
1077 Label ok; | 1077 Label ok; |
1078 test(result, Operand(result)); | 1078 test(result, Operand(result)); |
1079 j(not_zero, &ok, taken); | 1079 j(not_zero, &ok); |
1080 mov(scratch, Operand(op1)); | 1080 mov(scratch, Operand(op1)); |
1081 or_(scratch, Operand(op2)); | 1081 or_(scratch, Operand(op2)); |
1082 j(sign, then_label, not_taken); | 1082 j(sign, then_label); |
1083 bind(&ok); | 1083 bind(&ok); |
1084 } | 1084 } |
1085 | 1085 |
1086 | 1086 |
1087 void MacroAssembler::TryGetFunctionPrototype(Register function, | 1087 void MacroAssembler::TryGetFunctionPrototype(Register function, |
1088 Register result, | 1088 Register result, |
1089 Register scratch, | 1089 Register scratch, |
1090 Label* miss) { | 1090 Label* miss) { |
1091 // Check that the receiver isn't a smi. | 1091 // Check that the receiver isn't a smi. |
1092 test(function, Immediate(kSmiTagMask)); | 1092 test(function, Immediate(kSmiTagMask)); |
1093 j(zero, miss, not_taken); | 1093 j(zero, miss); |
1094 | 1094 |
1095 // Check that the function really is a function. | 1095 // Check that the function really is a function. |
1096 CmpObjectType(function, JS_FUNCTION_TYPE, result); | 1096 CmpObjectType(function, JS_FUNCTION_TYPE, result); |
1097 j(not_equal, miss, not_taken); | 1097 j(not_equal, miss); |
1098 | 1098 |
1099 // Make sure that the function has an instance prototype. | 1099 // Make sure that the function has an instance prototype. |
1100 Label non_instance; | 1100 Label non_instance; |
1101 movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset)); | 1101 movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset)); |
1102 test(scratch, Immediate(1 << Map::kHasNonInstancePrototype)); | 1102 test(scratch, Immediate(1 << Map::kHasNonInstancePrototype)); |
1103 j(not_zero, &non_instance, not_taken); | 1103 j(not_zero, &non_instance); |
1104 | 1104 |
1105 // Get the prototype or initial map from the function. | 1105 // Get the prototype or initial map from the function. |
1106 mov(result, | 1106 mov(result, |
1107 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); | 1107 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); |
1108 | 1108 |
1109 // If the prototype or initial map is the hole, don't return it and | 1109 // If the prototype or initial map is the hole, don't return it and |
1110 // simply miss the cache instead. This will allow us to allocate a | 1110 // simply miss the cache instead. This will allow us to allocate a |
1111 // prototype object on-demand in the runtime system. | 1111 // prototype object on-demand in the runtime system. |
1112 cmp(Operand(result), Immediate(isolate()->factory()->the_hole_value())); | 1112 cmp(Operand(result), Immediate(isolate()->factory()->the_hole_value())); |
1113 j(equal, miss, not_taken); | 1113 j(equal, miss); |
1114 | 1114 |
1115 // If the function does not have an initial map, we're done. | 1115 // If the function does not have an initial map, we're done. |
1116 Label done; | 1116 Label done; |
1117 CmpObjectType(result, MAP_TYPE, scratch); | 1117 CmpObjectType(result, MAP_TYPE, scratch); |
1118 j(not_equal, &done); | 1118 j(not_equal, &done); |
1119 | 1119 |
1120 // Get the prototype from the initial map. | 1120 // Get the prototype from the initial map. |
1121 mov(result, FieldOperand(result, Map::kPrototypeOffset)); | 1121 mov(result, FieldOperand(result, Map::kPrototypeOffset)); |
1122 jmp(&done); | 1122 jmp(&done); |
1123 | 1123 |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1384 } | 1384 } |
1385 | 1385 |
1386 Label empty_handle; | 1386 Label empty_handle; |
1387 Label prologue; | 1387 Label prologue; |
1388 Label promote_scheduled_exception; | 1388 Label promote_scheduled_exception; |
1389 Label delete_allocated_handles; | 1389 Label delete_allocated_handles; |
1390 Label leave_exit_frame; | 1390 Label leave_exit_frame; |
1391 | 1391 |
1392 // Check if the result handle holds 0. | 1392 // Check if the result handle holds 0. |
1393 test(eax, Operand(eax)); | 1393 test(eax, Operand(eax)); |
1394 j(zero, &empty_handle, not_taken); | 1394 j(zero, &empty_handle); |
1395 // It was non-zero. Dereference to get the result value. | 1395 // It was non-zero. Dereference to get the result value. |
1396 mov(eax, Operand(eax, 0)); | 1396 mov(eax, Operand(eax, 0)); |
1397 bind(&prologue); | 1397 bind(&prologue); |
1398 // No more valid handles (the result handle was the last one). Restore | 1398 // No more valid handles (the result handle was the last one). Restore |
1399 // previous handle scope. | 1399 // previous handle scope. |
1400 mov(Operand::StaticVariable(next_address), ebx); | 1400 mov(Operand::StaticVariable(next_address), ebx); |
1401 sub(Operand::StaticVariable(level_address), Immediate(1)); | 1401 sub(Operand::StaticVariable(level_address), Immediate(1)); |
1402 Assert(above_equal, "Invalid HandleScope level"); | 1402 Assert(above_equal, "Invalid HandleScope level"); |
1403 cmp(edi, Operand::StaticVariable(limit_address)); | 1403 cmp(edi, Operand::StaticVariable(limit_address)); |
1404 j(not_equal, &delete_allocated_handles, not_taken); | 1404 j(not_equal, &delete_allocated_handles); |
1405 bind(&leave_exit_frame); | 1405 bind(&leave_exit_frame); |
1406 | 1406 |
1407 // Check if the function scheduled an exception. | 1407 // Check if the function scheduled an exception. |
1408 ExternalReference scheduled_exception_address = | 1408 ExternalReference scheduled_exception_address = |
1409 ExternalReference::scheduled_exception_address(isolate()); | 1409 ExternalReference::scheduled_exception_address(isolate()); |
1410 cmp(Operand::StaticVariable(scheduled_exception_address), | 1410 cmp(Operand::StaticVariable(scheduled_exception_address), |
1411 Immediate(isolate()->factory()->the_hole_value())); | 1411 Immediate(isolate()->factory()->the_hole_value())); |
1412 j(not_equal, &promote_scheduled_exception, not_taken); | 1412 j(not_equal, &promote_scheduled_exception); |
1413 LeaveApiExitFrame(); | 1413 LeaveApiExitFrame(); |
1414 ret(stack_space * kPointerSize); | 1414 ret(stack_space * kPointerSize); |
1415 bind(&promote_scheduled_exception); | 1415 bind(&promote_scheduled_exception); |
1416 MaybeObject* result = | 1416 MaybeObject* result = |
1417 TryTailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); | 1417 TryTailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); |
1418 if (result->IsFailure()) { | 1418 if (result->IsFailure()) { |
1419 return result; | 1419 return result; |
1420 } | 1420 } |
1421 bind(&empty_handle); | 1421 bind(&empty_handle); |
1422 // It was zero; the result is undefined. | 1422 // It was zero; the result is undefined. |
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1842 Immediate(factory->fixed_cow_array_map())); | 1842 Immediate(factory->fixed_cow_array_map())); |
1843 j(equal, &ok); | 1843 j(equal, &ok); |
1844 Abort("JSObject with fast elements map has slow elements"); | 1844 Abort("JSObject with fast elements map has slow elements"); |
1845 bind(&ok); | 1845 bind(&ok); |
1846 } | 1846 } |
1847 } | 1847 } |
1848 | 1848 |
1849 | 1849 |
1850 void MacroAssembler::Check(Condition cc, const char* msg) { | 1850 void MacroAssembler::Check(Condition cc, const char* msg) { |
1851 Label L; | 1851 Label L; |
1852 j(cc, &L, taken); | 1852 j(cc, &L); |
1853 Abort(msg); | 1853 Abort(msg); |
1854 // will not return here | 1854 // will not return here |
1855 bind(&L); | 1855 bind(&L); |
1856 } | 1856 } |
1857 | 1857 |
1858 | 1858 |
1859 void MacroAssembler::CheckStackAlignment() { | 1859 void MacroAssembler::CheckStackAlignment() { |
1860 int frame_alignment = OS::ActivationFrameAlignment(); | 1860 int frame_alignment = OS::ActivationFrameAlignment(); |
1861 int frame_alignment_mask = frame_alignment - 1; | 1861 int frame_alignment_mask = frame_alignment - 1; |
1862 if (frame_alignment > kPointerSize) { | 1862 if (frame_alignment > kPointerSize) { |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2065 | 2065 |
2066 // Check that the code was patched as expected. | 2066 // Check that the code was patched as expected. |
2067 ASSERT(masm_.pc_ == address_ + size_); | 2067 ASSERT(masm_.pc_ == address_ + size_); |
2068 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 2068 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
2069 } | 2069 } |
2070 | 2070 |
2071 | 2071 |
2072 } } // namespace v8::internal | 2072 } } // namespace v8::internal |
2073 | 2073 |
2074 #endif // V8_TARGET_ARCH_IA32 | 2074 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |