1 /*
2    Copyright (c) 2003, 2019, 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 #define JAM_FILE_ID 215
31 
32 
33 class Interpreter {
34 public:
35 
mod4(Uint32 len)36   inline static Uint32 mod4(Uint32 len){
37     return len + ((4 - (len & 3)) & 3);
38   }
39 
40 
41   /**
42    * General Mnemonic format
43    *
44    * i = Instruction            -  5 Bits ( 0 - 5 ) max 63
45    * x = Register 1             -  3 Bits ( 6 - 8 ) max 7
46    * y = Register 2             -  3 Bits ( 9 -11 ) max 7
47    * b = Branch offset (only branches)
48    *
49    *           1111111111222222222233
50    * 01234567890123456789012345678901
51    * iiiiiixxxyyy    bbbbbbbbbbbbbbbb
52    *
53    *
54    */
55 
56   /**
57    * Instructions
58    */
59   STATIC_CONST( READ_ATTR_INTO_REG    = 1 );
60   STATIC_CONST( WRITE_ATTR_FROM_REG   = 2 );
61   STATIC_CONST( LOAD_CONST_NULL       = 3 );
62   STATIC_CONST( LOAD_CONST16          = 4 );
63   STATIC_CONST( LOAD_CONST32          = 5 );
64   STATIC_CONST( LOAD_CONST64          = 6 );
65   STATIC_CONST( ADD_REG_REG           = 7 );
66   STATIC_CONST( SUB_REG_REG           = 8 );
67   STATIC_CONST( BRANCH                = 9 );
68   STATIC_CONST( BRANCH_REG_EQ_NULL    = 10 );
69   STATIC_CONST( BRANCH_REG_NE_NULL    = 11 );
70   STATIC_CONST( BRANCH_EQ_REG_REG     = 12 );
71   STATIC_CONST( BRANCH_NE_REG_REG     = 13 );
72   STATIC_CONST( BRANCH_LT_REG_REG     = 14 );
73   STATIC_CONST( BRANCH_LE_REG_REG     = 15 );
74   STATIC_CONST( BRANCH_GT_REG_REG     = 16 );
75   STATIC_CONST( BRANCH_GE_REG_REG     = 17 );
76   STATIC_CONST( EXIT_OK               = 18 );
77   STATIC_CONST( EXIT_REFUSE           = 19 );
78   STATIC_CONST( CALL                  = 20 );
79   STATIC_CONST( RETURN                = 21 );
80   STATIC_CONST( EXIT_OK_LAST          = 22 );
81   STATIC_CONST( BRANCH_ATTR_OP_ARG    = 23 );
82   STATIC_CONST( BRANCH_ATTR_EQ_NULL   = 24 );
83   STATIC_CONST( BRANCH_ATTR_NE_NULL   = 25 );
84   STATIC_CONST( BRANCH_ATTR_OP_ARG_2  = 26 );
85   STATIC_CONST( BRANCH_ATTR_OP_ATTR   = 27 );
86 
87   /**
88    * Macros for creating code
89    */
90   static Uint32 Read(Uint32 AttrId, Uint32 Register);
91   static Uint32 Write(Uint32 AttrId, Uint32 Register);
92 
93   static Uint32 LoadNull(Uint32 Register);
94   static Uint32 LoadConst16(Uint32 Register, Uint32 Value);
95   static Uint32 LoadConst32(Uint32 Register); // Value in next word
96   static Uint32 LoadConst64(Uint32 Register); // Value in next 2 words
97   static Uint32 Add(Uint32 DstReg, Uint32 SrcReg1, Uint32 SrcReg2);
98   static Uint32 Sub(Uint32 DstReg, Uint32 SrcReg1, Uint32 SrcReg2);
99   static Uint32 Branch(Uint32 Inst, Uint32 Reg1, Uint32 Reg2);
100   static Uint32 ExitOK();
101   static Uint32 ExitLastOK();
102 
103   /**
104    * Branch OP_ARG (Attr1 <op> <value arg>)
105    *
106    * i = Instruction              -  5 Bits ( 0 - 5 ) max 63
107    * a = Attribute id             -  16 bits
108    * l = Length of string (bytes) -  16 bits OP_ARG
109    * p = parameter no             -  16 bits OP_ARG_2
110    * b = Branch offset (words)    -  16 bits
111    * t = branch type              -  4 bits
112    * d = Array length diff
113    * v = Varchar flag
114    *
115    *           1111111111222222222233
116    * 01234567890123456789012345678901
117    * iiiiii   ddvttttbbbbbbbbbbbbbbbb
118    * aaaaaaaaaaaaaaaallllllllllllllll
119    * -string....                    -
120    *
121    *
122    * Branch OP_ARG_2 (Attr1 <op> <ParamNo>)
123    *
124    * i = Instruction              -  5 Bits ( 0 - 5 ) max 63
125    * a = Attribute id             -  16 bits
126    * p = parameter no             -  16 bits OP_ARG_2
127    * b = Branch offset (words)    -  16 bits
128    * t = branch type              -  4 bits
129    *
130    *           1111111111222222222233
131    * 01234567890123456789012345678901
132    * iiiiii      ttttbbbbbbbbbbbbbbbb
133    * aaaaaaaaaaaaaaaapppppppppppppppp
134    *
135    *
136    * Branch OP_ATTR (Attr1 <op> Attr2)
137    *
138    * i = Instruction              -  5 Bits ( 0 - 5 ) max 63
139    * a = Attribute id1            -  16 bits
140    * A = Attribute id2            -  16 bits
141    * b = Branch offset (words)    -  16 bits
142    * t = branch type              -  4 bits
143    *
144    *           1111111111222222222233
145    * 01234567890123456789012345678901
146    * iiiiii      ttttbbbbbbbbbbbbbbbb
147    * aaaaaaaaaaaaaaaaAAAAAAAAAAAAAAAA
148    */
149 
150   enum UnaryCondition {
151     IS_NULL = 0,
152     IS_NOT_NULL = 1
153   };
154 
155   enum BinaryCondition {
156     EQ = 0,
157     NE = 1,
158     LT = 2,
159     LE = 3,
160     GT = 4,
161     GE = 5,
162     LIKE = 6,
163     NOT_LIKE = 7,
164     AND_EQ_MASK = 8,
165     AND_NE_MASK = 9,
166     AND_EQ_ZERO = 10,
167     AND_NE_ZERO = 11
168   };
169   // Compare Attr with literal
170   // TODO : Remove other 2 unused parameters.
171   static Uint32 BranchCol(BinaryCondition cond,
172 			  Uint32 arrayLengthDiff, Uint32 varchar);
173   static Uint32 BranchCol_2(Uint32 AttrId);
174   static Uint32 BranchCol_2(Uint32 AttrId, Uint32 Len);
175 
176   // Compare Attr with parameter
177   static Uint32 BranchColParameter(BinaryCondition cond);
178   static Uint32 BranchColParameter_2(Uint32 AttrId, Uint32 ParamNo);
179 
180   // Compare two Attr from same table
181   static Uint32 BranchColAttrId(BinaryCondition cond);
182   static Uint32 BranchColAttrId_2(Uint32 AttrId1, Uint32 AttrId2);
183 
184   static Uint32 getBinaryCondition(Uint32 op1);
185   static Uint32 getArrayLengthDiff(Uint32 op1);
186   static Uint32 isVarchar(Uint32 op1);
187   static Uint32 getBranchCol_AttrId(Uint32 op2);
188   static Uint32 getBranchCol_AttrId2(Uint32 op2);
189   static Uint32 getBranchCol_Len(Uint32 op2);
190   static Uint32 getBranchCol_ParamNo(Uint32 op2);
191 
192   /**
193    * Macros for decoding code
194    */
195   static Uint32 getOpCode(Uint32 op);
196   static Uint32 getReg1(Uint32 op);
197   static Uint32 getReg2(Uint32 op);
198   static Uint32 getReg3(Uint32 op);
199   static Uint32 getLabel(Uint32 op);
200 
201   /**
202    * Instruction pre-processing required.
203    */
204   enum InstructionPreProcessing
205   {
206     NONE,
207     LABEL_ADDRESS_REPLACEMENT,
208     SUB_ADDRESS_REPLACEMENT
209   };
210 
211   /* This method is used to determine what sort of
212    * instruction processing is required, and the address
213    * of the next instruction in the stream
214    */
215   static Uint32 *getInstructionPreProcessingInfo(Uint32 *op,
216                                                  InstructionPreProcessing& processing);
217 };
218 
219 inline
220 Uint32
Read(Uint32 AttrId,Uint32 Register)221 Interpreter::Read(Uint32 AttrId, Uint32 Register){
222   return (AttrId << 16) + (Register << 6) + READ_ATTR_INTO_REG;
223 }
224 
225 inline
226 Uint32
Write(Uint32 AttrId,Uint32 Register)227 Interpreter::Write(Uint32 AttrId, Uint32 Register){
228   return (AttrId << 16) + (Register << 6) + WRITE_ATTR_FROM_REG;
229 }
230 
231 inline
232 Uint32
LoadNull(Uint32 Register)233 Interpreter::LoadNull(Uint32 Register){
234   return (Register << 6) + LOAD_CONST_NULL;
235 }
236 
237 inline
238 Uint32
LoadConst16(Uint32 Register,Uint32 Value)239 Interpreter::LoadConst16(Uint32 Register, Uint32 Value){
240   return (Value << 16) + (Register << 6) + LOAD_CONST16;
241 }
242 
243 inline
244 Uint32
LoadConst32(Uint32 Register)245 Interpreter::LoadConst32(Uint32 Register){
246   return (Register << 6) + LOAD_CONST32;
247 }
248 
249 inline
250 Uint32
LoadConst64(Uint32 Register)251 Interpreter::LoadConst64(Uint32 Register){
252   return (Register << 6) + LOAD_CONST64;
253 }
254 
255 inline
256 Uint32
Add(Uint32 Dcoleg,Uint32 SrcReg1,Uint32 SrcReg2)257 Interpreter::Add(Uint32 Dcoleg, Uint32 SrcReg1, Uint32 SrcReg2){
258   return (SrcReg1 << 6) + (SrcReg2 << 9) + (Dcoleg << 16) + ADD_REG_REG;
259 }
260 
261 inline
262 Uint32
Sub(Uint32 Dcoleg,Uint32 SrcReg1,Uint32 SrcReg2)263 Interpreter::Sub(Uint32 Dcoleg, Uint32 SrcReg1, Uint32 SrcReg2){
264   return (SrcReg1 << 6) + (SrcReg2 << 9) + (Dcoleg << 16) + SUB_REG_REG;
265 }
266 
267 inline
268 Uint32
Branch(Uint32 Inst,Uint32 Reg1,Uint32 Reg2)269 Interpreter::Branch(Uint32 Inst, Uint32 Reg1, Uint32 Reg2){
270   return (Reg1 << 9) + (Reg2 << 6) + Inst;
271 }
272 
273 inline
274 Uint32
BranchColAttrId(BinaryCondition cond)275 Interpreter::BranchColAttrId(BinaryCondition cond) {
276   return
277     BRANCH_ATTR_OP_ATTR +     // Compare two ATTRs
278     (cond << 12);
279 }
280 
281 inline
282 Uint32
BranchColAttrId_2(Uint32 AttrId1,Uint32 AttrId2)283 Interpreter::BranchColAttrId_2(Uint32 AttrId1, Uint32 AttrId2) {
284   return (AttrId1 << 16) + AttrId2;
285 }
286 
287 inline
288 Uint32
BranchCol(BinaryCondition cond,Uint32 arrayLengthDiff,Uint32 varchar)289 Interpreter::BranchCol(BinaryCondition cond,
290 		       Uint32 arrayLengthDiff,
291 		       Uint32 varchar){
292   //ndbout_c("BranchCol: cond=%d diff=%u varchar=%u",
293       //cond, arrayLengthDiff, varchar);
294   return
295     BRANCH_ATTR_OP_ARG +
296     (arrayLengthDiff << 9) +
297     (varchar << 11) +
298     (cond << 12);
299 }
300 
301 inline
302 Uint32
BranchColParameter(BinaryCondition cond)303 Interpreter::BranchColParameter(BinaryCondition cond)
304 {
305   return BRANCH_ATTR_OP_ARG_2 + (cond << 12);
306 }
307 
308 inline
309 Uint32
BranchColParameter_2(Uint32 AttrId,Uint32 ParamNo)310 Interpreter::BranchColParameter_2(Uint32 AttrId, Uint32 ParamNo){
311   return (AttrId << 16) + ParamNo;
312 }
313 
314 inline
315 Uint32
BranchCol_2(Uint32 AttrId,Uint32 Len)316 Interpreter::BranchCol_2(Uint32 AttrId, Uint32 Len){
317   return (AttrId << 16) + Len;
318 }
319 
320 inline
321 Uint32
BranchCol_2(Uint32 AttrId)322 Interpreter::BranchCol_2(Uint32 AttrId){
323   return (AttrId << 16);
324 }
325 
326 inline
327 Uint32
getBinaryCondition(Uint32 op)328 Interpreter::getBinaryCondition(Uint32 op){
329   return (op >> 12) & 0xf;
330 }
331 
332 inline
333 Uint32
getArrayLengthDiff(Uint32 op)334 Interpreter::getArrayLengthDiff(Uint32 op){
335   return (op >> 9) & 0x3;
336 }
337 
338 inline
339 Uint32
isVarchar(Uint32 op)340 Interpreter::isVarchar(Uint32 op){
341   return (op >> 11) & 1;
342 }
343 
344 inline
345 Uint32
getBranchCol_AttrId(Uint32 op)346 Interpreter::getBranchCol_AttrId(Uint32 op){
347   return (op >> 16) & 0xFFFF;
348 }
349 
350 inline
351 Uint32
getBranchCol_AttrId2(Uint32 op)352 Interpreter::getBranchCol_AttrId2(Uint32 op){
353   return op & 0xFFFF;
354 }
355 
356 inline
357 Uint32
getBranchCol_Len(Uint32 op)358 Interpreter::getBranchCol_Len(Uint32 op){
359   return op & 0xFFFF;
360 }
361 
362 inline
363 Uint32
getBranchCol_ParamNo(Uint32 op)364 Interpreter::getBranchCol_ParamNo(Uint32 op){
365   return op & 0xFFFF;
366 }
367 
368 inline
369 Uint32
ExitOK()370 Interpreter::ExitOK(){
371   return EXIT_OK;
372 }
373 
374 inline
375 Uint32
ExitLastOK()376 Interpreter::ExitLastOK(){
377   return EXIT_OK_LAST;
378 }
379 
380 inline
381 Uint32
getOpCode(Uint32 op)382 Interpreter::getOpCode(Uint32 op){
383   return op & 0x3f;
384 }
385 
386 inline
387 Uint32
getReg1(Uint32 op)388 Interpreter::getReg1(Uint32 op){
389   return (op >> 6) & 0x7;
390 }
391 
392 inline
393 Uint32
getReg2(Uint32 op)394 Interpreter::getReg2(Uint32 op){
395   return (op >> 9) & 0x7;
396 }
397 
398 inline
399 Uint32
getReg3(Uint32 op)400 Interpreter::getReg3(Uint32 op){
401   return (op >> 16) & 0x7;
402 }
403 
404 inline
405 Uint32
getLabel(Uint32 op)406 Interpreter::getLabel(Uint32 op){
407   return (op >> 16) & 0xffff;
408 }
409 
410 inline
411 Uint32*
getInstructionPreProcessingInfo(Uint32 * op,InstructionPreProcessing & processing)412 Interpreter::getInstructionPreProcessingInfo(Uint32 *op,
413                                              InstructionPreProcessing& processing )
414 {
415   /* Given an instruction, get a pointer to the
416    * next instruction in the stream.
417    * Returns NULL on error.
418    */
419   processing= NONE;
420   Uint32 opCode= getOpCode(*op);
421 
422   switch( opCode )
423   {
424   case READ_ATTR_INTO_REG:
425   case WRITE_ATTR_FROM_REG:
426   case LOAD_CONST_NULL:
427   case LOAD_CONST16:
428     return op + 1;
429   case LOAD_CONST32:
430     return op + 2;
431   case LOAD_CONST64:
432     return op + 3;
433   case ADD_REG_REG:
434   case SUB_REG_REG:
435     return op + 1;
436   case BRANCH:
437   case BRANCH_REG_EQ_NULL:
438   case BRANCH_REG_NE_NULL:
439   case BRANCH_EQ_REG_REG:
440   case BRANCH_NE_REG_REG:
441   case BRANCH_LT_REG_REG:
442   case BRANCH_LE_REG_REG:
443   case BRANCH_GT_REG_REG:
444   case BRANCH_GE_REG_REG:
445     processing= LABEL_ADDRESS_REPLACEMENT;
446     return op + 1;
447   case BRANCH_ATTR_OP_ARG:
448   {
449     /* We need to take the length from the second word of the
450      * branch instruction so we can skip over the inline const
451      * comparison data.
452      */
453     processing= LABEL_ADDRESS_REPLACEMENT;
454     Uint32 byteLength= getBranchCol_Len(*(op+1));
455     Uint32 wordLength= (byteLength + 3) >> 2;
456     return op + 2 + wordLength;
457   }
458   case BRANCH_ATTR_OP_ARG_2:
459   case BRANCH_ATTR_OP_ATTR:
460   {
461     /* Second word of the branch instruction refer either paramNo
462      * or attrId to be compared -> fixed length.
463      */
464     processing= LABEL_ADDRESS_REPLACEMENT;
465     return op + 2;
466   }
467   case BRANCH_ATTR_EQ_NULL:
468   case BRANCH_ATTR_NE_NULL:
469     processing= LABEL_ADDRESS_REPLACEMENT;
470     return op + 2;
471   case EXIT_OK:
472   case EXIT_OK_LAST:
473   case EXIT_REFUSE:
474     return op + 1;
475   case CALL:
476     processing= SUB_ADDRESS_REPLACEMENT;
477     return op + 1;
478   case RETURN:
479     return op + 1;
480 
481   default:
482     return NULL;
483   }
484 }
485 
486 
487 #undef JAM_FILE_ID
488 
489 #endif
490