]> git.cworth.org Git - apitrace/blob - wrappers/trace.py
cbdc0c07122e2a9ee4390263f83746a68decb107
[apitrace] / wrappers / trace.py
1 ##########################################################################
2 #
3 # Copyright 2008-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 """Common trace code generation."""
27
28
29 # Adjust path
30 import os.path
31 import sys
32 sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
33
34
35 import specs.stdapi as stdapi
36
37
38 def getWrapperInterfaceName(interface):
39     return "Wrap" + interface.expr
40
41
42
43 class ExpanderMixin:
44     '''Mixin class that provides a bunch of methods to expand C expressions
45     from the specifications.'''
46
47     __structs = None
48     __indices = None
49
50     def expand(self, expr):
51         # Expand a C expression, replacing certain variables
52         if not isinstance(expr, basestring):
53             return expr
54         variables = {}
55
56         if self.__structs is not None:
57             variables['self'] = '(%s)' % self.__structs[0]
58         if self.__indices is not None:
59             variables['i'] = self.__indices[0]
60
61         expandedExpr = expr.format(**variables)
62         if expandedExpr != expr and 0:
63             sys.stderr.write("  %r -> %r\n" % (expr, expandedExpr))
64         return expandedExpr
65
66     def visitMember(self, structInstance, member_type, *args, **kwargs):
67         self.__structs = (structInstance, self.__structs)
68         try:
69             return self.visit(member_type, *args, **kwargs)
70         finally:
71             _, self.__structs = self.__structs
72
73     def visitElement(self, element_index, element_type, *args, **kwargs):
74         self.__indices = (element_index, self.__indices)
75         try:
76             return self.visit(element_type, *args, **kwargs)
77         finally:
78             _, self.__indices = self.__indices
79
80
81 class ComplexValueSerializer(stdapi.OnceVisitor):
82     '''Type visitors which generates serialization functions for
83     complex types.
84     
85     Simple types are serialized inline.
86     '''
87
88     def __init__(self, serializer):
89         stdapi.OnceVisitor.__init__(self)
90         self.serializer = serializer
91
92     def visitVoid(self, literal):
93         pass
94
95     def visitLiteral(self, literal):
96         pass
97
98     def visitString(self, string):
99         pass
100
101     def visitConst(self, const):
102         self.visit(const.type)
103
104     def visitStruct(self, struct):
105         print 'static const char * _struct%s_members[%u] = {' % (struct.tag, len(struct.members))
106         for type, name,  in struct.members:
107             print '    "%s",' % (name,)
108         print '};'
109         print 'static const trace::StructSig _struct%s_sig = {' % (struct.tag,)
110         print '   %u, "%s", %u, _struct%s_members' % (struct.id, struct.name, len(struct.members), struct.tag)
111         print '};'
112         print
113
114     def visitArray(self, array):
115         self.visit(array.type)
116
117     def visitBlob(self, array):
118         pass
119
120     def visitEnum(self, enum):
121         print 'static const trace::EnumValue _enum%s_values[] = {' % (enum.tag)
122         for value in enum.values:
123             print '   {"%s", %s},' % (value, value)
124         print '};'
125         print
126         print 'static const trace::EnumSig _enum%s_sig = {' % (enum.tag)
127         print '   %u, %u, _enum%s_values' % (enum.id, len(enum.values), enum.tag)
128         print '};'
129         print
130
131     def visitBitmask(self, bitmask):
132         print 'static const trace::BitmaskFlag _bitmask%s_flags[] = {' % (bitmask.tag)
133         for value in bitmask.values:
134             print '   {"%s", %s},' % (value, value)
135         print '};'
136         print
137         print 'static const trace::BitmaskSig _bitmask%s_sig = {' % (bitmask.tag)
138         print '   %u, %u, _bitmask%s_flags' % (bitmask.id, len(bitmask.values), bitmask.tag)
139         print '};'
140         print
141
142     def visitPointer(self, pointer):
143         self.visit(pointer.type)
144
145     def visitIntPointer(self, pointer):
146         pass
147
148     def visitObjPointer(self, pointer):
149         self.visit(pointer.type)
150
151     def visitLinearPointer(self, pointer):
152         self.visit(pointer.type)
153
154     def visitHandle(self, handle):
155         self.visit(handle.type)
156
157     def visitReference(self, reference):
158         self.visit(reference.type)
159
160     def visitAlias(self, alias):
161         self.visit(alias.type)
162
163     def visitOpaque(self, opaque):
164         pass
165
166     def visitInterface(self, interface):
167         pass
168
169     def visitPolymorphic(self, polymorphic):
170         if not polymorphic.contextLess:
171             return
172         print 'static void _write__%s(int selector, const %s & value) {' % (polymorphic.tag, polymorphic.expr)
173         print '    switch (selector) {'
174         for cases, type in polymorphic.iterSwitch():
175             for case in cases:
176                 print '    %s:' % case
177             self.serializer.visit(type, 'static_cast<%s>(value)' % (type,))
178             print '        break;'
179         print '    }'
180         print '}'
181         print
182
183
184 class ValueSerializer(stdapi.Visitor, ExpanderMixin):
185     '''Visitor which generates code to serialize any type.
186     
187     Simple types are serialized inline here, whereas the serialization of
188     complex types is dispatched to the serialization functions generated by
189     ComplexValueSerializer visitor above.
190     '''
191
192     def __init__(self):
193         #stdapi.Visitor.__init__(self)
194         self.indices = []
195         self.instances = []
196
197     def visitLiteral(self, literal, instance):
198         print '    trace::localWriter.write%s(%s);' % (literal.kind, instance)
199
200     def visitString(self, string, instance):
201         if not string.wide:
202             cast = 'const char *'
203             suffix = 'String'
204         else:
205             cast = 'const wchar_t *'
206             suffix = 'WString'
207         if cast != string.expr:
208             # reinterpret_cast is necessary for GLubyte * <=> char *
209             instance = 'reinterpret_cast<%s>(%s)' % (cast, instance)
210         if string.length is not None:
211             length = ', %s' % string.length
212         else:
213             length = ''
214         print '    trace::localWriter.write%s(%s%s);' % (suffix, instance, length)
215
216     def visitConst(self, const, instance):
217         self.visit(const.type, instance)
218
219     def visitStruct(self, struct, instance):
220         print '    trace::localWriter.beginStruct(&_struct%s_sig);' % (struct.tag,)
221         for type, name in struct.members:
222             self.visitMember(instance, type, '(%s).%s' % (instance, name,))
223         print '    trace::localWriter.endStruct();'
224
225     def visitArray(self, array, instance):
226         length = '_c' + array.type.tag
227         index = '_i' + array.type.tag
228         array_length = self.expand(array.length)
229         print '    if (%s) {' % instance
230         print '        size_t %s = %s > 0 ? %s : 0;' % (length, array_length, array_length)
231         print '        trace::localWriter.beginArray(%s);' % length
232         print '        for (size_t %s = 0; %s < %s; ++%s) {' % (index, index, length, index)
233         print '            trace::localWriter.beginElement();'
234         self.visitElement(index, array.type, '(%s)[%s]' % (instance, index))
235         print '            trace::localWriter.endElement();'
236         print '        }'
237         print '        trace::localWriter.endArray();'
238         print '    } else {'
239         print '        trace::localWriter.writeNull();'
240         print '    }'
241
242     def visitBlob(self, blob, instance):
243         print '    trace::localWriter.writeBlob(%s, %s);' % (instance, self.expand(blob.size))
244
245     def visitEnum(self, enum, instance):
246         print '    trace::localWriter.writeEnum(&_enum%s_sig, %s);' % (enum.tag, instance)
247
248     def visitBitmask(self, bitmask, instance):
249         print '    trace::localWriter.writeBitmask(&_bitmask%s_sig, %s);' % (bitmask.tag, instance)
250
251     def visitPointer(self, pointer, instance):
252         print '    if (%s) {' % instance
253         print '        trace::localWriter.beginArray(1);'
254         print '        trace::localWriter.beginElement();'
255         self.visit(pointer.type, "*" + instance)
256         print '        trace::localWriter.endElement();'
257         print '        trace::localWriter.endArray();'
258         print '    } else {'
259         print '        trace::localWriter.writeNull();'
260         print '    }'
261
262     def visitIntPointer(self, pointer, instance):
263         print '    trace::localWriter.writePointer((uintptr_t)%s);' % instance
264
265     def visitObjPointer(self, pointer, instance):
266         print '    trace::localWriter.writePointer((uintptr_t)%s);' % instance
267
268     def visitLinearPointer(self, pointer, instance):
269         print '    trace::localWriter.writePointer((uintptr_t)%s);' % instance
270
271     def visitReference(self, reference, instance):
272         self.visit(reference.type, instance)
273
274     def visitHandle(self, handle, instance):
275         self.visit(handle.type, instance)
276
277     def visitAlias(self, alias, instance):
278         self.visit(alias.type, instance)
279
280     def visitOpaque(self, opaque, instance):
281         print '    trace::localWriter.writePointer((uintptr_t)%s);' % instance
282
283     def visitInterface(self, interface, instance):
284         assert False
285
286     def visitPolymorphic(self, polymorphic, instance):
287         if polymorphic.contextLess:
288             print '    _write__%s(%s, %s);' % (polymorphic.tag, polymorphic.switchExpr, instance)
289         else:
290             print '    switch (%s) {' % polymorphic.switchExpr
291             for cases, type in polymorphic.iterSwitch():
292                 for case in cases:
293                     print '    %s:' % case
294                 self.visit(type, 'static_cast<%s>(%s)' % (type, instance))
295                 print '        break;'
296             print '    }'
297
298
299 class WrapDecider(stdapi.Traverser):
300     '''Type visitor which will decide wheter this type will need wrapping or not.
301     
302     For complex types (arrays, structures), we need to know this before hand.
303     '''
304
305     def __init__(self):
306         self.needsWrapping = False
307
308     def visitLinearPointer(self, void):
309         pass
310
311     def visitInterface(self, interface):
312         self.needsWrapping = True
313
314
315 class ValueWrapper(stdapi.Traverser, ExpanderMixin):
316     '''Type visitor which will generate the code to wrap an instance.
317     
318     Wrapping is necessary mostly for interfaces, however interface pointers can
319     appear anywhere inside complex types.
320     '''
321
322     def visitStruct(self, struct, instance):
323         for type, name in struct.members:
324             self.visitMember(instance, type, "(%s).%s" % (instance, name))
325
326     def visitArray(self, array, instance):
327         array_length = self.expand(array.length)
328         print "    if (%s) {" % instance
329         print "        for (size_t _i = 0, _s = %s; _i < _s; ++_i) {" % array_length
330         self.visitElement('_i', array.type, instance + "[_i]")
331         print "        }"
332         print "    }"
333
334     def visitPointer(self, pointer, instance):
335         print "    if (%s) {" % instance
336         self.visit(pointer.type, "*" + instance)
337         print "    }"
338     
339     def visitObjPointer(self, pointer, instance):
340         elem_type = pointer.type.mutable()
341         if isinstance(elem_type, stdapi.Interface):
342             self.visitInterfacePointer(elem_type, instance)
343         elif isinstance(elem_type, stdapi.Alias) and isinstance(elem_type.type, stdapi.Interface):
344             self.visitInterfacePointer(elem_type.type, instance)
345         else:
346             self.visitPointer(pointer, instance)
347     
348     def visitInterface(self, interface, instance):
349         raise NotImplementedError
350
351     def visitInterfacePointer(self, interface, instance):
352         print "    if (%s) {" % instance
353         print "        %s = new %s(%s);" % (instance, getWrapperInterfaceName(interface), instance)
354         print "    }"
355     
356     def visitPolymorphic(self, type, instance):
357         # XXX: There might be polymorphic values that need wrapping in the future
358         raise NotImplementedError
359
360
361 class ValueUnwrapper(ValueWrapper):
362     '''Reverse of ValueWrapper.'''
363
364     allocated = False
365
366     def visitStruct(self, struct, instance):
367         if not self.allocated:
368             # Argument is constant. We need to create a non const
369             print '    {'
370             print "        %s * _t = static_cast<%s *>(alloca(sizeof *_t));" % (struct, struct)
371             print '        *_t = %s;' % (instance,)
372             assert instance.startswith('*')
373             print '        %s = _t;' % (instance[1:],)
374             instance = '*_t'
375             self.allocated = True
376             try:
377                 return ValueWrapper.visitStruct(self, struct, instance)
378             finally:
379                 print '    }'
380         else:
381             return ValueWrapper.visitStruct(self, struct, instance)
382
383     def visitArray(self, array, instance):
384         if self.allocated or isinstance(instance, stdapi.Interface):
385             return ValueWrapper.visitArray(self, array, instance)
386         array_length = self.expand(array.length)
387         elem_type = array.type.mutable()
388         print "    if (%s && %s) {" % (instance, array_length)
389         print "        %s * _t = static_cast<%s *>(alloca(%s * sizeof *_t));" % (elem_type, elem_type, array_length)
390         print "        for (size_t _i = 0, _s = %s; _i < _s; ++_i) {" % array_length
391         print "            _t[_i] = %s[_i];" % instance 
392         self.allocated = True
393         self.visit(array.type, "_t[_i]")
394         print "        }"
395         print "        %s = _t;" % instance
396         print "    }"
397
398     def visitInterfacePointer(self, interface, instance):
399         print r'    if (%s) {' % instance
400         print r'        const %s *pWrapper = static_cast<const %s*>(%s);' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface), instance)
401         print r'        if (pWrapper && pWrapper->m_dwMagic == 0xd8365d6c) {'
402         print r'            %s = pWrapper->m_pInstance;' % (instance,)
403         print r'        } else {'
404         print r'            os::log("apitrace: warning: %%s: unexpected %%s pointer\n", __FUNCTION__, "%s");' % interface.name
405         print r'        }'
406         print r'    }'
407
408
409 class Tracer:
410     '''Base class to orchestrate the code generation of API tracing.'''
411
412     def __init__(self):
413         self.api = None
414
415     def serializerFactory(self):
416         '''Create a serializer.
417         
418         Can be overriden by derived classes to inject their own serialzer.
419         '''
420
421         return ValueSerializer()
422
423     def traceApi(self, api):
424         self.api = api
425
426         self.header(api)
427
428         # Includes
429         for header in api.headers:
430             print header
431         print
432
433         # Generate the serializer functions
434         types = api.getAllTypes()
435         visitor = ComplexValueSerializer(self.serializerFactory())
436         map(visitor.visit, types)
437         print
438
439         # Interfaces wrapers
440         self.traceInterfaces(api)
441
442         # Function wrappers
443         self.interface = None
444         self.base = None
445         map(self.traceFunctionDecl, api.functions)
446         map(self.traceFunctionImpl, api.functions)
447         print
448
449         self.footer(api)
450
451     def header(self, api):
452         print '#ifdef _WIN32'
453         print '#  include <malloc.h> // alloca'
454         print '#  ifndef alloca'
455         print '#    define alloca _alloca'
456         print '#  endif'
457         print '#else'
458         print '#  include <alloca.h> // alloca'
459         print '#endif'
460         print
461         print '#include "trace.hpp"'
462         print
463
464     def footer(self, api):
465         pass
466
467     def traceFunctionDecl(self, function):
468         # Per-function declarations
469
470         if not function.internal:
471             if function.args:
472                 print 'static const char * _%s_args[%u] = {%s};' % (function.name, len(function.args), ', '.join(['"%s"' % arg.name for arg in function.args]))
473             else:
474                 print 'static const char ** _%s_args = NULL;' % (function.name,)
475             print 'static const trace::FunctionSig _%s_sig = {%u, "%s", %u, _%s_args};' % (function.name, function.id, function.name, len(function.args), function.name)
476             print
477
478     def isFunctionPublic(self, function):
479         return True
480
481     def traceFunctionImpl(self, function):
482         if self.isFunctionPublic(function):
483             print 'extern "C" PUBLIC'
484         else:
485             print 'extern "C" PRIVATE'
486         print function.prototype() + ' {'
487         if function.type is not stdapi.Void:
488             print '    %s _result;' % function.type
489
490         # No-op if tracing is disabled
491         print '    if (!trace::isTracingEnabled()) {'
492         Tracer.invokeFunction(self, function)
493         if function.type is not stdapi.Void:
494             print '        return _result;'
495         else:
496             print '        return;'
497         print '    }'
498
499         self.traceFunctionImplBody(function)
500         if function.type is not stdapi.Void:
501             print '    return _result;'
502         print '}'
503         print
504
505     def traceFunctionImplBody(self, function):
506         if not function.internal:
507             print '    unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
508             for arg in function.args:
509                 if not arg.output:
510                     self.unwrapArg(function, arg)
511                     self.serializeArg(function, arg)
512             print '    trace::localWriter.endEnter();'
513         self.invokeFunction(function)
514         if not function.internal:
515             print '    trace::localWriter.beginLeave(_call);'
516             print '    if (%s) {' % self.wasFunctionSuccessful(function)
517             for arg in function.args:
518                 if arg.output:
519                     self.serializeArg(function, arg)
520                     self.wrapArg(function, arg)
521             print '    }'
522             if function.type is not stdapi.Void:
523                 self.serializeRet(function, "_result")
524             print '    trace::localWriter.endLeave();'
525             if function.type is not stdapi.Void:
526                 self.wrapRet(function, "_result")
527
528     def invokeFunction(self, function, prefix='_', suffix=''):
529         if function.type is stdapi.Void:
530             result = ''
531         else:
532             result = '_result = '
533         dispatch = prefix + function.name + suffix
534         print '    %s%s(%s);' % (result, dispatch, ', '.join([str(arg.name) for arg in function.args]))
535
536     def wasFunctionSuccessful(self, function):
537         if function.type is stdapi.Void:
538             return 'true'
539         if str(function.type) == 'HRESULT':
540             return 'SUCCEEDED(_result)'
541         return 'false'
542
543     def serializeArg(self, function, arg):
544         print '    trace::localWriter.beginArg(%u);' % (arg.index,)
545         self.serializeArgValue(function, arg)
546         print '    trace::localWriter.endArg();'
547
548     def serializeArgValue(self, function, arg):
549         self.serializeValue(arg.type, arg.name)
550
551     def wrapArg(self, function, arg):
552         assert not isinstance(arg.type, stdapi.ObjPointer)
553
554         from specs.winapi import REFIID
555         riid = None
556         for other_arg in function.args:
557             if not other_arg.output and other_arg.type is REFIID:
558                 riid = other_arg
559         if riid is not None \
560            and isinstance(arg.type, stdapi.Pointer) \
561            and isinstance(arg.type.type, stdapi.ObjPointer):
562             self.wrapIid(function, riid, arg)
563             return
564
565         self.wrapValue(arg.type, arg.name)
566
567     def unwrapArg(self, function, arg):
568         self.unwrapValue(arg.type, arg.name)
569
570     def serializeRet(self, function, instance):
571         print '    trace::localWriter.beginReturn();'
572         self.serializeValue(function.type, instance)
573         print '    trace::localWriter.endReturn();'
574
575     def serializeValue(self, type, instance):
576         serializer = self.serializerFactory()
577         serializer.visit(type, instance)
578
579     def wrapRet(self, function, instance):
580         self.wrapValue(function.type, instance)
581
582     def unwrapRet(self, function, instance):
583         self.unwrapValue(function.type, instance)
584
585     def needsWrapping(self, type):
586         visitor = WrapDecider()
587         visitor.visit(type)
588         return visitor.needsWrapping
589
590     def wrapValue(self, type, instance):
591         if self.needsWrapping(type):
592             visitor = ValueWrapper()
593             visitor.visit(type, instance)
594
595     def unwrapValue(self, type, instance):
596         if self.needsWrapping(type):
597             visitor = ValueUnwrapper()
598             visitor.visit(type, instance)
599
600     def traceInterfaces(self, api):
601         interfaces = api.getAllInterfaces()
602         if not interfaces:
603             return
604         map(self.declareWrapperInterface, interfaces)
605         self.implementIidWrapper(api)
606         map(self.implementWrapperInterface, interfaces)
607         print
608
609     def declareWrapperInterface(self, interface):
610         print "class %s : public %s " % (getWrapperInterfaceName(interface), interface.name)
611         print "{"
612         print "public:"
613         print "    %s(%s * pInstance);" % (getWrapperInterfaceName(interface), interface.name)
614         print "    virtual ~%s();" % getWrapperInterfaceName(interface)
615         print
616         for method in interface.iterMethods():
617             print "    " + method.prototype() + ";"
618         print
619         #print "private:"
620         for type, name, value in self.enumWrapperInterfaceVariables(interface):
621             print '    %s %s;' % (type, name)
622         print "};"
623         print
624
625     def enumWrapperInterfaceVariables(self, interface):
626         return [
627             ("DWORD", "m_dwMagic", "0xd8365d6c"),
628             ("%s *" % interface.name, "m_pInstance", "pInstance"),
629         ] 
630
631     def implementWrapperInterface(self, interface):
632         self.interface = interface
633
634         print '%s::%s(%s * pInstance) {' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface), interface.name)
635         for type, name, value in self.enumWrapperInterfaceVariables(interface):
636             print '    %s = %s;' % (name, value)
637         print '}'
638         print
639         print '%s::~%s() {' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface))
640         print '}'
641         print
642         
643         for base, method in interface.iterBaseMethods():
644             self.base = base
645             self.implementWrapperInterfaceMethod(interface, base, method)
646
647         print
648
649     def implementWrapperInterfaceMethod(self, interface, base, method):
650         print method.prototype(getWrapperInterfaceName(interface) + '::' + method.name) + ' {'
651         if method.type is not stdapi.Void:
652             print '    %s _result;' % method.type
653     
654         self.implementWrapperInterfaceMethodBody(interface, base, method)
655     
656         if method.type is not stdapi.Void:
657             print '    return _result;'
658         print '}'
659         print
660
661     def implementWrapperInterfaceMethodBody(self, interface, base, method):
662         assert not method.internal
663
664         print '    static const char * _args[%u] = {%s};' % (len(method.args) + 1, ', '.join(['"this"'] + ['"%s"' % arg.name for arg in method.args]))
665         print '    static const trace::FunctionSig _sig = {%u, "%s", %u, _args};' % (method.id, interface.name + '::' + method.name, len(method.args) + 1)
666
667         print '    %s *_this = static_cast<%s *>(m_pInstance);' % (base, base)
668
669         print '    unsigned _call = trace::localWriter.beginEnter(&_sig);'
670         print '    trace::localWriter.beginArg(0);'
671         print '    trace::localWriter.writePointer((uintptr_t)m_pInstance);'
672         print '    trace::localWriter.endArg();'
673         for arg in method.args:
674             if not arg.output:
675                 self.unwrapArg(method, arg)
676                 self.serializeArg(method, arg)
677         print '    trace::localWriter.endEnter();'
678         
679         self.invokeMethod(interface, base, method)
680
681         print '    trace::localWriter.beginLeave(_call);'
682
683         print '    if (%s) {' % self.wasFunctionSuccessful(method)
684         for arg in method.args:
685             if arg.output:
686                 self.serializeArg(method, arg)
687                 self.wrapArg(method, arg)
688         print '    }'
689
690         if method.type is not stdapi.Void:
691             self.serializeRet(method, '_result')
692         print '    trace::localWriter.endLeave();'
693         if method.type is not stdapi.Void:
694             self.wrapRet(method, '_result')
695
696         if method.name == 'Release':
697             assert method.type is not stdapi.Void
698             print '    if (!_result)'
699             print '        delete this;'
700
701     def implementIidWrapper(self, api):
702         print r'static void'
703         print r'warnIID(const char *functionName, REFIID riid, const char *reason) {'
704         print r'    os::log("apitrace: warning: %s: %s IID {0x%08lX,0x%04X,0x%04X,{0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X}}\n",'
705         print r'            functionName, reason,'
706         print r'            riid.Data1, riid.Data2, riid.Data3,'
707         print r'            riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3], riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]);'
708         print r'}'
709         print 
710         print r'static void'
711         print r'wrapIID(const char *functionName, REFIID riid, void * * ppvObj) {'
712         print r'    if (!ppvObj || !*ppvObj) {'
713         print r'        return;'
714         print r'    }'
715         else_ = ''
716         for iface in api.getAllInterfaces():
717             print r'    %sif (riid == IID_%s) {' % (else_, iface.name)
718             print r'        *ppvObj = new Wrap%s((%s *) *ppvObj);' % (iface.name, iface.name)
719             print r'    }'
720             else_ = 'else '
721         print r'    %s{' % else_
722         print r'        warnIID(functionName, riid, "unknown");'
723         print r'    }'
724         print r'}'
725         print
726
727     def wrapIid(self, function, riid, out):
728         # Cast output arg to `void **` if necessary
729         out_name = out.name
730         obj_type = out.type.type.type
731         if not obj_type is stdapi.Void:
732             assert isinstance(obj_type, stdapi.Interface)
733             out_name = 'reinterpret_cast<void * *>(%s)' % out_name
734
735         print r'    if (%s && *%s) {' % (out.name, out.name)
736         functionName = function.name
737         else_ = ''
738         if self.interface is not None:
739             functionName = self.interface.name + '::' + functionName
740             print r'        if (*%s == m_pInstance &&' % (out_name,)
741             print r'            (%s)) {' % ' || '.join('%s == IID_%s' % (riid.name, iface.name) for iface in self.interface.iterBases())
742             print r'            *%s = this;' % (out_name,)
743             print r'        }'
744             else_ = 'else '
745         print r'        %s{' % else_
746         print r'             wrapIID("%s", %s, %s);' % (functionName, riid.name, out_name)
747         print r'        }'
748         print r'    }'
749
750     def invokeMethod(self, interface, base, method):
751         if method.type is stdapi.Void:
752             result = ''
753         else:
754             result = '_result = '
755         print '    %s_this->%s(%s);' % (result, method.name, ', '.join([str(arg.name) for arg in method.args]))
756     
757     def emit_memcpy(self, dest, src, length):
758         print '        unsigned _call = trace::localWriter.beginEnter(&trace::memcpy_sig);'
759         print '        trace::localWriter.beginArg(0);'
760         print '        trace::localWriter.writePointer((uintptr_t)%s);' % dest
761         print '        trace::localWriter.endArg();'
762         print '        trace::localWriter.beginArg(1);'
763         print '        trace::localWriter.writeBlob(%s, %s);' % (src, length)
764         print '        trace::localWriter.endArg();'
765         print '        trace::localWriter.beginArg(2);'
766         print '        trace::localWriter.writeUInt(%s);' % length
767         print '        trace::localWriter.endArg();'
768         print '        trace::localWriter.endEnter();'
769         print '        trace::localWriter.beginLeave(_call);'
770         print '        trace::localWriter.endLeave();'
771     
772     def fake_call(self, function, args):
773         print '            unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
774         for arg, instance in zip(function.args, args):
775             assert not arg.output
776             print '            trace::localWriter.beginArg(%u);' % (arg.index,)
777             self.serializeValue(arg.type, instance)
778             print '            trace::localWriter.endArg();'
779         print '            trace::localWriter.endEnter();'
780         print '            trace::localWriter.beginLeave(_fake_call);'
781         print '            trace::localWriter.endLeave();'
782