1b1994897Sopenharmony_ci# Interaction of compiled code and the runtime 2b1994897Sopenharmony_ci 3b1994897Sopenharmony_ci## Introduction 4b1994897Sopenharmony_ci 5b1994897Sopenharmony_ciDuring execution compiled code and Panda runtime should interact with each other. This document describes the following aspects interation: 6b1994897Sopenharmony_ci* Runtime structures 7b1994897Sopenharmony_ci* Calling convention 8b1994897Sopenharmony_ci* The structure of compiled code stack frames and stack traversing 9b1994897Sopenharmony_ci* Transition from the interpeter to compiled code and vise versa 10b1994897Sopenharmony_ci* Calling the runtime 11b1994897Sopenharmony_ci* Deoptimization 12b1994897Sopenharmony_ci* Stack unwinding during exception handling 13b1994897Sopenharmony_ci 14b1994897Sopenharmony_ciDocumentation of meta information generated by the compiler is located in compiled_method_info.md document. 15b1994897Sopenharmony_ci 16b1994897Sopenharmony_ci## Panda runtime (the runtime) 17b1994897Sopenharmony_ciPanda runtime as a set of functions aimed to execute managed code. The runtime consists of several modules. 18b1994897Sopenharmony_ciThe document refers to the interpreter and the compiler modules. 19b1994897Sopenharmony_ci 20b1994897Sopenharmony_ciThe interpreter is a part of the runtime aimed to execute bytecode of managed functions. The interpreter is responsible to manage 21b1994897Sopenharmony_cihotness counter (see [Structure of `panda::Method`](#structure-of-pandamethod)) of managed functions. 22b1994897Sopenharmony_ci 23b1994897Sopenharmony_ciThe compiler is aimed to translate managed function's bytecode to native code. The compiler has an interface function 24b1994897Sopenharmony_ci`panda::CompilerInterface::CompileMethodSync` which starts compilation. When the function gets compiled the compiler 25b1994897Sopenharmony_cichanges its entrypoint to newly generated code. Next time when the function gets called native code will be executed. 26b1994897Sopenharmony_ci 27b1994897Sopenharmony_ci## Calling convention 28b1994897Sopenharmony_ciPanda runtime and managed code must call functions according to the target calling convention. 29b1994897Sopenharmony_ciCompiled code of a managed function must accept one extra argumnent: the pointer to `panda::Method` which describes this function. 30b1994897Sopenharmony_ciThis argument must be the first argument. 31b1994897Sopenharmony_ci 32b1994897Sopenharmony_ciExample: 33b1994897Sopenharmony_ciConsider a function int max(int a, int b). 34b1994897Sopenharmony_ciWhen the compiler generates native code for this function for ARM target it must consider that 35b1994897Sopenharmony_cithe function accepts 3 arguments: 36b1994897Sopenharmony_ci- a pointer to `panda::Method` in the register R0. 37b1994897Sopenharmony_ci- `a` in the register R1 38b1994897Sopenharmony_ci- `b` in the register R2 39b1994897Sopenharmony_ci 40b1994897Sopenharmony_ciThe function must return the result in the register R0. 41b1994897Sopenharmony_ci 42b1994897Sopenharmony_ci## Structure of `panda::ManagedThread` 43b1994897Sopenharmony_ci`panda::ManagedThread` has the following fields that compiled code may use: 44b1994897Sopenharmony_ci 45b1994897Sopenharmony_ci| Field | Type | Description | 46b1994897Sopenharmony_ci| --- | ---- | ----------- | 47b1994897Sopenharmony_ci| sp_flag_ | bool* | Safepoint flag. See *Safepoints* in memory_management.md | 48b1994897Sopenharmony_ci| pending_exception_ | panda::ObjectHeader* | A pointer to a thrown exception or 0 if there is no exception thrown. | 49b1994897Sopenharmony_ci| runtime_entrypoints_ | void*[] | A table of runtime entrypoints (See [Runtime entrypoints](#runtime_entrypoints)). | 50b1994897Sopenharmony_ci| stack_frame_kind_ | StackFrameKind | A kind of the current stack frame (compiled code or interpreter stack frame). | 51b1994897Sopenharmony_ci 52b1994897Sopenharmony_ci## Access to `panda::ManagedThread` from compiled code 53b1994897Sopenharmony_ciThere is an allocated register for each target architecture to store a pointer to `panda::ManagedThread`. This register is called `thread register` and 54b1994897Sopenharmony_cimust contains a valid pointer to `panda::ManagedThread` on entry to each compiled function. 55b1994897Sopenharmony_ci 56b1994897Sopenharmony_ci## Runtime entrypoints 57b1994897Sopenharmony_ciRuntime serves compiled code via runtime entrypoints. A runtime entrypoint is a function which conforms to the target calling convention. 58b1994897Sopenharmony_ciA table of the entrypoints is located in `panda::ManagedThread::runtime_entrypoints_` which could be accessed via `thread register`. 59b1994897Sopenharmony_ci 60b1994897Sopenharmony_ci## Structure of `panda::Method` 61b1994897Sopenharmony_ci`panda::Method` describes a managed function in the runtime. 62b1994897Sopenharmony_ciThis document refers to the following fields of `panda::Method`: 63b1994897Sopenharmony_ci 64b1994897Sopenharmony_ci| Field | Description | 65b1994897Sopenharmony_ci| ----- | ----------- | 66b1994897Sopenharmony_ci| hotness_counter_ | A hotness counter of the managed function. | 67b1994897Sopenharmony_ci| compiled_entry_point_ | Function entrypoint. | 68b1994897Sopenharmony_ci 69b1994897Sopenharmony_ci### Hotness counter 70b1994897Sopenharmony_ciThe field `hotness_counter_` reflects hotness of a managed function. The interpreter increments it each time the function gets called, 71b1994897Sopenharmony_cibackward branch is taken and call instruction is handled. 72b1994897Sopenharmony_ciWhen the hotness counter gets saturated (reaches the threshold) the interpreter triggers compilation of the function. 73b1994897Sopenharmony_ciPanda runtime provides a command line option to tune the hotness counter threshold: `--compiler-hotness-threshold`. 74b1994897Sopenharmony_ci 75b1994897Sopenharmony_ci### Entrypoint 76b1994897Sopenharmony_ciEntrypoint is a pointer to native code which can execute the function. This code must conform to the target calling convention and must accept 77b1994897Sopenharmony_cione extra argument: a pointer to `panda::Method` ( See [Calling convention](#calling_convention)). 78b1994897Sopenharmony_ciThe managed function could have compiled code or it could be executed by the interpreter. 79b1994897Sopenharmony_ciIn the case the function has compiled code the `compiled_entry_point_` must point to compiled code. 80b1994897Sopenharmony_ciIn the case the function is executed by the interpreter the `compiled_entry_point_` must point to a runtime function `CompiledCodeToInterpreterBridge` which calls the interpreter. 81b1994897Sopenharmony_ci 82b1994897Sopenharmony_ci## Stack frame 83b1994897Sopenharmony_ciA stack frame contains data necessary to execute the function the frame belongs to. 84b1994897Sopenharmony_ciThe runtime can create several kinds of stack frames. But all the frames of managed code must have the structure described in [Compiled code stack frame](#compiled-code-stack-frame). 85b1994897Sopenharmony_ci 86b1994897Sopenharmony_ci### Interpreter stack frame 87b1994897Sopenharmony_ciInterpreter stack frame is decribed by `panda::Frame` class. The class has fields to store virtual registers and a pointer to the previous stack frame. 88b1994897Sopenharmony_ciAll the consecutive interpreter stack frames are organized into a linked list. The field `panda::Frame::prev_` contains a pointer to the previous interpreter (or compiled bridge) frame. 89b1994897Sopenharmony_ci 90b1994897Sopenharmony_ci### Compiled code stack frame 91b1994897Sopenharmony_ciEach compiled function is responsible to reserve stack frame for its purpose and then release it when the function doesn't need it. 92b1994897Sopenharmony_ciGeneraly compiled function builds the stack frame in prolog and releases it in epilog. If a compiled function doesn't require 93b1994897Sopenharmony_cithe stack frame it can omit its creation. 94b1994897Sopenharmony_ciWhen compiled code is executing the `stack pointer` register must point to a valid stack frame (newly created stack frame of stack frame of caller) and 95b1994897Sopenharmony_ci`frame pointer` register must point to correct place in the frame before the following operations: 96b1994897Sopenharmony_ci* Managed objects access 97b1994897Sopenharmony_ci* Safepoint flag access 98b1994897Sopenharmony_ci* Call of managed functions or runtime entrypoints 99b1994897Sopenharmony_ci 100b1994897Sopenharmony_ciRelease of the stack frame could be done by restoring values of `stack pointer` and `frame pointer` registers to the value they have at the moment of function entry. 101b1994897Sopenharmony_ci 102b1994897Sopenharmony_ciCompiled code stack frames of caller and callee must be continuous in the stack i.e. the callee's stack frame must immediately follow the caller's stack frame. 103b1994897Sopenharmony_ci 104b1994897Sopenharmony_ciA compiled code stack frame must have the following structure: 105b1994897Sopenharmony_ci 106b1994897Sopenharmony_ci``` 107b1994897Sopenharmony_ci(Stack grows in increasing order: higher slot has lower address) 108b1994897Sopenharmony_ci-----+----------------------+ <- Stack pointer 109b1994897Sopenharmony_ci | Callee parameters | 110b1994897Sopenharmony_ci +----------------------+ 111b1994897Sopenharmony_ci | Spills | 112b1994897Sopenharmony_ci +----------------------+ 113b1994897Sopenharmony_ci | Caller saved fp regs | 114b1994897Sopenharmony_ci D +----------------------+ 115b1994897Sopenharmony_ci A | Caller saved regs | 116b1994897Sopenharmony_ci T +----------------------+ 117b1994897Sopenharmony_ci A | Callee saved fp regs | 118b1994897Sopenharmony_ci +----------------------+ 119b1994897Sopenharmony_ci | Callee saved regs | 120b1994897Sopenharmony_ci +----------------------+ 121b1994897Sopenharmony_ci | Locals | 122b1994897Sopenharmony_ci-----+----------------------+ 123b1994897Sopenharmony_ci H | Properties | 124b1994897Sopenharmony_ci E +----------------------+ 125b1994897Sopenharmony_ci A | panda::Method* | 126b1994897Sopenharmony_ci D +----------------------+ <- Frame pointer 127b1994897Sopenharmony_ci E | Frame pointer | 128b1994897Sopenharmony_ci R +----------------------+ 129b1994897Sopenharmony_ci | Return address | 130b1994897Sopenharmony_ci-----+----------------------+ 131b1994897Sopenharmony_ci``` 132b1994897Sopenharmony_ciStack frame elements: 133b1994897Sopenharmony_ci- data - arbitraty data necessary for function execution. May be omited. 134b1994897Sopenharmony_ci- properties - define properties of the frame, f.e. whether it is OSR frame or not. 135b1994897Sopenharmony_ci- `panda::Method*` - a pointer to `panda::Method` which describes the called function. 136b1994897Sopenharmony_ci- frame pointer - pointer to the previous frame. The value of `frame pointer` register at the moment of function entry. 137b1994897Sopenharmony_ci- return address - address to which control will be transfered after the function gets returned. 138b1994897Sopenharmony_ci 139b1994897Sopenharmony_ciThere are two special registers: `stack pointer` and `frame pointer`. 140b1994897Sopenharmony_ci`stack pointer` register contains a pointer to the last stack element. 141b1994897Sopenharmony_ci`frame pointer` register contains a pointer to the place in the stack where the return address is stored. 142b1994897Sopenharmony_ci 143b1994897Sopenharmony_ciPanda contains special class for getting cframe layout: `class CFrameLayout`. Everything related to the cframe layout 144b1994897Sopenharmony_cishould be processed via this class, 145b1994897Sopenharmony_ci 146b1994897Sopenharmony_ci## Calling a function from compiled code 147b1994897Sopenharmony_ciTo call a managed function compiled code must resolve it (i.e. retreive a pointer to callee's `panda::Method`), 148b1994897Sopenharmony_ciprepare arguments in the registers and the stack (if necessary) and jump to callee's entrypoint. 149b1994897Sopenharmony_ciResolving of a function could be done by calling the corresponding runtime entrypoint. 150b1994897Sopenharmony_ci 151b1994897Sopenharmony_ciExample: 152b1994897Sopenharmony_ciCalling `int max(int a, int b)` function from compiled code on ARM architecture with arguments `2` and `3` 153b1994897Sopenharmony_cicould be described by the following pseudocode: 154b1994897Sopenharmony_ci``` 155b1994897Sopenharmony_ci// tr - thread register 156b1994897Sopenharmony_ci// r0 contains a pointer to the current `panda::Method` 157b1994897Sopenharmony_ci// 1st step: resolve `int max(int, int)` 158b1994897Sopenharmony_cimov r1, MAX_INT_INT_ID // MAX_INT_INT_ID - identifier of int max(int, int) function 159b1994897Sopenharmony_cildr lr, [tr, #RESOLVE_RUNTIME_ENTRYPOINT_OFFSET] 160b1994897Sopenharmony_ciblx lr // call resolve(currentMethod, MAX_INT_INT_ID) 161b1994897Sopenharmony_ci// r0 contains a pointer to `panada::Method` which describes `int max(int, int)` function. 162b1994897Sopenharmony_ci// 2nd step: prepare arguments and entrypoint to call `int max(int, int)` 163b1994897Sopenharmony_cimov r1, #2 164b1994897Sopenharmony_cimov r2, #3 165b1994897Sopenharmony_cilr = ldr [r0, #entrypoint_offset] 166b1994897Sopenharmony_ci// 3rd step: call the function 167b1994897Sopenharmony_ciblx lr // call max('max_method', 2, 3) 168b1994897Sopenharmony_ci// r0 contains the function result 169b1994897Sopenharmony_ci``` 170b1994897Sopenharmony_ci 171b1994897Sopenharmony_ci## Calling a function from compiled code: Bridge function 172b1994897Sopenharmony_ciThe Compiler have an entrypoints table. Each entrypoint contains a link to the Bridge Function. 173b1994897Sopenharmony_ciThe Bridge Functions are auto-generated for each runtime function to be called using the macro assembly. 174b1994897Sopenharmony_ciThe Bridge Function sets up the Boundary Frame and performs the call to the actual runtime function. 175b1994897Sopenharmony_ci 176b1994897Sopenharmony_ciTo do a runtime call from compiled code the Compiler generates: 177b1994897Sopenharmony_ci* putting callee saved (if need) and param holding (if any) register values to the stack 178b1994897Sopenharmony_ci* (callee saved regisers goes to Bridge Function stack frame, caller saved registers goes to the current stack frame) 179b1994897Sopenharmony_ci* parameter holding registers values setup 180b1994897Sopenharmony_ci* Bridge Function address load and branch intruction 181b1994897Sopenharmony_ci* register values restore 182b1994897Sopenharmony_ci 183b1994897Sopenharmony_ciThe bridge function does: 184b1994897Sopenharmony_ci* setup the Bridge Function stack frame 185b1994897Sopenharmony_ci* push the caller saved registers (except of registers holding function parameters) to the caller's stack frame 186b1994897Sopenharmony_ci* adjust Stack Pointer, and pass execution to the runtime function 187b1994897Sopenharmony_ci* restore the Stack Pointer and caller saved registers 188b1994897Sopenharmony_ci 189b1994897Sopenharmony_ciBridge Function stack frame: 190b1994897Sopenharmony_ci``` 191b1994897Sopenharmony_ci--------+------------------------------------------+ 192b1994897Sopenharmony_ci | Return address | 193b1994897Sopenharmony_ci +------------------------------------------+ 194b1994897Sopenharmony_ci HEADER | Frame pointer | 195b1994897Sopenharmony_ci +------------------------------------------+ 196b1994897Sopenharmony_ci | COMPILED_CODE_TO_INTERPRETER_BRIDGE flag | 197b1994897Sopenharmony_ci +------------------------------------------+ 198b1994897Sopenharmony_ci | - unused - | 199b1994897Sopenharmony_ci--------+------------------------------------------+ 200b1994897Sopenharmony_ci | | 201b1994897Sopenharmony_ci | Callee saved regs | 202b1994897Sopenharmony_ci | | 203b1994897Sopenharmony_ci DATA +------------------------------------------+ 204b1994897Sopenharmony_ci | | 205b1994897Sopenharmony_ci | Callee saved fp regs | 206b1994897Sopenharmony_ci | | 207b1994897Sopenharmony_ci--------+------------------------------------------+ 208b1994897Sopenharmony_ci + 16-byte alignment pad to the next frame + 209b1994897Sopenharmony_ci``` 210b1994897Sopenharmony_ci 211b1994897Sopenharmony_ci## Transition from the interpreter to compiled code 212b1994897Sopenharmony_ciWhen the interpreter handles a call instruction first it should resolve the callee method. 213b1994897Sopenharmony_ciDepending on the callee's entrypoint there may be different cases. 214b1994897Sopenharmony_ciIf the entrypoint points to `CompiledCodeToInterpreterBridge` then the callee should be executed by the interpreter. In this case the interpreter calls itself directly. 215b1994897Sopenharmony_ciIn other cases the interpreter calls the function `InterpreterToCompiledCodeBridge` passing to it the resolved callee function, 216b1994897Sopenharmony_cithe call instruction, the interpreter's frame and the pointer to `panda::ManagedThread`. 217b1994897Sopenharmony_ci 218b1994897Sopenharmony_ci`InterpreterToCompiledCodeBridge` function does the following: 219b1994897Sopenharmony_ci* Build a boundary stack frame. 220b1994897Sopenharmony_ci* Set the pointer to `panda::ManagedThread` to the thread register. 221b1994897Sopenharmony_ci* Change stack frame kind in `panda::ManagedThread::stack_frame_kind_` to compiled code stack frame. 222b1994897Sopenharmony_ci* Prepare the arguments according to the target calling convention. The function uses the bytecode instruction (which must be a variant of `call` instruction) 223b1994897Sopenharmony_ci and interpreter's frame to retreive the function's arguments. 224b1994897Sopenharmony_ci* Jump to the callee's entrypoint. 225b1994897Sopenharmony_ci* After the return save the result to the interpreter stack frame. 226b1994897Sopenharmony_ci* Change stack frame kind in `panda::ManagedThread::stack_frame_kind_` back to interpreter stack frame. 227b1994897Sopenharmony_ci* Drop the boundary stack frame. 228b1994897Sopenharmony_ci 229b1994897Sopenharmony_ci`InterpreterToCompiledCodeBridge`'s boundary stack frame is necessary to link the interpreter's frame with the compiled code's frame. 230b1994897Sopenharmony_ciIts structure is depicted below: 231b1994897Sopenharmony_ci``` 232b1994897Sopenharmony_ci---- +----------------+ <- stack pointer 233b1994897Sopenharmony_cib s | INTERPRETER_ | 234b1994897Sopenharmony_cio t | TO_COMPILED_ | 235b1994897Sopenharmony_ciu a | CODE_BRIDGE | 236b1994897Sopenharmony_cin c +----------------+ <- frame pointer 237b1994897Sopenharmony_cid k | pointer to the | 238b1994897Sopenharmony_cia | interpreter | 239b1994897Sopenharmony_cir f | frame | 240b1994897Sopenharmony_ciy r | | 241b1994897Sopenharmony_ci a +----------------+ 242b1994897Sopenharmony_ci m | return address | 243b1994897Sopenharmony_ci e | | 244b1994897Sopenharmony_ci---- +----------------+ 245b1994897Sopenharmony_ci``` 246b1994897Sopenharmony_ci 247b1994897Sopenharmony_ciThe structure of boundary frame is the same as a stack frame of compiled code. 248b1994897Sopenharmony_ciInstead of pointer to `panda::Method` the frame contains constant `INTERPRETER_TO_COMPILED_CODE_BRIDGE`. 249b1994897Sopenharmony_ciFrame pointer points to the previous interpreter frame. 250b1994897Sopenharmony_ci 251b1994897Sopenharmony_ci## Transition from compiled code to the interpreter 252b1994897Sopenharmony_ciIf a function should be executed by the interpreter it must have `CompiledCodeToInterpreterBridge` as an entrypoint. 253b1994897Sopenharmony_ci`CompiledCodeToInterpreterBridge` does the following: 254b1994897Sopenharmony_ci* Change stack frame kind in `panda::ManagedThread::stack_frame_kind_` to interpreter stack frame. 255b1994897Sopenharmony_ci* Creates a boundary stack frame which contains room for interpreter frame. 256b1994897Sopenharmony_ci* Fill in the interpreter frame by the arguments passed to `CompiledCodeToInterpreterBridge` in the registers or via the stack. 257b1994897Sopenharmony_ci* Call the interpreter. 258b1994897Sopenharmony_ci* Store the result in registers or in the stack according to the target calling convention. 259b1994897Sopenharmony_ci* Drop the boundary stack frame. 260b1994897Sopenharmony_ci* Change stack frame kind in `panda::ManagedThread::stack_frame_kind_` back to compiled code stack frame. 261b1994897Sopenharmony_ci 262b1994897Sopenharmony_ci`CompiledCodeToInterpreterBridge`'s boundary stack frame is necessary to link the compiled code's frame with the interpreter's frame. 263b1994897Sopenharmony_ciIts structure is depicted below: 264b1994897Sopenharmony_ci``` 265b1994897Sopenharmony_ci---- +----------------+ <-+ stack pointer 266b1994897Sopenharmony_ci s | interpreter's | -+ `panda::Frame::prev_` 267b1994897Sopenharmony_cib t | frame | | 268b1994897Sopenharmony_cio a +----------------+ <+ frame pointer 269b1994897Sopenharmony_ciu c | frame pointer | 270b1994897Sopenharmony_cin k +----------------+ 271b1994897Sopenharmony_cid | COMPILED_CODE_ | 272b1994897Sopenharmony_cia f | TO_ | 273b1994897Sopenharmony_cir r | INTERPRETER_ | 274b1994897Sopenharmony_ciy a | BRIDGE | 275b1994897Sopenharmony_ci m +----------------+ 276b1994897Sopenharmony_ci e | return address | 277b1994897Sopenharmony_ci---- +----------------+ 278b1994897Sopenharmony_ci | ... | 279b1994897Sopenharmony_ci``` 280b1994897Sopenharmony_ci 281b1994897Sopenharmony_ciThe structure of boundary frame is the same as a stack frame of compiled code. 282b1994897Sopenharmony_ciInstead of a pointer to `panda::Method` the frame contains constant `COMPILED_CODE_TO_INTERPRETER_BRIDGE`. 283b1994897Sopenharmony_ciFrame pointer points to the previous frame in compiled code stack frame. 284b1994897Sopenharmony_ciThe field `panda::Frame::prev_` must point to the boundary frame pointer. 285b1994897Sopenharmony_ci 286b1994897Sopenharmony_ci## Stack traversing 287b1994897Sopenharmony_ciStack traversing is performed by the runtime. When the runtime examinates a managed thread's stack the thread mustn't execute any managed code. 288b1994897Sopenharmony_ciStack unwinding always starts from the top frame. Its kind could be determined from `panda::ManagedThread::stak_frame_kind_` field. A pointer 289b1994897Sopenharmony_cito the top frame could be determined depends on the kind of the top stack frame: 290b1994897Sopenharmony_ci* The top stack frame is an interpreter stack frame. Address of the interpreter's frame could be retrieved from `panda::ManagedThread::GetCurrentFrame()`. 291b1994897Sopenharmony_ci* The top stack frame is a compiled code stack frame. `frame pointer` register contains the address of the top stack frame. 292b1994897Sopenharmony_ci 293b1994897Sopenharmony_ciHaving a pointer to the top stack frame, its kind and structure the runtime can move to the next frame. 294b1994897Sopenharmony_ciMoving to the next frame is done according to the table below: 295b1994897Sopenharmony_ci 296b1994897Sopenharmony_ci| Kind of the current stack frame | How to get a pointer to the next stack frame | Kind of the previous stack frame | 297b1994897Sopenharmony_ci| ------------------------------- | -------------------------------------------- | -------------------------------- | 298b1994897Sopenharmony_ci| Interpreter stack frame | Read `panda::Frame::prev_` field | Interpreter stack frame or COMPILED_CODE_TO_INTERPRETER boundary frame | 299b1994897Sopenharmony_ci| INTERPRETER_TO_COMPILED_CODE_BRIDGE boundary stack frame | Read `pointer to the interpreter frame` from the stack | Interpreter stack frame | 300b1994897Sopenharmony_ci| COMPILED_CODE_TO_INTERPRETER_BRIDGE boundary stack frame | Read `frame pointer` from the stack | Compiled code stack frame | 301b1994897Sopenharmony_ci| Compiled code stack frame | Read `frame pointer` | Compiled code stack frame or INTERPRETER_TO_COMPILED_CODE_BRIDGE boundary frame| 302b1994897Sopenharmony_ci 303b1994897Sopenharmony_ciThus the runtime can traverse all the managed stack frames moving from one frame to the previous frame and changing frame type 304b1994897Sopenharmony_cicrossing the boundary frames. 305b1994897Sopenharmony_ci 306b1994897Sopenharmony_ciUnwinding of stack frames has specifics. 307b1994897Sopenharmony_ci* Compiled code could be combined from several managed functions (inlined functions). If the runtime needs to get information about inlined functions 308b1994897Sopenharmony_ciduring handling a compiled code stack frame it uses meta information generated by the compiler (See compiled_method_info.md). 309b1994897Sopenharmony_ci* Compiled code may save any callee-saved registers on the stack. Before moving to the next stack frame the runtime must restore values of these registers. 310b1994897Sopenharmony_ciTo do that the runtime uses information about callee-saved registers stored on the stack. This information is generated by the compiler (See compiled_method_info.md). 311b1994897Sopenharmony_ci* Values of virtual registers could be changed during stack unwinding. For example, when GC moves an object, it must update all the references to the object. 312b1994897Sopenharmony_ciThe runtime should provide an internal API for changing values of virtual registers. 313b1994897Sopenharmony_ci 314b1994897Sopenharmony_ciExample: 315b1994897Sopenharmony_ciConsider the following call sequence: 316b1994897Sopenharmony_ci``` 317b1994897Sopenharmony_ci calls calls 318b1994897Sopenharmony_ci foo --------> bar ------> baz 319b1994897Sopenharmony_ci(interpreted) (compiled) (interpreted) 320b1994897Sopenharmony_ci``` 321b1994897Sopenharmony_ciFunctions `foo` and `baz` are executed by the interpreter and the function `bar` has compiled code. 322b1994897Sopenharmony_ciIn this situation the stack might look as follow: 323b1994897Sopenharmony_ci``` 324b1994897Sopenharmony_ci---- +----------------+ <- stack pointer 325b1994897Sopenharmony_ciE | native frame | 326b1994897Sopenharmony_cix u | of | 327b1994897Sopenharmony_cie t | interpreter | 328b1994897Sopenharmony_cic e | | 329b1994897Sopenharmony_ci---- +----------------+ <--- `panda::ManagedThread::GetCurrentFrame()` 330b1994897Sopenharmony_cib | baz's | -+ 331b1994897Sopenharmony_cio s | interperer | | 332b1994897Sopenharmony_ciu t | stack frame | | 333b1994897Sopenharmony_cin a +----------------+<-+ 334b1994897Sopenharmony_cid c | frame pointer | -+ 335b1994897Sopenharmony_cia k +----------------+ | 336b1994897Sopenharmony_cir | COMPILED_CODE_ | | 337b1994897Sopenharmony_ciy f | TO_ | | 338b1994897Sopenharmony_ci r | INTERPRETER_ | | 339b1994897Sopenharmony_ci a | BRIDGE | | 340b1994897Sopenharmony_ci m +----------------+ | 341b1994897Sopenharmony_ci e | return address | | 342b1994897Sopenharmony_ci---- +----------------+ | 343b1994897Sopenharmony_ci | data | | 344b1994897Sopenharmony_ci +----------------+ | 345b1994897Sopenharmony_ci b | panda::Method* | | 346b1994897Sopenharmony_ci a +----------------+ <+ 347b1994897Sopenharmony_ci r | frame pointer | -+ 348b1994897Sopenharmony_ci +----------------+ | 349b1994897Sopenharmony_ci | return address | | 350b1994897Sopenharmony_ci---- +----------------+ | 351b1994897Sopenharmony_cib s | INTERPRETER_ | | 352b1994897Sopenharmony_cio t | TO_COMPILED_ | | 353b1994897Sopenharmony_ciu a | CODE_BRIDGE | | 354b1994897Sopenharmony_cin c +----------------+ <+ 355b1994897Sopenharmony_cid k | pointer to the | -+ 356b1994897Sopenharmony_cia | interpreter | | 357b1994897Sopenharmony_cir f | frame | | 358b1994897Sopenharmony_ciy r | | | 359b1994897Sopenharmony_ci a +----------------+ | 360b1994897Sopenharmony_ci m | return address | | 361b1994897Sopenharmony_ci e | | | 362b1994897Sopenharmony_ci---- +----------------+ | 363b1994897Sopenharmony_ciE | native frame | | 364b1994897Sopenharmony_cix u | of | | 365b1994897Sopenharmony_cie t | interpreter | | 366b1994897Sopenharmony_cic e | | | 367b1994897Sopenharmony_ci---- +----------------+ | 368b1994897Sopenharmony_ci | ... | | 369b1994897Sopenharmony_ci +----------------+ <+ 370b1994897Sopenharmony_ci | foo's | 371b1994897Sopenharmony_ci | interpreter | 372b1994897Sopenharmony_ci | frame | 373b1994897Sopenharmony_ci +----------------+ 374b1994897Sopenharmony_ci | ... | 375b1994897Sopenharmony_ci``` 376b1994897Sopenharmony_ci 377b1994897Sopenharmony_ciThe runtime determines kind of the top stack frame by reading `panda::ManagedThread::stack_frame_kind_` (the top stack frame kind must be interpreter stack frame). 378b1994897Sopenharmony_ci`panda::ManagedThread::GetCurrentFrame()` method must return the pointer to `baz`'s interpreter stack frame. 379b1994897Sopenharmony_ciTo go to the previous frame the runtime reads the field `panda::Frame::prev_` which must point to `COMPILED_CODE_TO_INTERPRETER_BRIDGE` boundary stack frame. 380b1994897Sopenharmony_ciIt means that to get `bar`'s stack frame the runtime must read `frame pointer` and the kind of the next frame will be compiled code's frame. 381b1994897Sopenharmony_ciAt this step the runtime has a pointer to `bar`'s compiled code stack frame. To go to the next frame runtime reads `frame pointer` again and gets 382b1994897Sopenharmony_ci`INTERPRETER_TO_COMPILED_CODE_BRIDGE` boundary stack frame. To reach `foo`'s interpreter stack frame the runtime reads `pointer to the interpreter's frame` field. 383b1994897Sopenharmony_ci 384b1994897Sopenharmony_ci## Deoptimization 385b1994897Sopenharmony_ciThere is may be a situation when compiled code cannot continue execution for some reason. 386b1994897Sopenharmony_ciFor such cases compiled code must call `void Deoptimize()` runtime entrypoint to continue execution of the method in the interpreter from the point where compiled code gets stopped. 387b1994897Sopenharmony_ciThe function reconstructs the interpreter stack frame and calls the interpreter. 388b1994897Sopenharmony_ciWhen compiled code is combined from several managed functions (inlined functions) `Deoptimize` reconstructs interpreter stack frame and calls the interpreter for each inlined function too. 389b1994897Sopenharmony_ci 390b1994897Sopenharmony_ciDetails in [deoptimization documentation](deoptimization.md) 391b1994897Sopenharmony_ci## Throwing an exception 392b1994897Sopenharmony_ciThrowing an exeption from compiled code is performed by calling a runtime entrypoint `void ThrowException(panda::ObjectHeader* exception)`. 393b1994897Sopenharmony_ciThe function `ThrowException` does the following: 394b1994897Sopenharmony_ci* Saves all the callee-saved registers to the stack 395b1994897Sopenharmony_ci* Stores the pointer to the exception object to `panda::ManagedThread::pending_exception_` 396b1994897Sopenharmony_ci* Unwind compiled code stack frames to find the corresponding exception handler by going from one stack frame to the previous and making checks. 397b1994897Sopenharmony_ci 398b1994897Sopenharmony_ciIf the corresponding catch handler is found in the current stack frame the runtime jumps to the handler. 399b1994897Sopenharmony_ci 400b1994897Sopenharmony_ciIf a INTERPRETER_TO_COMPILED_CODE_BRIDGE boundary stack frame is reached the runtime returns to the interpreter letting it to handle the exception. 401b1994897Sopenharmony_ciReturning to the interpreter is performed as follow: 402b1994897Sopenharmony_ci1. Determine the return address to the boundary frame. The return address is stored in the following compiled code stack frame. 403b1994897Sopenharmony_ci2. Set the pointer to the boundary frame into stack pointer, assign the return address determined at the previous step to program counter. 404b1994897Sopenharmony_ci 405b1994897Sopenharmony_ciIf there is no catch handler in the current frame then the runtime restores values of callee-saved registers and moves to the previous stack frame. 406b1994897Sopenharmony_ci 407b1994897Sopenharmony_ciDetails of stack travesing are described in [Stack traversing](#stack_traversing) 408b1994897Sopenharmony_ci 409b1994897Sopenharmony_ciFinding a catch handler in a compiled code stack frame is performed according meta information generated by the compiler (See compiled_method_info.md). 410b1994897Sopenharmony_ci 411b1994897Sopenharmony_ciThe interpreter must ignore the returned value if `panda::ManagedThread::pending_exception_` is not 0. 412b1994897Sopenharmony_ci 413