]> git.cworth.org Git - apitrace/blob - wrappers/trace.py
Merge branch 'modules'
[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 module in api.modules:
430             for header in module.headers:
431                 print header
432         print
433
434         # Generate the serializer functions
435         types = api.getAllTypes()
436         visitor = ComplexValueSerializer(self.serializerFactory())
437         map(visitor.visit, types)
438         print
439
440         # Interfaces wrapers
441         self.traceInterfaces(api)
442
443         # Function wrappers
444         self.interface = None
445         self.base = None
446         for function in api.getAllFunctions():
447             self.traceFunctionDecl(function)
448         for function in api.getAllFunctions():
449             self.traceFunctionImpl(function)
450         print
451
452         self.footer(api)
453
454     def header(self, api):
455         print '#ifdef _WIN32'
456         print '#  include <malloc.h> // alloca'
457         print '#  ifndef alloca'
458         print '#    define alloca _alloca'
459         print '#  endif'
460         print '#else'
461         print '#  include <alloca.h> // alloca'
462         print '#endif'
463         print
464         print '#include "trace.hpp"'
465         print
466
467     def footer(self, api):
468         pass
469
470     def traceFunctionDecl(self, function):
471         # Per-function declarations
472
473         if not function.internal:
474             if function.args:
475                 print 'static const char * _%s_args[%u] = {%s};' % (function.name, len(function.args), ', '.join(['"%s"' % arg.name for arg in function.args]))
476             else:
477                 print 'static const char ** _%s_args = NULL;' % (function.name,)
478             print 'static const trace::FunctionSig _%s_sig = {%u, "%s", %u, _%s_args};' % (function.name, function.id, function.name, len(function.args), function.name)
479             print
480
481     def isFunctionPublic(self, function):
482         return True
483
484     def traceFunctionImpl(self, function):
485         if self.isFunctionPublic(function):
486             print 'extern "C" PUBLIC'
487         else:
488             print 'extern "C" PRIVATE'
489         print function.prototype() + ' {'
490         if function.type is not stdapi.Void:
491             print '    %s _result;' % function.type
492
493         # No-op if tracing is disabled
494         print '    if (!trace::isTracingEnabled()) {'
495         Tracer.invokeFunction(self, function)
496         if function.type is not stdapi.Void:
497             print '        return _result;'
498         else:
499             print '        return;'
500         print '    }'
501
502         self.traceFunctionImplBody(function)
503         if function.type is not stdapi.Void:
504             print '    return _result;'
505         print '}'
506         print
507
508     def traceFunctionImplBody(self, function):
509         if not function.internal:
510             print '    unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
511             for arg in function.args:
512                 if not arg.output:
513                     self.unwrapArg(function, arg)
514                     self.serializeArg(function, arg)
515             print '    trace::localWriter.endEnter();'
516         self.invokeFunction(function)
517         if not function.internal:
518             print '    trace::localWriter.beginLeave(_call);'
519             print '    if (%s) {' % self.wasFunctionSuccessful(function)
520             for arg in function.args:
521                 if arg.output:
522                     self.serializeArg(function, arg)
523                     self.wrapArg(function, arg)
524             print '    }'
525             if function.type is not stdapi.Void:
526                 self.serializeRet(function, "_result")
527             print '    trace::localWriter.endLeave();'
528             if function.type is not stdapi.Void:
529                 self.wrapRet(function, "_result")
530
531     def invokeFunction(self, function, prefix='_', suffix=''):
532         if function.type is stdapi.Void:
533             result = ''
534         else:
535             result = '_result = '
536         dispatch = prefix + function.name + suffix
537         print '    %s%s(%s);' % (result, dispatch, ', '.join([str(arg.name) for arg in function.args]))
538
539     def wasFunctionSuccessful(self, function):
540         if function.type is stdapi.Void:
541             return 'true'
542         if str(function.type) == 'HRESULT':
543             return 'SUCCEEDED(_result)'
544         return 'true'
545
546     def serializeArg(self, function, arg):
547         print '    trace::localWriter.beginArg(%u);' % (arg.index,)
548         self.serializeArgValue(function, arg)
549         print '    trace::localWriter.endArg();'
550
551     def serializeArgValue(self, function, arg):
552         self.serializeValue(arg.type, arg.name)
553
554     def wrapArg(self, function, arg):
555         assert not isinstance(arg.type, stdapi.ObjPointer)
556
557         from specs.winapi import REFIID
558         riid = None
559         for other_arg in function.args:
560             if not other_arg.output and other_arg.type is REFIID:
561                 riid = other_arg
562         if riid is not None \
563            and isinstance(arg.type, stdapi.Pointer) \
564            and isinstance(arg.type.type, stdapi.ObjPointer):
565             self.wrapIid(function, riid, arg)
566             return
567
568         self.wrapValue(arg.type, arg.name)
569
570     def unwrapArg(self, function, arg):
571         self.unwrapValue(arg.type, arg.name)
572
573     def serializeRet(self, function, instance):
574         print '    trace::localWriter.beginReturn();'
575         self.serializeValue(function.type, instance)
576         print '    trace::localWriter.endReturn();'
577
578     def serializeValue(self, type, instance):
579         serializer = self.serializerFactory()
580         serializer.visit(type, instance)
581
582     def wrapRet(self, function, instance):
583         self.wrapValue(function.type, instance)
584
585     def unwrapRet(self, function, instance):
586         self.unwrapValue(function.type, instance)
587
588     def needsWrapping(self, type):
589         visitor = WrapDecider()
590         visitor.visit(type)
591         return visitor.needsWrapping
592
593     def wrapValue(self, type, instance):
594         if self.needsWrapping(type):
595             visitor = ValueWrapper()
596             visitor.visit(type, instance)
597
598     def unwrapValue(self, type, instance):
599         if self.needsWrapping(type):
600             visitor = ValueUnwrapper()
601             visitor.visit(type, instance)
602
603     def traceInterfaces(self, api):
604         interfaces = api.getAllInterfaces()
605         if not interfaces:
606             return
607         map(self.declareWrapperInterface, interfaces)
608         self.implementIidWrapper(api)
609         map(self.implementWrapperInterface, interfaces)
610         print
611
612     def declareWrapperInterface(self, interface):
613         print "class %s : public %s " % (getWrapperInterfaceName(interface), interface.name)
614         print "{"
615         print "public:"
616         print "    %s(%s * pInstance);" % (getWrapperInterfaceName(interface), interface.name)
617         print "    virtual ~%s();" % getWrapperInterfaceName(interface)
618         print
619         for method in interface.iterMethods():
620             print "    " + method.prototype() + ";"
621         print
622         #print "private:"
623         for type, name, value in self.enumWrapperInterfaceVariables(interface):
624             print '    %s %s;' % (type, name)
625         print "};"
626         print
627
628     def enumWrapperInterfaceVariables(self, interface):
629         return [
630             ("DWORD", "m_dwMagic", "0xd8365d6c"),
631             ("%s *" % interface.name, "m_pInstance", "pInstance"),
632         ] 
633
634     def implementWrapperInterface(self, interface):
635         self.interface = interface
636
637         print '%s::%s(%s * pInstance) {' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface), interface.name)
638         for type, name, value in self.enumWrapperInterfaceVariables(interface):
639             print '    %s = %s;' % (name, value)
640         print '}'
641         print
642         print '%s::~%s() {' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface))
643         print '}'
644         print
645         
646         for base, method in interface.iterBaseMethods():
647             self.base = base
648             self.implementWrapperInterfaceMethod(interface, base, method)
649
650         print
651
652     def implementWrapperInterfaceMethod(self, interface, base, method):
653         print method.prototype(getWrapperInterfaceName(interface) + '::' + method.name) + ' {'
654         if method.type is not stdapi.Void:
655             print '    %s _result;' % method.type
656     
657         self.implementWrapperInterfaceMethodBody(interface, base, method)
658     
659         if method.type is not stdapi.Void:
660             print '    return _result;'
661         print '}'
662         print
663
664     def implementWrapperInterfaceMethodBody(self, interface, base, method):
665         assert not method.internal
666
667         print '    static const char * _args[%u] = {%s};' % (len(method.args) + 1, ', '.join(['"this"'] + ['"%s"' % arg.name for arg in method.args]))
668         print '    static const trace::FunctionSig _sig = {%u, "%s", %u, _args};' % (method.id, interface.name + '::' + method.name, len(method.args) + 1)
669
670         print '    %s *_this = static_cast<%s *>(m_pInstance);' % (base, base)
671
672         print '    unsigned _call = trace::localWriter.beginEnter(&_sig);'
673         print '    trace::localWriter.beginArg(0);'
674         print '    trace::localWriter.writePointer((uintptr_t)m_pInstance);'
675         print '    trace::localWriter.endArg();'
676         for arg in method.args:
677             if not arg.output:
678                 self.unwrapArg(method, arg)
679                 self.serializeArg(method, arg)
680         print '    trace::localWriter.endEnter();'
681         
682         self.invokeMethod(interface, base, method)
683
684         print '    trace::localWriter.beginLeave(_call);'
685
686         print '    if (%s) {' % self.wasFunctionSuccessful(method)
687         for arg in method.args:
688             if arg.output:
689                 self.serializeArg(method, arg)
690                 self.wrapArg(method, arg)
691         print '    }'
692
693         if method.type is not stdapi.Void:
694             self.serializeRet(method, '_result')
695         print '    trace::localWriter.endLeave();'
696         if method.type is not stdapi.Void:
697             self.wrapRet(method, '_result')
698
699         if method.name == 'Release':
700             assert method.type is not stdapi.Void
701             print '    if (!_result)'
702             print '        delete this;'
703
704     def implementIidWrapper(self, api):
705         print r'static void'
706         print r'warnIID(const char *functionName, REFIID riid, const char *reason) {'
707         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",'
708         print r'            functionName, reason,'
709         print r'            riid.Data1, riid.Data2, riid.Data3,'
710         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]);'
711         print r'}'
712         print 
713         print r'static void'
714         print r'wrapIID(const char *functionName, REFIID riid, void * * ppvObj) {'
715         print r'    if (!ppvObj || !*ppvObj) {'
716         print r'        return;'
717         print r'    }'
718         else_ = ''
719         for iface in api.getAllInterfaces():
720             print r'    %sif (riid == IID_%s) {' % (else_, iface.name)
721             print r'        *ppvObj = new Wrap%s((%s *) *ppvObj);' % (iface.name, iface.name)
722             print r'    }'
723             else_ = 'else '
724         print r'    %s{' % else_
725         print r'        warnIID(functionName, riid, "unknown");'
726         print r'    }'
727         print r'}'
728         print
729
730     def wrapIid(self, function, riid, out):
731         # Cast output arg to `void **` if necessary
732         out_name = out.name
733         obj_type = out.type.type.type
734         if not obj_type is stdapi.Void:
735             assert isinstance(obj_type, stdapi.Interface)
736             out_name = 'reinterpret_cast<void * *>(%s)' % out_name
737
738         print r'    if (%s && *%s) {' % (out.name, out.name)
739         functionName = function.name
740         else_ = ''
741         if self.interface is not None:
742             functionName = self.interface.name + '::' + functionName
743             print r'        if (*%s == m_pInstance &&' % (out_name,)
744             print r'            (%s)) {' % ' || '.join('%s == IID_%s' % (riid.name, iface.name) for iface in self.interface.iterBases())
745             print r'            *%s = this;' % (out_name,)
746             print r'        }'
747             else_ = 'else '
748         print r'        %s{' % else_
749         print r'             wrapIID("%s", %s, %s);' % (functionName, riid.name, out_name)
750         print r'        }'
751         print r'    }'
752
753     def invokeMethod(self, interface, base, method):
754         if method.type is stdapi.Void:
755             result = ''
756         else:
757             result = '_result = '
758         print '    %s_this->%s(%s);' % (result, method.name, ', '.join([str(arg.name) for arg in method.args]))
759     
760     def emit_memcpy(self, dest, src, length):
761         print '        unsigned _call = trace::localWriter.beginEnter(&trace::memcpy_sig);'
762         print '        trace::localWriter.beginArg(0);'
763         print '        trace::localWriter.writePointer((uintptr_t)%s);' % dest
764         print '        trace::localWriter.endArg();'
765         print '        trace::localWriter.beginArg(1);'
766         print '        trace::localWriter.writeBlob(%s, %s);' % (src, length)
767         print '        trace::localWriter.endArg();'
768         print '        trace::localWriter.beginArg(2);'
769         print '        trace::localWriter.writeUInt(%s);' % length
770         print '        trace::localWriter.endArg();'
771         print '        trace::localWriter.endEnter();'
772         print '        trace::localWriter.beginLeave(_call);'
773         print '        trace::localWriter.endLeave();'
774     
775     def fake_call(self, function, args):
776         print '            unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
777         for arg, instance in zip(function.args, args):
778             assert not arg.output
779             print '            trace::localWriter.beginArg(%u);' % (arg.index,)
780             self.serializeValue(arg.type, instance)
781             print '            trace::localWriter.endArg();'
782         print '            trace::localWriter.endEnter();'
783         print '            trace::localWriter.beginLeave(_fake_call);'
784         print '            trace::localWriter.endLeave();'
785