1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #ifndef NDB_INTERPRETER_HPP
26 #define NDB_INTERPRETER_HPP
27 
28 #include <ndb_types.h>
29 
30 class Interpreter {
31 public:
32 
mod4(Uint32 len)33   inline static Uint32 mod4(Uint32 len){
34     return len + ((4 - (len & 3)) & 3);
35   }
36 
37 
38   /**
39    * General Mnemonic format
40    *
41    * i = Instruction            -  5 Bits ( 0 - 5 ) max 63
42    * x = Register 1             -  3 Bits ( 6 - 8 ) max 7
43    * y = Register 2             -  3 Bits ( 9 -11 ) max 7
44    * b = Branch offset (only branches)
45    *
46    *           1111111111222222222233
47    * 01234567890123456789012345678901
48    * iiiiiixxxyyy    bbbbbbbbbbbbbbbb
49    *
50    *
51    */
52 
53   /**
54    * Instructions
55    */
56   STATIC_CONST( READ_ATTR_INTO_REG    = 1 );
57   STATIC_CONST( WRITE_ATTR_FROM_REG   = 2 );
58   STATIC_CONST( LOAD_CONST_NULL       = 3 );
59   STATIC_CONST( LOAD_CONST16          = 4 );
60   STATIC_CONST( LOAD_CONST32          = 5 );
61   STATIC_CONST( LOAD_CONST64          = 6 );
62   STATIC_CONST( ADD_REG_REG           = 7 );
63   STATIC_CONST( SUB_REG_REG           = 8 );
64   STATIC_CONST( BRANCH                = 9 );
65   STATIC_CONST( BRANCH_REG_EQ_NULL    = 10 );
66   STATIC_CONST( BRANCH_REG_NE_NULL    = 11 );
67   STATIC_CONST( BRANCH_EQ_REG_REG     = 12 );
68   STATIC_CONST( BRANCH_NE_REG_REG     = 13 );
69   STATIC_CONST( BRANCH_LT_REG_REG     = 14 );
70   STATIC_CONST( BRANCH_LE_REG_REG     = 15 );
71   STATIC_CONST( BRANCH_GT_REG_REG     = 16 );
72   STATIC_CONST( BRANCH_GE_REG_REG     = 17 );
73   STATIC_CONST( EXIT_OK               = 18 );
74   STATIC_CONST( EXIT_REFUSE           = 19 );
75   STATIC_CONST( CALL                  = 20 );
76   STATIC_CONST( RETURN                = 21 );
77   STATIC_CONST( EXIT_OK_LAST          = 22 );
78   STATIC_CONST( BRANCH_ATTR_OP_ARG    = 23 );
79   STATIC_CONST( BRANCH_ATTR_EQ_NULL   = 24 );
80   STATIC_CONST( BRANCH_ATTR_NE_NULL   = 25 );
81   STATIC_CONST( BRANCH_ATTR_OP_ARG_2  = 26 );
82 
83   /**
84    * Macros for creating code
85    */
86   static Uint32 Read(Uint32 AttrId, Uint32 Register);
87   static Uint32 Write(Uint32 AttrId, Uint32 Register);
88 
89   static Uint32 LoadNull(Uint32 Register);
90   static Uint32 LoadConst16(Uint32 Register, Uint32 Value);
91   static Uint32 LoadConst32(Uint32 Register); // Value in next word
92   static Uint32 LoadConst64(Uint32 Register); // Value in next 2 words
93   static Uint32 Add(Uint32 DstReg, Uint32 SrcReg1, Uint32 SrcReg2);
94   static Uint32 Sub(Uint32 DstReg, Uint32 SrcReg1, Uint32 SrcReg2);
95   static Uint32 Branch(Uint32 Inst, Uint32 Reg1, Uint32 Reg2);
96   static Uint32 ExitOK();
97 
98   /**
99    * Branch OP_ARG
100    *
101    * i = Instruction              -  5 Bits ( 0 - 5 ) max 63
102    * a = Attribute id             -  16 bits
103    * l = Length of string (bytes) -  16 bits OP_ARG
104    * p = parameter no             -  16 bits OP_ARG_2
105    * b = Branch offset (words)    -  16 bits
106    * t = branch type              -  4 bits
107    * d = Array length diff
108    * v = Varchar flag
109    *
110    *           1111111111222222222233
111    * 01234567890123456789012345678901
112    * iiiiii   ddvttttbbbbbbbbbbbbbbbb
113    * aaaaaaaaaaaaaaaallllllllllllllll
114    * -string....                    -
115    */
116   enum UnaryCondition {
117     IS_NULL = 0,
118     IS_NOT_NULL = 1
119   };
120 
121   enum BinaryCondition {
122     EQ = 0,
123     NE = 1,
124     LT = 2,
125     LE = 3,
126     GT = 4,
127     GE = 5,
128     LIKE = 6,
129     NOT_LIKE = 7,
130     AND_EQ_MASK = 8,
131     AND_NE_MASK = 9,
132     AND_EQ_ZERO = 10,
133     AND_NE_ZERO = 11
134   };
135   // TODO : Remove other 2 unused parameters.
136   static Uint32 BranchCol(BinaryCondition cond,
137 			  Uint32 arrayLengthDiff, Uint32 varchar);
138   static Uint32 BranchCol_2(Uint32 AttrId);
139   static Uint32 BranchCol_2(Uint32 AttrId, Uint32 Len);
140 
141   static Uint32 BranchColParameter(BinaryCondition cond);
142   static Uint32 BranchColParameter_2(Uint32 AttrId, Uint32 ParamNo);
143 
144   static Uint32 getBinaryCondition(Uint32 op1);
145   static Uint32 getArrayLengthDiff(Uint32 op1);
146   static Uint32 isVarchar(Uint32 op1);
147   static Uint32 getBranchCol_AttrId(Uint32 op2);
148   static Uint32 getBranchCol_Len(Uint32 op2);
149   static Uint32 getBranchCol_ParamNo(Uint32 op2);
150 
151   /**
152    * Macros for decoding code
153    */
154   static Uint32 getOpCode(Uint32 op);
155   static Uint32 getReg1(Uint32 op);
156   static Uint32 getReg2(Uint32 op);
157   static Uint32 getReg3(Uint32 op);
158   static Uint32 getLabel(Uint32 op);
159 
160   /**
161    * Instruction pre-processing required.
162    */
163   enum InstructionPreProcessing
164   {
165     NONE,
166     LABEL_ADDRESS_REPLACEMENT,
167     SUB_ADDRESS_REPLACEMENT
168   };
169 
170   /* This method is used to determine what sort of
171    * instruction processing is required, and the address
172    * of the next instruction in the stream
173    */
174   static Uint32 *getInstructionPreProcessingInfo(Uint32 *op,
175                                                  InstructionPreProcessing& processing);
176 };
177 
178 inline
179 Uint32
Read(Uint32 AttrId,Uint32 Register)180 Interpreter::Read(Uint32 AttrId, Uint32 Register){
181   return (AttrId << 16) + (Register << 6) + READ_ATTR_INTO_REG;
182 }
183 
184 inline
185 Uint32
Write(Uint32 AttrId,Uint32 Register)186 Interpreter::Write(Uint32 AttrId, Uint32 Register){
187   return (AttrId << 16) + (Register << 6) + WRITE_ATTR_FROM_REG;
188 }
189 
190 inline
191 Uint32
LoadNull(Uint32 Register)192 Interpreter::LoadNull(Uint32 Register){
193   return (Register << 6) + LOAD_CONST_NULL;
194 }
195 
196 inline
197 Uint32
LoadConst16(Uint32 Register,Uint32 Value)198 Interpreter::LoadConst16(Uint32 Register, Uint32 Value){
199   return (Value << 16) + (Register << 6) + LOAD_CONST16;
200 }
201 
202 inline
203 Uint32
LoadConst32(Uint32 Register)204 Interpreter::LoadConst32(Uint32 Register){
205   return (Register << 6) + LOAD_CONST32;
206 }
207 
208 inline
209 Uint32
LoadConst64(Uint32 Register)210 Interpreter::LoadConst64(Uint32 Register){
211   return (Register << 6) + LOAD_CONST64;
212 }
213 
214 inline
215 Uint32
Add(Uint32 Dcoleg,Uint32 SrcReg1,Uint32 SrcReg2)216 Interpreter::Add(Uint32 Dcoleg, Uint32 SrcReg1, Uint32 SrcReg2){
217   return (SrcReg1 << 6) + (SrcReg2 << 9) + (Dcoleg << 16) + ADD_REG_REG;
218 }
219 
220 inline
221 Uint32
Sub(Uint32 Dcoleg,Uint32 SrcReg1,Uint32 SrcReg2)222 Interpreter::Sub(Uint32 Dcoleg, Uint32 SrcReg1, Uint32 SrcReg2){
223   return (SrcReg1 << 6) + (SrcReg2 << 9) + (Dcoleg << 16) + SUB_REG_REG;
224 }
225 
226 inline
227 Uint32
Branch(Uint32 Inst,Uint32 Reg1,Uint32 Reg2)228 Interpreter::Branch(Uint32 Inst, Uint32 Reg1, Uint32 Reg2){
229   return (Reg1 << 9) + (Reg2 << 6) + Inst;
230 }
231 
232 inline
233 Uint32
BranchCol(BinaryCondition cond,Uint32 arrayLengthDiff,Uint32 varchar)234 Interpreter::BranchCol(BinaryCondition cond,
235 		       Uint32 arrayLengthDiff,
236 		       Uint32 varchar){
237   //ndbout_c("BranchCol: cond=%d diff=%u varchar=%u",
238       //cond, arrayLengthDiff, varchar);
239   return
240     BRANCH_ATTR_OP_ARG +
241     (arrayLengthDiff << 9) +
242     (varchar << 11) +
243     (cond << 12);
244 }
245 
246 inline
247 Uint32
BranchColParameter(BinaryCondition cond)248 Interpreter::BranchColParameter(BinaryCondition cond)
249 {
250   return BRANCH_ATTR_OP_ARG_2 + (cond << 12);
251 }
252 
253 inline
254 Uint32
BranchColParameter_2(Uint32 AttrId,Uint32 ParamNo)255 Interpreter::BranchColParameter_2(Uint32 AttrId, Uint32 ParamNo){
256   return (AttrId << 16) + ParamNo;
257 }
258 
259 inline
260 Uint32
BranchCol_2(Uint32 AttrId,Uint32 Len)261 Interpreter::BranchCol_2(Uint32 AttrId, Uint32 Len){
262   return (AttrId << 16) + Len;
263 }
264 
265 inline
266 Uint32
BranchCol_2(Uint32 AttrId)267 Interpreter::BranchCol_2(Uint32 AttrId){
268   return (AttrId << 16);
269 }
270 
271 inline
272 Uint32
getBinaryCondition(Uint32 op)273 Interpreter::getBinaryCondition(Uint32 op){
274   return (op >> 12) & 0xf;
275 }
276 
277 inline
278 Uint32
getArrayLengthDiff(Uint32 op)279 Interpreter::getArrayLengthDiff(Uint32 op){
280   return (op >> 9) & 0x3;
281 }
282 
283 inline
284 Uint32
isVarchar(Uint32 op)285 Interpreter::isVarchar(Uint32 op){
286   return (op >> 11) & 1;
287 }
288 
289 inline
290 Uint32
getBranchCol_AttrId(Uint32 op)291 Interpreter::getBranchCol_AttrId(Uint32 op){
292   return (op >> 16) & 0xFFFF;
293 }
294 
295 inline
296 Uint32
getBranchCol_Len(Uint32 op)297 Interpreter::getBranchCol_Len(Uint32 op){
298   return op & 0xFFFF;
299 }
300 
301 inline
302 Uint32
getBranchCol_ParamNo(Uint32 op)303 Interpreter::getBranchCol_ParamNo(Uint32 op){
304   return op & 0xFFFF;
305 }
306 
307 inline
308 Uint32
ExitOK()309 Interpreter::ExitOK(){
310   return EXIT_OK;
311 }
312 
313 inline
314 Uint32
getOpCode(Uint32 op)315 Interpreter::getOpCode(Uint32 op){
316   return op & 0x3f;
317 }
318 
319 inline
320 Uint32
getReg1(Uint32 op)321 Interpreter::getReg1(Uint32 op){
322   return (op >> 6) & 0x7;
323 }
324 
325 inline
326 Uint32
getReg2(Uint32 op)327 Interpreter::getReg2(Uint32 op){
328   return (op >> 9) & 0x7;
329 }
330 
331 inline
332 Uint32
getReg3(Uint32 op)333 Interpreter::getReg3(Uint32 op){
334   return (op >> 16) & 0x7;
335 }
336 
337 inline
338 Uint32
getLabel(Uint32 op)339 Interpreter::getLabel(Uint32 op){
340   return (op >> 16) & 0xffff;
341 }
342 
343 inline
344 Uint32*
getInstructionPreProcessingInfo(Uint32 * op,InstructionPreProcessing & processing)345 Interpreter::getInstructionPreProcessingInfo(Uint32 *op,
346                                              InstructionPreProcessing& processing )
347 {
348   /* Given an instruction, get a pointer to the
349    * next instruction in the stream.
350    * Returns NULL on error.
351    */
352   processing= NONE;
353   Uint32 opCode= getOpCode(*op);
354 
355   switch( opCode )
356   {
357   case READ_ATTR_INTO_REG:
358   case WRITE_ATTR_FROM_REG:
359   case LOAD_CONST_NULL:
360   case LOAD_CONST16:
361     return op + 1;
362   case LOAD_CONST32:
363     return op + 2;
364   case LOAD_CONST64:
365     return op + 3;
366   case ADD_REG_REG:
367   case SUB_REG_REG:
368     return op + 1;
369   case BRANCH:
370   case BRANCH_REG_EQ_NULL:
371   case BRANCH_REG_NE_NULL:
372   case BRANCH_EQ_REG_REG:
373   case BRANCH_NE_REG_REG:
374   case BRANCH_LT_REG_REG:
375   case BRANCH_LE_REG_REG:
376   case BRANCH_GT_REG_REG:
377   case BRANCH_GE_REG_REG:
378     processing= LABEL_ADDRESS_REPLACEMENT;
379     return op + 1;
380   case BRANCH_ATTR_OP_ARG:
381   {
382     /* We need to take the length from the second word of the
383      * branch instruction so we can skip over the inline const
384      * comparison data.
385      */
386     processing= LABEL_ADDRESS_REPLACEMENT;
387     Uint32 byteLength= getBranchCol_Len(*(op+1));
388     Uint32 wordLength= (byteLength + 3) >> 2;
389     return op+2+wordLength;
390   }
391   case BRANCH_ATTR_OP_ARG_2:
392   {
393     /* We need to take the length from the second word of the
394      * branch instruction so we can skip over the inline const
395      * comparison data.
396      */
397     processing= LABEL_ADDRESS_REPLACEMENT;
398     return op+2;
399   }
400   case BRANCH_ATTR_EQ_NULL:
401   case BRANCH_ATTR_NE_NULL:
402     processing= LABEL_ADDRESS_REPLACEMENT;
403     return op+2;
404   case EXIT_OK:
405   case EXIT_OK_LAST:
406   case EXIT_REFUSE:
407     return op+1;
408   case CALL:
409     processing= SUB_ADDRESS_REPLACEMENT;
410   case RETURN:
411     return op+1;
412 
413   default:
414     return NULL;
415   }
416 }
417 
418 #endif
419