blob: 55df6ce4bc77b1d14f68588083d1a03e3b1d0ae7 [file] [log] [blame]
José Fonsecae0e61402010-11-25 15:03:23 +00001##########################################################################
2#
3# Copyright 2010 VMware, Inc.
4# All Rights Reserved.
5#
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:
12#
13# The above copyright notice and this permission notice shall be included in
14# all copies or substantial portions of the Software.
15#
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
22# THE SOFTWARE.
23#
24##########################################################################/
25
26
José Fonseca4a826ed2010-11-30 16:58:22 +000027"""Generic retracing code generator."""
28
José Fonsecae0e61402010-11-25 15:03:23 +000029import stdapi
30import glapi
José Fonseca522b7442010-11-27 15:30:40 +000031from codegen import *
José Fonsecae0e61402010-11-25 15:03:23 +000032
33
34class ConstRemover(stdapi.Rebuilder):
35
36 def visit_const(self, const):
37 return const.type
38
39 def visit_opaque(self, opaque):
José Fonsecaf01b7f52011-04-20 21:09:28 +010040 return opaque
José Fonsecae0e61402010-11-25 15:03:23 +000041
42
José Fonseca8a844ae2010-12-06 18:50:52 +000043def handle_entry(handle, value):
44 if handle.key is None:
45 return "__%s_map[%s]" % (handle.name, value)
46 else:
47 key_name, key_type = handle.key
48 return "__%s_map[%s][%s]" % (handle.name, key_name, value)
49
50
José Fonsecae0e61402010-11-25 15:03:23 +000051class ValueExtractor(stdapi.Visitor):
52
53 def visit_literal(self, literal, lvalue, rvalue):
José Fonseca56e093c2011-05-07 01:09:19 +010054 #if literal.format in ('Bool', 'UInt'):
55 print ' %s = (%s).to%s();' % (lvalue, rvalue, literal.format)
José Fonsecae0e61402010-11-25 15:03:23 +000056
57 def visit_const(self, const, lvalue, rvalue):
58 self.visit(const.type, lvalue, rvalue)
59
60 def visit_alias(self, alias, lvalue, rvalue):
61 self.visit(alias.type, lvalue, rvalue)
62
63 def visit_enum(self, enum, lvalue, rvalue):
José Fonseca56e093c2011-05-07 01:09:19 +010064 print ' %s = (%s).toSInt();' % (lvalue, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +000065
66 def visit_bitmask(self, bitmask, lvalue, rvalue):
67 self.visit(bitmask.type, lvalue, rvalue)
68
69 def visit_array(self, array, lvalue, rvalue):
70 print ' const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (array.id, rvalue)
71 print ' if (__a%s) {' % (array.id)
72 length = '__a%s->values.size()' % array.id
73 print ' %s = new %s[%s];' % (lvalue, array.type, length)
74 index = '__j' + array.id
José Fonsecadbaae492011-04-21 09:28:10 +010075 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
José Fonsecae0e61402010-11-25 15:03:23 +000076 try:
77 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.id, index))
78 finally:
79 print ' }'
80 print ' } else {'
81 print ' %s = NULL;' % lvalue
82 print ' }'
83
84 def visit_pointer(self, pointer, lvalue, rvalue):
85 print ' const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (pointer.id, rvalue)
86 print ' if (__a%s) {' % (pointer.id)
87 print ' %s = new %s;' % (lvalue, pointer.type)
88 try:
89 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.id,))
90 finally:
91 print ' } else {'
92 print ' %s = NULL;' % lvalue
93 print ' }'
94
95 def visit_handle(self, handle, lvalue, rvalue):
José Fonsecaa10af892011-04-11 09:10:55 +010096 OpaqueValueExtractor().visit(handle.type, lvalue, rvalue);
97 new_lvalue = handle_entry(handle, lvalue)
José Fonseca031b7382011-05-10 20:36:40 +010098 print ' if (retrace::verbosity >= 2) {'
José Fonsecaa10af892011-04-11 09:10:55 +010099 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
José Fonseca031b7382011-05-10 20:36:40 +0100100 print ' }'
José Fonsecaa10af892011-04-11 09:10:55 +0100101 print ' %s = %s;' % (lvalue, new_lvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000102
103 def visit_blob(self, blob, lvalue, rvalue):
José Fonseca7ebb9e22011-05-06 09:58:45 +0100104 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000105
106 def visit_string(self, string, lvalue, rvalue):
José Fonseca7ebb9e22011-05-06 09:58:45 +0100107 print ' %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000108
109
José Fonsecaa10af892011-04-11 09:10:55 +0100110class OpaqueValueExtractor(ValueExtractor):
111 '''Value extractor that also understands opaque values.
112
113 Normally opaque values can't be retraced, unless they are being extracted
114 in the context of handles.'''
115
116 def visit_opaque(self, opaque, lvalue, rvalue):
José Fonseca7ebb9e22011-05-06 09:58:45 +0100117 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, opaque, rvalue)
José Fonsecaa10af892011-04-11 09:10:55 +0100118
José Fonsecae0e61402010-11-25 15:03:23 +0000119
120class ValueWrapper(stdapi.Visitor):
121
122 def visit_literal(self, literal, lvalue, rvalue):
123 pass
124
125 def visit_alias(self, alias, lvalue, rvalue):
126 self.visit(alias.type, lvalue, rvalue)
127
128 def visit_enum(self, enum, lvalue, rvalue):
129 pass
130
131 def visit_bitmask(self, bitmask, lvalue, rvalue):
132 pass
133
134 def visit_array(self, array, lvalue, rvalue):
135 print ' const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (array.id, rvalue)
136 print ' if (__a%s) {' % (array.id)
137 length = '__a%s->values.size()' % array.id
138 index = '__j' + array.id
José Fonsecadbaae492011-04-21 09:28:10 +0100139 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
José Fonsecae0e61402010-11-25 15:03:23 +0000140 try:
141 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.id, index))
142 finally:
143 print ' }'
144 print ' }'
145
146 def visit_pointer(self, pointer, lvalue, rvalue):
147 print ' const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (pointer.id, rvalue)
148 print ' if (__a%s) {' % (pointer.id)
149 try:
150 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.id,))
151 finally:
152 print ' }'
153
José Fonsecae0e61402010-11-25 15:03:23 +0000154 def visit_handle(self, handle, lvalue, rvalue):
José Fonsecaa10af892011-04-11 09:10:55 +0100155 print ' %s __orig_result;' % handle.type
156 OpaqueValueExtractor().visit(handle.type, '__orig_result', rvalue);
José Fonsecad922e1d2010-11-25 17:14:02 +0000157 if handle.range is None:
José Fonsecaa10af892011-04-11 09:10:55 +0100158 rvalue = "__orig_result"
José Fonseca8a844ae2010-12-06 18:50:52 +0000159 entry = handle_entry(handle, rvalue)
160 print " %s = %s;" % (entry, lvalue)
José Fonseca031b7382011-05-10 20:36:40 +0100161 print ' if (retrace::verbosity >= 2) {'
José Fonseca8a844ae2010-12-06 18:50:52 +0000162 print ' std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
José Fonseca031b7382011-05-10 20:36:40 +0100163 print ' }'
José Fonsecad922e1d2010-11-25 17:14:02 +0000164 else:
165 i = '__h' + handle.id
José Fonseca8a844ae2010-12-06 18:50:52 +0000166 lvalue = "%s + %s" % (lvalue, i)
José Fonsecaa10af892011-04-11 09:10:55 +0100167 rvalue = "__orig_result + %s" % (i,)
José Fonseca8a844ae2010-12-06 18:50:52 +0000168 entry = handle_entry(handle, rvalue)
José Fonsecadbaae492011-04-21 09:28:10 +0100169 print ' for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
José Fonseca8a844ae2010-12-06 18:50:52 +0000170 print ' {entry} = {lvalue};'.format(**locals())
José Fonseca031b7382011-05-10 20:36:40 +0100171 print ' if (retrace::verbosity >= 2) {'
José Fonseca8a844ae2010-12-06 18:50:52 +0000172 print ' std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
José Fonseca031b7382011-05-10 20:36:40 +0100173 print ' }'
José Fonsecad922e1d2010-11-25 17:14:02 +0000174 print ' }'
José Fonsecae0e61402010-11-25 15:03:23 +0000175
176 def visit_blob(self, blob, lvalue, rvalue):
177 pass
178
179 def visit_string(self, string, lvalue, rvalue):
180 pass
181
182
José Fonsecae0e61402010-11-25 15:03:23 +0000183class Retracer:
184
185 def retrace_function(self, function):
186 print 'static void retrace_%s(Trace::Call &call) {' % function.name
José Fonseca62212972011-03-23 13:22:55 +0000187 self.retrace_function_body(function)
188 print '}'
189 print
190
191 def retrace_function_body(self, function):
José Fonseca4d7f1fe2011-05-09 20:54:31 +0100192 if not function.sideeffects:
193 return
194
José Fonsecae0e61402010-11-25 15:03:23 +0000195 success = True
196 for arg in function.args:
197 arg_type = ConstRemover().visit(arg.type)
198 #print ' // %s -> %s' % (arg.type, arg_type)
199 print ' %s %s;' % (arg_type, arg.name)
200 rvalue = 'call.arg(%u)' % (arg.index,)
201 lvalue = arg.name
202 try:
José Fonsecadacd8dd2010-11-25 17:50:26 +0000203 self.extract_arg(function, arg, arg_type, lvalue, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000204 except NotImplementedError:
205 success = False
206 print ' %s = 0; // FIXME' % arg.name
207 if not success:
José Fonsecafa15d332010-11-25 20:22:39 +0000208 self.fail_function(function)
209 self.call_function(function)
José Fonsecae0e61402010-11-25 15:03:23 +0000210 for arg in function.args:
211 if arg.output:
212 arg_type = ConstRemover().visit(arg.type)
213 rvalue = 'call.arg(%u)' % (arg.index,)
214 lvalue = arg.name
215 try:
216 ValueWrapper().visit(arg_type, lvalue, rvalue)
217 except NotImplementedError:
218 print ' // FIXME: %s' % arg.name
219 if function.type is not stdapi.Void:
220 rvalue = '*call.ret'
221 lvalue = '__result'
222 try:
223 ValueWrapper().visit(function.type, lvalue, rvalue)
224 except NotImplementedError:
225 print ' // FIXME: result'
José Fonsecae0e61402010-11-25 15:03:23 +0000226
José Fonsecafa15d332010-11-25 20:22:39 +0000227 def fail_function(self, function):
José Fonseca32871ed2011-04-10 13:40:52 +0100228 print ' if (retrace::verbosity >= 0)'
José Fonseca5e687162011-02-09 15:11:12 +0000229 print ' std::cerr << "warning: unsupported call %s\\n";' % function.name
José Fonsecafa15d332010-11-25 20:22:39 +0000230 print ' return;'
231
José Fonsecadacd8dd2010-11-25 17:50:26 +0000232 def extract_arg(self, function, arg, arg_type, lvalue, rvalue):
233 ValueExtractor().visit(arg_type, lvalue, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000234
José Fonsecafa15d332010-11-25 20:22:39 +0000235 def call_function(self, function):
236 arg_names = ", ".join([arg.name for arg in function.args])
237 if function.type is not stdapi.Void:
238 print ' %s __result;' % (function.type)
239 print ' __result = %s(%s);' % (function.name, arg_names)
240 else:
241 print ' %s(%s);' % (function.name, arg_names)
242
José Fonseca4441baf2010-11-25 19:55:27 +0000243 def filter_function(self, function):
244 return True
245
José Fonsecae0e61402010-11-25 15:03:23 +0000246 def retrace_functions(self, functions):
José Fonseca4441baf2010-11-25 19:55:27 +0000247 functions = filter(self.filter_function, functions)
248
José Fonsecae0e61402010-11-25 15:03:23 +0000249 for function in functions:
José Fonseca4d7f1fe2011-05-09 20:54:31 +0100250 self.retrace_function(function)
José Fonsecae0e61402010-11-25 15:03:23 +0000251
José Fonsecaf237aad2011-05-05 00:54:04 +0100252 print 'void retrace::retrace_call(Trace::Call &call) {'
José Fonseca522b7442010-11-27 15:30:40 +0000253 print ' const char *name = call.name().c_str();'
José Fonsecae0e61402010-11-25 15:03:23 +0000254 print
José Fonseca522b7442010-11-27 15:30:40 +0000255
256 func_dict = dict([(function.name, function) for function in functions])
257
258 def handle_case(function_name):
259 function = func_dict[function_name]
José Fonseca4d7f1fe2011-05-09 20:54:31 +0100260 print ' retrace_%s(call);' % function.name
José Fonsecaf237aad2011-05-05 00:54:04 +0100261 print ' return;'
José Fonseca522b7442010-11-27 15:30:40 +0000262
263 string_switch('name', func_dict.keys(), handle_case)
264
José Fonseca45b28c42011-05-05 01:08:00 +0100265 print ' retrace_unknown(call);'
José Fonsecae0e61402010-11-25 15:03:23 +0000266 print '}'
267 print
268
269
270 def retrace_api(self, api):
271
272 print '#include "trace_parser.hpp"'
José Fonseca91343f52011-04-01 08:37:06 +0100273 print '#include "retrace.hpp"'
José Fonsecae0e61402010-11-25 15:03:23 +0000274 print
275
276 types = api.all_types()
277 handles = [type for type in types if isinstance(type, stdapi.Handle)]
José Fonsecad922e1d2010-11-25 17:14:02 +0000278 handle_names = set()
José Fonsecae0e61402010-11-25 15:03:23 +0000279 for handle in handles:
José Fonsecad922e1d2010-11-25 17:14:02 +0000280 if handle.name not in handle_names:
José Fonseca8a844ae2010-12-06 18:50:52 +0000281 if handle.key is None:
José Fonseca91343f52011-04-01 08:37:06 +0100282 print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
José Fonseca8a844ae2010-12-06 18:50:52 +0000283 else:
284 key_name, key_type = handle.key
José Fonseca91343f52011-04-01 08:37:06 +0100285 print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
José Fonsecad922e1d2010-11-25 17:14:02 +0000286 handle_names.add(handle.name)
José Fonsecae0e61402010-11-25 15:03:23 +0000287 print
288
José Fonsecae0e61402010-11-25 15:03:23 +0000289 self.retrace_functions(api.functions)
290