Added features to dyninstAPI library, including the ability to delete
[dyninst.git] / dyninstAPI / src / ast.C
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 /* 
43  * $Log: ast.C,v $
44  * Revision 1.41  1997/04/29 16:58:50  buck
45  * Added features to dyninstAPI library, including the ability to delete
46  * inserted snippets and the start of type checking.
47  *
48  * Revision 1.1.1.1  1997/04/01 20:24:59  buck
49  * Update Maryland repository with latest from Wisconsin.
50  *
51  * Revision 1.40  1997/03/18 19:44:07  buck
52  * first commit of dyninst library.  Also includes:
53  *      moving templates from paradynd to dyninstAPI
54  *      converting showError into a function (in showerror.C)
55  *      many ifdefs for BPATCH_LIBRARY in dyinstAPI/src.
56  *
57  * Revision 1.39  1997/03/14 15:58:59  lzheng
58  * Dealing with complier optimization related to the return value
59  *
60  * Revision 1.38  1997/02/26 23:42:48  mjrg
61  * First part on WindowsNT port: changes for compiling with Visual C++;
62  * moved unix specific code to unix.C
63  *
64  * Revision 1.37  1997/02/21 20:13:16  naim
65  * Moving files from paradynd to dyninstAPI + moving references to dataReqNode
66  * out of the ast class. The is the first pre-dyninstAPI commit! - naim
67  *
68  * Revision 1.36  1997/01/27 19:40:36  naim
69  * Part of the base instrumentation for supporting multithreaded applications
70  * (vectors of counter/timers) implemented for all current platforms +
71  * different bug fixes - naim
72  *
73  * Revision 1.35  1996/11/14 14:42:52  naim
74  * Minor fix to my previous commit - naim
75  *
76  * Revision 1.34  1996/11/14 14:26:57  naim
77  * Changing AstNodes back to pointers to improve performance - naim
78  *
79  * Revision 1.33  1996/11/12 17:48:34  mjrg
80  * Moved the computation of cost to the basetramp in the x86 platform,
81  * and changed other platform to keep code consistent.
82  * Removed warnings, and made changes for compiling with Visual C++
83  *
84  * Revision 1.32  1996/11/11 01:45:30  lzheng
85  * Moved the instructions which is used to caculate the observed cost
86  * from the miniTramps to baseTramp
87  *
88  * Revision 1.31  1996/10/31 08:36:58  tamches
89  * the shm-sampling commit; added noCost param to some fns
90  *
91  * Revision 1.30  1996/10/04 16:12:38  naim
92  * Optimization for code generation (use of immediate operations whenever
93  * possible). This first commit is only for the sparc platform. Other platforms
94  * should follow soon - naim
95  *
96  * Revision 1.29  1996/09/13 21:41:57  mjrg
97  * Implemented opcode ReturnVal for ast's to get the return value of functions.
98  * Added missing calls to free registers in Ast.generateCode and emitFuncCall.
99  * Removed architecture dependencies from inst.C.
100  * Changed code to allow base tramps of variable size.
101  *
102  * Revision 1.28  1996/08/21 18:02:35  mjrg
103  * Changed the ast nodes generated for timers. This just affects the ast
104  * nodes, not the code generated.
105  *
106  * Revision 1.27  1996/08/20 19:07:30  lzheng
107  * Implementation of moving multiple instructions sequence and
108  * splitting the instrumentations into two phases.
109  *
110  * Revision 1.26  1996/08/16 21:18:14  tamches
111  * updated copyright for release 1.1
112  *
113  * Revision 1.25  1996/05/12 05:15:56  tamches
114  * aix 4.1 commit
115  *
116  * Revision 1.24  1996/04/26 20:16:16  lzheng
117  * Move part of code in AstNode::generateCode to machine dependent file.
118  * (Those code are put into the procedure emitFuncCall)
119  *
120  * Revision 1.23  1996/04/10 18:00:11  lzheng
121  * Added multiple arguments to calls for HPUX by using stack instead of extra
122  * registers.
123  *
124  * Revision 1.22  1996/04/08 21:21:11  lzheng
125  * changes for HP generateCode and emitFuncCall
126  *
127  * Revision 1.21  1996/03/25 20:20:39  tamches
128  * the reduce-mem-leaks-in-paradynd commit
129  *
130  * Revision 1.20  1996/03/20 17:02:36  mjrg
131  * Added multiple arguments to calls.
132  * Instrument pvm_send instead of pvm_recv to get tags.
133  *
134  * Revision 1.19  1995/12/19 01:04:44  hollings
135  * Moved the implementation of registerSpace::readOnlyRegister to processor
136  *   specific files (since it is).
137  * Fixed a bug in Power relOps cases.
138  *
139  */
140
141 #include "dyninstAPI/src/symtab.h"
142 #include "dyninstAPI/src/process.h"
143 #include "dyninstAPI/src/inst.h"
144 #include "dyninstAPI/src/instP.h"
145 #include "dyninstAPI/src/dyninstP.h"
146 #include "dyninstAPI/src/ast.h"
147 #include "dyninstAPI/src/util.h"
148 #include "paradynd/src/showerror.h"
149 #include "dyninstAPI/h/BPatch.h"
150 #include "dyninstAPI/src/BPatch_type.h"
151
152 #ifndef BPATCH_LIBRARY
153 #include "rtinst/h/rtinst.h"
154 #include "paradynd/src/metric.h"
155 #endif
156
157 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)
158 #include "dyninstAPI/src/inst-sparc.h"
159 #elif defined(hppa1_1_hp_hpux)
160 #include "dyninstAPI/src/inst-hppa.h"
161 #elif defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
162 #include "dyninstAPI/src/inst-power.h"
163 #elif defined(i386_unknown_solaris2_5) || defined(i386_unknown_nt4_0)
164 #include "dyninstAPI/src/inst-x86.h"
165 #else
166 #endif
167
168 extern registerSpace *regSpace;
169 extern bool doNotOverflow(int value);
170
171 registerSpace::registerSpace(int deadCount, int *dead, int liveCount, int *live)
172 {
173     int i;
174
175     numRegisters = deadCount + liveCount;
176     registers = new registerSlot[numRegisters];
177
178     // load dead ones
179     for (i=0; i < deadCount; i++) {
180         registers[i].number = dead[i];
181         registers[i].inUse = false;
182         registers[i].mustRestore = false;
183         registers[i].needsSaving = false;
184         registers[i].startsLive = false;
185     }
186
187     // load live ones;
188     for (i=0; i < liveCount; i++) {
189         registers[i+deadCount].number = live[i];
190         registers[i+deadCount].inUse = false;
191         registers[i+deadCount].mustRestore = false;
192         registers[i+deadCount].needsSaving = true;
193         registers[i+deadCount].startsLive = true;
194 #if defined(MT_THREAD)
195         if (registers[i+deadCount].number == REG_MT) {
196           registers[i+deadCount].inUse = true;
197           registers[i+deadCount].needsSaving = true;
198         }
199 #endif
200     }
201
202 }
203
204 reg registerSpace::allocateRegister(char *insn, unsigned &base, bool noCost) 
205 {
206     int i;
207     for (i=0; i < numRegisters; i++) {
208         if (!registers[i].inUse && !registers[i].needsSaving) {
209             registers[i].inUse = true;
210             highWaterRegister = (highWaterRegister > i) ? 
211                  highWaterRegister : i;
212             return(registers[i].number);
213         }
214     }
215
216     // now consider ones that need saving
217     for (i=0; i < numRegisters; i++) {
218         if (!registers[i].inUse) {
219 #if !defined(rs6000_ibm_aix4_1)
220             // MT_AIX: we are not saving registers on demand on the power
221             // architecture. Instead, we save/restore registers in the base
222             // trampoline - naim
223             emit(saveRegOp, registers[i].number, 0, 0, insn, base, noCost);
224 #endif
225             registers[i].inUse = true;
226 #if !defined(rs6000_ibm_aix4_1)
227             // MT_AIX
228             registers[i].mustRestore = true;
229 #endif
230             // prevent general spill (func call) from saving this register.
231             registers[i].needsSaving = false;
232             highWaterRegister = (highWaterRegister > i) ? 
233                  highWaterRegister : i;
234             return(registers[i].number);
235         }
236     }
237
238     logLine("==> WARNING! run out of registers...\n");
239     abort();
240     return(-1);
241 }
242
243 bool registerSpace::is_keep_register(reg k)
244 {
245   for (unsigned i=0;i<keep_list.size();i++) {
246     if (keep_list[i]==k) return(true);
247   }
248   return(false);
249 }
250
251 void registerSpace::keep_register(reg k)
252 {
253   if (!is_keep_register(k)) {
254     keep_list += k;
255 #if defined(ASTDEBUG)
256     sprintf(errorLine,"==> keeping register %d, size is %d <==\n",k,keep_list.size());
257     logLine(errorLine);
258 #endif
259   }
260 }
261
262 void registerSpace::unkeep_register(reg k) {
263   unsigned ksize = keep_list.size();
264   for (unsigned i=0;i<ksize;i++) {
265     if (keep_list[i]==k) {
266       keep_list[i]=keep_list[ksize-1];
267       ksize--;
268       keep_list.resize(ksize);
269       freeRegister(k);
270 #if defined(ASTDEBUG)
271       sprintf(errorLine,"==> un-keeping register %d, size is %d <==\n",k,keep_list.size());
272       logLine(errorLine);
273 #endif
274       break;
275     }
276   }
277 }
278
279 void registerSpace::freeRegister(int reg) {
280     int i;
281     if (is_keep_register(reg)) return;
282     for (i=0; i < numRegisters; i++) {
283         if (registers[i].number == reg) {
284             registers[i].inUse = false;
285             return;
286         }
287     }
288 }
289
290 bool registerSpace::isFreeRegister(int reg) {
291     int i;
292     for (i=0; i < numRegisters; i++) {
293         if ((registers[i].number == reg) &&
294             (registers[i].inUse == true)) {
295             return false;
296         }
297     }
298     return true;
299 }
300
301 void registerSpace::resetSpace() {
302     int i;
303     for (i=0; i < numRegisters; i++) {
304         if (registers[i].inUse && (registers[i].number != REG_MT)) {
305           sprintf(errorLine,"WARNING: register %d is still in use\n",registers[i].number);
306           logLine(errorLine);
307         }
308         registers[i].inUse = false;
309         registers[i].mustRestore = false;
310         registers[i].needsSaving = registers[i].startsLive;
311 #if defined(MT_THREAD)
312         if (registers[i].number == REG_MT) {
313           registers[i].inUse = true;
314           registers[i].needsSaving = true;
315         }
316 #endif
317     }
318     highWaterRegister = 0;
319 }
320
321 //
322 // How to use AstNodes:
323 //
324 // In order to avoid memory leaks, it is important to define and delete
325 // AstNodes properly. The general rules are the following:
326 //
327 // 1.- Any AstNode defined locally, should be destroyed at the end of that
328 //     procedure. The only exception occurs when we are returning a pointer
329 //     to the AstNode as a result of the function (i.e. we need to keep the
330 //     value alive).
331 // 2.- Every time we assign an AstNode to another, we have to use the
332 //     "assignAst" function. This function will update the reference count
333 //     of the AstNode being assigned and it will return a pointer to it. If
334 //     we are creating a new AstNode (e.g. AstNode *t1 = new AstNode(...))
335 //     then it is not necessary to use assign, because the constructor will
336 //     automatically increment the reference count for us.
337 // 3.- "removeAst" is the procedure to be used everytime we want to delete
338 //     an AstNode. In general, if an AstNode is re-used several times, it
339 //     should be enough to delete the root of the DAG to delete all nodes.
340 //     However, there are exceptions like this one:
341 //     AstNode *t1, *t2, *t3;
342 //     t1 = AstNode(...);   rc-t1=1
343 //     t2 = AstNode(...);   rc-t2=1
344 //     t3 = AstNode(t1,t2); rc-t1=2, rc-t2=2, rc-t3=1
345 //     if we say:
346 //     removeAst(t3);
347 //     it will delete t3, but not t1 or t2 (because the rc will be 1 for both
348 //     of them). Therefore, we need to add the following:
349 //     removeAst(t1); removeAst(t2);
350 //     We only delete AstNodes when the reference count is 0.
351 //
352
353 AstNode &AstNode::operator=(const AstNode &src) {
354    logLine("Calling AstNode COPY constructor\n");
355    if (&src == this)
356       return *this; // the usual check for x=x
357
358    // clean up self before overwriting self; i.e., release memory
359    // currently in use so it doesn't become leaked.
360    if (loperand) {
361       if (src.loperand) {
362         if (loperand!=src.loperand) {
363           removeAst(loperand);
364         }
365       } else {
366         removeAst(loperand);
367       }
368    }
369    if (roperand) {
370       if (src.roperand) {
371         if (roperand!=src.roperand) {
372           removeAst(roperand);
373         }
374       } else {
375         removeAst(roperand);
376       }
377    }
378    if (type == operandNode && oType == ConstantString)
379        free((char *)oValue);
380    referenceCount = src.referenceCount;
381    referenceCount++;
382
383    type = src.type;
384    if (type == opCodeNode)
385       op = src.op; // defined only for operand nodes
386
387    if (type == callNode) {
388       callee = src.callee; // defined only for call nodes
389       for (unsigned i=0;i<src.operands.size();i++) 
390         operands += assignAst(src.operands[i]);
391    }
392
393    if (type == operandNode) {
394       oType = src.oType;
395       // XXX This is for the string type.  If/when we fix the string type to
396       // make it less of a hack, we'll need to change this.
397       if (oType == ConstantString)
398           oValue = P_strdup((char *)src.oValue);
399       else
400           oValue = src.oValue;
401    }
402
403    loperand = assignAst(src.loperand);
404    roperand = assignAst(src.roperand);
405
406    firstInsn = src.firstInsn;
407    lastInsn = src.lastInsn;
408
409 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)
410    astFlag = src.astFlag;
411 #endif
412
413    bptype = src.bptype;
414    doTypeCheck = src.doTypeCheck;
415
416    return *this;
417 }
418
419 #if defined(ASTDEBUG)
420 static int ASTcount=0;
421
422 void ASTcounter()
423 {
424   ASTcount++;
425   sprintf(errorLine,"AstNode CONSTRUCTOR - ASTcount is %d\n",ASTcount);
426   logLine(errorLine);
427 }
428
429 void ASTcounterNP()
430 {
431   ASTcount++;
432 }
433 #endif
434
435 AstNode::AstNode() {
436 #if defined(ASTDEBUG)
437    ASTcounter();
438 #endif
439 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
440     astFlag = false;
441 #endif
442    // used in mdl.C
443    type = opCodeNode;
444    op = noOp;
445    loperand = roperand = NULL;
446    referenceCount = 1;
447    useCount = 0;
448    kept_register = -1;
449    // "operands" is left as an empty vector
450    bptype = NULL;
451    doTypeCheck = true;
452 }
453
454 AstNode::AstNode(const string &func, AstNode *l, AstNode *r) {
455 #if defined(ASTDEBUG)
456     ASTcounter();
457 #endif
458 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
459     astFlag = false;
460 #endif
461     referenceCount = 1;
462     useCount = 0;
463     kept_register = -1;
464     type = callNode;
465     callee = func;
466     if (l) operands += assignAst(l);
467     if (r) operands += assignAst(r);
468     bptype = NULL;
469     doTypeCheck = true;
470 }
471
472 AstNode::AstNode(const string &func, AstNode *l) {
473 #if defined(ASTDEBUG)
474     ASTcounter();
475 #endif
476 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
477     astFlag = false;
478 #endif
479     referenceCount = 1;
480     useCount = 0;
481     kept_register = -1;
482     loperand = assignAst(l);
483     roperand = NULL;
484     type = callNode;
485     callee = func;
486     if (l) operands += assignAst(l);
487     bptype = NULL;
488     doTypeCheck = true;
489 }
490
491 AstNode::AstNode(const string &func, vector<AstNode *> &ast_args) {
492 #if defined(ASTDEBUG)
493    ASTcounter();
494 #endif
495 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
496     astFlag = false;
497 #endif
498    referenceCount = 1;
499    useCount = 0;
500    kept_register = -1;
501    for (unsigned i=0;i<ast_args.size();i++) 
502      if (ast_args[i]) operands += assignAst(ast_args[i]);
503    loperand = roperand = NULL;
504    type = callNode;
505    callee = func;
506    bptype = NULL;
507    doTypeCheck = true;
508 }
509
510 AstNode::AstNode(operandType ot, void *arg) {
511 #if defined(ASTDEBUG)
512     ASTcounterNP();
513 #endif
514 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
515     astFlag = false;
516 #endif
517     referenceCount = 1;
518     useCount = 0;
519     kept_register = -1;
520     type = operandNode;
521     oType = ot;
522     if (ot == ConstantString)
523         oValue = (void *)P_strdup((char *)arg);
524     else
525         oValue = (void *) arg;
526     loperand = roperand = NULL;
527     bptype = NULL;
528     doTypeCheck = true;
529 };
530
531 AstNode::AstNode(operandType ot, AstNode *l) {
532 #if defined(ASTDEBUG)
533     ASTcounter();
534 #endif
535 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
536     astFlag = false;
537 #endif
538     referenceCount = 1;
539     useCount = 0;
540     kept_register = -1;
541     type = operandNode;
542     oType = ot;
543     oValue = NULL;
544     roperand = NULL;
545     loperand = assignAst(l);
546     bptype = NULL;
547     doTypeCheck = true;
548 };
549
550 AstNode::AstNode(AstNode *l, AstNode *r) {
551 #if defined(ASTDEBUG)
552    ASTcounter();
553 #endif
554 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
555     astFlag = false;
556 #endif
557    referenceCount = 1;
558    useCount = 0;
559    kept_register = -1;
560    type = sequenceNode;
561    loperand = assignAst(l);
562    roperand = assignAst(r);
563    bptype = NULL;
564    doTypeCheck = true;
565 };
566
567 AstNode::AstNode(opCode ot) {
568 #if defined(ASTDEBUG)
569    ASTcounter();
570 #endif
571 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
572     astFlag = false;
573 #endif
574    // a private constructor
575    referenceCount = 1;
576    useCount = 0;
577    kept_register = -1;
578    type = opCodeNode;
579    op = ot;
580    loperand = roperand = NULL;
581    bptype = NULL;
582    doTypeCheck = true;
583 }
584
585 AstNode::AstNode(opCode ot, AstNode *l) {
586 #if defined(ASTDEBUG)
587    ASTcounter();
588 #endif
589 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
590     astFlag = false;
591 #endif
592    // a private constructor
593    referenceCount = 1;
594    useCount = 0;
595    kept_register = -1;
596    type = opCodeNode;
597    op = ot;
598    loperand = assignAst(l);
599    roperand = NULL;
600    bptype = NULL;
601    doTypeCheck = true;
602 }
603
604 AstNode::AstNode(opCode ot, AstNode *l, AstNode *r) {
605 #if defined(ASTDEBUG)
606    ASTcounter();
607 #endif
608 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
609     astFlag = false;
610 #endif
611    referenceCount = 1;
612    useCount = 0;
613    kept_register = -1;
614    type = opCodeNode;
615    op = ot;
616    loperand = assignAst(l);
617    roperand = assignAst(r);
618    bptype = NULL;
619    doTypeCheck = true;
620 };
621
622 AstNode::AstNode(AstNode *src) {
623 #if defined(ASTDEBUG)
624    ASTcounter();
625 #endif
626 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
627     astFlag = false;
628 #endif
629    referenceCount = 1;
630    useCount = 0;
631    kept_register = -1;
632
633    type = src->type;   
634    if (type == opCodeNode)
635       op = src->op;             // defined only for operand nodes
636
637    if (type == callNode) {
638       callee = src->callee;     // defined only for call nodes
639       for (unsigned i=0;i<src->operands.size();i++) {
640         if (src->operands[i]) operands += assignAst(src->operands[i]);
641       }
642    }
643
644    if (type == operandNode) {
645       oType = src->oType;
646       // XXX This is for the string type.  If/when we fix the string type to
647       // make it less of a hack, we'll need to change this.
648       if (oType == ConstantString)
649           oValue = P_strdup((char *)src->oValue);
650       else
651           oValue = src->oValue;
652    }
653
654    loperand = assignAst(src->loperand);
655    roperand = assignAst(src->roperand);
656    firstInsn = src->firstInsn;
657    lastInsn = src->lastInsn;
658    bptype = src->bptype;
659    doTypeCheck = src->doTypeCheck;
660 }
661
662 #if defined(ASTDEBUG)
663 void AstNode::printRC()
664 {
665     sprintf(errorLine,"RC referenceCount=%d\n",referenceCount);
666     logLine(errorLine);
667     if (loperand) {
668       logLine("RC loperand\n");
669       loperand->printRC();
670     }
671     if (roperand) {
672       logLine("RC roperand\n");
673       roperand->printRC();
674     }
675 }
676 #endif
677
678 AstNode::~AstNode() {
679 #if defined(ASTDEBUG)
680   ASTcount--;
681   sprintf(errorLine,"AstNode DESTRUCTOR - ASTcount is %d\n",ASTcount);
682   logLine(errorLine);
683 #endif
684   if (loperand) {
685     removeAst(loperand);
686   }
687   if (roperand) {
688     removeAst(roperand);
689   }
690   if (type==callNode) {
691     for (unsigned i=0;i<operands.size();i++) {
692       removeAst(operands[i]);
693     }
694   } else if (type == operandNode && oType == ConstantString) {
695       free(oValue);
696   }
697 }
698
699 //
700 // Increments/decrements the reference counter for the operands of a call 
701 // node. If "flag" is true, it increments the counter. Otherwise, it 
702 // decrements it.
703 //
704 void AstNode::updateOperandsRC(bool flag)
705 {
706   if (type==callNode) {
707     for (unsigned i=0;i<operands.size();i++) {
708       if (operands[i]) {
709         if (flag) operands[i]->referenceCount++;
710         else operands[i]->referenceCount--;
711       }
712     }
713   }
714 }
715
716 //
717 // This procedure should be use every time we assign an AstNode pointer,
718 // because it increments the reference counter.
719 //
720 AstNode *assignAst(AstNode *src) {
721   if (src) {
722     src->referenceCount++;
723     src->updateOperandsRC(true);
724   }
725   return(src);
726 }
727
728 //
729 // Decrements the reference count for "ast". If it is "0", it calls the 
730 // AstNode destructor.
731 //
732 void removeAst(AstNode *&ast) {
733   if (ast) {
734     assert(ast->referenceCount>0);
735     ast->referenceCount--;
736     if (ast->referenceCount==0) {
737       delete ast;
738       ast=NULL;
739     } else {
740       ast->updateOperandsRC(false);
741     }
742   }
743 }
744
745 //
746 // This procedure decrements the reference count for "ast" until it is 0.
747 //
748 void terminateAst(AstNode *&ast) {
749   while (ast) {
750     removeAst(ast);
751   }
752 }
753
754 int AstNode::generateTramp(process *proc, char *i, 
755                            unsigned &count, 
756                            int &trampCost, bool noCost) {
757     static AstNode *trailer=NULL;
758     if (!trailer) trailer = new AstNode(trampTrailer); // private constructor
759                                                        // used to estimate cost
760     static AstNode *preambleTemplate=NULL;
761     if (!preambleTemplate) {
762       AstNode *tmp1 = new AstNode(Constant, (void *) 0);
763       preambleTemplate = new AstNode(trampPreamble, tmp1);
764       removeAst(tmp1);
765     }
766     // private constructor; assumes NULL for right child
767     
768     trampCost = preambleTemplate->cost() + cost() + trailer->cost();
769     int cycles = trampCost;
770
771     AstNode *preamble, *tmp2;
772     tmp2 = new AstNode(Constant, (void *) cycles);
773     preamble = new AstNode(trampPreamble, tmp2); 
774     removeAst(tmp2);
775     // private constructor; assumes NULL for right child
776
777     initTramps(); // needed to initialize regSpace below
778                   // shouldn't we do a "delete regSpace" first to avoid
779                   // leaking memory?
780
781     regSpace->resetSpace();
782     reg return_reg;
783     if (type != opCodeNode || op != noOp) {
784         reg tmp;
785         preamble->generateCode(proc, regSpace, i, count, noCost);
786         removeAst(preamble);
787         tmp = generateCode(proc, regSpace, i, count, noCost);
788         regSpace->freeRegister(tmp);
789         return_reg = trailer->generateCode(proc, regSpace, i, count, noCost);
790     } else {
791         removeAst(preamble);
792         return_reg = (unsigned) emit(op, 1, 0, 0, i, count, noCost);
793     }
794     regSpace->resetSpace();
795     return(return_reg);
796 }
797
798 bool isPowerOf2(int value, int &result)
799 {
800   if (value==1) {
801     result=0;
802     return(true);
803   }
804   if ((value%2)!=0) return(false);
805   if (isPowerOf2(value/2,result)) {
806     result++;
807     return(true);
808   }
809   else return(false);
810 }
811
812 void AstNode::setUseCount(void)
813 {
814   useCount++;
815   if (useCount>1) return;
816   kept_register=-1;
817   if (loperand) loperand->setUseCount();
818   if (roperand) roperand->setUseCount();
819 }
820
821 void AstNode::cleanUseCount(void)
822 {
823   useCount=0;
824   kept_register=-1;
825   if (loperand) loperand->cleanUseCount();
826   if (roperand) roperand->cleanUseCount();
827 }
828
829 #if defined(ASTDEBUG)
830 void AstNode::printUseCount(void)
831 {
832   static int i=0;
833   i++;
834   sprintf(errorLine,"(%d)=>useCount is %d\n",i,useCount);
835   logLine(errorLine);
836   if (loperand) {
837     sprintf(errorLine,"(%d)=>loperand\n",i);
838     logLine(errorLine);
839     loperand->printUseCount();
840   }
841   if (roperand) {
842     sprintf(errorLine,"(%d)=>roperand\n",i);
843     logLine(errorLine);
844     roperand->printUseCount();  
845   }
846 }
847 #endif
848
849 //
850 // This procedure generates code for an AST DAG. If there is a sub-graph
851 // being shared between more than 1 node, then the code is generated only
852 // once for this sub-graph and the register where the return value of the
853 // sub-graph is stored, is kept allocated until the last node sharing the
854 // sub-graph has used it (freeing it afterwards). A count called "useCount"
855 // is used to determine whether a particular node or sub-graph is being
856 // shared. At the end of the call to generate code, this count must be 0
857 // for every node. Another important issue to notice is that we have to make
858 // sure that if a node is not calling generate code recursively for either
859 // its left or right operands, we then need to make sure that we update the
860 // "useCount" for these nodes (otherwise we might be keeping registers
861 // allocated without reason). 
862 //
863 // This code was modified in order to set the proper "useCount" for every
864 // node in the DAG before calling the original generateCode procedure (now
865 // generateCode_phase2). This means that we are traversing the DAG twice,
866 // but with the advantage of potencially generating more efficient code.
867 //
868 // Note: a complex Ast DAG might require more registers than the ones 
869 // currently available. In order to fix this problem, we will need to 
870 // implement a "virtual" register allocator - naim 11/06/96
871 //
872 reg AstNode::generateCode(process *proc,
873                           registerSpace *rs,
874                           char *insn, 
875                           unsigned &base, bool noCost) {
876   cleanUseCount();
877   setUseCount();
878   reg tmp=generateCode_phase2(proc,rs,insn,base,noCost);
879   return(tmp);
880 }
881
882 reg AstNode::generateCode_phase2(process *proc,
883                                  registerSpace *rs,
884                                  char *insn, 
885                                  unsigned &base, bool noCost) {
886     unsigned addr;
887     unsigned fromAddr;
888     unsigned startInsn;
889     reg src1, src2;
890     reg src = -1;
891     reg dest = -1;
892     reg right_dest = -1;
893
894     useCount--;
895     if (kept_register>=0) {
896 #if defined(ASTDEBUG)
897       sprintf(errorLine,"==> Returning register %d <==\n",kept_register);
898       logLine(errorLine);
899 #endif
900       if (useCount==0) {
901         rs->unkeep_register(kept_register);
902         reg tmp=kept_register;
903         kept_register=-1;
904         return(tmp);
905       }
906       return(kept_register);
907     }
908
909     if (type == opCodeNode) {
910         if (op == ifOp) {
911             // This ast cannot be shared because it doesn't return a register
912             src = loperand->generateCode_phase2(proc, rs, insn, base, noCost);
913             startInsn = base;
914             fromAddr = emit(op, src, (reg) 0, (reg) 0, insn, base, noCost);
915             rs->freeRegister(src);
916             reg tmp = roperand->generateCode_phase2(proc, rs, insn, base, noCost);
917             rs->freeRegister(tmp);
918
919             // call emit again now with correct offset.
920             (void) emit(op, src, (reg) 0, (reg) ((int)base - (int)fromAddr), 
921                         insn, startInsn, noCost);
922             // sprintf(errorLine,branch forward %d\n", base - fromAddr);
923         } else if (op == storeOp) {
924             // This ast cannot be shared because it doesn't return a register
925             // Check loperand because we are not generating code for it on
926             // this node.
927             loperand->useCount--;
928             if (loperand->useCount==0 && loperand->kept_register>=0) {
929               rs->unkeep_register(loperand->kept_register);
930               loperand->kept_register=-1;
931             }
932             src1 = roperand->generateCode_phase2(proc, rs, insn, base, noCost);
933             src2 = rs->allocateRegister(insn, base, noCost);
934             addr = (unsigned) loperand->oValue;
935             assert(addr != 0); // check for NULL
936             (void) emit(op, src1, src2, (reg) addr, insn, base, noCost);
937             rs->freeRegister(src1);
938             rs->freeRegister(src2);
939         } else if (op == storeIndirOp) {
940             src1 = roperand->generateCode_phase2(proc, rs, insn, base, noCost);
941             dest = loperand->generateCode_phase2(proc, rs, insn, base, noCost);
942             (void) emit(op, src1, 0, dest, insn, base, noCost);          
943             rs->freeRegister(src1);
944             rs->freeRegister(dest);
945         } else if (op == trampTrailer) {
946             // This ast cannot be shared because it doesn't return a register
947             return((unsigned) emit(op, 0, 0, 0, insn, base, noCost));
948         } else if (op == trampPreamble) {
949             // This ast cannot be shared because it doesn't return a register
950 #ifdef i386_unknown_solaris2_5
951             // loperand is a constant AST node with the cost, in cycles.
952             int cost = noCost ? 0 : (int) loperand->oValue;
953             int costAddr = 0; // for now... (won't change if noCost is set)
954             loperand->useCount--;
955
956 #ifndef SHM_SAMPLING
957             bool err;
958             costAddr = proc->findInternalAddress("DYNINSTobsCostLow", true, err);
959             if (err) {
960 //              logLine("Internal error: unable to find addr of DYNINSTobsCostLow\n");
961                 showErrorCallback(79, "");
962                 P_abort();
963             }
964 #else
965             if (!noCost)
966                costAddr = (int)proc->getObsCostLowAddrInApplicSpace();
967 #endif
968             return (unsigned) emit(op, 0, 0, 0, insn, base, noCost);
969 #endif
970         } else {
971             AstNode *left = assignAst(loperand);
972             AstNode *right = assignAst(roperand);
973
974             if (left && right) {
975               if (left->type == operandNode && left->oType == Constant) {
976                 if (type == opCodeNode) {
977                   if (op == plusOp) {
978                     AstNode *temp = assignAst(right);
979                     right = assignAst(left);
980                     left = assignAst(temp);
981                     removeAst(temp);
982                   } else if (op == timesOp) {
983                     if (right->type == operandNode) {
984                       if (right->oType != Constant) {
985                         AstNode *temp = assignAst(right);
986                         right = assignAst(left);
987                         left = assignAst(temp);
988                         removeAst(temp);
989                       }
990                       else {
991                         int result;
992                         if (!isPowerOf2((int)right->oValue,result) &&
993                              isPowerOf2((int)left->oValue,result))
994                         {
995                           AstNode *temp = assignAst(right);
996                           right = assignAst(left);
997                           left = assignAst(temp);
998                           removeAst(temp);
999                         }
1000                       }
1001                     }
1002                   }
1003                 }
1004               }
1005             }
1006
1007             if (left)
1008               src = left->generateCode_phase2(proc, rs, insn, base, noCost);
1009
1010             rs->freeRegister(src);
1011             dest = rs->allocateRegister(insn, base, noCost);
1012             if (useCount>0) {
1013               kept_register=dest;
1014               rs->keep_register(dest);
1015             }
1016
1017             if (right && (right->type == operandNode) &&
1018                 (right->oType == Constant) &&
1019                 doNotOverflow((int)right->oValue) &&
1020                 (type == opCodeNode))
1021             {
1022               emitImm(op, src, (reg)right->oValue, dest, insn, base, noCost);
1023               right->useCount--;
1024               if (right->useCount==0 && right->kept_register>=0) {
1025                 rs->unkeep_register(right->kept_register);
1026                 right->kept_register=-1;
1027               }
1028             }
1029             else {
1030               if (right)
1031                 right_dest = right->generateCode_phase2(proc, rs, insn, base, noCost);
1032               rs->freeRegister(right_dest);
1033               (void) emit(op, src, right_dest, dest, insn, base, noCost);
1034             }
1035             removeAst(left);
1036             removeAst(right);
1037         }
1038     } else if (type == operandNode) {
1039         dest = rs->allocateRegister(insn, base, noCost);
1040         if (useCount>0) {
1041           kept_register=dest;
1042           rs->keep_register(dest);
1043         }
1044         if (oType == Constant) {
1045             (void) emit(loadConstOp, (reg) oValue, dest, dest, insn, base, noCost);
1046         } else if (oType == ConstantPtr) {
1047             (void) emit(loadConstOp, (reg) (*(unsigned int *) oValue),
1048                 dest, dest, insn, base, noCost);
1049         } else if (oType == DataPtr) {
1050             addr = (unsigned) oValue;
1051             assert(addr != 0); // check for NULL
1052             (void) emit(loadConstOp, (reg) addr, dest, dest, insn, base, noCost);
1053         } else if (oType == DataIndir) {
1054             src = loperand->generateCode_phase2(proc, rs, insn, base, noCost);
1055             (void) emit(loadIndirOp, src, 0, dest, insn, base, noCost); 
1056             rs->freeRegister(src);
1057         } else if (oType == DataReg) {
1058             rs->unkeep_register(dest);
1059             rs->freeRegister(dest);
1060             dest = (reg)oValue;
1061             if (useCount>0) {
1062               kept_register=dest;
1063               rs->keep_register(dest);
1064             }
1065         } else if (oType == DataId) {
1066 #if defined(MT_THREAD)
1067             unsigned position;
1068             Thread *thr = proc->threads[0];
1069             position = thr->CTvector->getCTmapId((unsigned) oValue);
1070             assert(position < thr->CTvector->size());
1071             assert(thr->CTvector->getCTusagePos(position)==1);
1072             (void) emit(loadConstOp, (reg) position, dest, dest, insn, base, noCost);
1073 #else
1074             (void) emit(loadConstOp, (reg) oValue, dest, dest, insn, base, noCost);
1075 #endif
1076         } else if (oType == DataValue) {
1077             addr = (unsigned) oValue;
1078
1079             assert(addr != 0); // check for NULL
1080             (void) emit(loadOp, (reg) addr, dest, dest, insn, base, noCost);
1081         } else if (oType == ReturnVal) {
1082             rs->unkeep_register(dest);
1083             rs->freeRegister(dest);
1084             src = rs->allocateRegister(insn, base, noCost);
1085 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
1086             if (loperand) {
1087                 unsigned emitOptReturn(unsigned, reg, char *, unsigned &, bool);
1088                 dest = emitOptReturn(loperand -> oValue, src, insn, base, noCost);
1089             }
1090             else if (astFlag)
1091                 dest = emit(getSysRetValOp, 0, 0, src, insn, base, noCost);
1092             else 
1093 #endif
1094                 dest = emit(getRetValOp, 0, 0, src, insn, base, noCost);
1095             if (useCount>0) {
1096               kept_register=dest;
1097               rs->keep_register(dest);
1098             }
1099             if (src != dest) {
1100                 rs->freeRegister(src);
1101             }
1102         } else if (oType == Param) {
1103             rs->unkeep_register(dest);
1104             rs->freeRegister(dest);
1105             src = rs->allocateRegister(insn, base, noCost);
1106             // return the actual reg it is in.
1107 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
1108             if (astFlag)
1109                 dest = emit(getSysParamOp, (reg)oValue, 0, src, insn, base, noCost);
1110             else 
1111 #endif
1112                 dest = emit(getParamOp, (reg)oValue, 0, src, insn, base, noCost);
1113             if (useCount>0) {
1114               kept_register=dest;
1115               rs->keep_register(dest);
1116             }
1117             if (src != dest) {
1118                 rs->freeRegister(src);
1119             }
1120         } else if (oType == DataAddr) {
1121           addr = (unsigned) oValue;
1122           emit(loadOp, (reg) addr, dest, dest, insn, base, noCost);
1123         } else if (oType == ConstantString) {
1124           // XXX This is for the string type.  If/when we fix the string type
1125           // to make it less of a hack, we'll need to change this.
1126           int len = strlen((char *)oValue) + 1;
1127           addr = (unsigned) inferiorMalloc(proc, len, dataHeap);
1128           proc->writeDataSpace((char *)addr, len, (char *)oValue);
1129           emit(loadConstOp, (reg) addr, dest, dest, insn, base, noCost);
1130         }
1131     } else if (type == callNode) {
1132         dest = emitFuncCall(callOp, rs, insn, base, operands, callee, proc, noCost);
1133         if (useCount>0) {
1134           kept_register=dest;
1135           rs->keep_register(dest);
1136         }
1137     } else if (type == sequenceNode) {
1138         (void) loperand->generateCode_phase2(proc, rs, insn, base, noCost);
1139         return(roperand->generateCode_phase2(proc, rs, insn, base, noCost));
1140     }
1141
1142     return(dest);
1143 }
1144
1145
1146 #if defined(ASTDEBUG)
1147 string getOpString(opCode op)
1148 {
1149     switch (op) {
1150         case plusOp: return("+");
1151         case minusOp: return("-");
1152         case timesOp: return("*");
1153         case divOp: return("/");
1154         case lessOp: return("<");
1155         case leOp: return("<=");
1156         case greaterOp: return(">");
1157         case geOp: return(">=");
1158         case eqOp: return("==");
1159         case neOp: return("!=");
1160         case loadOp: return("lda");
1161         case loadConstOp: return("load");
1162         case storeOp: return("=");
1163         case ifOp: return("if");
1164         case trampPreamble: return("preTramp");
1165         case trampTrailer: return("goto");
1166         case noOp: return("nop");
1167         case andOp: return("and");
1168         case orOp: return("or");
1169         case loadIndirOp: return("load&");
1170         case storeIndirOp: return("=&");
1171         default: return("ERROR");
1172     }
1173 }
1174 #endif
1175
1176 int AstNode::cost() const {
1177     int total = 0;
1178     int getInsnCost(opCode t);
1179
1180     if (type == opCodeNode) {
1181         if (op == ifOp) {
1182             if (loperand) total += loperand->cost();
1183             total += getInsnCost(op);
1184             if (roperand) total += roperand->cost();
1185         } else if (op == storeOp) {
1186             if (roperand) total += roperand->cost();
1187             total += getInsnCost(op);
1188         } else if (op == storeIndirOp) {
1189             if (loperand) total += loperand->cost();
1190             if (roperand) total += roperand->cost();
1191             total += getInsnCost(op);
1192         } else if (op == trampTrailer) {
1193             total = getInsnCost(op);
1194         } else if (op == trampPreamble) {
1195             total = getInsnCost(op);
1196         } else {
1197             if (loperand) 
1198                 total += loperand->cost();
1199             if (roperand) 
1200                 total += roperand->cost();
1201             total += getInsnCost(op);
1202         }
1203     } else if (type == operandNode) {
1204         if (oType == Constant) {
1205             total = getInsnCost(loadConstOp);
1206         } else if (oType == DataPtr) {
1207             total = getInsnCost(loadConstOp);
1208         } else if (oType == DataValue) {
1209             total = getInsnCost(loadOp);
1210         } else if (oType == DataId) {
1211             total = getInsnCost(loadConstOp);
1212         } else if (oType == DataIndir) {
1213             total = getInsnCost(loadIndirOp);
1214             total += loperand->cost();
1215         } else if (oType == DataReg) {
1216             total = getInsnCost(loadIndirOp);
1217         } else if (oType == Param) {
1218             total = getInsnCost(getParamOp);
1219         }
1220     } else if (type == callNode) {
1221         total = getPrimitiveCost(callee);
1222         for (unsigned u = 0; u < operands.size(); u++)
1223           if (operands[u]) total += operands[u]->cost();
1224     } else if (type == sequenceNode) {
1225         if (loperand) total += loperand->cost();
1226         if (roperand) total += roperand->cost();
1227     }
1228     return(total);
1229 }
1230
1231 #if defined(ASTDEBUG)
1232 void AstNode::print() const {
1233     if (type == operandNode) {
1234         if (oType == Constant) {
1235             sprintf(errorLine, " %d", (int) oValue);
1236             logLine(errorLine);
1237         } else if (oType == DataPtr) {
1238             sprintf(errorLine, " %d", (int) oValue);
1239             logLine(errorLine);
1240         } else if (oType == DataValue) {
1241             sprintf(errorLine, "@%d", (int) oValue);
1242             logLine(errorLine);
1243         } else if (oType == DataIndir) {
1244             logLine("@[");
1245             loperand->print();
1246             logLine("]");
1247         } else if (oType == DataReg) {
1248             sprintf(errorLine," reg%d ",(int)oValue);
1249             logLine(errorLine);
1250             loperand->print();
1251         } else if (oType == Param) {
1252             sprintf(errorLine, "param[%d]", (int) oValue);
1253             logLine(errorLine);
1254         }
1255     } else if (type == opCodeNode) {
1256         ostrstream os(errorLine, 1024, ios::out);
1257         os << "(" << getOpString(op) << ends;
1258         logLine(errorLine);
1259         if (loperand) loperand->print();
1260         if (roperand) roperand->print();
1261         logLine(")");
1262     } else if (type == callNode) {
1263         ostrstream os(errorLine, 1024, ios::out);
1264         os << "(" << callee << ends;
1265         logLine(errorLine);
1266         for (unsigned u = 0; u < operands.size(); u++)
1267           operands[u]->print();
1268         logLine(")");
1269     } else if (type == sequenceNode) {
1270         if (loperand) loperand->print();
1271         logLine(",");
1272         if (roperand) roperand->print();
1273     }
1274 }
1275 #endif
1276
1277 AstNode *createIf(AstNode *expression, AstNode *action) 
1278 {
1279   AstNode *t;
1280   t = new AstNode(ifOp, expression, action);
1281   return(t);
1282 }
1283
1284 #ifndef BPATCH_LIBRARY
1285 #if !defined(MT_THREAD)
1286
1287 AstNode *createTimer(const string &func, void *dataPtr, 
1288                      vector<AstNode *> &ast_args)
1289 {
1290   AstNode *t0=NULL,*t1=NULL;
1291
1292   t0 = new AstNode(AstNode::DataPtr, (void *) dataPtr);
1293   ast_args += assignAst(t0);
1294   removeAst(t0);
1295   t1 = new AstNode(func, ast_args);
1296   for (unsigned i=0;i<ast_args.size();i++) removeAst(ast_args[i]);  
1297   return(t1);
1298 }
1299
1300 AstNode *createCounter(const string &func, void *dataPtr, 
1301                        AstNode *ast) 
1302 {
1303    AstNode *t0=NULL, *t1=NULL, *t2=NULL;
1304
1305    t0 = new AstNode(AstNode::DataValue, (void *)dataPtr);
1306    if (func=="addCounter") {
1307      t1 = new AstNode(plusOp,t0,ast);
1308      t2 = new AstNode(storeOp,t0,t1);
1309    } else if (func=="subCounter") {
1310      t1 = new AstNode(minusOp,t0,ast);
1311      t2 = new AstNode(storeOp,t0,t1);
1312    } else if (func=="setCounter") {
1313      t2 = new AstNode(storeOp,t0,ast);
1314    } else abort();
1315    removeAst(t0);
1316    removeAst(t1);
1317    return(t2);
1318 }
1319
1320 #else
1321
1322 AstNode *computeAddress(void *dataPtr)
1323 {
1324   AstNode *t0=NULL,*t1=NULL,*t2=NULL,*t3=NULL;
1325   AstNode *t4=NULL,*t5=NULL,*t6=NULL;
1326   int value;
1327
1328   /* We don't need to check wether dataPtr is NULL, because it represents */
1329   /* an id rather than a pointer - naim 2/18/97                      */
1330
1331   /* DYNINSTthreadTable[thr_self()] */
1332   /* make sure we read updated base address */
1333   t0 = new AstNode(AstNode::DataReg, (void *)REG_MT);
1334   t1 = new AstNode(AstNode::DataIndir, t0); 
1335
1336   /* Counter_Timer_Table[counter/timerId] */
1337   value = sizeof(unsigned);
1338   t2 = new AstNode(AstNode::DataId, (void *)dataPtr);
1339   t3 = new AstNode(AstNode::Constant, (void *)value);
1340   t4 = new AstNode(timesOp, t2, t3);
1341   t5 = new AstNode(plusOp, t1, t4);
1342   t6 = new AstNode(AstNode::DataIndir, t5);
1343
1344   /* address of Counter_Timer->value */
1345   /* intCounter has value at position 0, so offset is 0 */
1346   /* tTimer is different */
1347
1348   removeAst(t0);
1349   removeAst(t1);
1350   removeAst(t2);
1351   removeAst(t3);
1352   removeAst(t4);
1353   removeAst(t5);
1354   return(t6);
1355 }
1356
1357 AstNode *createTimer(const string &func, void *dataPtr, 
1358                      vector<AstNode *> &ast_args)
1359 {
1360   AstNode *t0=NULL,*t1=NULL;
1361
1362   t0 = computeAddress(dataPtr);
1363   ast_args += assignAst(t0);
1364   removeAst(t0);
1365   t1 = new AstNode(func, ast_args);
1366   for (unsigned i=0;i<ast_args.size();i++) removeAst(ast_args[i]);  
1367
1368   return(t1);
1369 }
1370
1371 AstNode *createCounter(const string &func, void *dataPtr, 
1372                        AstNode *ast) 
1373
1374   AstNode *t0=NULL,*t1=NULL,*t2=NULL,*t3=NULL;
1375
1376   t0 = computeAddress(dataPtr);
1377
1378   if (func == "addCounter") {
1379     t1 = new AstNode(AstNode::DataIndir, t0);
1380     t2 = new AstNode(plusOp, t1, ast);
1381     t3 = new AstNode(storeIndirOp, t0, t2);
1382   } else if (func == "subCounter") {
1383     t1 = new AstNode(AstNode::DataIndir, t0);
1384     t2 = new AstNode(minusOp, t1, ast);
1385     t3 = new AstNode(storeIndirOp, t0, t2);
1386   } else if (func == "setCounter") {
1387     t3 = new AstNode(storeIndirOp, t0, ast);
1388   }
1389
1390   removeAst(t0);
1391   removeAst(t1);
1392   removeAst(t2);
1393
1394   return(t3);
1395 }
1396
1397 #endif
1398 #endif
1399
1400 #ifdef BPATCH_LIBRARY
1401 BPatch_type *AstNode::checkType()
1402 {
1403     BPatch_type *ret = NULL;
1404     BPatch_type *lType = NULL, *rType = NULL;
1405     bool errorFlag = false;
1406
1407     assert(BPatch::bpatch != NULL);     /* We'll use this later. */
1408
1409     assert( (!loperand && !roperand) || getType() == NULL );
1410
1411     if (loperand)
1412         lType = loperand->checkType();
1413
1414     if (roperand)
1415         rType = roperand->checkType();
1416
1417     if (lType == BPatch::bpatch->type_Error ||
1418         rType == BPatch::bpatch->type_Error)
1419         errorFlag = true;
1420
1421     
1422     switch (type) { // Type here is nodeType, not BPatch library type
1423         case sequenceNode:
1424             ret = rType;
1425             break;
1426         case opCodeNode:
1427             if (lType != NULL && rType != NULL) {
1428                 if (!lType->isCompatible(*rType)) {
1429                     errorFlag = true;
1430                 }
1431             }
1432             // XXX The following line must change to decide based on the types
1433             // and operation involved what the return type of the expression
1434             // will be.
1435             ret = lType;
1436             break;
1437         case operandNode:
1438             assert(loperand == NULL && roperand == NULL);
1439             if (oType == Param)
1440                 ret = BPatch::bpatch->type_Untyped; //XXX Params untyped for now
1441             else
1442                 ret = getType();
1443             assert(ret != NULL);
1444             break;
1445         case callNode:
1446             for (int i = 0; i < operands.size(); i++) {
1447                 BPatch_type *operandType = operands[i]->checkType();
1448                 /* XXX Check operands for compatibility */
1449                 if (operandType == BPatch::bpatch->type_Error)
1450                     errorFlag = true;
1451             }
1452             /* XXX Should set to return type of function. */
1453             ret = BPatch::bpatch->type_Untyped;
1454             break;
1455       default:
1456         assert(0);
1457     }
1458
1459     assert(ret != NULL);
1460
1461     if (errorFlag && doTypeCheck) {
1462         ret = BPatch::bpatch->type_Error;
1463     }
1464
1465     return ret;
1466 }
1467 #endif