]> git.cworth.org Git - apitrace/blob - gltrace.py
Merge branch 'master' into multi-context
[apitrace] / gltrace.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
27 """GL tracing generator."""
28
29
30 import stdapi
31 import glapi
32 import glparams
33 from glxapi import glxapi
34 from trace import Tracer, dump_instance
35
36
37 class TypeGetter(stdapi.Visitor):
38     '''Determine which glGet*v function that matches the specified type.'''
39
40     def __init__(self, prefix = 'glGet', long_suffix = True):
41         self.prefix = prefix
42         self.long_suffix = long_suffix
43
44     def visit_const(self, const):
45         return self.visit(const.type)
46
47     def visit_alias(self, alias):
48         if alias.expr == 'GLboolean':
49             if self.long_suffix:
50                 return self.prefix + 'Booleanv', alias.expr
51             else:
52                 return self.prefix + 'iv', 'GLint'
53         elif alias.expr == 'GLdouble':
54             if self.long_suffix:
55                 return self.prefix + 'Doublev', alias.expr
56             else:
57                 return self.prefix + 'dv', alias.expr
58         elif alias.expr == 'GLfloat':
59             if self.long_suffix:
60                 return self.prefix + 'Floatv', alias.expr
61             else:
62                 return self.prefix + 'fv', alias.expr
63         elif alias.expr in ('GLint', 'GLuint', 'GLsizei'):
64             if self.long_suffix:
65                 return self.prefix + 'Integerv', 'GLint'
66             else:
67                 return self.prefix + 'iv', 'GLint'
68         else:
69             print alias.expr
70             assert False
71     
72     def visit_enum(self, enum):
73         return self.visit(glapi.GLint)
74
75     def visit_bitmask(self, bitmask):
76         return self.visit(glapi.GLint)
77
78     def visit_opaque(self, pointer):
79         return self.prefix + 'Pointerv', 'GLvoid *'
80
81
82 class GlTracer(Tracer):
83
84     arrays = [
85         ("Vertex", "VERTEX"),
86         ("Normal", "NORMAL"),
87         ("Color", "COLOR"),
88         ("Index", "INDEX"),
89         ("TexCoord", "TEXTURE_COORD"),
90         ("EdgeFlag", "EDGE_FLAG"),
91         ("FogCoord", "FOG_COORD"),
92         ("SecondaryColor", "SECONDARY_COLOR"),
93     ]
94     arrays.reverse()
95
96     def header(self, api):
97         Tracer.header(self, api)
98
99         print '// Whether user arrays were used'
100         print 'static bool __user_arrays = false;'
101         print
102         # Whether we need user arrays
103         print 'static inline bool __need_user_arrays(void)'
104         print '{'
105         print '    if (!__user_arrays) {'
106         print '        return false;'
107         print '    }'
108         print
109
110         for camelcase_name, uppercase_name in self.arrays:
111             function_name = 'gl%sPointer' % camelcase_name
112             enable_name = 'GL_%s_ARRAY' % uppercase_name
113             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
114             print '    // %s' % function_name
115             self.array_prolog(api, uppercase_name)
116             print '    if (__glIsEnabled(%s)) {' % enable_name
117             print '        GLint __binding = 0;'
118             print '        __glGetIntegerv(%s, &__binding);' % binding_name
119             print '        if (!__binding) {'
120             self.array_cleanup(api, uppercase_name)
121             print '            return true;'
122             print '        }'
123             print '    }'
124             self.array_epilog(api, uppercase_name)
125             print
126
127         print '    // glVertexAttribPointer'
128         print '    GLint __max_vertex_attribs = 0;'
129         print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
130         print '    for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
131         print '        GLint __enabled = 0;'
132         print '        __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
133         print '        if (__enabled) {'
134         print '            GLint __binding = 0;'
135         print '            __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
136         print '            if (!__binding) {'
137         print '                return true;'
138         print '            }'
139         print '        }'
140         print '    }'
141         print
142
143         print '    return false;'
144         print '}'
145         print
146
147         print 'static void __trace_user_arrays(GLuint maxindex);'
148         print
149
150         print 'struct buffer_mapping {'
151         print '    void *map;'
152         print '    GLint length;'
153         print '    bool write;'
154         print '};'
155         print
156         for target in self.buffer_targets:
157             print 'struct buffer_mapping __%s_mapping;' % target.lower();
158         print
159         print 'static inline struct buffer_mapping *'
160         print 'get_buffer_mapping(GLenum target) {'
161         print '    switch(target) {'
162         for target in self.buffer_targets:
163             print '    case GL_%s:' % target
164             print '        return & __%s_mapping;' % target.lower()
165         print '    default:'
166         print '        OS::DebugMessage("warning: unknown buffer target 0x%04X\\n", target);'
167         print '        return NULL;'
168         print '    }'
169         print '}'
170         print
171
172         # Generate memcpy's signature
173         self.trace_function_decl(glapi.memcpy)
174
175         # Generate a helper function to determine whether a parameter name
176         # refers to a symbolic value or not
177         print 'static bool'
178         print 'is_symbolic_pname(GLenum pname) {'
179         print '    switch(pname) {'
180         for function, type, count, name in glparams.parameters:
181             if type is glapi.GLenum:
182                 print '    case %s:' % name
183         print '        return true;'
184         print '    default:'
185         print '        return false;'
186         print '    }'
187         print '}'
188         print
189         
190         # Generate a helper function to determine whether a parameter value is
191         # potentially symbolic or not; i.e., if the value can be represented in
192         # an enum or not
193         print 'template<class T>'
194         print 'static inline bool'
195         print 'is_symbolic_param(T param) {'
196         print '    return static_cast<T>(static_cast<GLenum>(param)) == param;'
197         print '}'
198         print
199
200         # Generate a helper function to know how many elements a parameter has
201         print 'static size_t'
202         print '__gl_param_size(GLenum pname) {'
203         print '    switch(pname) {'
204         for function, type, count, name in glparams.parameters:
205             if type is not None:
206                 print '    case %s: return %u;' % (name, count)
207         print '    case GL_COMPRESSED_TEXTURE_FORMATS: {'
208         print '            GLint num_compressed_texture_formats = 0;'
209         print '            __glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_texture_formats);'
210         print '            return num_compressed_texture_formats;'
211         print '        }'
212         print '    default:'
213         print r'        OS::DebugMessage("warning: %s: unknown GLenum 0x%04X\n", __FUNCTION__, pname);'
214         print '        return 1;'
215         print '    }'
216         print '}'
217         print
218
219     array_pointer_function_names = set((
220         "glVertexPointer",
221         "glNormalPointer",
222         "glColorPointer",
223         "glIndexPointer",
224         "glTexCoordPointer",
225         "glEdgeFlagPointer",
226         "glFogCoordPointer",
227         "glSecondaryColorPointer",
228         
229         "glInterleavedArrays",
230
231         "glVertexPointerEXT",
232         "glNormalPointerEXT",
233         "glColorPointerEXT",
234         "glIndexPointerEXT",
235         "glTexCoordPointerEXT",
236         "glEdgeFlagPointerEXT",
237         "glFogCoordPointerEXT",
238         "glSecondaryColorPointerEXT",
239
240         "glVertexAttribPointer",
241         "glVertexAttribPointerARB",
242         "glVertexAttribPointerNV",
243         "glVertexAttribIPointer",
244         "glVertexAttribIPointerEXT",
245         "glVertexAttribLPointer",
246         "glVertexAttribLPointerEXT",
247         
248         #"glMatrixIndexPointerARB",
249     ))
250
251     draw_function_names = set((
252         'glDrawArrays',
253         'glDrawElements',
254         'glDrawRangeElements',
255         'glMultiDrawArrays',
256         'glMultiDrawElements',
257         'glDrawArraysInstanced',
258         'glDrawElementsInstanced',
259         'glDrawArraysInstancedARB',
260         'glDrawElementsInstancedARB',
261         'glDrawElementsBaseVertex',
262         'glDrawRangeElementsBaseVertex',
263         'glDrawElementsInstancedBaseVertex',
264         'glMultiDrawElementsBaseVertex',
265         'glDrawArraysIndirect',
266         'glDrawElementsIndirect',
267         'glDrawArraysEXT',
268         'glDrawRangeElementsEXT',
269         'glDrawRangeElementsEXT_size',
270         'glMultiDrawArraysEXT',
271         'glMultiDrawElementsEXT',
272         'glMultiModeDrawArraysIBM',
273         'glMultiModeDrawElementsIBM',
274         'glDrawArraysInstancedEXT',
275         'glDrawElementsInstancedEXT',
276     ))
277
278     interleaved_formats = [
279          'GL_V2F',
280          'GL_V3F',
281          'GL_C4UB_V2F',
282          'GL_C4UB_V3F',
283          'GL_C3F_V3F',
284          'GL_N3F_V3F',
285          'GL_C4F_N3F_V3F',
286          'GL_T2F_V3F',
287          'GL_T4F_V4F',
288          'GL_T2F_C4UB_V3F',
289          'GL_T2F_C3F_V3F',
290          'GL_T2F_N3F_V3F',
291          'GL_T2F_C4F_N3F_V3F',
292          'GL_T4F_C4F_N3F_V4F',
293     ]
294
295     def trace_function_impl_body(self, function):
296         # Defer tracing of user array pointers...
297         if function.name in self.array_pointer_function_names:
298             print '    GLint __array_buffer = 0;'
299             print '    __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
300             print '    if (!__array_buffer) {'
301             print '        __user_arrays = true;'
302             self.dispatch_function(function)
303
304             # And also break down glInterleavedArrays into the individual calls
305             if function.name == 'glInterleavedArrays':
306                 print
307
308                 # Initialize the enable flags
309                 for camelcase_name, uppercase_name in self.arrays:
310                     flag_name = '__' + uppercase_name.lower()
311                     print '        GLboolean %s = GL_FALSE;' % flag_name
312                 print
313
314                 # Switch for the interleaved formats
315                 print '        switch (format) {'
316                 for format in self.interleaved_formats:
317                     print '            case %s:' % format
318                     for camelcase_name, uppercase_name in self.arrays:
319                         flag_name = '__' + uppercase_name.lower()
320                         if format.find('_' + uppercase_name[0]) >= 0:
321                             print '                %s = GL_TRUE;' % flag_name
322                     print '                break;'
323                 print '            default:'
324                 print '               return;'
325                 print '        }'
326                 print
327
328                 # Emit fake glEnableClientState/glDisableClientState flags
329                 for camelcase_name, uppercase_name in self.arrays:
330                     flag_name = '__' + uppercase_name.lower()
331                     enable_name = 'GL_%s_ARRAY' % uppercase_name
332
333                     # Emit a fake function
334                     print '        {'
335                     print '            static const Trace::FunctionSig &__sig = %s ? __glEnableClientState_sig : __glDisableClientState_sig;' % flag_name
336                     print '            unsigned __call = Trace::BeginEnter(__sig);'
337                     print '            Trace::BeginArg(0);'
338                     dump_instance(glapi.GLenum, enable_name)
339                     print '            Trace::EndArg();'
340                     print '            Trace::EndEnter();'
341                     print '            Trace::BeginLeave(__call);'
342                     print '            Trace::EndLeave();'
343                     print '        }'
344
345             print '        return;'
346             print '    }'
347
348         # ... to the draw calls
349         if function.name in self.draw_function_names:
350             print '    if (__need_user_arrays()) {'
351             arg_names = ', '.join([arg.name for arg in function.args[1:]])
352             print '        GLuint maxindex = __%s_maxindex(%s);' % (function.name, arg_names)
353             print '        __trace_user_arrays(maxindex);'
354             print '    }'
355         
356         # Emit a fake memcpy on
357         if function.name in ('glUnmapBuffer', 'glUnmapBufferARB'):
358             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
359             print '    if (mapping && mapping->write) {'
360             print '        unsigned __call = Trace::BeginEnter(__memcpy_sig);'
361             print '        Trace::BeginArg(0);'
362             print '        Trace::LiteralOpaque(mapping->map);'
363             print '        Trace::EndArg();'
364             print '        Trace::BeginArg(1);'
365             print '        Trace::LiteralBlob(mapping->map, mapping->length);'
366             print '        Trace::EndArg();'
367             print '        Trace::BeginArg(2);'
368             print '        Trace::LiteralUInt(mapping->length);'
369             print '        Trace::EndArg();'
370             print '        Trace::EndEnter();'
371             print '        Trace::BeginLeave(__call);'
372             print '        Trace::EndLeave();'
373             print '    }'
374
375         Tracer.trace_function_impl_body(self, function)
376        
377     buffer_targets = [
378         'ARRAY_BUFFER',
379         'ELEMENT_ARRAY_BUFFER',
380         'PIXEL_PACK_BUFFER',
381         'PIXEL_UNPACK_BUFFER',
382     ]
383
384     def wrap_ret(self, function, instance):
385         Tracer.wrap_ret(self, function, instance)
386             
387         if function.name in ('glMapBuffer', 'glMapBufferARB'):
388             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
389             print '    if (mapping) {'
390             print '        mapping->map = %s;' % (instance)
391             print '        mapping->length = 0;'
392             print '        __glGetBufferParameteriv(target, GL_BUFFER_SIZE, &mapping->length);'
393             print '        mapping->write = (access != GL_READ_ONLY);'
394             print '    }'
395
396         if function.name == 'glMapBufferRange':
397             print '    struct buffer_mapping *mapping = get_buffer_mapping(target);'
398             print '    if (mapping) {'
399             print '        mapping->map = %s;' % (instance)
400             print '        mapping->length = length;'
401             print '        mapping->write = access & GL_MAP_WRITE_BIT;'
402             print '    }'
403
404     boolean_names = [
405         'GL_FALSE',
406         'GL_TRUE',
407     ]
408
409     def gl_boolean(self, value):
410         return self.boolean_names[int(bool(value))]
411
412     def dump_arg_instance(self, function, arg):
413         if function.name in self.draw_function_names and arg.name == 'indices':
414             print '    GLint __element_array_buffer = 0;'
415             print '    __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
416             print '    if (!__element_array_buffer) {'
417             if isinstance(arg.type, stdapi.Array):
418                 Tracer.dump_arg_instance(self, function, arg)
419                 print '        Trace::BeginArray(%s);' % arg.type.length
420                 print '        for(GLsizei i = 0; i < %s; ++i) {' % arg.type.length
421                 print '            Trace::BeginElement();'
422                 print '            Trace::LiteralBlob((const void *)%s, count[i]*__gl_type_size(type));' % (arg.name)
423                 print '            Trace::EndElement();'
424                 print '        }'
425                 print '        Trace::EndArray();'
426             else:
427                 print '        Trace::LiteralBlob((const void *)%s, count*__gl_type_size(type));' % (arg.name)
428             print '    } else {'
429             Tracer.dump_arg_instance(self, function, arg)
430             print '    }'
431             return
432
433         # Several GL state functions take GLenum symbolic names as
434         # integer/floats; so dump the symbolic name whenever possible
435         if arg.type in (glapi.GLint, glapi.GLfloat) and arg.name == 'param':
436             assert arg.index > 0
437             assert function.args[arg.index - 1].name == 'pname'
438             assert function.args[arg.index - 1].type == glapi.GLenum
439             print '    if (is_symbolic_pname(pname) && is_symbolic_param(%s)) {' % arg.name
440             dump_instance(glapi.GLenum, arg.name)
441             print '    } else {'
442             Tracer.dump_arg_instance(self, function, arg)
443             print '    }'
444             return
445
446         Tracer.dump_arg_instance(self, function, arg)
447
448     def footer(self, api):
449         Tracer.footer(self, api)
450
451         # A simple state tracker to track the pointer values
452         # update the state
453         print 'static void __trace_user_arrays(GLuint maxindex)'
454         print '{'
455
456         for camelcase_name, uppercase_name in self.arrays:
457             function_name = 'gl%sPointer' % camelcase_name
458             enable_name = 'GL_%s_ARRAY' % uppercase_name
459             binding_name = 'GL_%s_ARRAY_BUFFER_BINDING' % uppercase_name
460             function = api.get_function_by_name(function_name)
461
462             print '    // %s' % function.name
463             self.array_trace_prolog(api, uppercase_name)
464             self.array_prolog(api, uppercase_name)
465             print '    if (__glIsEnabled(%s)) {' % enable_name
466             print '        GLint __binding = 0;'
467             print '        __glGetIntegerv(%s, &__binding);' % binding_name
468             print '        if (!__binding) {'
469
470             # Get the arguments via glGet*
471             for arg in function.args:
472                 arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
473                 arg_get_function, arg_type = TypeGetter().visit(arg.type)
474                 print '            %s %s = 0;' % (arg_type, arg.name)
475                 print '            __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
476             
477             arg_names = ', '.join([arg.name for arg in function.args[:-1]])
478             print '            size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
479
480             # Emit a fake function
481             self.array_trace_intermezzo(api, uppercase_name)
482             print '            unsigned __call = Trace::BeginEnter(__%s_sig);' % (function.name,)
483             for arg in function.args:
484                 assert not arg.output
485                 print '            Trace::BeginArg(%u);' % (arg.index,)
486                 if arg.name != 'pointer':
487                     dump_instance(arg.type, arg.name)
488                 else:
489                     print '            Trace::LiteralBlob((const void *)%s, __size);' % (arg.name)
490                 print '            Trace::EndArg();'
491             
492             print '            Trace::EndEnter();'
493             print '            Trace::BeginLeave(__call);'
494             print '            Trace::EndLeave();'
495             print '        }'
496             print '    }'
497             self.array_epilog(api, uppercase_name)
498             self.array_trace_epilog(api, uppercase_name)
499             print
500
501         # Samething, but for glVertexAttribPointer
502         print '    // glVertexAttribPointer'
503         print '    GLint __max_vertex_attribs = 0;'
504         print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &__max_vertex_attribs);'
505         print '    for (GLint index = 0; index < __max_vertex_attribs; ++index) {'
506         print '        GLint __enabled = 0;'
507         print '        __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &__enabled);'
508         print '        if (__enabled) {'
509         print '            GLint __binding = 0;'
510         print '            __glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &__binding);'
511         print '            if (!__binding) {'
512
513         function = api.get_function_by_name('glVertexAttribPointer')
514
515         # Get the arguments via glGet*
516         for arg in function.args[1:]:
517             arg_get_enum = 'GL_VERTEX_ATTRIB_ARRAY_%s' % (arg.name.upper(),)
518             arg_get_function, arg_type = TypeGetter('glGetVertexAttrib', False).visit(arg.type)
519             print '                %s %s = 0;' % (arg_type, arg.name)
520             print '                __%s(index, %s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
521         
522         arg_names = ', '.join([arg.name for arg in function.args[1:-1]])
523         print '                size_t __size = __%s_size(%s, maxindex);' % (function.name, arg_names)
524
525         # Emit a fake function
526         print '                unsigned __call = Trace::BeginEnter(__%s_sig);' % (function.name,)
527         for arg in function.args:
528             assert not arg.output
529             print '                Trace::BeginArg(%u);' % (arg.index,)
530             if arg.name != 'pointer':
531                 dump_instance(arg.type, arg.name)
532             else:
533                 print '                Trace::LiteralBlob((const void *)%s, __size);' % (arg.name)
534             print '                Trace::EndArg();'
535         
536         print '                Trace::EndEnter();'
537         print '                Trace::BeginLeave(__call);'
538         print '                Trace::EndLeave();'
539         print '            }'
540         print '        }'
541         print '    }'
542         print
543
544         print '}'
545         print
546
547     #
548     # Hooks for glTexCoordPointer, which is identical to the other array
549     # pointers except the fact that it is indexed by glClientActiveTexture.
550     #
551
552     def array_prolog(self, api, uppercase_name):
553         if uppercase_name == 'TEXTURE_COORD':
554             print '    GLint client_active_texture = 0;'
555             print '    __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
556             print '    GLint max_texture_coords = 0;'
557             print '    __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
558             print '    for (GLint unit = 0; unit < max_texture_coords; ++unit) {'
559             print '        GLenum texture = GL_TEXTURE0 + unit;'
560             print '        __glClientActiveTexture(texture);'
561
562     def array_trace_prolog(self, api, uppercase_name):
563         if uppercase_name == 'TEXTURE_COORD':
564             print '    bool client_active_texture_dirty = false;'
565
566     def array_epilog(self, api, uppercase_name):
567         if uppercase_name == 'TEXTURE_COORD':
568             print '    }'
569         self.array_cleanup(api, uppercase_name)
570
571     def array_cleanup(self, api, uppercase_name):
572         if uppercase_name == 'TEXTURE_COORD':
573             print '    __glClientActiveTexture(client_active_texture);'
574         
575     def array_trace_intermezzo(self, api, uppercase_name):
576         if uppercase_name == 'TEXTURE_COORD':
577             print '    if (texture != client_active_texture || client_active_texture_dirty) {'
578             print '        client_active_texture_dirty = true;'
579             self.fake_glClientActiveTexture_call(api, "texture");
580             print '    }'
581
582     def array_trace_epilog(self, api, uppercase_name):
583         if uppercase_name == 'TEXTURE_COORD':
584             print '    if (client_active_texture_dirty) {'
585             self.fake_glClientActiveTexture_call(api, "client_active_texture");
586             print '    }'
587
588     def fake_glClientActiveTexture_call(self, api, texture):
589         function = api.get_function_by_name('glClientActiveTexture')
590         self.fake_call(function, [texture])
591
592     def fake_call(self, function, args):
593         print '            unsigned __fake_call = Trace::BeginEnter(__%s_sig);' % (function.name,)
594         for arg, instance in zip(function.args, args):
595             assert not arg.output
596             print '            Trace::BeginArg(%u);' % (arg.index,)
597             dump_instance(arg.type, instance)
598             print '            Trace::EndArg();'
599         print '            Trace::EndEnter();'
600         print '            Trace::BeginLeave(__fake_call);'
601         print '            Trace::EndLeave();'
602
603
604
605
606
607
608
609
610
611
612