1%def invoke(helper="NterpUnimplemented"):
2    call    SYMBOL($helper)
3
4%def op_invoke_custom():
5   EXPORT_PC
6   movzwl 2(rPC), %eax // call_site index, first argument of runtime call.
7   jmp NterpCommonInvokeCustom
8
9%def op_invoke_custom_range():
10   EXPORT_PC
11   movzwl 2(rPC), %eax // call_site index, first argument of runtime call.
12   jmp NterpCommonInvokeCustomRange
13
14%def invoke_direct_or_super(helper="", range="", is_super=""):
15   EXPORT_PC
16   // Fast-path which gets the method from thread-local cache.
17%  fetch_from_thread_cache("%eax", miss_label="2f")
181:
19   // Load the first argument (the 'this' pointer).
20   movzwl 4(rPC), %ecx // arguments
21   .if !$range
22   andl $$0xf, %ecx
23   .endif
24   movl (rFP, %ecx, 4), %ecx
25   // NullPointerException check.
26   testl %ecx, %ecx
27   je common_errNullObject
28   jmp $helper
292:
30   movl rSELF:THREAD_SELF_OFFSET, ARG0
31   movl 0(%esp), ARG1
32   movl rPC, ARG2
33   call nterp_get_method
34   .if $is_super
35   jmp 1b
36   .else
37   testl MACRO_LITERAL(1), %eax
38   je 1b
39   andl $$-2, %eax  // Remove the extra bit that marks it's a String.<init> method.
40   .if $range
41   jmp NterpHandleStringInitRange
42   .else
43   jmp NterpHandleStringInit
44   .endif
45   .endif
46
47%def op_invoke_direct():
48%  invoke_direct_or_super(helper="NterpCommonInvokeInstance", range="0", is_super="0")
49
50%def op_invoke_direct_range():
51%  invoke_direct_or_super(helper="NterpCommonInvokeInstanceRange", range="1", is_super="0")
52
53%def op_invoke_polymorphic():
54   EXPORT_PC
55   // No need to fetch the target method.
56   // Load the first argument (the 'this' pointer).
57   movzwl 4(rPC), %ecx // arguments
58   andl $$0xf, %ecx
59   movl (rFP, %ecx, 4), %ecx
60   // NullPointerException check.
61   testl %ecx, %ecx
62   je common_errNullObject
63   jmp NterpCommonInvokePolymorphic
64
65%def op_invoke_polymorphic_range():
66   EXPORT_PC
67   // No need to fetch the target method.
68   // Load the first argument (the 'this' pointer).
69   movzwl 4(rPC), %ecx // arguments
70   movl (rFP, %ecx, 4), %ecx
71   // NullPointerException check.
72   testl %ecx, %ecx
73   je common_errNullObject
74   jmp NterpCommonInvokePolymorphicRange
75
76%def invoke_interface(helper="", range=""):
77%  slow_path = add_slow_path(op_invoke_interface_slow_path)
78   EXPORT_PC
79   // Fast-path which gets the interface method from thread-local cache.
80%  fetch_from_thread_cache("%eax", miss_label=slow_path)
81.L${opcode}_resume:
82   // First argument is the 'this' pointer.
83   movzwl 4(rPC), %ecx // arguments
84   .if !$range
85   andl $$0xf, %ecx
86   .endif
87   movl (rFP, %ecx, 4), %ecx
88   movl MIRROR_OBJECT_CLASS_OFFSET(%ecx), %edx
89   UNPOISON_HEAP_REF edx
90   // Test the first two bits of the fetched ArtMethod:
91   // - If the first bit is set, this is a method on j.l.Object
92   // - If the second bit is set, this is a default method.
93   testl $$3, %eax
94   jne 2f
95   // Save interface method as hidden argument.
96   movd %eax, %xmm7
97   movzw ART_METHOD_IMT_INDEX_OFFSET(%eax), %eax
981:
99   movl MIRROR_CLASS_IMT_PTR_OFFSET_32(%edx), %edx
100   movl (%edx, %eax, 4), %eax
101   jmp $helper
1022:
103   testl $$1, %eax
104   .if $range
105   jne NterpHandleInvokeInterfaceOnObjectMethodRange
106   .else
107   jne NterpHandleInvokeInterfaceOnObjectMethod
108   .endif
109   // Default method
110   andl $$-4, %eax
111   // Save interface method as hidden argument.
112   movd %eax, %xmm7
113   movzw ART_METHOD_METHOD_INDEX_OFFSET(%eax), %eax
114   andl $$ART_METHOD_IMT_MASK, %eax
115   jmp 1b
116
117%def op_invoke_interface_slow_path():
118   movl rSELF:THREAD_SELF_OFFSET, ARG0
119   movl 0(%esp), ARG1
120   movl rPC, ARG2
121   call nterp_get_method
122   jmp .L${opcode}_resume
123
124%def op_invoke_interface():
125%  invoke_interface(helper="NterpCommonInvokeInterface", range="0")
126
127%def op_invoke_interface_range():
128%  invoke_interface(helper="NterpCommonInvokeInterfaceRange", range="1")
129
130%def invoke_static(helper=""):
131   EXPORT_PC
132   // Fast-path which gets the method from thread-local cache.
133%  fetch_from_thread_cache("%eax", miss_label="1f")
134   jmp $helper
1351:
136   movl rSELF:THREAD_SELF_OFFSET, ARG0
137   movl 0(%esp), ARG1
138   movl rPC, ARG2
139   call nterp_get_method
140   jmp $helper
141
142%def op_invoke_static():
143%  invoke_static(helper="NterpCommonInvokeStatic")
144
145%def op_invoke_static_range():
146%  invoke_static(helper="NterpCommonInvokeStaticRange")
147
148%def op_invoke_super():
149%  invoke_direct_or_super(helper="NterpCommonInvokeInstance", range="0", is_super="1")
150
151%def op_invoke_super_range():
152%  invoke_direct_or_super(helper="NterpCommonInvokeInstanceRange", range="1", is_super="1")
153
154%def invoke_virtual(helper="", range=""):
155   EXPORT_PC
156   // Fast-path which gets the method from thread-local cache.
157%  fetch_from_thread_cache("%eax", miss_label="2f")
1581:
159   // First argument is the 'this' pointer.
160   movzwl 4(rPC), %ecx // arguments
161   .if !$range
162   andl $$0xf, %ecx
163   .endif
164   movl (rFP, %ecx, 4), %ecx
165   // Note: if ecx is null, this will be handled by our SIGSEGV handler.
166   movl MIRROR_OBJECT_CLASS_OFFSET(%ecx), %edx
167   UNPOISON_HEAP_REF edx
168   movl MIRROR_CLASS_VTABLE_OFFSET_32(%edx, %eax, 4), %eax
169   jmp $helper
1702:
171   movl rSELF:THREAD_SELF_OFFSET, ARG0
172   movl 0(%esp), ARG1
173   movl rPC, ARG2
174   call nterp_get_method
175   jmp 1b
176
177%def op_invoke_virtual():
178%  invoke_virtual(helper="NterpCommonInvokeInstance", range="0")
179
180%def op_invoke_virtual_range():
181%  invoke_virtual(helper="NterpCommonInvokeInstanceRange", range="1")
182