1/** 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "arch/asm_support.h" 17#include "arch/x86/shorty.S" 18 19#define SHORTY_PTR_REG DEFAULT_SHORTY_PTR_REG 20#define SHORTY_REG DEFAULT_SHORTY_REG 21 22.macro PUSH_ARG arg_ptr, stack_ptr, tmp1, tmp2 23 cmpl $SHORTY_TAGGED, %ecx 24 je 2f 25 26 subl $SHORTY_FIRST_64, %ecx 27 cmpl $(SHORTY_NUM_64BIT_TYPES - 1), %ecx 28 jbe 1f 29 30 // it is a 32bit value 31 movl (\arg_ptr), \tmp1 32 movl \tmp1, (\stack_ptr) 33 addl $4, \stack_ptr 34 jmp 3f 351: 36 // it is a 64bit value 37 movl (\arg_ptr), \tmp1 38 movl 4(\arg_ptr), \tmp2 39 movl \tmp1, (\stack_ptr) 40 movl \tmp2, 4(\stack_ptr) 41 addl $8, \stack_ptr 42 jne 3f 43 442: // it is a value of type 'any' 45 // copy the value 46 movl (\arg_ptr), \tmp1 47 movl 4(\arg_ptr), \tmp2 48 movl \tmp1, (\stack_ptr) 49 movl \tmp2, 4(\stack_ptr) 50 // copy the tag 51 movl 8(\arg_ptr), \tmp1 52 movl 12(\arg_ptr), \tmp2 53 movl \tmp1, 8(\stack_ptr) 54 movl \tmp2, 12(\stack_ptr) 55 addl $16, \stack_ptr 56 573: 58.endm 59 60// The macro reserves stack space for the arguments 61// Input: 62// %eax - SHORTY_PTR_REG 63// %edx - SHORTY_REG 64// %ecx - shorty value (no initialization needed) 65// %ebx - method 66// The macro musn't use other registers 67.macro PREPARE_ARG_STACK 68 // check the return type 69 NEXT_SHORTY %ecx 70 71 cmpl $SHORTY_TAGGED, %ecx 72 jne 1f 73 // reserve space for the pointer to which the result will be stored 74 subl $4, %esp 75 761: subl $4, %esp // space for Method 77 78 // parameter 'this' of instance methods is not encoded in the shorty 79 // check whether the method is an instance 80 movl METHOD_ACCESS_FLAGS_OFFSET(%ebx), %ecx 81 testl $ACCESS_STATIC, %ecx 82 jne 3f 83 // it is an instance method 84 subl $4, %esp // reserve space for this 85 863: 87 NEXT_SHORTY %ecx 88 cmpl $0, %ecx 89 je 6f 90 91 cmpl $SHORTY_TAGGED, %ecx 92 je 5f 93 94 subl $SHORTY_FIRST_64, %ecx 95 cmpl $(SHORTY_NUM_64BIT_TYPES - 1), %ecx 96 jbe 4f 97 98 // it is a 32bit value 99 subl $4, %esp 100 jmp 3b 1014: 102 // it is a 64bit value 103 subl $8, %esp 104 jne 3b 105 1065: // it is 'any' 107 subl $16, %esp 108 jne 3b 109 1106: 111 // align arg slot 16 byte 112 andl $0xFFFFFFF0, %esp 113.endm 114 115// void InterpreterToCompiledCodeBridge(const BytecodeInstruction* insn, const Frame *iframe, const Method *method, ManagedThread* thread) 116.global InterpreterToCompiledCodeBridge 117.type InterpreterToCompiledCodeBridge, %function 118InterpreterToCompiledCodeBridge: 119 // %esp % 16 == 12 here (-4 == 12 (mod 16)) 120 movl %esp, %eax 121 122 pushl 8(%eax) // iframe* 123 124 // According to the current frame kind set the bridge type 125 movl 16(%eax), %ecx 126 movb MANAGED_THREAD_FRAME_KIND_OFFSET(%ecx), %cl 127 testb %cl, %cl 128 jz 1f 129 pushl $BYPASS_BRIDGE 130 jmp 2f 1311: 132 pushl $INTERPRETER_TO_COMPILED_CODE_BRIDGE 1332: 134 135 pushl %ebp 136 pushl %THREAD_REG:thread_pointer@NTPOFF 137 138 pushl %ebx 139 pushl %esi 140 pushl %edi 141 // %esp should be 16-byte aligned here 142 143 movl %eax, %ebp // set frame pointer 144 145 movl 16(%ebp), %eax // thread* 146 movl %eax, %THREAD_REG:thread_pointer@NTPOFF 147 148 movl 12(%ebp), %ebx // method* 149 movl METHOD_SHORTY_OFFSET(%ebx), %SHORTY_PTR_REG // method->shorty* 150 INIT_SHORTY_REG 151 152 PREPARE_ARG_STACK 153 154 // setup regs and memory as follow 155 // %eax - SHORTY_PTR_REG, %edx - SHORTY_REG, %ecx - shorty value, (%esp) - insn_ptr, 156 // 8(%ebp) - iframe, 4(%esp) - iframe->vregs[], %edi - pointer to stack 157 movl METHOD_SHORTY_OFFSET(%ebx), %SHORTY_PTR_REG // method->shorty* 158 INIT_SHORTY_REG 159 160 movl %esp, %edi 161 subl $8, %esp 162 163 movl 8(%ebp), %ebx // iframe* 164 addl $FRAME_VREGS_OFFSET, %ebx // iframe->vregs[] 165 pushl %ebx 166 167 // check the return type 168 NEXT_SHORTY %ecx 169 cmpl $SHORTY_TAGGED, %ecx 170 jne 1f 171 // the return type is 'any' 172 movl 8(%ebp), %ebx 173 addl $FRAME_ACC_OFFSET, %ebx // iframe->acc 174 movl %ebx, (%edi) 175 addl $4, %edi 176 1771: movl 12(%ebp), %ebx // method* 178 movl %ebx, (%edi) // push method to the stack 179 addl $4, %edi 180 181 // parameter 'this' of instance methods is not encoded in the shorty 182 // in case of instance method hack SHORTY_REG by replacing the return type by REF 183 // in the another case just skip the return type 184 // check whether the method is an instance 185 movl METHOD_ACCESS_FLAGS_OFFSET(%ebx), %ecx 186 testl $ACCESS_STATIC, %ecx 187 jne 1f 188 // it is an instance method 189 // replace the return type by REF 190 shll $4, %SHORTY_REG // unshift SHORTY_REG back 191 orl $SHORTY_REFERENCE, %SHORTY_REG 192 1931: movl 4(%ebp), %esi // insn* 194 movzbl (%esi), %ebx // read opcode and advance insn_ptr 195 addl $1, %esi 196 pushl %esi 197 198 // The file contains code which checks opcode and jumps 199 // to the corresponding handler. 200 // At the end each handler jumps to .Linvoke_from_bridge label. 201 // The file is autogenerated from runtime/templates/bridge_dispatch.S.erb 202 // Handlers are distinguished by format and located in the corresponding files with name: 203 // handle_call_<format>.S 204 // If you get a compilation error that there is no such file it seems 205 // new call format was introduced and you have to implement the corresponding handler. 206#include "bridge_dispatch_x86.S" 207 208.Linvoke_from_bridge: 209 addl $16, %esp 210 // %esp should be 16-byte aligned here 211 movl 12(%ebp), %ebx // method* 212 movl METHOD_SHORTY_OFFSET(%ebx), %esi // method->shorty* 213 movl METHOD_COMPILED_ENTRY_POINT_OFFSET(%ebx), %ebx // method->entry_point* 214 215 calll *%ebx 216 217 // handle the result 218 // setup registers as follow 219 // %eax, %edx - result, %esi - shorty[0] & 0xF, %edi - frame.acc, %ebx, %ecx - temp 220 movzbl (%esi), %esi 221 andl $0xF, %esi 222 223 cmpl $SHORTY_VOID, %esi 224 je .Lreturn 225 cmpl $SHORTY_TAGGED, %esi 226 je .Lreturn 227 228 movl 8(%ebp), %edi // iframe* 229 addl $FRAME_ACC_OFFSET, %edi 230 231 xorl %ecx, %ecx 232 cmpl $SHORTY_REFERENCE, %esi 233 sete %cl 234 movl %ecx, FRAME_ACC_MIRROR_OFFSET(%edi) 235 je .L32bit_arg 236 237 movl %esi, %ebx 238 movl %esi, %ecx 239 240 subl $SHORTY_FIRST_FLOAT, %ebx 241 cmpl $(SHORTY_NUM_FLOAT_TYPES - 1), %ebx 242 jbe .Lfloat 243 244 subl $SHORTY_FIRST_64, %esi 245 cmpl $(SHORTY_NUM_64BIT_TYPES - 1), %esi 246 jbe .L64bit_arg 247 248 cmpl $SHORTY_I32, %ecx 249 jae .L32bit_arg 250 251 // less than 32-bit 252 cmpl $SHORTY_I16, %ecx 253 je .LI16 254 ja .LU16 255 256 cmpl $SHORTY_I8, %ecx 257 je .LI8 258 jne .LU1_U8 259 260.LU1_U8: 261 movzbl %al, %eax 262 jmp .L32bit_arg 263.LI8: 264 movsbl %al, %eax 265 jmp .L32bit_arg 266.LI16: 267 movswl %ax, %eax 268 jmp .L32bit_arg 269.LU16: 270 movzwl %ax, %eax 271.L32bit_arg: 272 movl %eax, (%edi) 273 jmp .Lreturn 274.Lfloat: 275 fstpl (%edi) 276 jmp .Lreturn 277.L64bit_arg: 278 movl %eax, (%edi) 279 movl %edx, 4(%edi) 280 281.Lreturn: 282 leal -28(%ebp), %esp 283 284 popl %edi 285 popl %esi 286 popl %ebx 287 popl %THREAD_REG:thread_pointer@NTPOFF 288 popl %ebp 289 290 addl $8, %esp 291 retl 292 293 294// uint64_t InvokeCompiledCodeWithArgArray(const int64_t* args, const Frame *iframe, const Method *method, ManagedThread* thread) 295.global InvokeCompiledCodeWithArgArray 296.type InvokeCompiledCodeWithArgArray, %function 297InvokeCompiledCodeWithArgArray: 298 // Since Invocation result is 128bit structure the first argument is a pointer to 299 // memory where the result must be stored 300 301 // %esp % 16 == 12 here (-4 == 12 (mod 16)) 302 movl %esp, %eax 303 304 pushl 12(%eax) // iframe* 305 306 // According to the current frame kind set the bridge type 307 movl 20(%eax), %ecx 308 movb MANAGED_THREAD_FRAME_KIND_OFFSET(%ecx), %cl 309 testb %cl, %cl 310 jz 1f 311 pushl $BYPASS_BRIDGE 312 jmp 2f 3131: 314 pushl $INTERPRETER_TO_COMPILED_CODE_BRIDGE 3152: 316 317 pushl %ebp 318 pushl %THREAD_REG:thread_pointer@NTPOFF 319 320 pushl %ebx 321 pushl %esi 322 pushl %edi 323 // %esp should be 16-byte aligned here 324 325 movl %eax, %ebp // set frame pointer 326 327 movl 20(%ebp), %eax // thread* 328 movl %eax, %THREAD_REG:thread_pointer@NTPOFF 329 330 movl 16(%ebp), %ebx // method* 331 movl METHOD_SHORTY_OFFSET(%ebx), %esi // method->shorty* 332 3331: 334 movl METHOD_SHORTY_OFFSET(%ebx), %SHORTY_PTR_REG // method->shorty* 335 INIT_SHORTY_REG 336 337 PREPARE_ARG_STACK 338 339 // setup regs and memory as follow 340 // %eax - SHORTY_PTR_REG, %edx - SHORTY_REG, %ecx - shorty value, %esi - args[], 341 // %edi - pointer to stack 342 movl METHOD_SHORTY_OFFSET(%ebx), %SHORTY_PTR_REG // method->shorty* 343 INIT_SHORTY_REG 344 345 movl 8(%ebp), %esi // args[] 346 movl %esp, %edi 347 subl $8, %esp 348 349 // check the return type 350 NEXT_SHORTY %ecx 351 cmpl $SHORTY_TAGGED, %ecx 352 jne 1f 353 // the return type is 'any' 354 // push the pointer to memory where the result must be stored 355 movl 4(%ebp), %ecx 356 movl %ecx, (%edi) 357 addl $4, %edi 358 3591: movl %ebx, (%edi) // push method to the stack 360 addl $4, %edi 361 362 // parameter 'this' of instance methods is not encoded in the shorty 363 // in case of instance method hack SHORTY_REG by replacing the return type by REF 364 // in the another case just skip the return type 365 // check whether the method is an instance 366 movl METHOD_ACCESS_FLAGS_OFFSET(%ebx), %ecx 367 testl $ACCESS_STATIC, %ecx 368 jne .Lloop_args_push 369 // it is an instance method 370 // replace the return type by REF 371 shll $4, %SHORTY_REG // unshift SHORTY_REG back 372 orl $SHORTY_REFERENCE, %SHORTY_REG 373 374.Lloop_args_push: 375 NEXT_SHORTY %ecx 376 cmpl $0, %ecx 377 je .Lloopend_args_push 378 379 movl %eax, (%esp) 380 movl %edx, 4(%esp) 381 // handle the first arg index 382 PUSH_ARG %esi, %edi, %eax, %edx 383 movl (%esp), %eax 384 movl 4(%esp), %edx 385 386 addl $8, %esi 387 jmp .Lloop_args_push 388.Lloopend_args_push: 389 movl METHOD_SHORTY_OFFSET(%ebx), %esi // method->shorty* 390 addl $8, %esp 391 392.Linvoke_with_args: 393 movl METHOD_COMPILED_ENTRY_POINT_OFFSET(%ebx), %ebx // method->entry_point* 394 calll *%ebx 395 396 // handle the result 397 // setup registers as follow 398 // %eax, %edx - result, %esi - shorty[0] & 0xF, %edi - tag, %ebx - temp 399 movzbl (%esi), %esi 400 andl $0xF, %esi 401 402 cmpl $SHORTY_VOID, %esi 403 je .Lreturn_ 404 cmpl $SHORTY_TAGGED, %esi 405 je .Lreturn_ 406 407 movl %esi, %ebx 408 movl %esi, %ecx 409 410 subl $SHORTY_FIRST_FLOAT, %ebx 411 cmpl $(SHORTY_NUM_FLOAT_TYPES - 1), %ebx 412 jbe .Lfloat_ 413 414 subl $SHORTY_FIRST_64, %esi 415 cmpl $(SHORTY_NUM_64BIT_TYPES - 1), %esi 416 jbe .Lstore_result_ 417 418 // set high 32 bits of 64bit value to 0 419 xorl %edx, %edx 420 421 cmpl $SHORTY_I32, %ecx 422 jae .Lstore_result_ // i32, u32 or ref 423 424 // less than 32-bit 425 cmpl $SHORTY_I16, %ecx 426 je .LI16_ 427 ja .LU16_ 428 429 cmpl $SHORTY_I8, %ecx 430 je .LI8_ 431 jne .LU1_U8_ 432 433.LU1_U8_: 434 movzbl %al, %eax 435 jmp .Lstore_result_ 436.LI8_: 437 movsbl %al, %eax 438 jmp .Lstore_result_ 439.LI16_: 440 movswl %ax, %eax 441 jmp .Lstore_result_ 442.LU16_: 443 movzwl %ax, %eax 444 jmp .Lstore_result_ 445.Lfloat_: 446 subl $8, %esp 447 fstpl (%esp) 448 movl (%esp), %eax 449 movl 4(%esp), %edx 450 addl $8, %esp 451 452.Lstore_result_: 453 // get result ptr in %ebx 454 movl 4(%ebp), %ebx 455 // store value 456 movl %eax, (%ebx) 457 movl %edx, 4(%ebx) 458.Lreturn_: 459 leal -28(%ebp), %esp 460 461 popl %edi 462 popl %esi 463 popl %ebx 464 popl %THREAD_REG:thread_pointer@NTPOFF 465 popl %ebp 466 467 addl $8, %esp 468 // return and pop the pointer to the result 469 retl $4 470 471.type thread_pointer,@object 472.section .tbss,"awT",@nobits 473.globl thread_pointer 474.p2align 2 475thread_pointer: 476 .long 0 477 .size thread_pointer, 4 478