180 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
			
		
		
	
	
			180 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
| %def invoke(helper="NterpUnimplemented"):
 | |
|     call    SYMBOL($helper)
 | |
| 
 | |
| %def op_invoke_custom():
 | |
|    EXPORT_PC
 | |
|    movzwl 2(rPC), %eax // call_site index, first argument of runtime call.
 | |
|    jmp NterpCommonInvokeCustom
 | |
| 
 | |
| %def op_invoke_custom_range():
 | |
|    EXPORT_PC
 | |
|    movzwl 2(rPC), %eax // call_site index, first argument of runtime call.
 | |
|    jmp NterpCommonInvokeCustomRange
 | |
| 
 | |
| %def invoke_direct_or_super(helper="", range="", is_super=""):
 | |
|    EXPORT_PC
 | |
|    // Fast-path which gets the method from thread-local cache.
 | |
| %  fetch_from_thread_cache("%eax", miss_label="2f")
 | |
| 1:
 | |
|    // Load the first argument (the 'this' pointer).
 | |
|    movzwl 4(rPC), %ecx // arguments
 | |
|    .if !$range
 | |
|    andl $$0xf, %ecx
 | |
|    .endif
 | |
|    movl (rFP, %ecx, 4), %ecx
 | |
|    // NullPointerException check.
 | |
|    testl %ecx, %ecx
 | |
|    je common_errNullObject
 | |
|    jmp $helper
 | |
| 2:
 | |
|    movl rSELF:THREAD_SELF_OFFSET, ARG0
 | |
|    movl 0(%esp), ARG1
 | |
|    movl rPC, ARG2
 | |
|    call nterp_get_method
 | |
|    .if $is_super
 | |
|    jmp 1b
 | |
|    .else
 | |
|    testl MACRO_LITERAL(1), %eax
 | |
|    je 1b
 | |
|    andl $$-2, %eax  // Remove the extra bit that marks it's a String.<init> method.
 | |
|    .if $range
 | |
|    jmp NterpHandleStringInitRange
 | |
|    .else
 | |
|    jmp NterpHandleStringInit
 | |
|    .endif
 | |
|    .endif
 | |
| 
 | |
| %def op_invoke_direct():
 | |
| %  invoke_direct_or_super(helper="NterpCommonInvokeInstance", range="0", is_super="0")
 | |
| 
 | |
| %def op_invoke_direct_range():
 | |
| %  invoke_direct_or_super(helper="NterpCommonInvokeInstanceRange", range="1", is_super="0")
 | |
| 
 | |
| %def op_invoke_polymorphic():
 | |
|    EXPORT_PC
 | |
|    // No need to fetch the target method.
 | |
|    // Load the first argument (the 'this' pointer).
 | |
|    movzwl 4(rPC), %ecx // arguments
 | |
|    andl $$0xf, %ecx
 | |
|    movl (rFP, %ecx, 4), %ecx
 | |
|    // NullPointerException check.
 | |
|    testl %ecx, %ecx
 | |
|    je common_errNullObject
 | |
|    jmp NterpCommonInvokePolymorphic
 | |
| 
 | |
| %def op_invoke_polymorphic_range():
 | |
|    EXPORT_PC
 | |
|    // No need to fetch the target method.
 | |
|    // Load the first argument (the 'this' pointer).
 | |
|    movzwl 4(rPC), %ecx // arguments
 | |
|    movl (rFP, %ecx, 4), %ecx
 | |
|    // NullPointerException check.
 | |
|    testl %ecx, %ecx
 | |
|    je common_errNullObject
 | |
|    jmp NterpCommonInvokePolymorphicRange
 | |
| 
 | |
| %def invoke_interface(helper="", range=""):
 | |
| %  slow_path = add_slow_path(op_invoke_interface_slow_path)
 | |
|    EXPORT_PC
 | |
|    // Fast-path which gets the interface method from thread-local cache.
 | |
| %  fetch_from_thread_cache("%eax", miss_label=slow_path)
 | |
| .L${opcode}_resume:
 | |
|    // First argument is the 'this' pointer.
 | |
|    movzwl 4(rPC), %ecx // arguments
 | |
|    .if !$range
 | |
|    andl $$0xf, %ecx
 | |
|    .endif
 | |
|    movl (rFP, %ecx, 4), %ecx
 | |
|    movl MIRROR_OBJECT_CLASS_OFFSET(%ecx), %edx
 | |
|    // Test the first two bits of the fetched ArtMethod:
 | |
|    // - If the first bit is set, this is a method on j.l.Object
 | |
