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