| * |
| * Copyright 2014, The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| |
| Introduction |
| This is the documentation of the stack based virtual machine implemented in Interpreter.h and in |
| Interpreter.cpp for replaying arbitrary opcode streams generated by the server. |
| |
| Base types |
| * int8_t, int16_t, int32_t, int64_t |
| * uint8_t, uint16_t, unit32_t, uint64_t |
| * float, double |
| * absolute pointer, volatile pointer, constant pointer |
| |
| Pointers |
| The interpreter and the underlying stack support 3 different types of pointer. The absolute |
| pointer is a regular (untyped) pointer pointing to an arbitrary memory location or a null |
| pointer. The volatile pointer is an offset in the volatile memory and the constant pointer is an |
| offset inside the constant memory. |
| |
| Stack |
| A standard LIFO stack where each element is a type (one of the base types), value pair. The |
| implementation of the type storage is implementation dependent (can be on a different stack). |
| The size of the stored elements are unified to the size of the largest storable type and all of |
| the elements are aligned. |
| |
| Each operation, except for CLONE, consumes the operands from the current stack and pushes the |
| result back to the stack. |
| |
| Opcodes |
| Each opcode is 32 bits long where the first 6 bits are the instruction code and the rest of the |
| bits contain the instruction data. This leaves room for additional instructions to be added in |
| the future. |
| |
| Notation: <field_name:field_size_in_bits> |
| |
| Function call |
| <code:6> <padding:1> <push-return:1> <padding:8> <function id:16> |
| * CALL(push-return, function) [-{arg-count} (any type) / +{push-return} (any type)] |
| * Call the specified function and if push-return is 1 then save the return value to the |
| stack; otherwise discard the return value |
| * The arguments are popped from the stack and they are type checked with the arguments |
| of the called function |
| * The arguments have to be pushed onto the stack in order (the last argument is on the |
| top of the stack) |
| * Function IDs in range 0xff00-0xffff are reserved for the implementation (callbacks) |
| |
| Push |
| <code:6> <type:6> <data:20> |
| * PUSH_I(type, data) [+1 (type)] |
| * Push the data to the stack specified inside the opcode |
| * If the data type is an integer or a pointer type, then the data is copied into the |
| least-significant-bits of the target word, sign-extending if the type is signed. |
| * If the data type is a float or double, then the value is written to the sign and |
| exponent bits of the floating point number, and the fractional bits are set to 0. |
| <code:6> <type:6> <constant-address:20> |
| * LOAD_C(type, address) [+1 (type)] |
| * Push data from the given constant memory address to the stack |
| <code:6> <type:6> <volatile-address:20> |
| * LOAD_V(type, address) [+1 (type)] |
| * Push data from the given volatile memory address to the stack |
| <code:6> <type:6> <padding:20> |
| * LOAD(type) [-1 (pointer) / +1 (type)] |
| * Pop a memory address from the top of the stack and push the data at that address to |
| the top of the stack |
| |
| Pop |
| <code:6> <count:26> |
| * POP(count) [-{count} (any type)] |
| * Pop and discard count values from the top of the stack |
| <code:6> <volatile-address:26> |
| * STORE_V(volatile-address) [-1 (any type)] |
| * Pop the top value from the the stack and save it to the given volatile memory address. |
| All pointer values, regardless of the pointer type on the stack, will be stored as an |
| absolute pointer address. |
| <code:6> <padding:26> |
| * STORE() [-2 (pointer, any type)] |
| * Pop the target address and then the value from the top of the stack, and then store |
| the value to the target address. |
| All pointer values, regardless of the pointer type on the stack, will be stored as an |
| absolute pointer address. |
| |
| Load resource |
| <code:6> <resource-id:26> |
| * RESOURCE(resource-id) [-1 (pointer)] |
| * Pop the volatile-address from the top of the stack and loads the resource with the |
| given id to that address |
| |
| Post data |
| <code:6> <padding:26> |
| * POST() [-2 (uint32_t, pointer)] |
| * Pop size and a pointer from the top of the stack and post size bytes of data from |
| the address to the server |
| |
| Copy |
| <code:6> <count:26> |
| * COPY(count) [-2 (pointer, pointer)] |
| * Pop the target address then the source address from the top of the stack, and then |
| copy count bytes from source to target. |
| <code:6> <n:26> |
| * CLONE(n) [+1 (any type)] |
| * Copy the n-th element from the stack to the top of the stack |
| <code:6> <max-count:26> |
| * STRCPY() [-2 (pointer, pointer)] |
| * Pop the target address then the source address from the top of the stack, and |
| then copy at most max-count minus one bytes from source to target. If the |
| max-count is greater than the source string length, then the target will be padded |
| with 0s. The destination buffer will always be 0-terminated. |
| |
| Calculation |
| <code:6> <value:26> |
| * EXTEND(value) [no change] |
| * Extend the value at the top of the stack with the given data, in-place. |
| * If the data type of the top of the stack is an integer or a pointer type, then the |
| value on the stack is left-shifted by 26 bits and is bitwise-OR’ed with the |
| specified value. |
| * If the data type is a float or double, then the fractional part of the floating |
| point value on the stack is left-shifted by 26 bits and is bitwise-OR’ed with the |
| specified value. Bits shifted beyond the fractional part of the floating point |
| number are discarded. |
| |
| Debug |
| <code:6> <value:26> |
| * LABEL(value) [no change] |
| * Set the current label to value. The label value is displayed in debug messages or |
| in the case of a crash. |