Index: src/trusted/validator/x86/decoder/ncop_exps.c |
diff --git a/src/trusted/validator/x86/decoder/ncop_exps.c b/src/trusted/validator/x86/decoder/ncop_exps.c |
deleted file mode 100644 |
index cb52b74ba71f872f72fbc1fd415261af526adddc..0000000000000000000000000000000000000000 |
--- a/src/trusted/validator/x86/decoder/ncop_exps.c |
+++ /dev/null |
@@ -1,613 +0,0 @@ |
-/* |
- * Copyright (c) 2012 The Native Client Authors. All rights reserved. |
- * Use of this source code is governed by a BSD-style license that can be |
- * found in the LICENSE file. |
- */ |
- |
-#include "native_client/src/trusted/validator/x86/decoder/ncop_exps.h" |
- |
-#include <stdio.h> |
-#include <ctype.h> |
-#include <string.h> |
-#include <assert.h> |
-#include <sys/stat.h> |
- |
-#include "native_client/src/include/portability.h" |
-#include "native_client/src/shared/platform/nacl_log.h" |
-#include "native_client/src/shared/utils/types.h" |
-#include "native_client/src/trusted/validator/x86/decoder/gen/ncop_expr_node_flag_impl.h" |
-#include "native_client/src/trusted/validator/x86/decoder/gen/ncop_expr_node_kind_impl.h" |
-#include "native_client/src/trusted/validator/x86/decoder/nc_decode_tables_types.h" |
-#include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal.h" |
- |
-/* To turn on debugging of instruction decoding, change value of |
- * DEBUGGING to 1. |
- * |
- * WARNING: Debugging messages inside of print messages must be sent to the |
- * same gio stream as being printed, since they may be used by another |
- * nacl log message that has locked the access to NaClLogGetGio(). |
- */ |
-#define DEBUGGING 0 |
- |
-#include "native_client/src/shared/utils/debugging.h" |
- |
-#include "native_client/src/trusted/validator/x86/decoder/ncopcode_desc_inl.c" |
-#include "native_client/src/trusted/validator/x86/decoder/ncop_exps_inl.c" |
- |
-void NaClPrintExpFlags(struct Gio* file, NaClExpFlags flags) { |
- if (flags == 0) { |
- gprintf(file, "0"); |
- } else { |
- NaClExpFlag f; |
- Bool is_first = TRUE; |
- for (f = 0; f < NaClExpFlagEnumSize; f++) { |
- if (flags & NACL_EFLAG(f)) { |
- if (is_first) { |
- is_first = FALSE; |
- } else { |
- gprintf(file, " | "); |
- } |
- gprintf(file, "%s", NaClExpFlagName(f)); |
- } |
- } |
- } |
-} |
- |
-typedef struct NaClExpKindDescriptor { |
- /* The name of the expression operator. */ |
- NaClExpKind name; |
- /* The rank (i.e. number of children) the expression operator has. */ |
- const int rank; |
-} NaClExpKindDescriptor; |
- |
-/* The print names of valid NaClExpKind values. */ |
-static const NaClExpKindDescriptor |
-g_NaClExpKindDesc[NaClExpKindEnumSize + 1]= { |
- {UndefinedExp, 0}, |
- {ExprRegister, 0}, |
- {OperandReference, 1}, |
- {ExprConstant, 0}, |
- {ExprSegmentAddress, 2}, |
- {ExprMemOffset, 4}, |
- {ExprNaClIllegal, 0}, |
-}; |
- |
-int NaClExpKindRank(NaClExpKind kind) { |
- assert(kind == g_NaClExpKindDesc[kind].name); |
- return g_NaClExpKindDesc[kind].rank; |
-} |
- |
-/* Returns the register defined by the given node. */ |
-NaClOpKind NaClGetExpRegister(NaClExp* node) { |
- return NaClGetExpRegisterInline(node); |
-} |
- |
-/* Returns the name of the register defined by the indexed node in the |
- * vector of nodes. |
- */ |
-NaClOpKind NaClGetExpVectorRegister(NaClExpVector* vector, |
- int node) { |
- return NaClGetExpRegisterInline(&vector->node[node]); |
-} |
- |
-static int NaClPrintDisassembledExp(struct Gio* file, |
- NaClInstState* state, |
- uint32_t index); |
- |
-/* Print the characters in the given string using lower case. */ |
-static void NaClPrintLower(struct Gio* file, char* str) { |
- while (*str) { |
- gprintf(file, "%c", tolower(*str)); |
- ++str; |
- } |
-} |
- |
-/* Print out the given constant expression node to the given file. */ |
-static void NaClPrintDisassembledConst( |
- struct Gio* file, NaClInstState* state, NaClExp* node) { |
- assert(node->kind == ExprConstant); |
- if (node->flags & NACL_EFLAG(ExprJumpTarget)) { |
- NaClPcAddress target = NaClInstStatePrintableAddress(state) |
- + state->bytes.length + (NaClPcNumber) NaClGetExprSignedValue(node); |
- gprintf(file, "0x%"NACL_PRIxNaClPcAddress, target); |
- }else if (node->flags & NACL_EFLAG(ExprUnsignedHex)) { |
- gprintf(file, "0x%"NACL_PRIx64, NaClGetExprUnsignedValue(node)); |
- } else if (node->flags & NACL_EFLAG(ExprSignedHex)) { |
- int64_t val = NaClGetExprSignedValue(node); |
- if (val < 0) { |
- val = -val; |
- gprintf(file, "-0x%"NACL_PRIx64, val); |
- } else { |
- gprintf(file, "0x%"NACL_PRIx64, val); |
- } |
- } else if (node->flags & NACL_EFLAG(ExprUnsignedInt)) { |
- gprintf(file, "%"NACL_PRIu64, NaClGetExprUnsignedValue(node)); |
- } else { |
- /* Assume ExprSignedInt. */ |
- gprintf(file, "%"NACL_PRId64, NaClGetExprSignedValue(node)); |
- } |
-} |
- |
-#define NACLOP_REG_PREFIX "Reg" |
- |
-size_t NaClOpRegName(NaClOpKind reg, char* buffer, size_t buffer_size) { |
- const char* name = NaClOpKindName(reg); |
- char* str; |
- size_t index; |
- |
- /* Fail if no room to put register name. */ |
- if (buffer_size == 0) return 0; |
- buffer[0] = '\0'; /* To be safe, in case we exit prematurely. */ |
- |
- /* Get name for register. */ |
- name = NaClOpKindName(reg); |
- if (NULL == name) return 0; |
- |
- /* Strip off 'Reg' prefix from register name, if it exists. */ |
- str = strstr(name, NACLOP_REG_PREFIX); |
- if (str != name) return 0; |
- str += strlen(NACLOP_REG_PREFIX); |
- |
- /* Copy the name, converting characters to lower case. */ |
- for (index = 0; (index + 1) < buffer_size; ++index) { |
- char ch = tolower(str[index]); |
- if ('\0' == ch) break; |
- buffer[index] = tolower(str[index]); |
- } |
- |
- /* Be sure to add null character at end. */ |
- buffer[index] = '\0'; |
- return index; |
-} |
- |
-#define MAX_REGISTER_SIZE 256 |
- |
-/* Print out the disassembled representation of the given register |
- * to the given file. |
- */ |
-static void NaClPrintDisassembledRegKind(struct Gio* file, NaClOpKind reg) { |
- char buffer[MAX_REGISTER_SIZE]; |
- NaClOpRegName(reg, buffer, MAX_REGISTER_SIZE); |
- gprintf(file, "%c%s", '%', buffer); |
-} |
- |
-static INLINE void NaClPrintDisassembledReg(struct Gio* file, NaClExp* node) { |
- NaClPrintDisassembledRegKind(file, NaClGetExpRegisterInline(node)); |
-} |
- |
-void NaClExpVectorPrint(struct Gio* file, NaClInstState* state) { |
- uint32_t i; |
- NaClExpVector* vector = NaClInstStateExpVector(state); |
- gprintf(file, "NaClExpVector[%d] = {\n", vector->number_expr_nodes); |
- for (i = 0; i < vector->number_expr_nodes; i++) { |
- NaClExp* node = &vector->node[i]; |
- gprintf(file, " { %s[%d] , ", |
- NaClExpKindName(node->kind), |
- NaClExpKindRank(node->kind)); |
- switch (node->kind) { |
- case ExprRegister: |
- NaClPrintDisassembledReg(file, node); |
- break; |
- case ExprConstant: |
- NaClPrintDisassembledConst(file, state, node); |
- break; |
- default: |
- gprintf(file, "%"NACL_PRIu64, NaClGetExprUnsignedValue(node)); |
- break; |
- } |
- gprintf(file, ", "); |
- NaClPrintExpFlags(file, node->flags); |
- gprintf(file, " },\n"); |
- } |
- gprintf(file, "};\n"); |
-} |
- |
-/* Print out the given (memory offset) expression node to the given file. |
- * Returns the index of the node following the given (indexed) memory offset. |
- */ |
-static int NaClPrintDisassembledMemOffset(struct Gio* file, |
- NaClInstState *state, |
- int index) { |
- NaClExpVector* vector = NaClInstStateExpVector(state); |
- int r1_index = index + 1; |
- int r2_index = r1_index + NaClExpWidth(vector, r1_index); |
- int scale_index = r2_index + NaClExpWidth(vector, r2_index); |
- int disp_index = scale_index + NaClExpWidth(vector, scale_index); |
- NaClOpKind r1 = NaClGetExpVectorRegister(vector, r1_index); |
- NaClOpKind r2 = NaClGetExpVectorRegister(vector, r2_index); |
- uint64_t scale = NaClGetExprUnsignedValue(&vector->node[scale_index]); |
- int64_t disp = NaClGetExprSignedValue(&vector->node[disp_index]); |
- assert(ExprMemOffset == vector->node[index].kind); |
- gprintf(file,"["); |
- if (r1 != RegUnknown) { |
- NaClPrintDisassembledRegKind(file, r1); |
- } |
- if (r2 != RegUnknown) { |
- if (r1 != RegUnknown) { |
- gprintf(file, "+"); |
- } |
- NaClPrintDisassembledRegKind(file, r2); |
- gprintf(file, "*%d", (uint32_t) scale); |
- } |
- if (disp != 0) { |
- if ((r1 != RegUnknown || r2 != RegUnknown) && |
- !NaClIsExpNegativeConstant(vector, disp_index)) { |
- gprintf(file, "+"); |
- } |
- /* Recurse to handle print using format flags. */ |
- NaClPrintDisassembledExp(file, state, disp_index); |
- } else if (r1 == RegUnknown && r2 == RegUnknown) { |
- /* be sure to generate case: [0x0]. */ |
- NaClPrintDisassembledExp(file, state, disp_index); |
- } |
- gprintf(file, "]"); |
- return disp_index + NaClExpWidth(vector, disp_index); |
-} |
- |
-/* Retrurns true if the segment register of the indexed segment address is DS, |
- * and DS has been marked (by the instruction) as the default register |
- * for the segment address. |
- */ |
-static Bool IsSegmentAddressDsRegPair(NaClInstState* state, |
- int index) { |
- NaClExpVector* vector = NaClInstStateExpVector(state); |
- NaClExp* segment_address = &vector->node[index]; |
- NaClExp* segment_register = |
- &vector->node[NaClGetExpKidIndex(vector, index, 0)]; |
- return NaClHasBit(segment_address->flags, NACL_EFLAG(ExprDSrCase)) && |
- (segment_register->kind == ExprRegister) && |
- (RegDS == NaClGetExpRegisterInline(segment_register)); |
-} |
- |
-/* Retrurns true if the segment register of the index segment address is ES, |
- * and ES has been marked (by the instruction) as the default register |
- * for the segment address. |
- */ |
-static Bool IsSegmentAddressEsRegPair(NaClInstState* state, |
- int index) { |
- NaClExpVector* vector = NaClInstStateExpVector(state); |
- NaClExp* segment_address = &vector->node[index]; |
- NaClExp* segment_register = |
- &vector->node[NaClGetExpKidIndex(vector, index, 0)]; |
- return NaClHasBit(segment_address->flags, NACL_EFLAG(ExprESrCase)) && |
- (segment_register->kind == ExprRegister) && |
- (RegES == NaClGetExpRegisterInline(segment_register)); |
-} |
- |
-/* Print out the given (segment address) expression node to the |
- * given file. Returns the index of the node following the |
- * given (indexed) segment address. |
- */ |
-static int NaClPrintDisassembledSegmentAddr(struct Gio* file, |
- NaClInstState* state, |
- int index) { |
- int memory_address; |
- NaClExpVector* vector = NaClInstStateExpVector(state); |
- /* If segment register is default. If so, do not print. */ |
- if (IsSegmentAddressDsRegPair(state, index) || |
- IsSegmentAddressEsRegPair(state, index)) { |
- /* Segment register matches default. Don't print. */ |
- } else { |
- /* Print the segment register associated with the segment address. */ |
- NaClPrintDisassembledExp(file, state, index + 1); |
- gprintf(file, ":"); |
- } |
- memory_address = NaClGetExpKidIndex(vector, index, 1); |
- if (vector->node[memory_address].kind == ExprRegister) { |
- /* Special case segment address, where the register corresponds to |
- * a memory address. Print out the register in '[]' brackets to |
- * communicate that it is a memory reference. |
- */ |
- int result; |
- gprintf(file, "["); |
- result = NaClPrintDisassembledExp(file, state, memory_address); |
- gprintf(file, "]"); |
- return result; |
- } else { |
- /* print out memory address associated with segment address. */ |
- return NaClPrintDisassembledExp(file, state, memory_address); |
- } |
-} |
- |
-/* Print out the given expression node to the given file. |
- * Returns the index of the node following the given indexed |
- * expression. |
- */ |
-static int NaClPrintDisassembledExp(struct Gio* file, |
- NaClInstState* state, |
- uint32_t index) { |
- NaClExp* node; |
- NaClExpVector* vector = NaClInstStateExpVector(state); |
- assert(index < vector->number_expr_nodes); |
- node = &vector->node[index]; |
- switch (node->kind) { |
- default: |
- gprintf(file, "undefined"); |
- return index + 1; |
- case ExprRegister: |
- NaClPrintDisassembledReg(file, node); |
- return index + 1; |
- case OperandReference: |
- return NaClPrintDisassembledExp(file, state, index + 1); |
- case ExprConstant: |
- NaClPrintDisassembledConst(file, state, node); |
- return index + 1; |
- case ExprSegmentAddress: |
- return NaClPrintDisassembledSegmentAddr(file, state, index); |
- case ExprMemOffset: |
- return NaClPrintDisassembledMemOffset(file, state, index); |
- case ExprNaClIllegal: |
- gprintf(file, "*NaClIllegal*"); |
- return index + 1; |
- } |
-} |
- |
-/* Returns true if there is a segment override in the segment address |
- * node defined by vector[seg_addr_index]. |
- * |
- * Parameters: |
- * vector - The node expression tree associated with the instruction. |
- * seg_addr_index - The index to the segment address node to check. |
- * seg_eflag - The expr flag that must be associated with the |
- * segment address node to be considered for an override. |
- * seg_reg - The expected (i.e. default) segment register |
- * to be associated with the segment address. |
- */ |
-static Bool NaClHasSegmentOverride(NaClExpVector* vector, |
- int seg_addr_index, |
- NaClExpFlag seg_eflag, |
- NaClOpKind seg_reg) { |
- NaClExp* seg_node = &vector->node[seg_addr_index]; |
- if (seg_node->flags & NACL_EFLAG(seg_eflag)) { |
- int seg_index = seg_addr_index + 1; |
- NaClExp* node = &vector->node[seg_index]; |
- if ((ExprRegister == node->kind) && |
- (seg_reg != NaClGetExpRegisterInline(node))) { |
- return TRUE; |
- } |
- } |
- return FALSE; |
-} |
- |
-/* Prints out the segment register associated with the segment |
- * address node defined by vector[seg_addr_index]. |
- * |
- * Parameters: |
- * file - The Gio file to print the segment register to. |
- * is_first - True if the first operand of the instruction. |
- * vector - The node expression tree associated with the instruction. |
- * seg_addr_index - The index to the segment address node to check. |
- */ |
-static void NaClPrintSegmentOverride(struct Gio* file, |
- Bool* is_first, |
- NaClInstState* state, |
- NaClExpVector* vector, |
- int seg_addr_index) { |
- int seg_index = seg_addr_index + 1; |
- if (*is_first) { |
- gprintf(file, " "); |
- *is_first = FALSE; |
- } else { |
- gprintf(file, ", "); |
- } |
- NaClPrintDisassembledExp(file, state, seg_index); |
-} |
- |
-/* Print the flag name if the flag is defined for the corresponding operand. |
- * Used to print out set/use/zero extend information for partial instructions. |
- */ |
-static void NaClPrintAddOperandFlag(struct Gio* f, |
- const NaClOp* op, |
- NaClOpFlag flag, |
- const char* flag_name) { |
- if (op->flags & NACL_OPFLAG(flag)) { |
- gprintf(f, "%s", flag_name); |
- } |
-} |
- |
-/* Print the given instruction opcode of the give state, to the |
- * given file. |
- */ |
-static void NaClPrintDisassembled(struct Gio* file, |
- NaClInstState* state, |
- const NaClInst* inst) { |
- uint32_t tree_index = 0; |
- Bool is_first = TRUE; |
- Bool not_printed_prefix_segment = TRUE; |
- NaClExp* node; |
- NaClExpVector* vector = NaClInstStateExpVector(state); |
- |
- /* Print the name of the instruction. */ |
- if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction))) { |
- /* Instruction has been simplified. Print out corresponding |
- * hints to the reader, so that they know that the instruction |
- * has been simplified. |
- */ |
- gprintf(file, "[P] "); |
- NaClPrintLower(file, (char*) NaClMnemonicName(inst->name)); |
- if (NaClHasBit(inst->flags, NACL_IFLAG(NaClIllegal))) { |
- gprintf(file, "(illegal)"); |
- } |
- } else { |
- NaClPrintLower(file, (char*) NaClMnemonicName(inst->name)); |
- } |
- |
- /* Use the generated expression tree to print out (non-implicit) operands |
- * of the instruction. |
- */ |
- while (tree_index < vector->number_expr_nodes) { |
- node = &vector->node[tree_index]; |
- if (node->kind != OperandReference || |
- (NACL_EMPTY_EFLAGS == (node->flags & NACL_EFLAG(ExprImplicit)))) { |
- if (is_first) { |
- gprintf(file, " "); |
- is_first = FALSE; |
- } else { |
- gprintf(file, ", "); |
- } |
- NaClPrintDisassembledExp(file, state, tree_index); |
- |
- /* If this is a partial instruction, add set/use information |
- * so that that it is more clear what was matched. |
- */ |
- if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction)) && |
- node->kind == OperandReference) { |
- const NaClOp* op = |
- NaClGetInstOperandInline(state->decoder_tables, |
- inst, |
- (uint8_t) NaClGetExprUnsignedValue(node)); |
- if (NaClHasBit(op->flags, (NACL_OPFLAG(OpSet) | |
- NACL_OPFLAG(OpUse) | |
- NACL_OPFLAG(OperandZeroExtends_v)))) { |
- gprintf(file, " ("); |
- NaClPrintAddOperandFlag(file, op, OpSet, "s"); |
- NaClPrintAddOperandFlag(file, op, OpUse, "u"); |
- NaClPrintAddOperandFlag(file, op, OperandZeroExtends_v, "z"); |
- gprintf(file, ")"); |
- } |
- } |
- } else if (not_printed_prefix_segment && |
- (OperandReference == node->kind) && |
- (node->flags & NACL_EFLAG(ExprImplicit))) { |
- /* Print out segment override of implicit segment address, if |
- * applicable. |
- */ |
- if (OperandReference == node->kind) { |
- int seg_addr_index = tree_index + 1; |
- if (ExprSegmentAddress == vector->node[seg_addr_index].kind) { |
- if (NaClHasSegmentOverride(vector, seg_addr_index, |
- ExprDSrCase, RegDS)) { |
- NaClPrintSegmentOverride(file, &is_first, state, vector, |
- seg_addr_index); |
- } else if (NaClHasSegmentOverride(vector, seg_addr_index, |
- ExprESrCase, RegES)) { |
- NaClPrintSegmentOverride(file, &is_first, state, vector, |
- seg_addr_index); |
- } |
- } |
- } |
- } |
- /* Skip over expression to next expresssion. */ |
- tree_index += NaClExpWidth(vector, tree_index); |
- } |
-} |
- |
-void NaClInstStateInstPrint(struct Gio* file, NaClInstState* state) { |
- int i; |
- const NaClInst* inst; |
- |
- /* Print out the address and the inst bytes. */ |
- int length = NaClInstStateLength(state); |
- |
- DEBUG_OR_ERASE( |
- NaClInstPrint(file, state->decoder_tables, NaClInstStateInst(state))); |
- DEBUG(NaClExpVectorPrint(file, state)); |
- gprintf(file, "%"NACL_PRIxNaClPcAddressAll": ", |
- NaClInstStatePrintableAddress(state)); |
- for (i = 0; i < length; ++i) { |
- gprintf(file, "%02"NACL_PRIx8" ", NaClInstStateByte(state, i)); |
- } |
- for (i = length; i < NACL_MAX_BYTES_PER_X86_INSTRUCTION; ++i) { |
- gprintf(file, " "); |
- } |
- |
- /* Print out the assembly instruction it disassembles to. */ |
- inst = NaClInstStateInst(state); |
- NaClPrintDisassembled(file, state, inst); |
- gprintf(file, "\n"); |
-} |
- |
-/* Defines a buffer size big enough to hold an instruction. */ |
-#define MAX_INST_TEXT_SIZE 256 |
- |
-char* NaClInstStateInstructionToString(struct NaClInstState* state) { |
- /* Print to a memory buffer, and then duplicate. */ |
- struct GioMemoryFile filemem; |
- struct Gio *file = (struct Gio*) &filemem; |
- char buffer[MAX_INST_TEXT_SIZE]; |
- char* result; |
- |
- /* Note: Be sure to leave an extra byte to add the null character to |
- * the end of the string. |
- */ |
- GioMemoryFileCtor(&filemem, buffer, MAX_INST_TEXT_SIZE - 1); |
- NaClInstStateInstPrint(file, state); |
- buffer[filemem.curpos < MAX_INST_TEXT_SIZE |
- ? filemem.curpos : MAX_INST_TEXT_SIZE] ='\0'; |
- result = strdup(buffer); |
- GioMemoryFileDtor(file); |
- return result; |
-} |
- |
-int NaClExpWidth(NaClExpVector* vector, int node) { |
- int i; |
- int count = 1; |
- int num_kids = NaClExpKindRank(vector->node[node].kind); |
- for (i = 0; i < num_kids; i++) { |
- count += NaClExpWidth(vector, node + count); |
- } |
- return count; |
-} |
- |
-int NaClGetExpKidIndex(NaClExpVector* vector, int node, int kid) { |
- node++; |
- while (kid-- > 0) { |
- node += NaClExpWidth(vector, node); |
- } |
- return node; |
-} |
- |
-int NaClGetExpParentIndex(NaClExpVector* vector, int index) { |
- int node_rank; |
- int num_kids = 1; |
- while (index > 0) { |
- --index; |
- node_rank = NaClExpKindRank(vector->node[index].kind); |
- if (node_rank >= num_kids) { |
- return index; |
- } else { |
- num_kids -= (node_rank - 1); |
- } |
- } |
- return -1; |
-} |
- |
-int NaClGetNthExpKind(NaClExpVector* vector, |
- NaClExpKind kind, |
- int n) { |
- if (n > 0) { |
- uint32_t i; |
- for (i = 0; i < vector->number_expr_nodes; ++i) { |
- if (kind == vector->node[i].kind) { |
- --n; |
- if (n == 0) return i; |
- } |
- } |
- } |
- return -1; |
-} |
- |
-Bool NaClIsExpNegativeConstant(NaClExpVector* vector, int index) { |
- NaClExp* node = &vector->node[index]; |
- switch (node->kind) { |
- case ExprConstant: |
- if (node->flags & NACL_EFLAG(ExprUnsignedHex) || |
- node->flags & NACL_EFLAG(ExprUnsignedInt)) { |
- return FALSE; |
- } else { |
- /* Assume signed value. */ |
- return NaClGetExprSignedValue(node) < 0; |
- } |
- break; |
- default: |
- break; |
- } |
- return FALSE; |
-} |
- |
-/* Dummy routine to allow unreferenced NaClGetInstNumberOperandsInline |
- * inline. |
- */ |
-uint8_t NaClNcopExpsDummyNaClGetInstNumberOperands(const NaClInst* inst) { |
- return NaClGetInstNumberOperandsInline(inst); |
-} |