blob: a51973e93b31c10768b18c6709c0eb2768c793fa [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é Fonseca0a37edf2011-10-09 09:45:22 +010029
José Fonseca9d27a542012-04-14 17:22:57 +010030# Adjust path
31import os.path
José Fonseca0a37edf2011-10-09 09:45:22 +010032import sys
José Fonseca9d27a542012-04-14 17:22:57 +010033sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
34
José Fonseca0a37edf2011-10-09 09:45:22 +010035
José Fonsecabd86a222011-09-27 09:21:38 +010036import specs.stdapi as stdapi
José Fonsecae0e61402010-11-25 15:03:23 +000037
38
José Fonseca2672a7d2012-04-14 15:17:12 +010039class UnsupportedType(Exception):
40 pass
41
42
Cass Everitt3b595cb2013-06-19 19:30:32 -050043def lookupHandle(handle, value, lval=False):
José Fonseca8a844ae2010-12-06 18:50:52 +000044 if handle.key is None:
José Fonseca632a78d2012-04-19 07:18:59 +010045 return "_%s_map[%s]" % (handle.name, value)
José Fonseca8a844ae2010-12-06 18:50:52 +000046 else:
47 key_name, key_type = handle.key
Cass Everitt3b595cb2013-06-19 19:30:32 -050048 if handle.name == "location" and lval == False:
49 return "_location_map[%s].lookupUniformLocation(%s)" % (key_name, value)
50 else:
51 return "_%s_map[%s][%s]" % (handle.name, key_name, value)
José Fonseca8a844ae2010-12-06 18:50:52 +000052
53
José Fonseca4a2c57b2012-04-07 10:50:53 +010054class ValueAllocator(stdapi.Visitor):
55
56 def visitLiteral(self, literal, lvalue, rvalue):
57 pass
58
59 def visitConst(self, const, lvalue, rvalue):
60 self.visit(const.type, lvalue, rvalue)
61
62 def visitAlias(self, alias, lvalue, rvalue):
63 self.visit(alias.type, lvalue, rvalue)
64
65 def visitEnum(self, enum, lvalue, rvalue):
66 pass
67
68 def visitBitmask(self, bitmask, lvalue, rvalue):
69 pass
70
71 def visitArray(self, array, lvalue, rvalue):
José Fonseca915d4da2014-09-05 11:55:17 +010072 print ' %s = _allocator.allocArray<%s>(&%s);' % (lvalue, array.type, rvalue)
José Fonseca4a2c57b2012-04-07 10:50:53 +010073
74 def visitPointer(self, pointer, lvalue, rvalue):
José Fonseca915d4da2014-09-05 11:55:17 +010075 print ' %s = _allocator.allocArray<%s>(&%s);' % (lvalue, pointer.type, rvalue)
José Fonseca4a2c57b2012-04-07 10:50:53 +010076
77 def visitIntPointer(self, pointer, lvalue, rvalue):
78 pass
79
80 def visitObjPointer(self, pointer, lvalue, rvalue):
81 pass
82
83 def visitLinearPointer(self, pointer, lvalue, rvalue):
84 pass
85
86 def visitReference(self, reference, lvalue, rvalue):
87 self.visit(reference.type, lvalue, rvalue);
88
89 def visitHandle(self, handle, lvalue, rvalue):
90 pass
91
92 def visitBlob(self, blob, lvalue, rvalue):
93 pass
94
95 def visitString(self, string, lvalue, rvalue):
96 pass
97
98 def visitStruct(self, struct, lvalue, rvalue):
99 pass
100
101 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
José Fonsecadbf714b2012-11-20 17:03:43 +0000102 assert polymorphic.defaultType is not None
José Fonseca4a2c57b2012-04-07 10:50:53 +0100103 self.visit(polymorphic.defaultType, lvalue, rvalue)
104
José Fonseca2672a7d2012-04-14 15:17:12 +0100105 def visitOpaque(self, opaque, lvalue, rvalue):
106 pass
107
José Fonseca4a2c57b2012-04-07 10:50:53 +0100108
José Fonsecadbf714b2012-11-20 17:03:43 +0000109class ValueDeserializer(stdapi.Visitor, stdapi.ExpanderMixin):
José Fonsecae0e61402010-11-25 15:03:23 +0000110
José Fonseca54f304a2012-01-14 19:33:08 +0000111 def visitLiteral(self, literal, lvalue, rvalue):
José Fonseca2f2ea482011-10-15 15:10:06 +0100112 print ' %s = (%s).to%s();' % (lvalue, rvalue, literal.kind)
José Fonsecae0e61402010-11-25 15:03:23 +0000113
José Fonseca54f304a2012-01-14 19:33:08 +0000114 def visitConst(self, const, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000115 self.visit(const.type, lvalue, rvalue)
116
José Fonseca54f304a2012-01-14 19:33:08 +0000117 def visitAlias(self, alias, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000118 self.visit(alias.type, lvalue, rvalue)
119
José Fonseca54f304a2012-01-14 19:33:08 +0000120 def visitEnum(self, enum, lvalue, rvalue):
José Fonseca96ce6002012-04-02 08:10:48 +0200121 print ' %s = static_cast<%s>((%s).toSInt());' % (lvalue, enum, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000122
José Fonseca54f304a2012-01-14 19:33:08 +0000123 def visitBitmask(self, bitmask, lvalue, rvalue):
Jose Fonsecab29a5802016-05-20 23:40:35 +0100124 print ' %s = static_cast<%s>((%s).toUInt());' % (lvalue, bitmask, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000125
José Fonseca54f304a2012-01-14 19:33:08 +0000126 def visitArray(self, array, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100127 tmp = '_a_' + array.tag + '_' + str(self.seq)
José Fonseca68013c92012-04-05 19:58:38 +0100128 self.seq += 1
129
Jose Fonsecaf48264d2015-07-17 17:00:23 +0100130 print ' const trace::Array *%s = (%s).toArray();' % (tmp, rvalue)
131 print ' if (%s) {' % (tmp,)
Jose Fonseca41efd942015-06-10 22:54:18 +0100132
Jose Fonsecaf48264d2015-07-17 17:00:23 +0100133 length = '%s->values.size()' % (tmp,)
Jose Fonseca41efd942015-06-10 22:54:18 +0100134 if self.insideStruct:
135 if isinstance(array.length, int):
136 # Member is an array
137 print r' static_assert( std::is_array< std::remove_reference< decltype( %s ) >::type >::value , "lvalue must be an array" );' % lvalue
138 print r' static_assert( std::extent< std::remove_reference< decltype( %s ) >::type >::value == %s, "array size mismatch" );' % (lvalue, array.length)
Jose Fonsecaf48264d2015-07-17 17:00:23 +0100139 print r' assert( %s );' % (tmp,)
140 print r' assert( %s->size() == %s );' % (tmp, array.length)
141 length = str(array.length)
Jose Fonseca41efd942015-06-10 22:54:18 +0100142 else:
143 # Member is a pointer to an array, hence must be allocated
144 print r' static_assert( std::is_pointer< std::remove_reference< decltype( %s ) >::type >::value , "lvalue must be a pointer" );' % lvalue
145 print r' %s = _allocator.allocArray<%s>(&%s);' % (lvalue, array.type, rvalue)
146
José Fonseca632a78d2012-04-19 07:18:59 +0100147 index = '_j' + array.tag
José Fonsecadbaae492011-04-21 09:28:10 +0100148 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
José Fonsecae0e61402010-11-25 15:03:23 +0000149 try:
José Fonseca68013c92012-04-05 19:58:38 +0100150 self.visit(array.type, '%s[%s]' % (lvalue, index), '*%s->values[%s]' % (tmp, index))
José Fonsecae0e61402010-11-25 15:03:23 +0000151 finally:
152 print ' }'
José Fonsecae0e61402010-11-25 15:03:23 +0000153 print ' }'
154
José Fonseca54f304a2012-01-14 19:33:08 +0000155 def visitPointer(self, pointer, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100156 tmp = '_a_' + pointer.tag + '_' + str(self.seq)
José Fonseca68013c92012-04-05 19:58:38 +0100157 self.seq += 1
158
Jose Fonseca2e295882016-05-16 14:20:39 +0100159 if self.insideStruct:
160 # Member is a pointer to an object, hence must be allocated
161 print r' static_assert( std::is_pointer< std::remove_reference< decltype( %s ) >::type >::value , "lvalue must be a pointer" );' % lvalue
162 print r' %s = _allocator.allocArray<%s>(&%s);' % (lvalue, pointer.type, rvalue)
163
José Fonseca4a2c57b2012-04-07 10:50:53 +0100164 print ' if (%s) {' % (lvalue,)
Nigel Stewartabaef292013-07-10 09:01:01 -0500165 print ' const trace::Array *%s = (%s).toArray();' % (tmp, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000166 try:
José Fonseca68013c92012-04-05 19:58:38 +0100167 self.visit(pointer.type, '%s[0]' % (lvalue,), '*%s->values[0]' % (tmp,))
José Fonsecae0e61402010-11-25 15:03:23 +0000168 finally:
José Fonsecae0e61402010-11-25 15:03:23 +0000169 print ' }'
170
José Fonseca59ee88e2012-01-15 14:24:10 +0000171 def visitIntPointer(self, pointer, lvalue, rvalue):
172 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, pointer, rvalue)
173
José Fonsecafbcf6832012-04-05 07:10:30 +0100174 def visitObjPointer(self, pointer, lvalue, rvalue):
José Fonseca915d4da2014-09-05 11:55:17 +0100175 print ' %s = retrace::asObjPointer<%s>(call, %s);' % (lvalue, pointer.type, rvalue)
José Fonsecafbcf6832012-04-05 07:10:30 +0100176
José Fonseca59ee88e2012-01-15 14:24:10 +0000177 def visitLinearPointer(self, pointer, lvalue, rvalue):
178 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, pointer, rvalue)
179
José Fonsecab89c5932012-04-01 22:47:11 +0200180 def visitReference(self, reference, lvalue, rvalue):
181 self.visit(reference.type, lvalue, rvalue);
182
José Fonseca54f304a2012-01-14 19:33:08 +0000183 def visitHandle(self, handle, lvalue, rvalue):
José Fonseca59ee88e2012-01-15 14:24:10 +0000184 #OpaqueValueDeserializer().visit(handle.type, lvalue, rvalue);
185 self.visit(handle.type, lvalue, rvalue);
José Fonseca54f304a2012-01-14 19:33:08 +0000186 new_lvalue = lookupHandle(handle, lvalue)
Jose Fonseca28e29ee2017-07-30 14:21:48 +0100187 shaderObject = new_lvalue.startswith('_program_map') or new_lvalue.startswith('_shader_map')
188 if shaderObject:
189 print 'if (glretrace::supportsARBShaderObjects) {'
190 print ' if (retrace::verbosity >= 2) {'
191 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(_handleARB_map[%s]) << "\\n";' % (handle.name, lvalue, lvalue)
192 print ' }'
193 print ' %s = _handleARB_map[%s];' % (lvalue, lvalue)
194 print '} else {'
José Fonseca031b7382011-05-10 20:36:40 +0100195 print ' if (retrace::verbosity >= 2) {'
José Fonsecaa10af892011-04-11 09:10:55 +0100196 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
José Fonseca031b7382011-05-10 20:36:40 +0100197 print ' }'
Jose Fonseca28e29ee2017-07-30 14:21:48 +0100198 print ' %s = %s;' % (lvalue, new_lvalue)
199 if shaderObject:
Carl Worth37007772012-08-28 11:45:52 -0700200 print '}'
José Fonsecae0e61402010-11-25 15:03:23 +0000201
José Fonseca54f304a2012-01-14 19:33:08 +0000202 def visitBlob(self, blob, lvalue, rvalue):
José Fonseca7ebb9e22011-05-06 09:58:45 +0100203 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000204
José Fonseca54f304a2012-01-14 19:33:08 +0000205 def visitString(self, string, lvalue, rvalue):
José Fonseca7ebb9e22011-05-06 09:58:45 +0100206 print ' %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000207
José Fonsecaa65a23a2012-04-02 08:10:06 +0200208 seq = 0
209
Jose Fonseca41efd942015-06-10 22:54:18 +0100210 insideStruct = 0
211
José Fonsecaa65a23a2012-04-02 08:10:06 +0200212 def visitStruct(self, struct, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100213 tmp = '_s_' + struct.tag + '_' + str(self.seq)
José Fonsecaa65a23a2012-04-02 08:10:06 +0200214 self.seq += 1
215
Jose Fonseca41efd942015-06-10 22:54:18 +0100216 self.insideStruct += 1
217
Nigel Stewartabaef292013-07-10 09:01:01 -0500218 print ' const trace::Struct *%s = (%s).toStruct();' % (tmp, rvalue)
José Fonsecaa65a23a2012-04-02 08:10:06 +0200219 print ' assert(%s);' % (tmp)
José Fonsecaa65a23a2012-04-02 08:10:06 +0200220 for i in range(len(struct.members)):
José Fonsecadbf714b2012-11-20 17:03:43 +0000221 member = struct.members[i]
222 self.visitMember(member, lvalue, '*%s->members[%s]' % (tmp, i))
José Fonsecaa65a23a2012-04-02 08:10:06 +0200223
Jose Fonseca41efd942015-06-10 22:54:18 +0100224 self.insideStruct -= 1
225
José Fonseca4a2c57b2012-04-07 10:50:53 +0100226 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
José Fonsecaeb216e62012-11-20 11:08:08 +0000227 if polymorphic.defaultType is None:
José Fonsecadbf714b2012-11-20 17:03:43 +0000228 switchExpr = self.expand(polymorphic.switchExpr)
229 print r' switch (%s) {' % switchExpr
230 for cases, type in polymorphic.iterSwitch():
231 for case in cases:
232 print r' %s:' % case
233 caseLvalue = lvalue
234 if type.expr is not None:
235 caseLvalue = 'static_cast<%s>(%s)' % (type, caseLvalue)
236 print r' {'
237 try:
238 self.visit(type, caseLvalue, rvalue)
239 finally:
240 print r' }'
241 print r' break;'
242 if polymorphic.defaultType is None:
243 print r' default:'
244 print r' retrace::warning(call) << "unexpected polymorphic case" << %s << "\n";' % (switchExpr,)
245 print r' break;'
246 print r' }'
247 else:
248 self.visit(polymorphic.defaultType, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100249
250 def visitOpaque(self, opaque, lvalue, rvalue):
251 raise UnsupportedType
José Fonseca4a2c57b2012-04-07 10:50:53 +0100252
José Fonsecae0e61402010-11-25 15:03:23 +0000253
José Fonseca54f304a2012-01-14 19:33:08 +0000254class OpaqueValueDeserializer(ValueDeserializer):
José Fonsecaa10af892011-04-11 09:10:55 +0100255 '''Value extractor that also understands opaque values.
256
257 Normally opaque values can't be retraced, unless they are being extracted
258 in the context of handles.'''
259
José Fonseca54f304a2012-01-14 19:33:08 +0000260 def visitOpaque(self, opaque, lvalue, rvalue):
José Fonseca46a48392011-10-14 11:34:27 +0100261 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, opaque, rvalue)
José Fonsecaa10af892011-04-11 09:10:55 +0100262
José Fonsecae0e61402010-11-25 15:03:23 +0000263
José Fonsecadbf714b2012-11-20 17:03:43 +0000264class SwizzledValueRegistrator(stdapi.Visitor, stdapi.ExpanderMixin):
José Fonseca54f304a2012-01-14 19:33:08 +0000265 '''Type visitor which will register (un)swizzled value pairs, to later be
266 swizzled.'''
José Fonsecae0e61402010-11-25 15:03:23 +0000267
José Fonseca54f304a2012-01-14 19:33:08 +0000268 def visitLiteral(self, literal, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000269 pass
270
José Fonseca54f304a2012-01-14 19:33:08 +0000271 def visitAlias(self, alias, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000272 self.visit(alias.type, lvalue, rvalue)
273
José Fonseca54f304a2012-01-14 19:33:08 +0000274 def visitEnum(self, enum, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000275 pass
276
José Fonseca54f304a2012-01-14 19:33:08 +0000277 def visitBitmask(self, bitmask, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000278 pass
279
José Fonseca54f304a2012-01-14 19:33:08 +0000280 def visitArray(self, array, lvalue, rvalue):
Nigel Stewartabaef292013-07-10 09:01:01 -0500281 print ' const trace::Array *_a%s = (%s).toArray();' % (array.tag, rvalue)
José Fonseca632a78d2012-04-19 07:18:59 +0100282 print ' if (_a%s) {' % (array.tag)
283 length = '_a%s->values.size()' % array.tag
284 index = '_j' + array.tag
José Fonsecadbaae492011-04-21 09:28:10 +0100285 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
José Fonsecae0e61402010-11-25 15:03:23 +0000286 try:
José Fonseca632a78d2012-04-19 07:18:59 +0100287 self.visit(array.type, '%s[%s]' % (lvalue, index), '*_a%s->values[%s]' % (array.tag, index))
José Fonsecae0e61402010-11-25 15:03:23 +0000288 finally:
289 print ' }'
290 print ' }'
291
José Fonseca54f304a2012-01-14 19:33:08 +0000292 def visitPointer(self, pointer, lvalue, rvalue):
Nigel Stewartabaef292013-07-10 09:01:01 -0500293 print ' const trace::Array *_a%s = (%s).toArray();' % (pointer.tag, rvalue)
José Fonseca632a78d2012-04-19 07:18:59 +0100294 print ' if (_a%s) {' % (pointer.tag)
José Fonsecae0e61402010-11-25 15:03:23 +0000295 try:
José Fonseca632a78d2012-04-19 07:18:59 +0100296 self.visit(pointer.type, '%s[0]' % (lvalue,), '*_a%s->values[0]' % (pointer.tag,))
José Fonsecae0e61402010-11-25 15:03:23 +0000297 finally:
298 print ' }'
299
José Fonseca59ee88e2012-01-15 14:24:10 +0000300 def visitIntPointer(self, pointer, lvalue, rvalue):
301 pass
302
José Fonsecafbcf6832012-04-05 07:10:30 +0100303 def visitObjPointer(self, pointer, lvalue, rvalue):
José Fonsecad8068b32012-11-13 21:37:42 +0000304 print r' retrace::addObj(call, %s, %s);' % (rvalue, lvalue)
José Fonsecafbcf6832012-04-05 07:10:30 +0100305
José Fonseca59ee88e2012-01-15 14:24:10 +0000306 def visitLinearPointer(self, pointer, lvalue, rvalue):
307 assert pointer.size is not None
308 if pointer.size is not None:
Jose Fonsecae05718d2015-05-20 10:22:56 +0100309 print r' retrace::addRegion(call, (%s).toUIntPtr(), %s, %s);' % (rvalue, lvalue, pointer.size)
José Fonseca59ee88e2012-01-15 14:24:10 +0000310
José Fonsecab89c5932012-04-01 22:47:11 +0200311 def visitReference(self, reference, lvalue, rvalue):
312 pass
313
José Fonseca54f304a2012-01-14 19:33:08 +0000314 def visitHandle(self, handle, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100315 print ' %s _origResult;' % handle.type
316 OpaqueValueDeserializer().visit(handle.type, '_origResult', rvalue);
José Fonsecad922e1d2010-11-25 17:14:02 +0000317 if handle.range is None:
José Fonseca632a78d2012-04-19 07:18:59 +0100318 rvalue = "_origResult"
Cass Everitt3b595cb2013-06-19 19:30:32 -0500319 entry = lookupHandle(handle, rvalue, True)
Carl Worth37007772012-08-28 11:45:52 -0700320 if (entry.startswith('_program_map') or entry.startswith('_shader_map')):
321 print 'if (glretrace::supportsARBShaderObjects) {'
322 print ' _handleARB_map[%s] = %s;' % (rvalue, lvalue)
323 print '} else {'
324 print ' %s = %s;' % (entry, lvalue)
325 print '}'
326 else:
327 print " %s = %s;" % (entry, lvalue)
José Fonseca031b7382011-05-10 20:36:40 +0100328 print ' if (retrace::verbosity >= 2) {'
José Fonseca8a844ae2010-12-06 18:50:52 +0000329 print ' std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
José Fonseca031b7382011-05-10 20:36:40 +0100330 print ' }'
José Fonsecad922e1d2010-11-25 17:14:02 +0000331 else:
José Fonseca632a78d2012-04-19 07:18:59 +0100332 i = '_h' + handle.tag
José Fonseca8a844ae2010-12-06 18:50:52 +0000333 lvalue = "%s + %s" % (lvalue, i)
José Fonseca632a78d2012-04-19 07:18:59 +0100334 rvalue = "_origResult + %s" % (i,)
José Fonseca54f304a2012-01-14 19:33:08 +0000335 entry = lookupHandle(handle, rvalue)
José Fonsecadbaae492011-04-21 09:28:10 +0100336 print ' for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
José Fonseca8a844ae2010-12-06 18:50:52 +0000337 print ' {entry} = {lvalue};'.format(**locals())
José Fonseca031b7382011-05-10 20:36:40 +0100338 print ' if (retrace::verbosity >= 2) {'
José Fonseca8a844ae2010-12-06 18:50:52 +0000339 print ' std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
José Fonseca031b7382011-05-10 20:36:40 +0100340 print ' }'
José Fonsecad922e1d2010-11-25 17:14:02 +0000341 print ' }'
José Fonsecae0e61402010-11-25 15:03:23 +0000342
José Fonseca54f304a2012-01-14 19:33:08 +0000343 def visitBlob(self, blob, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000344 pass
345
José Fonseca54f304a2012-01-14 19:33:08 +0000346 def visitString(self, string, lvalue, rvalue):
José Fonsecae0e61402010-11-25 15:03:23 +0000347 pass
348
José Fonseca4a2c57b2012-04-07 10:50:53 +0100349 seq = 0
350
351 def visitStruct(self, struct, lvalue, rvalue):
José Fonseca632a78d2012-04-19 07:18:59 +0100352 tmp = '_s_' + struct.tag + '_' + str(self.seq)
José Fonseca4a2c57b2012-04-07 10:50:53 +0100353 self.seq += 1
354
Nigel Stewartabaef292013-07-10 09:01:01 -0500355 print ' const trace::Struct *%s = (%s).toStruct();' % (tmp, rvalue)
José Fonseca4a2c57b2012-04-07 10:50:53 +0100356 print ' assert(%s);' % (tmp,)
357 print ' (void)%s;' % (tmp,)
358 for i in range(len(struct.members)):
José Fonsecadbf714b2012-11-20 17:03:43 +0000359 member = struct.members[i]
360 self.visitMember(member, lvalue, '*%s->members[%s]' % (tmp, i))
José Fonseca4a2c57b2012-04-07 10:50:53 +0100361
362 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
José Fonsecadbf714b2012-11-20 17:03:43 +0000363 assert polymorphic.defaultType is not None
José Fonseca4a2c57b2012-04-07 10:50:53 +0100364 self.visit(polymorphic.defaultType, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100365
366 def visitOpaque(self, opaque, lvalue, rvalue):
367 pass
José Fonseca4a2c57b2012-04-07 10:50:53 +0100368
José Fonsecae0e61402010-11-25 15:03:23 +0000369
José Fonsecae0e61402010-11-25 15:03:23 +0000370class Retracer:
371
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000372 def makeFunctionId(self, function):
373 name = function.name
374 if function.overloaded:
375 # TODO: Use a sequence number
376 name += '__%08x' % (hash(function) & 0xffffffff)
377 return name
378
José Fonseca54f304a2012-01-14 19:33:08 +0000379 def retraceFunction(self, function):
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000380 print 'static void retrace_%s(trace::Call &call) {' % self.makeFunctionId(function)
José Fonseca54f304a2012-01-14 19:33:08 +0000381 self.retraceFunctionBody(function)
José Fonseca62212972011-03-23 13:22:55 +0000382 print '}'
383 print
384
José Fonseca8e3c2c02012-01-23 00:30:35 +0000385 def retraceInterfaceMethod(self, interface, method):
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000386 print 'static void retrace_%s__%s(trace::Call &call) {' % (interface.name, self.makeFunctionId(method))
José Fonseca8e3c2c02012-01-23 00:30:35 +0000387 self.retraceInterfaceMethodBody(interface, method)
388 print '}'
389 print
390
José Fonseca54f304a2012-01-14 19:33:08 +0000391 def retraceFunctionBody(self, function):
José Fonsecadd27f9f2012-04-13 13:57:23 +0100392 assert function.sideeffects
José Fonseca4d7f1fe2011-05-09 20:54:31 +0100393
José Fonseca7c7c9062012-04-27 13:02:08 +0100394 if function.type is not stdapi.Void:
395 self.checkOrigResult(function)
396
José Fonseca8e3c2c02012-01-23 00:30:35 +0000397 self.deserializeArgs(function)
398
José Fonseca3db3b2f2012-05-11 14:55:50 +0100399 self.declareRet(function)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000400 self.invokeFunction(function)
401
402 self.swizzleValues(function)
403
404 def retraceInterfaceMethodBody(self, interface, method):
José Fonseca1da480d2012-04-13 17:36:19 +0100405 assert method.sideeffects
José Fonseca8e3c2c02012-01-23 00:30:35 +0000406
José Fonseca7c7c9062012-04-27 13:02:08 +0100407 if method.type is not stdapi.Void:
408 self.checkOrigResult(method)
409
José Fonseca8e3c2c02012-01-23 00:30:35 +0000410 self.deserializeThisPointer(interface)
411
412 self.deserializeArgs(method)
413
José Fonseca3db3b2f2012-05-11 14:55:50 +0100414 self.declareRet(method)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000415 self.invokeInterfaceMethod(interface, method)
416
417 self.swizzleValues(method)
418
José Fonseca7c7c9062012-04-27 13:02:08 +0100419 def checkOrigResult(self, function):
420 '''Hook for checking the original result, to prevent succeeding now
421 where the original did not, which would cause diversion and potentially
422 unpredictable results.'''
423
424 assert function.type is not stdapi.Void
425
426 if str(function.type) == 'HRESULT':
427 print r' if (call.ret && FAILED(call.ret->toSInt())) {'
428 print r' return;'
429 print r' }'
430
José Fonseca8e3c2c02012-01-23 00:30:35 +0000431 def deserializeThisPointer(self, interface):
José Fonsecadc279372012-04-05 19:58:20 +0100432 print r' %s *_this;' % (interface.name,)
José Fonseca915d4da2014-09-05 11:55:17 +0100433 print r' _this = retrace::asObjPointer<%s>(call, call.arg(0));' % (interface.name,)
José Fonsecadc279372012-04-05 19:58:20 +0100434 print r' if (!_this) {'
José Fonsecadc279372012-04-05 19:58:20 +0100435 print r' return;'
436 print r' }'
José Fonseca8e3c2c02012-01-23 00:30:35 +0000437
438 def deserializeArgs(self, function):
José Fonsecad994cf02011-11-03 19:35:53 +0000439 print ' retrace::ScopedAllocator _allocator;'
440 print ' (void)_allocator;'
José Fonsecae0e61402010-11-25 15:03:23 +0000441 success = True
442 for arg in function.args:
José Fonseca0075f152012-04-14 20:25:52 +0100443 arg_type = arg.type.mutable()
José Fonsecae0e61402010-11-25 15:03:23 +0000444 print ' %s %s;' % (arg_type, arg.name)
445 rvalue = 'call.arg(%u)' % (arg.index,)
446 lvalue = arg.name
447 try:
José Fonseca54f304a2012-01-14 19:33:08 +0000448 self.extractArg(function, arg, arg_type, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100449 except UnsupportedType:
José Fonseca8e3c2c02012-01-23 00:30:35 +0000450 success = False
José Fonseca2d216ae2012-04-01 22:48:24 +0200451 print ' memset(&%s, 0, sizeof %s); // FIXME' % (arg.name, arg.name)
José Fonseca4a2c57b2012-04-07 10:50:53 +0100452 print
José Fonseca8e3c2c02012-01-23 00:30:35 +0000453
José Fonsecae0e61402010-11-25 15:03:23 +0000454 if not success:
José Fonseca9109c3a2011-05-24 19:31:26 +0100455 print ' if (1) {'
José Fonseca54f304a2012-01-14 19:33:08 +0000456 self.failFunction(function)
José Fonsecaeb216e62012-11-20 11:08:08 +0000457 sys.stderr.write('warning: unsupported %s call\n' % function.name)
José Fonseca9109c3a2011-05-24 19:31:26 +0100458 print ' }'
José Fonseca8e3c2c02012-01-23 00:30:35 +0000459
460 def swizzleValues(self, function):
José Fonsecae0e61402010-11-25 15:03:23 +0000461 for arg in function.args:
462 if arg.output:
José Fonseca0075f152012-04-14 20:25:52 +0100463 arg_type = arg.type.mutable()
José Fonsecae0e61402010-11-25 15:03:23 +0000464 rvalue = 'call.arg(%u)' % (arg.index,)
465 lvalue = arg.name
466 try:
José Fonseca54f304a2012-01-14 19:33:08 +0000467 self.regiterSwizzledValue(arg_type, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100468 except UnsupportedType:
José Fonseca0a37edf2011-10-09 09:45:22 +0100469 print ' // XXX: %s' % arg.name
José Fonsecae0e61402010-11-25 15:03:23 +0000470 if function.type is not stdapi.Void:
471 rvalue = '*call.ret'
José Fonseca632a78d2012-04-19 07:18:59 +0100472 lvalue = '_result'
José Fonsecae0e61402010-11-25 15:03:23 +0000473 try:
José Fonseca54f304a2012-01-14 19:33:08 +0000474 self.regiterSwizzledValue(function.type, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100475 except UnsupportedType:
José Fonsecafbcf6832012-04-05 07:10:30 +0100476 raise
José Fonseca46a48392011-10-14 11:34:27 +0100477 print ' // XXX: result'
José Fonsecae0e61402010-11-25 15:03:23 +0000478
José Fonseca54f304a2012-01-14 19:33:08 +0000479 def failFunction(self, function):
José Fonsecab1bb3c22011-10-08 20:23:18 +0100480 print ' if (retrace::verbosity >= 0) {'
José Fonsecaf5cda412011-10-09 17:27:23 +0100481 print ' retrace::unsupported(call);'
José Fonsecab1bb3c22011-10-08 20:23:18 +0100482 print ' }'
José Fonsecafa15d332010-11-25 20:22:39 +0000483 print ' return;'
484
José Fonseca54f304a2012-01-14 19:33:08 +0000485 def extractArg(self, function, arg, arg_type, lvalue, rvalue):
José Fonseca4a2c57b2012-04-07 10:50:53 +0100486 ValueAllocator().visit(arg_type, lvalue, rvalue)
487 if arg.input:
488 ValueDeserializer().visit(arg_type, lvalue, rvalue)
José Fonsecafd34e4e2011-06-03 19:34:29 +0100489
José Fonseca54f304a2012-01-14 19:33:08 +0000490 def extractOpaqueArg(self, function, arg, arg_type, lvalue, rvalue):
José Fonseca4a2c57b2012-04-07 10:50:53 +0100491 try:
492 ValueAllocator().visit(arg_type, lvalue, rvalue)
José Fonseca2672a7d2012-04-14 15:17:12 +0100493 except UnsupportedType:
José Fonseca4a2c57b2012-04-07 10:50:53 +0100494 pass
José Fonseca54f304a2012-01-14 19:33:08 +0000495 OpaqueValueDeserializer().visit(arg_type, lvalue, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000496
José Fonseca54f304a2012-01-14 19:33:08 +0000497 def regiterSwizzledValue(self, type, lvalue, rvalue):
498 visitor = SwizzledValueRegistrator()
499 visitor.visit(type, lvalue, rvalue)
500
José Fonseca3db3b2f2012-05-11 14:55:50 +0100501 def declareRet(self, function):
502 if function.type is not stdapi.Void:
503 print ' %s _result;' % (function.type)
504
José Fonseca54f304a2012-01-14 19:33:08 +0000505 def invokeFunction(self, function):
Jose Fonsecaf39fd602017-08-23 15:13:39 +0100506 # Same as invokeFunction, but without error checking
507 #
508 # XXX: Find a better name
509 self.doInvokeFunction(function)
510 if function.type is not stdapi.Void:
511 self.checkResult(None, function)
512
513 def doInvokeFunction(self, function):
José Fonseca59ee88e2012-01-15 14:24:10 +0000514 arg_names = ", ".join(function.argNames())
José Fonsecafa15d332010-11-25 20:22:39 +0000515 if function.type is not stdapi.Void:
José Fonseca632a78d2012-04-19 07:18:59 +0100516 print ' _result = %s(%s);' % (function.name, arg_names)
José Fonsecafa15d332010-11-25 20:22:39 +0000517 else:
518 print ' %s(%s);' % (function.name, arg_names)
519
Jose Fonsecad9ff09f2016-05-16 14:04:36 +0100520 def doInvokeInterfaceMethod(self, interface, method):
521 # Same as invokeInterfaceMethod, but without error checking
522 #
523 # XXX: Find a better name
524
José Fonseca8e3c2c02012-01-23 00:30:35 +0000525 arg_names = ", ".join(method.argNames())
526 if method.type is not stdapi.Void:
José Fonseca632a78d2012-04-19 07:18:59 +0100527 print ' _result = _this->%s(%s);' % (method.name, arg_names)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000528 else:
529 print ' _this->%s(%s);' % (method.name, arg_names)
530
José Fonsecada777082015-02-09 11:18:36 +0000531 # Adjust reference count when QueryInterface fails. This is
532 # particularly useful when replaying traces on older Direct3D runtimes
533 # which might miss newer versions of interfaces, yet none of those
534 # methods are actually used.
535 #
536 # TODO: Generalize to other methods that return interfaces
537 if method.name == 'QueryInterface':
538 print r' if (FAILED(_result)) {'
539 print r' IUnknown *pObj = retrace::asObjPointer<IUnknown>(call, *call.arg(2).toArray()->values[0]);'
540 print r' if (pObj) {'
541 print r' pObj->AddRef();'
542 print r' }'
543 print r' }'
544
José Fonseca8a4462e2014-09-23 14:39:01 +0100545 # Debug COM reference counting. Disabled by default as reported
546 # reference counts depend on internal implementation details.
547 if method.name in ('AddRef', 'Release'):
548 print r' if (0) retrace::checkMismatch(call, "cRef", call.ret, _result);'
549
550 # On release our reference when we reach Release() == 0 call in the
551 # trace.
552 if method.name == 'Release':
553 print r' ULONG _orig_result = call.ret->toUInt();'
554 print r' if (_orig_result == 0 || _result == 0) {'
555 print r' if (_orig_result != 0) {'
556 print r' retrace::warning(call) << "unexpected object destruction\n";'
557 print r' }'
Jose Fonsecaf56b86d2016-06-28 22:26:45 +0100558 print r' // NOTE: Must not delete the object mapping here. See'
559 print r' // https://github.com/apitrace/apitrace/issues/462'
José Fonseca8a4462e2014-09-23 14:39:01 +0100560 print r' }'
561
Jose Fonsecad9ff09f2016-05-16 14:04:36 +0100562 def invokeInterfaceMethod(self, interface, method):
563 self.doInvokeInterfaceMethod(interface, method)
564
565 if method.type is not stdapi.Void:
566 self.checkResult(interface, method)
567
Jose Fonseca5c487ec2015-06-02 22:16:52 +0100568 def checkResult(self, interface, methodOrFunction):
569 assert methodOrFunction.type is not stdapi.Void
570 if str(methodOrFunction.type) == 'HRESULT':
José Fonseca4f49d212012-11-14 14:02:35 +0000571 print r' if (FAILED(_result)) {'
José Fonseca64add5f2014-09-05 11:53:11 +0100572 print r' retrace::failed(call, _result);'
Jose Fonsecad0094a22017-05-30 12:31:37 +0100573 self.handleFailure(interface, methodOrFunction)
José Fonseca4f49d212012-11-14 14:02:35 +0000574 print r' }'
José Fonseca31983872015-02-09 11:16:20 +0000575 else:
576 print r' (void)_result;'
José Fonseca4f49d212012-11-14 14:02:35 +0000577
Jose Fonsecad0094a22017-05-30 12:31:37 +0100578 def handleFailure(self, interface, methodOrFunction):
579 print r' return;'
580
José Fonsecafacdb352014-09-05 13:22:01 +0100581 def checkPitchMismatch(self, method):
José Fonseca9a3abc72014-09-23 14:39:18 +0100582 # Warn for mismatches in 2D/3D mappings.
583 # FIXME: We should try to swizzle them. It's a bit of work, but possible.
584 for outArg in method.args:
585 if outArg.output \
586 and isinstance(outArg.type, stdapi.Pointer) \
587 and isinstance(outArg.type.type, stdapi.Struct):
588 print r' const trace::Array *_%s = call.arg(%u).toArray();' % (outArg.name, outArg.index)
589 print r' if (%s) {' % outArg.name
590 print r' const trace::Struct *_struct = _%s->values[0]->toStruct();' % (outArg.name)
591 print r' if (_struct) {'
592 struct = outArg.type.type
593 for memberIndex in range(len(struct.members)):
594 memberType, memberName = struct.members[memberIndex]
595 if memberName.endswith('Pitch'):
Jose Fonseca1e3c0f72015-07-20 21:50:42 +0100596 print r' if (%s->%s) {' % (outArg.name, memberName)
597 print r' retrace::checkMismatch(call, "%s", _struct->members[%u], %s->%s);' % (memberName, memberIndex, outArg.name, memberName)
598 print r' }'
José Fonseca9a3abc72014-09-23 14:39:18 +0100599 print r' }'
600 print r' }'
José Fonsecafacdb352014-09-05 13:22:01 +0100601
José Fonseca54f304a2012-01-14 19:33:08 +0000602 def filterFunction(self, function):
José Fonseca4441baf2010-11-25 19:55:27 +0000603 return True
604
José Fonseca2741ed82011-10-07 23:36:39 +0100605 table_name = 'retrace::callbacks'
606
José Fonseca54f304a2012-01-14 19:33:08 +0000607 def retraceApi(self, api):
José Fonsecae0e61402010-11-25 15:03:23 +0000608
José Fonseca412149c2012-04-01 22:47:30 +0200609 print '#include "os_time.hpp"'
José Fonsecae0e61402010-11-25 15:03:23 +0000610 print '#include "trace_parser.hpp"'
José Fonseca91343f52011-04-01 08:37:06 +0100611 print '#include "retrace.hpp"'
José Fonsecaab8142f2012-05-13 10:04:19 +0100612 print '#include "retrace_swizzle.hpp"'
José Fonsecae0e61402010-11-25 15:03:23 +0000613 print
614
José Fonseca44703822012-01-31 10:48:58 +0000615 types = api.getAllTypes()
José Fonsecae0e61402010-11-25 15:03:23 +0000616 handles = [type for type in types if isinstance(type, stdapi.Handle)]
José Fonsecad922e1d2010-11-25 17:14:02 +0000617 handle_names = set()
José Fonsecae0e61402010-11-25 15:03:23 +0000618 for handle in handles:
José Fonsecad922e1d2010-11-25 17:14:02 +0000619 if handle.name not in handle_names:
José Fonseca8a844ae2010-12-06 18:50:52 +0000620 if handle.key is None:
José Fonseca632a78d2012-04-19 07:18:59 +0100621 print 'static retrace::map<%s> _%s_map;' % (handle.type, handle.name)
José Fonseca8a844ae2010-12-06 18:50:52 +0000622 else:
623 key_name, key_type = handle.key
José Fonseca632a78d2012-04-19 07:18:59 +0100624 print 'static std::map<%s, retrace::map<%s> > _%s_map;' % (key_type, handle.type, handle.name)
José Fonsecad922e1d2010-11-25 17:14:02 +0000625 handle_names.add(handle.name)
José Fonsecae0e61402010-11-25 15:03:23 +0000626 print
627
José Fonseca81301932012-11-11 00:10:20 +0000628 functions = filter(self.filterFunction, api.getAllFunctions())
José Fonseca8e3c2c02012-01-23 00:30:35 +0000629 for function in functions:
José Fonseca84cea3b2012-05-09 21:12:30 +0100630 if function.sideeffects and not function.internal:
José Fonseca1da480d2012-04-13 17:36:19 +0100631 self.retraceFunction(function)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000632 interfaces = api.getAllInterfaces()
633 for interface in interfaces:
José Fonseca14aa1712014-08-22 15:36:55 +0100634 for method in interface.methods:
José Fonseca84cea3b2012-05-09 21:12:30 +0100635 if method.sideeffects and not method.internal:
José Fonseca1da480d2012-04-13 17:36:19 +0100636 self.retraceInterfaceMethod(interface, method)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000637
638 print 'const retrace::Entry %s[] = {' % self.table_name
639 for function in functions:
José Fonseca84cea3b2012-05-09 21:12:30 +0100640 if not function.internal:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000641 sigName = function.sigName()
José Fonseca84cea3b2012-05-09 21:12:30 +0100642 if function.sideeffects:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000643 print ' {"%s", &retrace_%s},' % (sigName, self.makeFunctionId(function))
José Fonseca84cea3b2012-05-09 21:12:30 +0100644 else:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000645 print ' {"%s", &retrace::ignore},' % (sigName,)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000646 for interface in interfaces:
José Fonseca14aa1712014-08-22 15:36:55 +0100647 for base, method in interface.iterBaseMethods():
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000648 sigName = method.sigName()
José Fonseca1da480d2012-04-13 17:36:19 +0100649 if method.sideeffects:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000650 print ' {"%s::%s", &retrace_%s__%s},' % (interface.name, sigName, base.name, self.makeFunctionId(method))
José Fonseca1da480d2012-04-13 17:36:19 +0100651 else:
Jose Fonsecafdcd30b2016-02-01 14:13:40 +0000652 print ' {"%s::%s", &retrace::ignore},' % (interface.name, sigName)
José Fonseca8e3c2c02012-01-23 00:30:35 +0000653 print ' {NULL, NULL}'
654 print '};'
655 print
José Fonsecae0e61402010-11-25 15:03:23 +0000656