1 ##########################################################################
3 # Copyright 2010 VMware, Inc.
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to deal
8 # in the Software without restriction, including without limitation the rights
9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 ##########################################################################/
27 """Generic retracing code generator."""
32 import specs.stdapi as stdapi
33 import specs.glapi as glapi
36 class ConstRemover(stdapi.Rebuilder):
37 '''Type visitor which strips out const qualifiers from types.'''
39 def visitConst(self, const):
42 def visitOpaque(self, opaque):
46 def lookupHandle(handle, value):
47 if handle.key is None:
48 return "__%s_map[%s]" % (handle.name, value)
50 key_name, key_type = handle.key
51 return "__%s_map[%s][%s]" % (handle.name, key_name, value)
54 class ValueDeserializer(stdapi.Visitor):
56 def visitLiteral(self, literal, lvalue, rvalue):
57 print ' %s = (%s).to%s();' % (lvalue, rvalue, literal.kind)
59 def visitConst(self, const, lvalue, rvalue):
60 self.visit(const.type, lvalue, rvalue)
62 def visitAlias(self, alias, lvalue, rvalue):
63 self.visit(alias.type, lvalue, rvalue)
65 def visitEnum(self, enum, lvalue, rvalue):
66 print ' %s = (%s).toSInt();' % (lvalue, rvalue)
68 def visitBitmask(self, bitmask, lvalue, rvalue):
69 self.visit(bitmask.type, lvalue, rvalue)
71 def visitArray(self, array, lvalue, rvalue):
72 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (array.tag, rvalue)
73 print ' if (__a%s) {' % (array.tag)
74 length = '__a%s->values.size()' % array.tag
75 print ' %s = new %s[%s];' % (lvalue, array.type, length)
76 index = '__j' + array.tag
77 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
79 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.tag, index))
83 print ' %s = NULL;' % lvalue
86 def visitPointer(self, pointer, lvalue, rvalue):
87 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (pointer.tag, rvalue)
88 print ' if (__a%s) {' % (pointer.tag)
89 print ' %s = new %s;' % (lvalue, pointer.type)
91 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.tag,))
94 print ' %s = NULL;' % lvalue
97 def visitIntPointer(self, pointer, lvalue, rvalue):
98 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, pointer, rvalue)
100 def visitLinearPointer(self, pointer, lvalue, rvalue):
101 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, pointer, rvalue)
103 def visitHandle(self, handle, lvalue, rvalue):
104 #OpaqueValueDeserializer().visit(handle.type, lvalue, rvalue);
105 self.visit(handle.type, lvalue, rvalue);
106 new_lvalue = lookupHandle(handle, lvalue)
107 print ' if (retrace::verbosity >= 2) {'
108 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
110 print ' %s = %s;' % (lvalue, new_lvalue)
112 def visitBlob(self, blob, lvalue, rvalue):
113 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
115 def visitString(self, string, lvalue, rvalue):
116 print ' %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
119 class OpaqueValueDeserializer(ValueDeserializer):
120 '''Value extractor that also understands opaque values.
122 Normally opaque values can't be retraced, unless they are being extracted
123 in the context of handles.'''
125 def visitOpaque(self, opaque, lvalue, rvalue):
126 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, opaque, rvalue)
129 class SwizzledValueRegistrator(stdapi.Visitor):
130 '''Type visitor which will register (un)swizzled value pairs, to later be
133 def visitLiteral(self, literal, lvalue, rvalue):
136 def visitAlias(self, alias, lvalue, rvalue):
137 self.visit(alias.type, lvalue, rvalue)
139 def visitEnum(self, enum, lvalue, rvalue):
142 def visitBitmask(self, bitmask, lvalue, rvalue):
145 def visitArray(self, array, lvalue, rvalue):
146 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (array.tag, rvalue)
147 print ' if (__a%s) {' % (array.tag)
148 length = '__a%s->values.size()' % array.tag
149 index = '__j' + array.tag
150 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
152 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.tag, index))
157 def visitPointer(self, pointer, lvalue, rvalue):
158 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (pointer.tag, rvalue)
159 print ' if (__a%s) {' % (pointer.tag)
161 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.tag,))
165 def visitIntPointer(self, pointer, lvalue, rvalue):
168 def visitLinearPointer(self, pointer, lvalue, rvalue):
169 assert pointer.size is not None
170 if pointer.size is not None:
171 print r' retrace::addRegion((%s).toUIntPtr(), %s, %s);' % (rvalue, lvalue, pointer.size)
173 def visitHandle(self, handle, lvalue, rvalue):
174 print ' %s __orig_result;' % handle.type
175 OpaqueValueDeserializer().visit(handle.type, '__orig_result', rvalue);
176 if handle.range is None:
177 rvalue = "__orig_result"
178 entry = lookupHandle(handle, rvalue)
179 print " %s = %s;" % (entry, lvalue)
180 print ' if (retrace::verbosity >= 2) {'
181 print ' std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
184 i = '__h' + handle.tag
185 lvalue = "%s + %s" % (lvalue, i)
186 rvalue = "__orig_result + %s" % (i,)
187 entry = lookupHandle(handle, rvalue)
188 print ' for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
189 print ' {entry} = {lvalue};'.format(**locals())
190 print ' if (retrace::verbosity >= 2) {'
191 print ' std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
195 def visitBlob(self, blob, lvalue, rvalue):
198 def visitString(self, string, lvalue, rvalue):
204 def retraceFunction(self, function):
205 print 'static void retrace_%s(trace::Call &call) {' % function.name
206 self.retraceFunctionBody(function)
210 def retraceFunctionBody(self, function):
211 if not function.sideeffects:
216 for arg in function.args:
217 arg_type = ConstRemover().visit(arg.type)
218 #print ' // %s -> %s' % (arg.type, arg_type)
219 print ' %s %s;' % (arg_type, arg.name)
220 rvalue = 'call.arg(%u)' % (arg.index,)
223 self.extractArg(function, arg, arg_type, lvalue, rvalue)
224 except NotImplementedError:
226 print ' %s = 0; // FIXME' % arg.name
229 self.failFunction(function)
231 self.invokeFunction(function)
232 for arg in function.args:
234 arg_type = ConstRemover().visit(arg.type)
235 rvalue = 'call.arg(%u)' % (arg.index,)
238 self.regiterSwizzledValue(arg_type, lvalue, rvalue)
239 except NotImplementedError:
240 print ' // XXX: %s' % arg.name
241 if function.type is not stdapi.Void:
245 self.regiterSwizzledValue(function.type, lvalue, rvalue)
246 except NotImplementedError:
247 print ' // XXX: result'
249 if function.name[-1].islower():
250 sys.stderr.write('warning: unsupported %s call\n' % function.name)
252 def failFunction(self, function):
253 print ' if (retrace::verbosity >= 0) {'
254 print ' retrace::unsupported(call);'
258 def extractArg(self, function, arg, arg_type, lvalue, rvalue):
259 ValueDeserializer().visit(arg_type, lvalue, rvalue)
261 def extractOpaqueArg(self, function, arg, arg_type, lvalue, rvalue):
262 OpaqueValueDeserializer().visit(arg_type, lvalue, rvalue)
264 def regiterSwizzledValue(self, type, lvalue, rvalue):
265 visitor = SwizzledValueRegistrator()
266 visitor.visit(type, lvalue, rvalue)
268 def invokeFunction(self, function):
269 arg_names = ", ".join(function.argNames())
270 if function.type is not stdapi.Void:
271 print ' %s __result;' % (function.type)
272 print ' __result = %s(%s);' % (function.name, arg_names)
273 print ' (void)__result;'
275 print ' %s(%s);' % (function.name, arg_names)
277 def filterFunction(self, function):
280 table_name = 'retrace::callbacks'
282 def retraceFunctions(self, functions):
283 functions = filter(self.filterFunction, functions)
285 for function in functions:
286 self.retraceFunction(function)
288 print 'const retrace::Entry %s[] = {' % self.table_name
289 for function in functions:
290 print ' {"%s", &retrace_%s},' % (function.name, function.name)
291 print ' {NULL, NULL}'
296 def retraceApi(self, api):
298 print '#include "trace_parser.hpp"'
299 print '#include "retrace.hpp"'
302 types = api.getAllTypes()
303 handles = [type for type in types if isinstance(type, stdapi.Handle)]
305 for handle in handles:
306 if handle.name not in handle_names:
307 if handle.key is None:
308 print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
310 key_name, key_type = handle.key
311 print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
312 handle_names.add(handle.name)
315 self.retraceFunctions(api.functions)