[pypy-svn] r71629 - in pypy/trunk/pypy: rpython/memory/gctransform translator/c translator/c/gcc translator/c/gcc/test translator/c/gcc/test/darwin translator/c/gcc/test/elf translator/c/gcc/test/msvc translator/c/src
arigo at codespeak.net
arigo at codespeak.net
Tue Mar 2 14:05:03 CET 2010
Author: arigo
Date: Tue Mar 2 14:05:01 2010
New Revision: 71629
Added:
pypy/trunk/pypy/translator/c/gcc/test/darwin/track9.s
- copied unchanged from r71628, pypy/branch/asmgcc-cantcollect/pypy/translator/c/gcc/test/darwin/track9.s
pypy/trunk/pypy/translator/c/gcc/test/elf/track9.s
- copied unchanged from r71628, pypy/branch/asmgcc-cantcollect/pypy/translator/c/gcc/test/elf/track9.s
pypy/trunk/pypy/translator/c/gcc/test/msvc/track9.s
- copied unchanged from r71628, pypy/branch/asmgcc-cantcollect/pypy/translator/c/gcc/test/msvc/track9.s
Modified:
pypy/trunk/pypy/rpython/memory/gctransform/asmgcroot.py
pypy/trunk/pypy/rpython/memory/gctransform/framework.py
pypy/trunk/pypy/translator/c/gcc/instruction.py
pypy/trunk/pypy/translator/c/gcc/test/elf/track5.s
pypy/trunk/pypy/translator/c/gcc/test/msvc/track0.s
pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py
pypy/trunk/pypy/translator/c/gcc/trackgcroot.py
pypy/trunk/pypy/translator/c/genc.py
pypy/trunk/pypy/translator/c/src/mem.h
Log:
Merge of branch/asmgcc-cantcollect:
Don't analyze in trackgcroot calls to functions that cannot collect.
Some of these are very small and the C compiler perform some optimizations
that we don't want to follow.
Modified: pypy/trunk/pypy/rpython/memory/gctransform/asmgcroot.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gctransform/asmgcroot.py (original)
+++ pypy/trunk/pypy/rpython/memory/gctransform/asmgcroot.py Tue Mar 2 14:05:01 2010
@@ -40,6 +40,9 @@
def build_root_walker(self):
return AsmStackRootWalker(self)
+ def mark_call_cannotcollect(self, hop, name):
+ hop.genop("direct_call", [c_asm_nocollect, name])
+
def gct_direct_call(self, hop):
fnptr = hop.spaceop.args[0].value
try:
@@ -487,6 +490,12 @@
_nowrapper=True)
c_asm_gcroot = Constant(pypy_asm_gcroot, lltype.typeOf(pypy_asm_gcroot))
+pypy_asm_nocollect = rffi.llexternal('pypy_asm_gc_nocollect',
+ [rffi.CCHARP], lltype.Void,
+ sandboxsafe=True,
+ _nowrapper=True)
+c_asm_nocollect = Constant(pypy_asm_nocollect, lltype.typeOf(pypy_asm_nocollect))
+
QSORT_CALLBACK_PTR = lltype.Ptr(lltype.FuncType([llmemory.Address,
llmemory.Address], rffi.INT))
qsort = rffi.llexternal('qsort',
Modified: pypy/trunk/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gctransform/framework.py (original)
+++ pypy/trunk/pypy/rpython/memory/gctransform/framework.py Tue Mar 2 14:05:01 2010
@@ -40,7 +40,12 @@
return True
return graphanalyze.GraphAnalyzer.analyze_direct_call(self, graph,
seen)
-
+ def analyze_external_call(self, op, seen=None):
+ funcobj = op.args[0].value._obj
+ if funcobj._name == 'pypy_asm_stackwalk':
+ return True
+ return graphanalyze.GraphAnalyzer.analyze_external_call(self, op,
+ seen)
def analyze_simple_operation(self, op):
if op.opname in ('malloc', 'malloc_varsize'):
flags = op.args[1].value
@@ -577,6 +582,11 @@
self.pop_roots(hop, livevars)
else:
self.default(hop)
+ if hop.spaceop.opname == "direct_call":
+ self.mark_call_cannotcollect(hop, hop.spaceop.args[0])
+
+ def mark_call_cannotcollect(self, hop, name):
+ pass
gct_indirect_call = gct_direct_call
Modified: pypy/trunk/pypy/translator/c/gcc/instruction.py
==============================================================================
--- pypy/trunk/pypy/translator/c/gcc/instruction.py (original)
+++ pypy/trunk/pypy/translator/c/gcc/instruction.py Tue Mar 2 14:05:01 2010
@@ -164,8 +164,8 @@
return dict(zip(self.registers, self.registers))
class InsnCall(Insn):
- _args_ = ['lineno', 'gcroots']
- def __init__(self, lineno):
+ _args_ = ['lineno', 'name', 'gcroots']
+ def __init__(self, name, lineno):
# 'gcroots' is a dict built by side-effect during the call to
# FunctionGcRootTracker.trackgcroots(). Its meaning is as
# follows: the keys are the locations that contain gc roots
@@ -189,12 +189,13 @@
# %ebx from there in the prologue and epilogue).
self.gcroots = {}
self.lineno = lineno
+ self.name = name
def source_of(self, localvar, tag):
tag1 = self.gcroots.setdefault(localvar, tag)
assert tag1 == tag, (
- "conflicting entries for InsnCall.gcroots[%s]:\n%r and %r" % (
- localvar, tag1, tag))
+ "conflicting entries for\n%s.gcroots[%s]:\n%r and %r" % (
+ self, localvar, tag1, tag))
return localvar
def all_sources_of(self, localvar):
Modified: pypy/trunk/pypy/translator/c/gcc/test/elf/track5.s
==============================================================================
--- pypy/trunk/pypy/translator/c/gcc/test/elf/track5.s (original)
+++ pypy/trunk/pypy/translator/c/gcc/test/elf/track5.s Tue Mar 2 14:05:01 2010
@@ -42,9 +42,9 @@
call pypy_g_SemiSpaceGC_get_size
;; expected {28(%esp) | 20(%esp), 24(%esp), %edi, %ebp | }
addl %eax, %ebx
+ jmp .L1221
.L1227:
call RPyAbort
- ;; expected {28(%esp) | 20(%esp), 24(%esp), %edi, %ebp | }
cmpl 12(%esi), %ebx
jb .L1229
addl $20, %esp
Modified: pypy/trunk/pypy/translator/c/gcc/test/msvc/track0.s
==============================================================================
--- pypy/trunk/pypy/translator/c/gcc/test/msvc/track0.s (original)
+++ pypy/trunk/pypy/translator/c/gcc/test/msvc/track0.s Tue Mar 2 14:05:01 2010
@@ -64,7 +64,6 @@
jl SHORT $LN15 at pypy_g_ll_@139
$LN14 at pypy_g_ll_@139:
call _RPyAbort
- ;; expected {24(%esp) | 12(%esp), 4(%esp), (%esp), 8(%esp) | 32(%esp)}
$LN15 at pypy_g_ll_@139:
; 1529 : l_v420 = l_v419;
@@ -76,7 +75,6 @@
test ebx, ebx
jne SHORT $LN16 at pypy_g_ll_@139
call _RPyAbort
- ;; expected {24(%esp) | 12(%esp), 4(%esp), (%esp), 8(%esp) | 32(%esp)}
$LN16 at pypy_g_ll_@139:
; 1531 : OP_INT_ADD(l_v402, l_v421, l_v422);
@@ -183,7 +181,6 @@
jl SHORT $LN10 at pypy_g_ll_@139
$LN9 at pypy_g_ll_@139:
call _RPyAbort
- ;; expected {24(%esp) | 12(%esp), 4(%esp), (%esp), 8(%esp) | }
$LN10 at pypy_g_ll_@139:
; 1517 : l_v413 = l_v412;
@@ -195,7 +192,6 @@
test edi, edi
jne SHORT $LN11 at pypy_g_ll_@139
call _RPyAbort
- ;; expected {24(%esp) | 12(%esp), 4(%esp), (%esp), 8(%esp) | }
$LN11 at pypy_g_ll_@139:
mov edi, DWORD PTR [edi+8]
@@ -208,7 +204,6 @@
jl SHORT $LN13 at pypy_g_ll_@139
$LN12 at pypy_g_ll_@139:
call _RPyAbort
- ;; expected {24(%esp) | 12(%esp), 4(%esp), (%esp), 8(%esp) | }
$LN13 at pypy_g_ll_@139:
; 1520 : pypy_g_copy_string_contents__rpy_stringPtr_rpy_stringPt(l_v415, l_result_2, 0L, l_res_index_0, l_v414);
Modified: pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py
==============================================================================
--- pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py (original)
+++ pypy/trunk/pypy/translator/c/gcc/test/test_trackgcroot.py Tue Mar 2 14:05:01 2010
@@ -169,6 +169,9 @@
assert len(seen) == len(tabledict), (
"computed table contains unexpected entries:\n%r" %
[key for key in tabledict if key not in seen])
- print lines
- print expectedlines
+ print '--------------- got ---------------'
+ print ''.join(lines)
+ print '------------- expected ------------'
+ print ''.join(expectedlines)
+ print '-----------------------------------'
assert lines == expectedlines
Modified: pypy/trunk/pypy/translator/c/gcc/trackgcroot.py
==============================================================================
--- pypy/trunk/pypy/translator/c/gcc/trackgcroot.py (original)
+++ pypy/trunk/pypy/translator/c/gcc/trackgcroot.py Tue Mar 2 14:05:01 2010
@@ -43,7 +43,8 @@
self.findlabels()
self.parse_instructions()
try:
- if not self.list_call_insns():
+ self.find_noncollecting_calls()
+ if not self.list_collecting_call_insns():
return []
self.findframesize()
self.fixlocalvars()
@@ -62,7 +63,7 @@
See format_callshape() for more details about callshape_tuple.
"""
table = []
- for insn in self.list_call_insns():
+ for insn in self.list_collecting_call_insns():
if not hasattr(insn, 'framesize'):
continue # calls that never end up reaching a RET
if self.is_stack_bottom:
@@ -81,10 +82,11 @@
if isinstance(localvar, LocalVar):
loc = localvar.getlocation(insn.framesize,
self.uses_frame_pointer)
- else:
- assert localvar in self.REG2LOC, "%s: %s" % (self.funcname,
- localvar)
+ elif localvar in self.REG2LOC:
loc = self.REG2LOC[localvar]
+ else:
+ assert False, "%s: %s" % (self.funcname,
+ localvar)
assert isinstance(loc, int)
if tag is None:
gcroots.append(loc)
@@ -116,6 +118,20 @@
assert label not in self.labels, "duplicate label: %s" % label
self.labels[label] = Label(label, lineno)
+ def find_noncollecting_calls(self):
+ cannot_collect = self.CANNOT_COLLECT.copy()
+ for line in self.lines:
+ match = self.r_gcnocollect_marker.search(line)
+ if match:
+ name = match.group(1)
+ cannot_collect[name] = True
+ #
+ if self.format in ('darwin', 'mingw32', 'msvc'):
+ self.cannot_collect = dict.fromkeys(
+ ['_' + name for name in cannot_collect])
+ else:
+ self.cannot_collect = cannot_collect
+
def append_instruction(self, insn):
# Add the instruction to the list, and link it to the previous one.
previnsn = self.insns[-1]
@@ -179,8 +195,9 @@
raise UnrecognizedOperation(opname)
setattr(cls, 'visit_' + opname, cls.visit_nop)
- def list_call_insns(self):
- return [insn for insn in self.insns if isinstance(insn, InsnCall)]
+ def list_collecting_call_insns(self):
+ return [insn for insn in self.insns if isinstance(insn, InsnCall)
+ if insn.name not in self.cannot_collect]
def findframesize(self):
# the 'framesize' attached to an instruction is the number of bytes
@@ -292,7 +309,7 @@
# walk backwards, because inserting the global labels in self.lines
# is going to invalidate the lineno of all the InsnCall objects
# after the current one.
- for call in self.list_call_insns()[::-1]:
+ for call in self.list_collecting_call_insns()[::-1]:
if hasattr(call, 'framesize'):
self.create_global_label(call)
@@ -334,6 +351,12 @@
# ____________________________________________________________
+ CANNOT_COLLECT = { # some of the most used functions that cannot collect
+ 'pypy_debug_catch_fatal_exception': None,
+ 'RPyAbort': None,
+ 'RPyAssertFailed': None,
+ }
+
def _visit_gcroot_marker(self, line):
match = self.r_gcroot_marker.match(line)
loc = match.group(1)
@@ -641,7 +664,7 @@
if match is None:
assert self.r_unaryinsn_star.match(line) # indirect call
- return [InsnCall(self.currentlineno),
+ return [InsnCall('<indirect>', self.currentlineno),
InsnSetLocal(self.EAX)] # the result is there
target = match.group(1)
@@ -691,7 +714,7 @@
assert lineoffset in (1,2)
return [InsnStackAdjust(-4)]
- insns = [InsnCall(self.currentlineno),
+ insns = [InsnCall(target, self.currentlineno),
InsnSetLocal(self.EAX)] # the result is there
if self.format in ('mingw32', 'msvc'):
# handle __stdcall calling convention:
@@ -737,6 +760,7 @@
r_jmptable_end = re.compile(r"\t.text|\t.section\s+.text|\t\.align|"+LABEL)
r_gcroot_marker = re.compile(r"\t/[*] GCROOT ("+LOCALVARFP+") [*]/")
+ r_gcnocollect_marker = re.compile(r"\t/[*] GC_NOCOLLECT ("+OPERAND+") [*]/")
r_bottom_marker = re.compile(r"\t/[*] GC_STACK_BOTTOM [*]/")
FUNCTIONS_NOT_RETURNING = {
@@ -813,6 +837,7 @@
r_gcroot_marker = re.compile(r"$1") # never matches
r_gcroot_marker_var = re.compile(r"DWORD PTR .+_constant_always_one_.+pypy_asm_gcroot")
+ r_gcnocollect_marker = re.compile(r"\spypy_asm_gc_nocollect\(("+OPERAND+")\);")
r_bottom_marker = re.compile(r"; .+\tpypy_asm_stack_bottom\(\);")
FUNCTIONS_NOT_RETURNING = {
@@ -864,10 +889,21 @@
'visit_' + name + 'l')
visit_int = FunctionGcRootTracker.visit_nop
- visit_npad = FunctionGcRootTracker.visit_nop
# probably not GC pointers
visit_cdq = FunctionGcRootTracker.visit_nop
+ def visit_npad(self, line):
+ # MASM has a nasty bug: it implements "npad 5" with "add eax, 0"
+ # which is a not no-op because it clears flags.
+ # I've seen this instruction appear between "test" and "jne"...
+ # see http://www.masm32.com/board/index.php?topic=13122
+ match = self.r_unaryinsn.match(line)
+ arg = match.group(1)
+ if arg == "5":
+ # replace with "npad 3; npad 2"
+ self.lines[self.currentlineno] = "\tnpad\t3\n" "\tnpad\t2\n"
+ return []
+
def extract_immediate(self, value):
try:
return int(value)
@@ -1183,229 +1219,209 @@
def dump(self, output):
assert self.seen_main
- shapes = {}
- shapelines = []
- shapeofs = 0
+
def _globalname(name, disp=""):
if self.format in ('darwin', 'mingw32', 'msvc'):
name = '_' + name
+ return name
- if self.format == 'msvc':
- if disp:
- return "DWORD PTR [%s+%s]" % (name, disp)
- else:
- return name
- else:
- if disp:
- return "%s + %s" % (name, disp)
- else:
- return name
-
- def _globl(name):
- if self.format == 'msvc':
- print >> output, "PUBLIC %s" % _globalname(name)
- else:
- print >> output, "\t.globl %s" % _globalname(name)
- def _label(name):
- print >> output, "%s:" % _globalname(name)
def _variant(**kwargs):
txt = kwargs[self.format]
print >> output, "\t%s" % txt
- def _comment(comment):
- if self.format == 'msvc':
- print >> output, "; %s" % comment
- else:
- print >> output, "/* %s */" % comment
-
- def _movl(source, target, comment):
- if self.format == 'msvc':
- print >> output, "\tmov\t%s, %s\t\t; %s" % (target, source, comment)
- else:
- print >> output, "\tmovl\t%s, %s\t\t/* %s */ " % (source, target, comment)
-
- def _pushl(source, comment):
- if self.format == 'msvc':
- print >> output, "\tpush\t%s\t\t; %s" % (source, comment)
- else:
- print >> output, "\tpushl\t%s\t\t/* %s */ " % (source, comment)
-
- def _popl(source, comment):
- if self.format == 'msvc':
- print >> output, "\tpop\t%s\t\t; %s" % (source, comment)
- else:
- print >> output, "\tpopl\t%s\t\t/* %s */ " % (source, comment)
-
-
- def _register(name, disp=""):
- if self.format == 'msvc':
- if disp:
- return "DWORD PTR [%s+%s]" % (name, disp)
- else:
- return name
- else:
- if disp:
- return "%s(%%%s)" % (disp, name)
- else:
- return '%' + name
-
- def _offset(name):
- if self.format == 'msvc':
- return "OFFSET %s" % _globalname(name)
- else:
- return "$%s" % _globalname(name)
-
- def _call(arg, comment):
- if self.format == 'msvc':
- print >> output, "\tcall\t%s\t\t;%s" % (arg, comment)
- else:
- print >> output, "\tcall\t%s\t\t/* %s */" % (arg, comment)
-
- def _indirectjmp(arg):
- if self.format == 'msvc':
- return "DWORD PTR " + arg
- else:
- return "*%" + arg
+ # The pypy_asm_stackwalk() function
if self.format == 'msvc':
print >> output, """\
- TITLE\tgcmaptable.s
- .686P
- .XMM
- .model\tflat
+ /* A circular doubly-linked list of all
+ * the ASM_FRAMEDATAs currently alive
+ */
+ struct asm_framedata {
+ struct asm_framedata* prev;
+ struct asm_framedata* next;
+ } __gcrootanchor = { &__gcrootanchor, &__gcrootanchor };
+
+ /* See description in asmgcroot.py */
+ __declspec(naked)
+ long pypy_asm_stackwalk(void *callback)
+ {
+ __asm {
+ mov\tedx, DWORD PTR [esp+4]\t; my argument, which is the callback
+ mov\teax, esp\t\t; my frame top address
+ push\teax\t\t\t; ASM_FRAMEDATA[6]
+ push\tebp\t\t\t; ASM_FRAMEDATA[5]
+ push\tedi\t\t\t; ASM_FRAMEDATA[4]
+ push\tesi\t\t\t; ASM_FRAMEDATA[3]
+ push\tebx\t\t\t; ASM_FRAMEDATA[2]
+
+ ; Add this ASM_FRAMEDATA to the front of the circular linked
+ ; list. Let's call it 'self'.
+
+ mov\teax, DWORD PTR [__gcrootanchor+4]\t\t; next = gcrootanchor->next
+ push\teax\t\t\t\t\t\t\t\t\t; self->next = next
+ push\tOFFSET __gcrootanchor ; self->prev = gcrootanchor
+ mov\tDWORD PTR [__gcrootanchor+4], esp\t\t; gcrootanchor->next = self
+ mov\tDWORD PTR [eax+0], esp\t\t\t\t\t; next->prev = self
+
+ call\tedx\t\t\t\t\t\t; invoke the callback
+
+ ; Detach this ASM_FRAMEDATA from the circular linked list
+ pop\tesi\t\t\t\t\t\t\t; prev = self->prev
+ pop\tedi\t\t\t\t\t\t\t; next = self->next
+ mov\tDWORD PTR [esi+4], edi\t\t; prev->next = next
+ mov\tDWORD PTR [edi+0], esi\t\t; next->prev = prev
+
+ pop\tebx\t\t\t\t; restore from ASM_FRAMEDATA[2]
+ pop\tesi\t\t\t\t; restore from ASM_FRAMEDATA[3]
+ pop\tedi\t\t\t\t; restore from ASM_FRAMEDATA[4]
+ pop\tebp\t\t\t\t; restore from ASM_FRAMEDATA[5]
+ pop\tecx\t\t\t\t; ignored ASM_FRAMEDATA[6]
+ ; the return value is the one of the 'call' above,
+ ; because %eax (and possibly %edx) are unmodified
+ ret
+ }
+ }
"""
- _variant(elf='\t.text',
- darwin='\t.text',
- mingw32='\t.text',
- msvc='_TEXT\tSEGMENT')
-
- _globl('pypy_asm_stackwalk')
- _variant(elf='.type pypy_asm_stackwalk, @function',
- darwin='',
- mingw32='',
- msvc='')
- _label('pypy_asm_stackwalk')
- _comment("See description in asmgcroot.py")
- _movl(_register("esp", disp="4"), _register("edx"), "my argument, which is the callback")
- _movl(_register("esp"), _register("eax"), "my frame top address")
- _pushl(_register("eax"), "ASM_FRAMEDATA[6]")
- _pushl(_register("ebp"), "ASM_FRAMEDATA[5]")
- _pushl(_register("edi"), "ASM_FRAMEDATA[4]")
- _pushl(_register("esi"), "ASM_FRAMEDATA[3]")
- _pushl(_register("ebx"), "ASM_FRAMEDATA[2]")
-
- print >> output
- _comment("Add this ASM_FRAMEDATA to the front of the circular linked")
- _comment("list. Let's call it 'self'.")
- print >> output
- _movl(_globalname("__gcrootanchor", disp=4), _register("eax"), "next = gcrootanchor->next")
- _pushl(_register("eax"), "self->next = next")
- _pushl(_offset("__gcrootanchor"), "self->prev = gcrootanchor")
- _movl(_register("esp"), _globalname("__gcrootanchor", disp=4), "gcrootanchor->next = self")
- _movl(_register("esp"), _register("eax", "0"), "next->prev = self")
- print >> output
-
- _comment("note: the Mac OS X 16 bytes aligment must be respected.")
- _call(_indirectjmp("edx"), "invoke the callback")
- print >> output
-
- _comment("Detach this ASM_FRAMEDATA from the circular linked list")
- _popl(_register("esi"), "prev = self->prev")
- _popl(_register("edi"), "next = self->next")
- _movl(_register("edi"), _register("esi", disp="4"), "prev->next = next")
- _movl(_register("esi"), _register("edi", disp="0"), "next->prev = prev")
- print >> output
-
- _popl(_register("ebx"), "restore from ASM_FRAMEDATA[2]")
- _popl(_register("esi"), "restore from ASM_FRAMEDATA[3]")
- _popl(_register("edi"), "restore from ASM_FRAMEDATA[4]")
- _popl(_register("ebp"), "restore from ASM_FRAMEDATA[5]")
- _popl(_register("ecx"), "ignored ASM_FRAMEDATA[6]")
- _comment("the return value is the one of the 'call' above,")
- _comment("because %eax (and possibly %edx) are unmodified")
-
- print >> output, "\tret"
-
- _variant(elf='.size pypy_asm_stackwalk, .-pypy_asm_stackwalk',
- darwin='',
- mingw32='',
- msvc='')
-
- if self.format == 'msvc':
- for label, state, is_range in self.gcmaptable:
- print >> output, "EXTERN %s:NEAR" % label
+ else:
+ print >> output, "\t.text"
+ print >> output, "\t.globl %s" % _globalname('pypy_asm_stackwalk')
+ _variant(elf='.type pypy_asm_stackwalk, @function',
+ darwin='',
+ mingw32='')
+ print >> output, "%s:" % _globalname('pypy_asm_stackwalk')
- if self.format == 'msvc':
- print >> output, '_DATA SEGMENT'
+ print >> output, """\
+ /* See description in asmgcroot.py */
+ movl\t4(%esp), %edx\t/* my argument, which is the callback */
+ movl\t%esp, %eax\t/* my frame top address */
+ pushl\t%eax\t\t/* ASM_FRAMEDATA[6] */
+ pushl\t%ebp\t\t/* ASM_FRAMEDATA[5] */
+ pushl\t%edi\t\t/* ASM_FRAMEDATA[4] */
+ pushl\t%esi\t\t/* ASM_FRAMEDATA[3] */
+ pushl\t%ebx\t\t/* ASM_FRAMEDATA[2] */
+
+ /* Add this ASM_FRAMEDATA to the front of the circular linked */
+ /* list. Let's call it 'self'. */
+
+ movl\t__gcrootanchor + 4, %eax\t/* next = gcrootanchor->next */
+ pushl\t%eax\t\t\t\t/* self->next = next */
+ pushl\t$__gcrootanchor\t\t\t/* self->prev = gcrootanchor */
+ movl\t%esp, __gcrootanchor + 4\t/* gcrootanchor->next = self */
+ movl\t%esp, 0(%eax)\t\t\t/* next->prev = self */
+
+ /* note: the Mac OS X 16 bytes aligment must be respected. */
+ call\t*%edx\t\t/* invoke the callback */
+
+ /* Detach this ASM_FRAMEDATA from the circular linked list */
+ popl\t%esi\t\t/* prev = self->prev */
+ popl\t%edi\t\t/* next = self->next */
+ movl\t%edi, 4(%esi)\t/* prev->next = next */
+ movl\t%esi, 0(%edi)\t/* next->prev = prev */
+
+ popl\t%ebx\t\t/* restore from ASM_FRAMEDATA[2] */
+ popl\t%esi\t\t/* restore from ASM_FRAMEDATA[3] */
+ popl\t%edi\t\t/* restore from ASM_FRAMEDATA[4] */
+ popl\t%ebp\t\t/* restore from ASM_FRAMEDATA[5] */
+ popl\t%ecx\t\t/* ignored ASM_FRAMEDATA[6] */
+
+ /* the return value is the one of the 'call' above, */
+ /* because %eax (and possibly %edx) are unmodified */
+ ret
+ """.replace("__gcrootanchor", _globalname("__gcrootanchor"))
+
+ _variant(elf='.size pypy_asm_stackwalk, .-pypy_asm_stackwalk',
+ darwin='',
+ mingw32='')
- _comment("A circular doubly-linked list of all")
- _comment("the ASM_FRAMEDATAs currently alive")
if self.format == 'msvc':
- _globl('__gcrootanchor')
- print >> output, '%s\tDD FLAT:___gcrootanchor ; prev' % _globalname("__gcrootanchor")
- print >> output, '\tDD FLAT:___gcrootanchor ; next'
- else:
- print >> output, '\t.data'
- print >> output, '\t.align\t4'
- _globl('__gcrootanchor')
- _label('__gcrootanchor')
+ for label, state, is_range in self.gcmaptable:
+ label = label[1:]
+ print >> output, "extern void* %s;" % label
+ else:
print >> output, """\
+ /* A circular doubly-linked list of all */
+ /* the ASM_FRAMEDATAs currently alive */
+ .data
+ .align 4
+ .globl __gcrootanchor
+ __gcrootanchor:
.long\t__gcrootanchor /* prev */
.long\t__gcrootanchor /* next */
-""".replace("__gcrootanchor", _globalname("__gcrootanchor"))
+ """.replace("__gcrootanchor", _globalname("__gcrootanchor"))
+
+ shapes = {}
+ shapelines = []
+ shapeofs = 0
+
+ # write the tables
- _globl('__gcmapstart')
if self.format == 'msvc':
- print >> output, '%s' % _globalname('__gcmapstart'),
+ print >> output, """\
+ static struct { void* addr; long shape; } __gcmap[%d] = {
+ """ % (len(self.gcmaptable),)
+ for label, state, is_range in self.gcmaptable:
+ label = label[1:]
+ try:
+ n = shapes[state]
+ except KeyError:
+ n = shapes[state] = shapeofs
+ bytes = [str(b) for b in compress_callshape(state)]
+ shapelines.append('\t%s,\t/* %s */\n' % (
+ ', '.join(bytes),
+ shapeofs))
+ shapeofs += len(bytes)
+ if is_range:
+ n = ~ n
+ print >> output, '{ &%s, %d},' % (label, n)
+ print >> output, """\
+ };
+ void* __gcmapstart = __gcmap;
+ void* __gcmapend = __gcmap + %d;
+
+ char __gccallshapes[] = {
+ """ % (len(self.gcmaptable),)
+ output.writelines(shapelines)
+ print >> output, """\
+ };
+ """
else:
- _label('__gcmapstart')
- for label, state, is_range in self.gcmaptable:
- try:
- n = shapes[state]
- except KeyError:
- n = shapes[state] = shapeofs
- bytes = [str(b) for b in compress_callshape(state)]
- if self.format == 'msvc':
- shapelines.append('\tDB\t%s\t;%s\n' % (
- ', '.join(bytes),
- shapeofs))
- else:
+ print >> output, """\
+ .globl __gcmapstart
+ __gcmapstart:
+ """.replace("__gcmapstart", _globalname("__gcmapstart"))
+
+ for label, state, is_range in self.gcmaptable:
+ try:
+ n = shapes[state]
+ except KeyError:
+ n = shapes[state] = shapeofs
+ bytes = [str(b) for b in compress_callshape(state)]
shapelines.append('\t/*%d*/\t.byte\t%s\n' % (
shapeofs,
', '.join(bytes)))
- shapeofs += len(bytes)
- if is_range:
- n = ~ n
- if self.format == 'msvc':
- print >> output, '\tDD\t%s' % (label,)
- print >> output, '\tDD\t%d' % (n,)
- else:
+ shapeofs += len(bytes)
+ if is_range:
+ n = ~ n
print >> output, '\t.long\t%s-%d' % (
label,
PARSERS[self.format].FunctionGcRootTracker.OFFSET_LABELS)
print >> output, '\t.long\t%d' % (n,)
- _globl('__gcmapend')
- if self.format == 'msvc':
- print >> output, '%s DD ?' % _globalname('__gcmapend')
- else:
- _label('__gcmapend')
- _variant(elf='.section\t.rodata',
- darwin='.const',
- mingw32='',
- msvc='')
-
- _globl('__gccallshapes')
- if self.format == 'msvc':
- print >> output, _globalname('__gccallshapes'),
- else:
- _label('__gccallshapes')
- output.writelines(shapelines)
+ print >> output, """\
+ .globl __gcmapend
+ __gcmapend:
+ """.replace("__gcmapend", _globalname("__gcmapend"))
+
+ _variant(elf='.section\t.rodata',
+ darwin='.const',
+ mingw32='')
- if self.format == 'msvc':
- print >> output, "_DATA\tENDS"
- print >> output, "END"
+ print >> output, """\
+ .globl __gccallshapes
+ __gccallshapes:
+ """.replace("__gccallshapes", _globalname("__gccallshapes"))
+ output.writelines(shapelines)
def process(self, iterlines, newfile, entrypoint='main', filename='?'):
parser = PARSERS[format](verbose=self.verbose, shuffle=self.shuffle)
Modified: pypy/trunk/pypy/translator/c/genc.py
==============================================================================
--- pypy/trunk/pypy/translator/c/genc.py (original)
+++ pypy/trunk/pypy/translator/c/genc.py Tue Mar 2 14:05:01 2010
@@ -532,7 +532,7 @@
['$(CC) /nologo $(ASM_CFLAGS) /c /FAs /Fa$*.s $< $(INCLUDEDIRS)',
'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc -t $*.s > $@']
)
- mk.rule('gcmaptable.s', '$(GCMAPFILES)',
+ mk.rule('gcmaptable.c', '$(GCMAPFILES)',
'cmd /c ' + python + '$(PYPYDIR)/translator/c/gcc/trackgcroot.py -fmsvc $(GCMAPFILES) > $@')
else:
Modified: pypy/trunk/pypy/translator/c/src/mem.h
==============================================================================
--- pypy/trunk/pypy/translator/c/src/mem.h (original)
+++ pypy/trunk/pypy/translator/c/src/mem.h Tue Mar 2 14:05:01 2010
@@ -2,6 +2,7 @@
/************************************************************/
/*** C header subsection: operations on LowLevelTypes ***/
+#ifndef _MSC_VER
extern char __gcmapstart;
extern char __gcmapend;
extern char __gccallshapes;
@@ -18,7 +19,6 @@
and one in a register), pass one to GCROOT, and later use the other
one. In practice the pypy_asm_gcroot() is often a no-op in the final
machine code and doesn't prevent most optimizations. */
-#ifndef _MSC_VER
/* With gcc, getting the asm() right was tricky, though. The asm() is
not volatile so that gcc is free to delete it if the output variable
@@ -34,13 +34,28 @@
"0" (p), "m" (__gcnoreorderhack)); \
_r; })
+#define pypy_asm_gc_nocollect(f) asm volatile ("/* GC_NOCOLLECT " #f " */" \
+ : : )
+
#define pypy_asm_keepalive(v) asm volatile ("/* keepalive %0 */" : : \
"g" (v))
/* marker for trackgcroot.py */
#define pypy_asm_stack_bottom() asm volatile ("/* GC_STACK_BOTTOM */" : : )
+#define OP_GC_ASMGCROOT_STATIC(i, r) r = \
+ i == 0 ? (void*)&__gcmapstart : \
+ i == 1 ? (void*)&__gcmapend : \
+ i == 2 ? (void*)&__gccallshapes : \
+ i == 3 ? (void*)&__gcrootanchor : \
+ NULL
+
#else
+extern void* __gcmapstart;
+extern void* __gcmapend;
+extern char* __gccallshapes;
+extern void* __gcrootanchor;
+extern long pypy_asm_stackwalk(void*);
/* With the msvc Microsoft Compiler, the optimizer seems free to move
any code (even asm) that involves local memory (registers and stack).
@@ -58,20 +73,22 @@
return _r1;
}
+#define pypy_asm_gc_nocollect(f) "/* GC_NOCOLLECT " #f " */"
+
#define pypy_asm_keepalive(v) __asm { }
static __declspec(noinline) void pypy_asm_stack_bottom() { }
-#endif
-
-
-
#define OP_GC_ASMGCROOT_STATIC(i, r) r = \
- i == 0 ? (void*)&__gcmapstart : \
- i == 1 ? (void*)&__gcmapend : \
+ i == 0 ? (void*)__gcmapstart : \
+ i == 1 ? (void*)__gcmapend : \
i == 2 ? (void*)&__gccallshapes : \
i == 3 ? (void*)&__gcrootanchor : \
NULL
+#endif
+
+
+
#define RAW_MALLOC_ZERO_FILLED 0
#if RAW_MALLOC_ZERO_FILLED
More information about the Pypy-commit
mailing list