polardbxengine/storage/ndb/include/kernel/Interpreter.hpp

490 lines
12 KiB
C++

/*
Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have included with MySQL.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License, version 2.0, for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef NDB_INTERPRETER_HPP
#define NDB_INTERPRETER_HPP
#include <ndb_types.h>
#define JAM_FILE_ID 215
class Interpreter {
public:
inline static Uint32 mod4(Uint32 len){
return len + ((4 - (len & 3)) & 3);
}
/**
* General Mnemonic format
*
* i = Instruction - 5 Bits ( 0 - 5 ) max 63
* x = Register 1 - 3 Bits ( 6 - 8 ) max 7
* y = Register 2 - 3 Bits ( 9 -11 ) max 7
* b = Branch offset (only branches)
*
* 1111111111222222222233
* 01234567890123456789012345678901
* iiiiiixxxyyy bbbbbbbbbbbbbbbb
*
*
*/
/**
* Instructions
*/
STATIC_CONST( READ_ATTR_INTO_REG = 1 );
STATIC_CONST( WRITE_ATTR_FROM_REG = 2 );
STATIC_CONST( LOAD_CONST_NULL = 3 );
STATIC_CONST( LOAD_CONST16 = 4 );
STATIC_CONST( LOAD_CONST32 = 5 );
STATIC_CONST( LOAD_CONST64 = 6 );
STATIC_CONST( ADD_REG_REG = 7 );
STATIC_CONST( SUB_REG_REG = 8 );
STATIC_CONST( BRANCH = 9 );
STATIC_CONST( BRANCH_REG_EQ_NULL = 10 );
STATIC_CONST( BRANCH_REG_NE_NULL = 11 );
STATIC_CONST( BRANCH_EQ_REG_REG = 12 );
STATIC_CONST( BRANCH_NE_REG_REG = 13 );
STATIC_CONST( BRANCH_LT_REG_REG = 14 );
STATIC_CONST( BRANCH_LE_REG_REG = 15 );
STATIC_CONST( BRANCH_GT_REG_REG = 16 );
STATIC_CONST( BRANCH_GE_REG_REG = 17 );
STATIC_CONST( EXIT_OK = 18 );
STATIC_CONST( EXIT_REFUSE = 19 );
STATIC_CONST( CALL = 20 );
STATIC_CONST( RETURN = 21 );
STATIC_CONST( EXIT_OK_LAST = 22 );
STATIC_CONST( BRANCH_ATTR_OP_ARG = 23 );
STATIC_CONST( BRANCH_ATTR_EQ_NULL = 24 );
STATIC_CONST( BRANCH_ATTR_NE_NULL = 25 );
STATIC_CONST( BRANCH_ATTR_OP_ARG_2 = 26 );
STATIC_CONST( BRANCH_ATTR_OP_ATTR = 27 );
/**
* Macros for creating code
*/
static Uint32 Read(Uint32 AttrId, Uint32 Register);
static Uint32 Write(Uint32 AttrId, Uint32 Register);
static Uint32 LoadNull(Uint32 Register);
static Uint32 LoadConst16(Uint32 Register, Uint32 Value);
static Uint32 LoadConst32(Uint32 Register); // Value in next word
static Uint32 LoadConst64(Uint32 Register); // Value in next 2 words
static Uint32 Add(Uint32 DstReg, Uint32 SrcReg1, Uint32 SrcReg2);
static Uint32 Sub(Uint32 DstReg, Uint32 SrcReg1, Uint32 SrcReg2);
static Uint32 Branch(Uint32 Inst, Uint32 Reg1, Uint32 Reg2);
static Uint32 ExitOK();
static Uint32 ExitLastOK();
/**
* Branch OP_ARG (Attr1 <op> <value arg>)
*
* i = Instruction - 5 Bits ( 0 - 5 ) max 63
* a = Attribute id - 16 bits
* l = Length of string (bytes) - 16 bits OP_ARG
* p = parameter no - 16 bits OP_ARG_2
* b = Branch offset (words) - 16 bits
* t = branch type - 4 bits
* d = Array length diff
* v = Varchar flag
*
* 1111111111222222222233
* 01234567890123456789012345678901
* iiiiii ddvttttbbbbbbbbbbbbbbbb
* aaaaaaaaaaaaaaaallllllllllllllll
* -string.... -
*
*
* Branch OP_ARG_2 (Attr1 <op> <ParamNo>)
*
* i = Instruction - 5 Bits ( 0 - 5 ) max 63
* a = Attribute id - 16 bits
* p = parameter no - 16 bits OP_ARG_2
* b = Branch offset (words) - 16 bits
* t = branch type - 4 bits
*
* 1111111111222222222233
* 01234567890123456789012345678901
* iiiiii ttttbbbbbbbbbbbbbbbb
* aaaaaaaaaaaaaaaapppppppppppppppp
*
*
* Branch OP_ATTR (Attr1 <op> Attr2)
*
* i = Instruction - 5 Bits ( 0 - 5 ) max 63
* a = Attribute id1 - 16 bits
* A = Attribute id2 - 16 bits
* b = Branch offset (words) - 16 bits
* t = branch type - 4 bits
*
* 1111111111222222222233
* 01234567890123456789012345678901
* iiiiii ttttbbbbbbbbbbbbbbbb
* aaaaaaaaaaaaaaaaAAAAAAAAAAAAAAAA
*/
enum UnaryCondition {
IS_NULL = 0,
IS_NOT_NULL = 1
};
enum BinaryCondition {
EQ = 0,
NE = 1,
LT = 2,
LE = 3,
GT = 4,
GE = 5,
LIKE = 6,
NOT_LIKE = 7,
AND_EQ_MASK = 8,
AND_NE_MASK = 9,
AND_EQ_ZERO = 10,
AND_NE_ZERO = 11
};
// Compare Attr with literal
// TODO : Remove other 2 unused parameters.
static Uint32 BranchCol(BinaryCondition cond,
Uint32 arrayLengthDiff, Uint32 varchar);
static Uint32 BranchCol_2(Uint32 AttrId);
static Uint32 BranchCol_2(Uint32 AttrId, Uint32 Len);
// Compare Attr with parameter
static Uint32 BranchColParameter(BinaryCondition cond);
static Uint32 BranchColParameter_2(Uint32 AttrId, Uint32 ParamNo);
// Compare two Attr from same table
static Uint32 BranchColAttrId(BinaryCondition cond);
static Uint32 BranchColAttrId_2(Uint32 AttrId1, Uint32 AttrId2);
static Uint32 getBinaryCondition(Uint32 op1);
static Uint32 getArrayLengthDiff(Uint32 op1);
static Uint32 isVarchar(Uint32 op1);
static Uint32 getBranchCol_AttrId(Uint32 op2);
static Uint32 getBranchCol_AttrId2(Uint32 op2);
static Uint32 getBranchCol_Len(Uint32 op2);
static Uint32 getBranchCol_ParamNo(Uint32 op2);
/**
* Macros for decoding code
*/
static Uint32 getOpCode(Uint32 op);
static Uint32 getReg1(Uint32 op);
static Uint32 getReg2(Uint32 op);
static Uint32 getReg3(Uint32 op);
static Uint32 getLabel(Uint32 op);
/**
* Instruction pre-processing required.
*/
enum InstructionPreProcessing
{
NONE,
LABEL_ADDRESS_REPLACEMENT,
SUB_ADDRESS_REPLACEMENT
};
/* This method is used to determine what sort of
* instruction processing is required, and the address
* of the next instruction in the stream
*/
static Uint32 *getInstructionPreProcessingInfo(Uint32 *op,
InstructionPreProcessing& processing);
};
inline
Uint32
Interpreter::Read(Uint32 AttrId, Uint32 Register){
return (AttrId << 16) + (Register << 6) + READ_ATTR_INTO_REG;
}
inline
Uint32
Interpreter::Write(Uint32 AttrId, Uint32 Register){
return (AttrId << 16) + (Register << 6) + WRITE_ATTR_FROM_REG;
}
inline
Uint32
Interpreter::LoadNull(Uint32 Register){
return (Register << 6) + LOAD_CONST_NULL;
}
inline
Uint32
Interpreter::LoadConst16(Uint32 Register, Uint32 Value){
return (Value << 16) + (Register << 6) + LOAD_CONST16;
}
inline
Uint32
Interpreter::LoadConst32(Uint32 Register){
return (Register << 6) + LOAD_CONST32;
}
inline
Uint32
Interpreter::LoadConst64(Uint32 Register){
return (Register << 6) + LOAD_CONST64;
}
inline
Uint32
Interpreter::Add(Uint32 Dcoleg, Uint32 SrcReg1, Uint32 SrcReg2){
return (SrcReg1 << 6) + (SrcReg2 << 9) + (Dcoleg << 16) + ADD_REG_REG;
}
inline
Uint32
Interpreter::Sub(Uint32 Dcoleg, Uint32 SrcReg1, Uint32 SrcReg2){
return (SrcReg1 << 6) + (SrcReg2 << 9) + (Dcoleg << 16) + SUB_REG_REG;
}
inline
Uint32
Interpreter::Branch(Uint32 Inst, Uint32 Reg1, Uint32 Reg2){
return (Reg1 << 9) + (Reg2 << 6) + Inst;
}
inline
Uint32
Interpreter::BranchColAttrId(BinaryCondition cond) {
return
BRANCH_ATTR_OP_ATTR + // Compare two ATTRs
(cond << 12);
}
inline
Uint32
Interpreter::BranchColAttrId_2(Uint32 AttrId1, Uint32 AttrId2) {
return (AttrId1 << 16) + AttrId2;
}
inline
Uint32
Interpreter::BranchCol(BinaryCondition cond,
Uint32 arrayLengthDiff,
Uint32 varchar){
//ndbout_c("BranchCol: cond=%d diff=%u varchar=%u",
//cond, arrayLengthDiff, varchar);
return
BRANCH_ATTR_OP_ARG +
(arrayLengthDiff << 9) +
(varchar << 11) +
(cond << 12);
}
inline
Uint32
Interpreter::BranchColParameter(BinaryCondition cond)
{
return BRANCH_ATTR_OP_ARG_2 + (cond << 12);
}
inline
Uint32
Interpreter::BranchColParameter_2(Uint32 AttrId, Uint32 ParamNo){
return (AttrId << 16) + ParamNo;
}
inline
Uint32
Interpreter::BranchCol_2(Uint32 AttrId, Uint32 Len){
return (AttrId << 16) + Len;
}
inline
Uint32
Interpreter::BranchCol_2(Uint32 AttrId){
return (AttrId << 16);
}
inline
Uint32
Interpreter::getBinaryCondition(Uint32 op){
return (op >> 12) & 0xf;
}
inline
Uint32
Interpreter::getArrayLengthDiff(Uint32 op){
return (op >> 9) & 0x3;
}
inline
Uint32
Interpreter::isVarchar(Uint32 op){
return (op >> 11) & 1;
}
inline
Uint32
Interpreter::getBranchCol_AttrId(Uint32 op){
return (op >> 16) & 0xFFFF;
}
inline
Uint32
Interpreter::getBranchCol_AttrId2(Uint32 op){
return op & 0xFFFF;
}
inline
Uint32
Interpreter::getBranchCol_Len(Uint32 op){
return op & 0xFFFF;
}
inline
Uint32
Interpreter::getBranchCol_ParamNo(Uint32 op){
return op & 0xFFFF;
}
inline
Uint32
Interpreter::ExitOK(){
return EXIT_OK;
}
inline
Uint32
Interpreter::ExitLastOK(){
return EXIT_OK_LAST;
}
inline
Uint32
Interpreter::getOpCode(Uint32 op){
return op & 0x3f;
}
inline
Uint32
Interpreter::getReg1(Uint32 op){
return (op >> 6) & 0x7;
}
inline
Uint32
Interpreter::getReg2(Uint32 op){
return (op >> 9) & 0x7;
}
inline
Uint32
Interpreter::getReg3(Uint32 op){
return (op >> 16) & 0x7;
}
inline
Uint32
Interpreter::getLabel(Uint32 op){
return (op >> 16) & 0xffff;
}
inline
Uint32*
Interpreter::getInstructionPreProcessingInfo(Uint32 *op,
InstructionPreProcessing& processing )
{
/* Given an instruction, get a pointer to the
* next instruction in the stream.
* Returns NULL on error.
*/
processing= NONE;
Uint32 opCode= getOpCode(*op);
switch( opCode )
{
case READ_ATTR_INTO_REG:
case WRITE_ATTR_FROM_REG:
case LOAD_CONST_NULL:
case LOAD_CONST16:
return op + 1;
case LOAD_CONST32:
return op + 2;
case LOAD_CONST64:
return op + 3;
case ADD_REG_REG:
case SUB_REG_REG:
return op + 1;
case BRANCH:
case BRANCH_REG_EQ_NULL:
case BRANCH_REG_NE_NULL:
case BRANCH_EQ_REG_REG:
case BRANCH_NE_REG_REG:
case BRANCH_LT_REG_REG:
case BRANCH_LE_REG_REG:
case BRANCH_GT_REG_REG:
case BRANCH_GE_REG_REG:
processing= LABEL_ADDRESS_REPLACEMENT;
return op + 1;
case BRANCH_ATTR_OP_ARG:
{
/* We need to take the length from the second word of the
* branch instruction so we can skip over the inline const
* comparison data.
*/
processing= LABEL_ADDRESS_REPLACEMENT;
Uint32 byteLength= getBranchCol_Len(*(op+1));
Uint32 wordLength= (byteLength + 3) >> 2;
return op + 2 + wordLength;
}
case BRANCH_ATTR_OP_ARG_2:
case BRANCH_ATTR_OP_ATTR:
{
/* Second word of the branch instruction refer either paramNo
* or attrId to be compared -> fixed length.
*/
processing= LABEL_ADDRESS_REPLACEMENT;
return op + 2;
}
case BRANCH_ATTR_EQ_NULL:
case BRANCH_ATTR_NE_NULL:
processing= LABEL_ADDRESS_REPLACEMENT;
return op + 2;
case EXIT_OK:
case EXIT_OK_LAST:
case EXIT_REFUSE:
return op + 1;
case CALL:
processing= SUB_ADDRESS_REPLACEMENT;
return op + 1;
case RETURN:
return op + 1;
default:
return NULL;
}
}
#undef JAM_FILE_ID
#endif