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 visitHandle(self, handle, lvalue, rvalue):
98 OpaqueValueDeserializer().visit(handle.type, lvalue, rvalue);
99 new_lvalue = lookupHandle(handle, lvalue)
100 print ' if (retrace::verbosity >= 2) {'
101 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
103 print ' %s = %s;' % (lvalue, new_lvalue)
105 def visitBlob(self, blob, lvalue, rvalue):
106 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
108 def visitString(self, string, lvalue, rvalue):
109 print ' %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
112 class OpaqueValueDeserializer(ValueDeserializer):
113 '''Value extractor that also understands opaque values.
115 Normally opaque values can't be retraced, unless they are being extracted
116 in the context of handles.'''
118 def visitOpaque(self, opaque, lvalue, rvalue):
119 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, opaque, rvalue)
122 class SwizzledValueRegistrator(stdapi.Visitor):
123 '''Type visitor which will register (un)swizzled value pairs, to later be
126 def visitLiteral(self, literal, lvalue, rvalue):
129 def visitAlias(self, alias, lvalue, rvalue):
130 self.visit(alias.type, lvalue, rvalue)
132 def visitEnum(self, enum, lvalue, rvalue):
135 def visitBitmask(self, bitmask, lvalue, rvalue):
138 def visitArray(self, array, lvalue, rvalue):
139 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (array.tag, rvalue)
140 print ' if (__a%s) {' % (array.tag)
141 length = '__a%s->values.size()' % array.tag
142 index = '__j' + array.tag
143 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
145 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.tag, index))
150 def visitPointer(self, pointer, lvalue, rvalue):
151 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (pointer.tag, rvalue)
152 print ' if (__a%s) {' % (pointer.tag)
154 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.tag,))
158 def visitHandle(self, handle, lvalue, rvalue):
159 print ' %s __orig_result;' % handle.type
160 OpaqueValueDeserializer().visit(handle.type, '__orig_result', rvalue);
161 if handle.range is None:
162 rvalue = "__orig_result"
163 entry = lookupHandle(handle, rvalue)
164 print " %s = %s;" % (entry, lvalue)
165 print ' if (retrace::verbosity >= 2) {'
166 print ' std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
169 i = '__h' + handle.tag
170 lvalue = "%s + %s" % (lvalue, i)
171 rvalue = "__orig_result + %s" % (i,)
172 entry = lookupHandle(handle, rvalue)
173 print ' for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
174 print ' {entry} = {lvalue};'.format(**locals())
175 print ' if (retrace::verbosity >= 2) {'
176 print ' std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
180 def visitBlob(self, blob, lvalue, rvalue):
183 def visitString(self, string, lvalue, rvalue):
189 def retraceFunction(self, function):
190 print 'static void retrace_%s(trace::Call &call) {' % function.name
191 self.retraceFunctionBody(function)
195 def retraceFunctionBody(self, function):
196 if not function.sideeffects:
201 for arg in function.args:
202 arg_type = ConstRemover().visit(arg.type)
203 #print ' // %s -> %s' % (arg.type, arg_type)
204 print ' %s %s;' % (arg_type, arg.name)
205 rvalue = 'call.arg(%u)' % (arg.index,)
208 self.extractArg(function, arg, arg_type, lvalue, rvalue)
209 except NotImplementedError:
211 print ' %s = 0; // FIXME' % arg.name
214 self.failFunction(function)
216 self.invokeFunction(function)
217 for arg in function.args:
219 arg_type = ConstRemover().visit(arg.type)
220 rvalue = 'call.arg(%u)' % (arg.index,)
223 self.regiterSwizzledValue(arg_type, lvalue, rvalue)
224 except NotImplementedError:
225 print ' // XXX: %s' % arg.name
226 if function.type is not stdapi.Void:
230 self.regiterSwizzledValue(function.type, lvalue, rvalue)
231 except NotImplementedError:
232 print ' // XXX: result'
234 if function.name[-1].islower():
235 sys.stderr.write('warning: unsupported %s call\n' % function.name)
237 def failFunction(self, function):
238 print ' if (retrace::verbosity >= 0) {'
239 print ' retrace::unsupported(call);'
243 def extractArg(self, function, arg, arg_type, lvalue, rvalue):
244 ValueDeserializer().visit(arg_type, lvalue, rvalue)
246 def extractOpaqueArg(self, function, arg, arg_type, lvalue, rvalue):
247 OpaqueValueDeserializer().visit(arg_type, lvalue, rvalue)
249 def regiterSwizzledValue(self, type, lvalue, rvalue):
250 visitor = SwizzledValueRegistrator()
251 visitor.visit(type, lvalue, rvalue)
253 def invokeFunction(self, function):
254 arg_names = ", ".join([arg.name for arg in function.args])
255 if function.type is not stdapi.Void:
256 print ' %s __result;' % (function.type)
257 print ' __result = %s(%s);' % (function.name, arg_names)
258 print ' (void)__result;'
260 print ' %s(%s);' % (function.name, arg_names)
262 def filterFunction(self, function):
265 table_name = 'retrace::callbacks'
267 def retraceFunctions(self, functions):
268 functions = filter(self.filterFunction, functions)
270 for function in functions:
271 self.retraceFunction(function)
273 print 'const retrace::Entry %s[] = {' % self.table_name
274 for function in functions:
275 print ' {"%s", &retrace_%s},' % (function.name, function.name)
276 print ' {NULL, NULL}'
281 def retraceApi(self, api):
283 print '#include "trace_parser.hpp"'
284 print '#include "retrace.hpp"'
287 types = api.all_types()
288 handles = [type for type in types if isinstance(type, stdapi.Handle)]
290 for handle in handles:
291 if handle.name not in handle_names:
292 if handle.key is None:
293 print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
295 key_name, key_type = handle.key
296 print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
297 handle_names.add(handle.name)
300 self.retraceFunctions(api.functions)