1 /*
2    Copyright (c) 2003, 2021, Oracle and/or its affiliates.
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 
86   /**
87    * Macros for creating code
88    */
89   static Uint32 Read(Uint32 AttrId, Uint32 Register);
90   static Uint32 Write(Uint32 AttrId, Uint32 Register);
91 
92   static Uint32 LoadNull(Uint32 Register);
93   static Uint32 LoadConst16(Uint32 Register, Uint32 Value);
94   static Uint32 LoadConst32(Uint32 Register); // Value in next word
95   static Uint32 LoadConst64(Uint32 Register); // Value in next 2 words
96   static Uint32 Add(Uint32 DstReg, Uint32 SrcReg1, Uint32 SrcReg2);
97   static Uint32 Sub(Uint32 DstReg, Uint32 SrcReg1, Uint32 SrcReg2);
98   static Uint32 Branch(Uint32 Inst, Uint32 Reg1, Uint32 Reg2);
99   static Uint32 ExitOK();
100   static Uint32 ExitLastOK();
101 
102   /**
103    * Branch OP_ARG
104    *
105    * i = Instruction              -  5 Bits ( 0 - 5 ) max 63
106    * a = Attribute id             -  16 bits
107    * l = Length of string (bytes) -  16 bits OP_ARG
108    * p = parameter no             -  16 bits OP_ARG_2
109    * b = Branch offset (words)    -  16 bits
110    * t = branch type              -  4 bits
111    * d = Array length diff
112    * v = Varchar flag
113    *
114    *           1111111111222222222233
115    * 01234567890123456789012345678901
116    * iiiiii   ddvttttbbbbbbbbbbbbbbbb
117    * aaaaaaaaaaaaaaaallllllllllllllll
118    * -string....                    -
119    */
120   enum UnaryCondition {
121     IS_NULL = 0,
122     IS_NOT_NULL = 1
123   };
124 
125   enum BinaryCondition {
126     EQ = 0,
127     NE = 1,
128     LT = 2,
129     LE = 3,
130     GT = 4,
131     GE = 5,
132     LIKE = 6,
133     NOT_LIKE = 7,
134     AND_EQ_MASK = 8,
135     AND_NE_MASK = 9,
136     AND_EQ_ZERO = 10,
137     AND_NE_ZERO = 11
138   };
139   // TODO : Remove other 2 unused parameters.
140   static Uint32 BranchCol(BinaryCondition cond,
141 			  Uint32 arrayLengthDiff, Uint32 varchar);
142   static Uint32 BranchCol_2(Uint32 AttrId);
143   static Uint32 BranchCol_2(Uint32 AttrId, Uint32 Len);
144 
145   static Uint32 BranchColParameter(BinaryCondition cond);
146   static Uint32 BranchColParameter_2(Uint32 AttrId, Uint32 ParamNo);
147 
148   static Uint32 getBinaryCondition(Uint32 op1);
149   static Uint32 getArrayLengthDiff(Uint32 op1);
150   static Uint32 isVarchar(Uint32 op1);
151   static Uint32 getBranchCol_AttrId(Uint32 op2);
152   static Uint32 getBranchCol_Len(Uint32 op2);
153   static Uint32 getBranchCol_ParamNo(Uint32 op2);
154 
155   /**
156    * Macros for decoding code
157    */
158   static Uint32 getOpCode(Uint32 op);
159   static Uint32 getReg1(Uint32 op);
160   static Uint32 getReg2(Uint32 op);
161   static Uint32 getReg3(Uint32 op);
162   static Uint32 getLabel(Uint32 op);
163 
164   /**
165    * Instruction pre-processing required.
166    */
167   enum InstructionPreProcessing
168   {
169     NONE,
170     LABEL_ADDRESS_REPLACEMENT,
171     SUB_ADDRESS_REPLACEMENT
172   };
173 
174   /* This method is used to determine what sort of
175    * instruction processing is required, and the address
176    * of the next instruction in the stream
177    */
178   static Uint32 *getInstructionPreProcessingInfo(Uint32 *op,
179                                                  InstructionPreProcessing& processing);
180 };
181 
182 inline
183 Uint32
Read(Uint32 AttrId,Uint32 Register)184 Interpreter::Read(Uint32 AttrId, Uint32 Register){
185   return (AttrId << 16) + (Register << 6) + READ_ATTR_INTO_REG;
186 }
187 
188 inline
189 Uint32
Write(Uint32 AttrId,Uint32 Register)190 Interpreter::Write(Uint32 AttrId, Uint32 Register){
191   return (AttrId << 16) + (Register << 6) + WRITE_ATTR_FROM_REG;
192 }
193 
194 inline
195 Uint32
LoadNull(Uint32 Register)196 Interpreter::LoadNull(Uint32 Register){
197   return (Register << 6) + LOAD_CONST_NULL;
198 }
199 
200 inline
201 Uint32
LoadConst16(Uint32 Register,Uint32 Value)202 Interpreter::LoadConst16(Uint32 Register, Uint32 Value){
203   return (Value << 16) + (Register << 6) + LOAD_CONST16;
204 }
205 
206 inline
207 Uint32
LoadConst32(Uint32 Register)208 Interpreter::LoadConst32(Uint32 Register){
209   return (Register << 6) + LOAD_CONST32;
210 }
211 
212 inline
213 Uint32
LoadConst64(Uint32 Register)214 Interpreter::LoadConst64(Uint32 Register){
215   return (Register << 6) + LOAD_CONST64;
216 }
217 
218 inline
219 Uint32
Add(Uint32 Dcoleg,Uint32 SrcReg1,Uint32 SrcReg2)220 Interpreter::Add(Uint32 Dcoleg, Uint32 SrcReg1, Uint32 SrcReg2){
221   return (SrcReg1 << 6) + (SrcReg2 << 9) + (Dcoleg << 16) + ADD_REG_REG;
222 }
223 
224 inline
225 Uint32
Sub(Uint32 Dcoleg,Uint32 SrcReg1,Uint32 SrcReg2)226 Interpreter::Sub(Uint32 Dcoleg, Uint32 SrcReg1, Uint32 SrcReg2){
227   return (SrcReg1 << 6) + (SrcReg2 << 9) + (Dcoleg << 16) + SUB_REG_REG;
228 }
229 
230 inline
231 Uint32
Branch(Uint32 Inst,Uint32 Reg1,Uint32 Reg2)232 Interpreter::Branch(Uint32 Inst, Uint32 Reg1, Uint32 Reg2){
233   return (Reg1 << 9) + (Reg2 << 6) + Inst;
234 }
235 
236 inline
237 Uint32
BranchCol(BinaryCondition cond,Uint32 arrayLengthDiff,Uint32 varchar)238 Interpreter::BranchCol(BinaryCondition cond,
239 		       Uint32 arrayLengthDiff,
240 		       Uint32 varchar){
241   //ndbout_c("BranchCol: cond=%d diff=%u varchar=%u",
242       //cond, arrayLengthDiff, varchar);
243   return
244     BRANCH_ATTR_OP_ARG +
245     (arrayLengthDiff << 9) +
246     (varchar << 11) +
247     (cond << 12);
248 }
249 
250 inline
251 Uint32
BranchColParameter(BinaryCondition cond)252 Interpreter::BranchColParameter(BinaryCondition cond)
253 {
254   return BRANCH_ATTR_OP_ARG_2 + (cond << 12);
255 }
256 
257 inline
258 Uint32
BranchColParameter_2(Uint32 AttrId,Uint32 ParamNo)259 Interpreter::BranchColParameter_2(Uint32 AttrId, Uint32 ParamNo){
260   return (AttrId << 16) + ParamNo;
261 }
262 
263 inline
264 Uint32
BranchCol_2(Uint32 AttrId,Uint32 Len)265 Interpreter::BranchCol_2(Uint32 AttrId, Uint32 Len){
266   return (AttrId << 16) + Len;
267 }
268 
269 inline
270 Uint32
BranchCol_2(Uint32 AttrId)271 Interpreter::BranchCol_2(Uint32 AttrId){
272   return (AttrId << 16);
273 }
274 
275 inline
276 Uint32
getBinaryCondition(Uint32 op)277 Interpreter::getBinaryCondition(Uint32 op){
278   return (op >> 12) & 0xf;
279 }
280 
281 inline
282 Uint32
getArrayLengthDiff(Uint32 op)283 Interpreter::getArrayLengthDiff(Uint32 op){
284   return (op >> 9) & 0x3;
285 }
286 
287 inline
288 Uint32
isVarchar(Uint32 op)289 Interpreter::isVarchar(Uint32 op){
290   return (op >> 11) & 1;
291 }
292 
293 inline
294 Uint32
getBranchCol_AttrId(Uint32 op)295 Interpreter::getBranchCol_AttrId(Uint32 op){
296   return (op >> 16) & 0xFFFF;
297 }
298 
299 inline
300 Uint32
getBranchCol_Len(Uint32 op)301 Interpreter::getBranchCol_Len(Uint32 op){
302   return op & 0xFFFF;
303 }
304 
305 inline
306 Uint32
getBranchCol_ParamNo(Uint32 op)307 Interpreter::getBranchCol_ParamNo(Uint32 op){
308   return op & 0xFFFF;
309 }
310 
311 inline
312 Uint32
ExitOK()313 Interpreter::ExitOK(){
314   return EXIT_OK;
315 }
316 
317 inline
318 Uint32
ExitLastOK()319 Interpreter::ExitLastOK(){
320   return EXIT_OK_LAST;
321 }
322 
323 inline
324 Uint32
getOpCode(Uint32 op)325 Interpreter::getOpCode(Uint32 op){
326   return op & 0x3f;
327 }
328 
329 inline
330 Uint32
getReg1(Uint32 op)331 Interpreter::getReg1(Uint32 op){
332   return (op >> 6) & 0x7;
333 }
334 
335 inline
336 Uint32
getReg2(Uint32 op)337 Interpreter::getReg2(Uint32 op){
338   return (op >> 9) & 0x7;
339 }
340 
341 inline
342 Uint32
getReg3(Uint32 op)343 Interpreter::getReg3(Uint32 op){
344   return (op >> 16) & 0x7;
345 }
346 
347 inline
348 Uint32
getLabel(Uint32 op)349 Interpreter::getLabel(Uint32 op){
350   return (op >> 16) & 0xffff;
351 }
352 
353 inline
354 Uint32*
getInstructionPreProcessingInfo(Uint32 * op,InstructionPreProcessing & processing)355 Interpreter::getInstructionPreProcessingInfo(Uint32 *op,
356                                              InstructionPreProcessing& processing )
357 {
358   /* Given an instruction, get a pointer to the
359    * next instruction in the stream.
360    * Returns NULL on error.
361    */
362   processing= NONE;
363   Uint32 opCode= getOpCode(*op);
364 
365   switch( opCode )
366   {
367   case READ_ATTR_INTO_REG:
368   case WRITE_ATTR_FROM_REG:
369   case LOAD_CONST_NULL:
370   case LOAD_CONST16:
371     return op + 1;
372   case LOAD_CONST32:
373     return op + 2;
374   case LOAD_CONST64:
375     return op + 3;
376   case ADD_REG_REG:
377   case SUB_REG_REG:
378     return op + 1;
379   case BRANCH:
380   case BRANCH_REG_EQ_NULL:
381   case BRANCH_REG_NE_NULL:
382   case BRANCH_EQ_REG_REG:
383   case BRANCH_NE_REG_REG:
384   case BRANCH_LT_REG_REG:
385   case BRANCH_LE_REG_REG:
386   case BRANCH_GT_REG_REG:
387   case BRANCH_GE_REG_REG:
388     processing= LABEL_ADDRESS_REPLACEMENT;
389     return op + 1;
390   case BRANCH_ATTR_OP_ARG:
391   {
392     /* We need to take the length from the second word of the
393      * branch instruction so we can skip over the inline const
394      * comparison data.
395      */
396     processing= LABEL_ADDRESS_REPLACEMENT;
397     Uint32 byteLength= getBranchCol_Len(*(op+1));
398     Uint32 wordLength= (byteLength + 3) >> 2;
399     return op+2+wordLength;
400   }
401   case BRANCH_ATTR_OP_ARG_2:
402   {
403     /* We need to take the length from the second word of the
404      * branch instruction so we can skip over the inline const
405      * comparison data.
406      */
407     processing= LABEL_ADDRESS_REPLACEMENT;
408     return op+2;
409   }
410   case BRANCH_ATTR_EQ_NULL:
411   case BRANCH_ATTR_NE_NULL:
412     processing= LABEL_ADDRESS_REPLACEMENT;
413     return op+2;
414   case EXIT_OK:
415   case EXIT_OK_LAST:
416   case EXIT_REFUSE:
417     return op+1;
418   case CALL:
419     processing= SUB_ADDRESS_REPLACEMENT;
420   case RETURN:
421     return op+1;
422 
423   default:
424     return NULL;
425   }
426 }
427 
428 
429 #undef JAM_FILE_ID
430 
431 #endif
432