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