|    // - If the second bit is set, this is a default method.
 | |
|    testl $$3, %eax
 | |
|    jne 2f
 | |
|    // Save interface method as hidden argument.
 | |
|    movd %eax, %xmm7
 | |
|    movzw ART_METHOD_IMT_INDEX_OFFSET(%eax), %eax
 | |
| 1:
 | |
|    movl MIRROR_CLASS_IMT_PTR_OFFSET_32(%edx), %edx
 | |
|    movl (%edx, %eax, 4), %eax
 | |
|    jmp $helper
 | |
| 2:
 | |
|    testl $$1, %eax
 | |
|    .if $range
 | |
|    jne NterpHandleInvokeInterfaceOnObjectMethodRange
 | |
|    .else
 | |
|    jne NterpHandleInvokeInterfaceOnObjectMethod
 | |
|    .endif
 | |
|    // Default method
 | |
|    andl $$-4, %eax
 | |
|    // Save interface method as hidden argument.
 | |
|    movd %eax, %xmm7
 | |
|    movzw ART_METHOD_METHOD_INDEX_OFFSET(%eax), %eax
 | |
|    andl $$ART_METHOD_IMT_MASK, %eax
 | |
|    jmp 1b
 | |
| 
 | |
| %def op_invoke_interface_slow_path():
 | |
|    movl rSELF:THREAD_SELF_OFFSET, ARG0
 | |
|    movl 0(%esp), ARG1
 | |
|    movl rPC, ARG2
 | |
|    call nterp_get_method
 | |
|    jmp .L${opcode}_resume
 | |
| 
 | |
| %def op_invoke_interface():
 | |
| %  invoke_interface(helper="NterpCommonInvokeInterface", range="0")
 | |
| 
 | |
| %def op_invoke_interface_range():
 | |
| %  invoke_interface(helper="NterpCommonInvokeInterfaceRange", range="1")
 | |
| 
 | |
| %def invoke_static(helper=""):
 | |
|    EXPORT_PC
 | |
|    // Fast-path which gets the method from thread-local cache.
 | |
| %  fetch_from_thread_cache("%eax", miss_label="1f")
 | |
|    jmp $helper
 | |
| 1:
 | |
|    movl rSELF:THREAD_SELF_OFFSET, ARG0
 | |
|    movl 0(%esp), ARG1
 | |
|    movl rPC, ARG2
 | |
|    call nterp_get_method
 | |
|    jmp $helper
 | |
| 
 | |
| %def op_invoke_static():
 | |
| %  invoke_static(helper="NterpCommonInvokeStatic")
 | |
| 
 | |
| %def op_invoke_static_range():
 | |
| %  invoke_static(helper="NterpCommonInvokeStaticRange")
 | |
| 
 | |
| %def op_invoke_super():
 | |
| %  invoke_direct_or_super(helper="NterpCommonInvokeInstance", range="0", is_super="1")
 | |
| 
 | |
| %def op_invoke_super_range():
 | |
| %  invoke_direct_or_super(helper="NterpCommonInvokeInstanceRange", range="1", is_super="1")
 | |
| 
 | |
| %def invoke_virtual(helper="", range=""):
 | |
|    EXPORT_PC
 | |
|    // Fast-path which gets the method from thread-local cache.
 | |
| %  fetch_from_thread_cache("%eax", miss_label="2f")
 | |
| 1:
 | |
|    // First argument is the 'this' pointer.
 | |
|    movzwl 4(rPC), %ecx // arguments
 | |
|    .if !$range
 | |
|    andl $$0xf, %ecx
 | |
|    .endif
 | |
|    movl (rFP, %ecx, 4), %ecx
 | |
|    // Note: if ecx is null, this will be handled by our SIGSEGV handler.
 | |
|    movl MIRROR_OBJECT_CLASS_OFFSET(%ecx), %edx
 | |
|    movl MIRROR_CLASS_VTABLE_OFFSET_32(%edx, %eax, 4), %eax
 | |
|    jmp $helper
 | |
| 2:
 | |
|    movl rSELF:THREAD_SELF_OFFSET, ARG0
 | |
|    movl 0(%esp), ARG1
 | |
|    movl rPC, ARG2
 | |
|    call nterp_get_method
 | |
|    jmp 1b
 | |
| 
 | |
| %def op_invoke_virtual():
 | |
| %  invoke_virtual(helper="NterpCommonInvokeInstance", range="0")
 | |
| 
 | |
| %def op_invoke_virtual_range():
 | |
| %  invoke_virtual(helper="NterpCommonInvokeInstanceRange", range="1")
 |