File: SyncTransformer.cc

package info (click to toggle)
aspectc%2B%2B 1%3A1.1%2Bsvn20120529-2
  • links: PTS
  • area: main
  • in suites: wheezy
  • size: 222,560 kB
  • sloc: cpp: 3,935,531; ansic: 18,166; pascal: 14,783; sh: 2,188; makefile: 1,110; python: 340
file content (141 lines) | stat: -rw-r--r-- 5,744 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// This file is part of PUMA.
// Copyright (C) 1999-2003  The PUMA developer team.
//                                                                
// This program is free software;  you can redistribute it and/or 
// modify it under the terms of the GNU General Public License as 
// published by the Free Software Foundation; either version 2 of 
// the License, or (at your option) any later version.            
//                                                                
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
// GNU General Public License for more details.                   
//                                                                
// You should have received a copy of the GNU General Public      
// License along with this program; if not, write to the Free     
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
// MA  02111-1307  USA                                            

#include "SyncTransformer.h"
#include <Puma/CUnit.h>
#include <Puma/ManipCommander.h>


// Counter for generating variable names.
unsigned SyncTransformer::m_Counter = 0;


// Constructor.
SyncTransformer::SyncTransformer(Puma::ErrorStream &err) : m_Err(err) {
}


void SyncTransformer::transform(Puma::CTree *node) {
  // Start the transformation of the "synchronized" 
  // statements. visit() starts traversing the tree
  // beginning at the given node.
  visit(node);
}
  

void SyncTransformer::pre_visit(Puma::CTree *node) {
  // This method is called for every node before the 
  // sub-nodes of the node are visited. It is part 
  // of the visitor mechanism.

  // Better to check it.
  if (! node) {
    return;
  }
    
  // Check if this is a "synchronized" statement by 
  // comparing the unique identifier returned by
  // calling NodeName() on the node with the unqiue
  // identifier of a "synchronized" statement node.
  if (node->NodeName() == SyncStmt::NodeId()) {
    // This is a "synchronized" statement node, so
    // transform it.
    pre_action((SyncStmt*)node);
  }
}


void SyncTransformer::pre_action(SyncStmt *node) {
  // This method performs the transformation of a
  // "synchronized" statement. The name "pre_action"
  // was chosen because this action is performed 
  // before the sub-nodes of the "synchronized" 
  // statement node are visited. Accordingly a 
  // transformation performed after visiting the 
  // sub-nodes would be called "post_action". Since
  // this transformation is so simple, an extra
  // "post_action" is not necessary.
  
  // The performed transformation is the following:
  // * Replace the "synchronized" keyword and the 
  //   opening bracket with:
  //
  //   pthread_mutex_t mutex;
  //   pthread_mutex_init(&mutex, 0);
  //   pthread_mutex_lock(&mutex);
  //
  // * Replace the closing bracket with: 
  //
  //   pthread_mutex_unlock(&mutex);
  //   pthread_mutex_destroy(&mutex);
  
  // First the tokens of the code to replace with are needed. 
  // These tokens can be easily generated from a string using
  // the class CUnit, derived from std::ostringstream. The 
  // collected string is scanned after delivering the stream 
  // manipulator Puma::endu.
  // TODO: Implement a better creation of the variable name
  //       checking if it already exists in the current scope.
  Puma::CUnit lock(m_Err);
  lock << "\npthread_mutex_t __mutex_" << ++m_Counter << ";" << std::endl;
  lock << "pthread_mutex_init(&__mutex_" << m_Counter << ", 0);" << std::endl;
  lock << "pthread_mutex_lock(&__mutex_" << m_Counter << ");" << std::endl;
  lock << Puma::endu;
  
  Puma::CUnit unlock(m_Err);
  unlock << "\npthread_mutex_unlock(&__mutex_" << m_Counter << ");" << std::endl;
  unlock << "pthread_mutex_destroy(&__mutex_" << m_Counter << ");" << std::endl;
  unlock << Puma::endu;
  
  // For this kind of code manipulation the class ManipCommander 
  // provides a set of manipulation operations. The manipulations 
  // performed by this class are based on transactions, i.e.
  // single manipulations are collected and then executed all 
  // at once after calling commit().
  Puma::ManipCommander mc;
  
  // Replace the "synchronized" keyword and the opening bracket.
  // For this manipulation the "replace" operation can be used 
  // expecting the first and last tokens of the code to replace 
  // and of the replacement code as arguments. This means here
  // to replace the first two tokens of the of the statement
  // with the whole replacement token list. token() returns
  // the first token referred in a sub-tree.
  mc.replace(node->Son(0)->token(), node->Son(1)->token(), 
             (Puma::Token*)lock.first(), (Puma::Token*)lock.last());
  // Replace the closing bracket. The closing bracket is the 
  // last token of the statement. end_token() returns the last 
  // token referred in a sub-tree.
  mc.replace(node->end_token(), node->end_token(), 
             (Puma::Token*)unlock.first(), (Puma::Token*)unlock.last());
  
  // Execute the two manipulations now, together. It is also
  // possible first to check if the manipulations are valid
  // by calling valid() on the ManipCommander object. The 
  // transaction is valid if the following conditions are 
  // true:
  // 1. The start-token is not NULL.
  // 2. The start-token and end-token belong to the same 
  //    unit and are not the result of a macro expansion
  // 3. There are only balanced preprocessor directives 
  //    within the manipulation range.
  // Because this manipulation is so simple, it is not 
  // necessary to check its validity.
  //if (mc.valid())  
  mc.commit();
}