GitLab will be upgraded on 30 Jan 2023 from 2.00 pm (AEDT) to 3.00 pm (AEDT). During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to us at N110 (b) CSIT building.

gc.py 28.3 KB
Newer Older
1
import os
Alexander Hesse's avatar
Alexander Hesse committed
2
3
4
from rpython.rlib import rgc
from rpython.rlib.objectmodel import we_are_translated, specialize
from rpython.rlib.rarithmetic import ovfcheck
5
6
from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr
from rpython.rtyper import rclass
Alexander Hesse's avatar
Alexander Hesse committed
7
8
from rpython.rtyper.lltypesystem import llgroup
from rpython.rtyper.lltypesystem.lloperation import llop
Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
9
from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref
Alexander Hesse's avatar
Alexander Hesse committed
10
11
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.jit.codewriter import heaptracker
12
from rpython.jit.metainterp.history import ConstPtr, AbstractDescr, ConstInt
13
from rpython.jit.metainterp.resoperation import rop, ResOperation
Alexander Hesse's avatar
Alexander Hesse committed
14
from rpython.jit.backend.llsupport import symbolic, jitframe
Alexander Hesse's avatar
Alexander Hesse committed
15
from rpython.jit.backend.llsupport.symbolic import WORD
16
from rpython.jit.backend.llsupport.descr import SizeDescr, ArrayDescr, FieldDescr
Alexander Hesse's avatar
Alexander Hesse committed
17
18
19
from rpython.jit.backend.llsupport.descr import GcCache, get_field_descr
from rpython.jit.backend.llsupport.descr import get_array_descr
from rpython.jit.backend.llsupport.descr import get_call_descr
20
from rpython.jit.backend.llsupport.descr import unpack_arraydescr
Alexander Hesse's avatar
Alexander Hesse committed
21
from rpython.jit.backend.llsupport.rewrite import GcRewriterAssembler
22
from rpython.memory.gctransform import asmgcroot
23
from rpython.jit.codewriter.effectinfo import EffectInfo
24

25
# ____________________________________________________________
26

27
class GcLLDescription(GcCache):
28

29
30
    def __init__(self, gcdescr, translator=None, rtyper=None):
        GcCache.__init__(self, translator is not None, rtyper)
31
        self.gcdescr = gcdescr
Armin Rigo's avatar
Armin Rigo committed
32
33
34
35
36
        if translator and translator.config.translation.gcremovetypeptr:
            self.fielddescr_vtable = None
        else:
            self.fielddescr_vtable = get_field_descr(self, rclass.OBJECT,
                                                     'typeptr')
Armin Rigo's avatar
Armin Rigo committed
37
        self._generated_functions = []
Armin Rigo's avatar
Armin Rigo committed
38

Armin Rigo's avatar
Armin Rigo committed
39
40
41
    def _setup_str(self):
        self.str_descr     = get_array_descr(self, rstr.STR)
        self.unicode_descr = get_array_descr(self, rstr.UNICODE)
42
43
        self.str_hash_descr     = get_field_descr(self, rstr.STR,     'hash')
        self.unicode_hash_descr = get_field_descr(self, rstr.UNICODE, 'hash')
Armin Rigo's avatar
Armin Rigo committed
44

Armin Rigo's avatar
Armin Rigo committed
45
46
    def generate_function(self, funcname, func, ARGS, RESULT=llmemory.GCREF):
        """Generates a variant of malloc with the given name and the given
47
48
        arguments.  It should return NULL if out of memory.  If it raises
        anything, it must be an optional MemoryError.
Armin Rigo's avatar
Armin Rigo committed
49
50
        """
        FUNCPTR = lltype.Ptr(lltype.FuncType(ARGS, RESULT))
Armin Rigo's avatar
Fix    
Armin Rigo committed
51
52
53
54
        # Note: the call may invoke the GC, which may run finalizers.
        # Finalizers are constrained in what they can do, but we can't
        # really express that in a useful way here.
        descr = get_call_descr(self, ARGS, RESULT, EffectInfo.MOST_GENERAL)
Armin Rigo's avatar
Armin Rigo committed
55
56
57
        setattr(self, funcname, func)
        setattr(self, funcname + '_FUNCPTR', FUNCPTR)
        setattr(self, funcname + '_descr', descr)
Armin Rigo's avatar
Armin Rigo committed
58
        self._generated_functions.append(funcname)
59

Armin Rigo's avatar
Armin Rigo committed
60
61
62
63
64
65
66
67
68
69
70
    @specialize.arg(1)
    def get_malloc_fn(self, funcname):
        func = getattr(self, funcname)
        FUNC = getattr(self, funcname + '_FUNCPTR')
        return llhelper(FUNC, func)

    @specialize.arg(1)
    def get_malloc_fn_addr(self, funcname):
        ll_func = self.get_malloc_fn(funcname)
        return heaptracker.adr2int(llmemory.cast_ptr_to_adr(ll_func))

71
72
    def _freeze_(self):
        return True
73
74
    def initialize(self):
        pass
Armin Rigo's avatar
Armin Rigo committed
75
    def can_use_nursery_malloc(self, size):
76
        return False
77
78
    def has_write_barrier_class(self):
        return None
Armin Rigo's avatar
fixes    
Armin Rigo committed
79
80
81
82
    def get_nursery_free_addr(self):
        raise NotImplementedError
    def get_nursery_top_addr(self):
        raise NotImplementedError
83

Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
84
85
86
    def freeing_block(self, rawstart, rawstop):
        pass

Armin Rigo's avatar
Armin Rigo committed
87
88
89
    def gc_malloc(self, sizedescr):
        """Blackhole: do a 'bh_new'.  Also used for 'bh_new_with_vtable',
        with the vtable pointer set manually afterwards."""
Armin Rigo's avatar
Armin Rigo committed
90
91
        assert isinstance(sizedescr, SizeDescr)
        return self._bh_malloc(sizedescr)
Armin Rigo's avatar
Armin Rigo committed
92

93
    def gc_malloc_array(self, num_elem, arraydescr):
Armin Rigo's avatar
Armin Rigo committed
94
        assert isinstance(arraydescr, ArrayDescr)
95
        return self._bh_malloc_array(num_elem, arraydescr)
Armin Rigo's avatar
Armin Rigo committed
96
97

    def gc_malloc_str(self, num_elem):
98
        return self._bh_malloc_array(num_elem, self.str_descr)
99

Armin Rigo's avatar
Armin Rigo committed
100
    def gc_malloc_unicode(self, num_elem):
101
        return self._bh_malloc_array(num_elem, self.unicode_descr)
102

Armin Rigo's avatar
Armin Rigo committed
103
    def rewrite_assembler(self, cpu, operations, gcrefs_output_list):
104
        rewriter = GcRewriterAssembler(self, cpu)
Armin Rigo's avatar
Armin Rigo committed
105
106
107
        newops = rewriter.rewrite(operations, gcrefs_output_list)
        return newops

108
109
    @specialize.memo()
    def getframedescrs(self, cpu):
Armin Rigo's avatar
Armin Rigo committed
110
        descrs = JitFrameDescrs()
111
        descrs.arraydescr = cpu.arraydescrof(jitframe.JITFRAME)
112
        for name in ['jf_descr', 'jf_guard_exc', 'jf_force_descr',
113
114
                     'jf_frame_info', 'jf_gcmap', 'jf_extra_stack_depth',
                     'jf_savedata', 'jf_forward']:
115
            setattr(descrs, name, cpu.fielddescrof(jitframe.JITFRAME, name))
116
117
        descrs.jfi_frame_size = cpu.fielddescrof(jitframe.JITFRAMEINFO,
                                                  'jfi_frame_size')
118
119
        descrs.jfi_frame_depth = cpu.fielddescrof(jitframe.JITFRAMEINFO,
                                                  'jfi_frame_depth')
Armin Rigo's avatar
Armin Rigo committed
120
121
        return descrs

122
123
124
    def getarraydescr_for_frame(self, type):
        """ This functions retuns an arraydescr of type for the JITFRAME"""
        raise NotImplementedError
125

Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
126
    def malloc_jitframe(self, frame_info):
127
128
        """ Allocate a new frame, overwritten by tests
        """
129
        return jitframe.JITFRAME.allocate(frame_info)
130

131
132
133
134
135
136
137
138
    def make_gcref_tracer(self, array_base_addr, gcrefs):
        # for tests, or for Boehm.  Overridden for framework GCs
        from rpython.jit.backend.llsupport import gcreftracer
        return gcreftracer.make_boehm_tracer(array_base_addr, gcrefs)

    def clear_gcref_tracer(self, tracer):
        pass    # nothing needed unless overridden

Armin Rigo's avatar
Armin Rigo committed
139
140
141
class JitFrameDescrs:
    def _freeze_(self):
        return True
142

143
144
145
# ____________________________________________________________

class GcLLDescr_boehm(GcLLDescription):
Armin Rigo's avatar
Armin Rigo committed
146
    kind                  = 'boehm'
147
    malloc_zero_filled    = True
Armin Rigo's avatar
Armin Rigo committed
148
    moving_gc             = False
149
    round_up              = False
Armin Rigo's avatar
Armin Rigo committed
150
151
    write_barrier_descr   = None
    fielddescr_tid        = None
Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
152
    gcrootmap             = None
Armin Rigo's avatar
Armin Rigo committed
153
154
    str_type_id           = 0
    unicode_type_id       = 0
155
    get_malloc_slowpath_addr = None
156
    supports_guard_gc_type   = False
157

Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
158
159
160
    def is_shadow_stack(self):
        return False

161
162
163
164
165
166
    @classmethod
    def configure_boehm_once(cls):
        """ Configure boehm only once, since we don't cache failures
        """
        if hasattr(cls, 'malloc_fn_ptr'):
            return cls.malloc_fn_ptr
Alexander Hesse's avatar
Alexander Hesse committed
167
        from rpython.rtyper.tool import rffi_platform
168
        compilation_info = rffi_platform.configure_boehm()
169

Armin Rigo's avatar
Armin Rigo committed
170
171
172
173
174
175
176
177
178
179
        # on some platform GC_init is required before any other
        # GC_* functions, call it here for the benefit of tests
        # XXX move this to tests
        init_fn_ptr = rffi.llexternal("GC_init",
                                      [], lltype.Void,
                                      compilation_info=compilation_info,
                                      sandboxsafe=True,
                                      _nowrapper=True)
        init_fn_ptr()

180
181
182
183
184
185
186
187
188
189
190
191
192
        # Versions 6.x of libgc needs to use GC_local_malloc().
        # Versions 7.x of libgc removed this function; GC_malloc() has
        # the same behavior if libgc was compiled with
        # THREAD_LOCAL_ALLOC.
        class CConfig:
            _compilation_info_ = compilation_info
            HAS_LOCAL_MALLOC = rffi_platform.Has("GC_local_malloc")
        config = rffi_platform.configure(CConfig)
        if config['HAS_LOCAL_MALLOC']:
            GC_MALLOC = "GC_local_malloc"
        else:
            GC_MALLOC = "GC_malloc"
        malloc_fn_ptr = rffi.llexternal(GC_MALLOC,
193
194
195
196
197
                                        [lltype.Signed], # size_t, but good enough
                                        llmemory.GCREF,
                                        compilation_info=compilation_info,
                                        sandboxsafe=True,
                                        _nowrapper=True)
198
199
200
201
202
203
        cls.malloc_fn_ptr = malloc_fn_ptr
        return malloc_fn_ptr

    def __init__(self, gcdescr, translator, rtyper):
        GcLLDescription.__init__(self, gcdescr, translator, rtyper)
        # grab a pointer to the Boehm 'malloc' function
Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
204
        self.malloc_fn_ptr = self.configure_boehm_once()
Armin Rigo's avatar
Armin Rigo committed
205
        self._setup_str()
206
        self._make_functions()
207
        self.memory = 0
208
209

    def _make_functions(self):
210

211
        def malloc_fixedsize(size):
212
            return self.malloc_fn_ptr(size)
Armin Rigo's avatar
Armin Rigo committed
213
214
        self.generate_function('malloc_fixedsize', malloc_fixedsize,
                               [lltype.Signed])
215

Armin Rigo's avatar
Armin Rigo committed
216
        def malloc_array(basesize, num_elem, itemsize, ofs_length):
217
            try:
218
                totalsize = ovfcheck(basesize + ovfcheck(itemsize * num_elem))
219
220
            except OverflowError:
                return lltype.nullptr(llmemory.GCREF.TO)
Armin Rigo's avatar
Armin Rigo committed
221
            res = self.malloc_fn_ptr(totalsize)
222
223
224
            if res:
                arrayptr = rffi.cast(rffi.CArrayPtr(lltype.Signed), res)
                arrayptr[ofs_length/WORD] = num_elem
225
            return res
226
        self.generate_function('malloc_array', malloc_array,
Armin Rigo's avatar
Armin Rigo committed
227
                               [lltype.Signed] * 4)
228

Armin Rigo's avatar
Armin Rigo committed
229
230
    def _bh_malloc(self, sizedescr):
        return self.malloc_fixedsize(sizedescr.size)
231

232
    def _bh_malloc_array(self, num_elem, arraydescr):
Armin Rigo's avatar
Armin Rigo committed
233
234
235
        return self.malloc_array(arraydescr.basesize, num_elem,
                                 arraydescr.itemsize,
                                 arraydescr.lendescr.offset)
236

237
# ____________________________________________________________
Armin Rigo's avatar
Armin Rigo committed
238
# All code below is for the hybrid or minimark GC
239

Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
240
241
242
class GcRootMap_asmgcc(object):
    is_shadow_stack = False

Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
243
244
245
    def __init__(self, gcdescr):
        pass

Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
246
247
248
249
250
251
    def register_asm_addr(self, start, mark):
        pass

class GcRootMap_shadowstack(object):
    is_shadow_stack = True

Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
252
253
254
    def __init__(self, gcdescr):
        pass

Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
255
256
    def register_asm_addr(self, start, mark):
        pass
257

258
259
260
261
    def get_root_stack_top_addr(self):
        rst_addr = llop.gc_adr_of_root_stack_top(llmemory.Address)
        return rffi.cast(lltype.Signed, rst_addr)

262
263
264
265
class WriteBarrierDescr(AbstractDescr):
    def __init__(self, gc_ll_descr):
        self.llop1 = gc_ll_descr.llop1
        self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR
Armin Rigo's avatar
Armin Rigo committed
266
        self.fielddescr_tid = gc_ll_descr.fielddescr_tid
267
        #
Armin Rigo's avatar
Armin Rigo committed
268
269
270
        GCClass = gc_ll_descr.GCClass
        if GCClass is None:     # for tests
            return
271
272
273
274
275
276
277
278
279
        self.jit_wb_if_flag = GCClass.JIT_WB_IF_FLAG
        self.jit_wb_if_flag_byteofs, self.jit_wb_if_flag_singlebyte = (
            self.extract_flag_byte(self.jit_wb_if_flag))
        #
        if hasattr(GCClass, 'JIT_WB_CARDS_SET'):
            self.jit_wb_cards_set = GCClass.JIT_WB_CARDS_SET
            self.jit_wb_card_page_shift = GCClass.JIT_WB_CARD_PAGE_SHIFT
            self.jit_wb_cards_set_byteofs, self.jit_wb_cards_set_singlebyte = (
                self.extract_flag_byte(self.jit_wb_cards_set))
280
281
282
283
284
            #
            # the x86 backend uses the following "accidental" facts to
            # avoid one instruction:
            assert self.jit_wb_cards_set_byteofs == self.jit_wb_if_flag_byteofs
            assert self.jit_wb_cards_set_singlebyte == -0x80
285
286
287
288
289
        else:
            self.jit_wb_cards_set = 0

    def extract_flag_byte(self, flag_word):
        # if convenient for the backend, we compute the info about
290
291
        # the flag as (byte-offset, single-byte-flag).
        import struct
292
        value = struct.pack(lltype.SignedFmt, flag_word)
293
294
295
        assert value.count('\x00') == len(value) - 1    # only one byte is != 0
        i = 0
        while value[i] == '\x00': i += 1
296
        return (i, struct.unpack('b', value[i])[0])
297
298
299
300
301
302
303

    def get_write_barrier_fn(self, cpu):
        llop1 = self.llop1
        funcptr = llop1.get_write_barrier_failing_case(self.WB_FUNCPTR)
        funcaddr = llmemory.cast_ptr_to_adr(funcptr)
        return cpu.cast_adr_to_int(funcaddr)

304
    def get_write_barrier_from_array_fn(self, cpu):
305
        # returns a function with arguments [array, index, newvalue]
306
307
        llop1 = self.llop1
        funcptr = llop1.get_write_barrier_from_array_failing_case(
308
            self.WB_FUNCPTR)
309
310
311
        funcaddr = llmemory.cast_ptr_to_adr(funcptr)
        return cpu.cast_adr_to_int(funcaddr)    # this may return 0

312
313
314
    def has_write_barrier_from_array(self, cpu):
        return self.get_write_barrier_from_array_fn(cpu) != 0

315

316
class GcLLDescr_framework(GcLLDescription):
317
    DEBUG = False    # forced to True by x86/test/test_zrpy_gc.py
Armin Rigo's avatar
Armin Rigo committed
318
    kind = 'framework'
319
    round_up = True
Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
320
    layoutbuilder = None
321
    supports_guard_gc_type = True
322

Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
323
324
325
    def is_shadow_stack(self):
        return self.gcrootmap.is_shadow_stack

326
327
    def __init__(self, gcdescr, translator, rtyper, llop1=llop,
                 really_not_translated=False):
328
        GcLLDescription.__init__(self, gcdescr, translator, rtyper)
329
330
        self.translator = translator
        self.llop1 = llop1
331
332
333
334
335
336
337
        if really_not_translated:
            assert not self.translate_support_code  # but half does not work
            self._initialize_for_tests()
        else:
            assert self.translate_support_code,"required with the framework GC"
            self._check_valid_gc()
            self._make_layoutbuilder()
Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
338
            self._make_gcrootmap()
339
            self._setup_gcclass()
Armin Rigo's avatar
Armin Rigo committed
340
            self._setup_tid()
Armin Rigo's avatar
Armin Rigo committed
341
            self._setup_guard_is_object()
Armin Rigo's avatar
Armin Rigo committed
342
        self._setup_write_barrier()
Armin Rigo's avatar
Armin Rigo committed
343
        self._setup_str()
Armin Rigo's avatar
Armin Rigo committed
344
        self._make_functions(really_not_translated)
345

Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
346
347
348
349
350
351
352
353
354
355
356
    def _make_gcrootmap(self):
        # to find roots in the assembler, make a GcRootMap
        name = self.gcdescr.config.translation.gcrootfinder
        try:
            cls = globals()['GcRootMap_' + name]
        except KeyError:
            raise NotImplementedError("--gcrootfinder=%s not implemented"
                                      " with the JIT" % (name,))
        gcrootmap = cls(self.gcdescr)
        self.gcrootmap = gcrootmap

357
358
    def _initialize_for_tests(self):
        self.layoutbuilder = None
359
        self.fielddescr_tid = FieldDescr("test_tid",0,8,0)
360
        self.max_size_of_young_obj = 1000
Armin Rigo's avatar
Armin Rigo committed
361
        self.GCClass = None
Armin Rigo's avatar
Armin Rigo committed
362

363
    def _check_valid_gc(self):
364
        # we need the hybrid or minimark GC for rgc._make_sure_does_not_move()
365
        # to work.  'hybrid' could work but isn't tested with the JIT.
Armin Rigo's avatar
Armin Rigo committed
366
367
        if self.gcdescr.config.translation.gc not in ('minimark',
                                                      'incminimark'):
368
            raise NotImplementedError("--gc=%s not implemented with the JIT" %
369
                                      (self.gcdescr.config.translation.gc,))
370

371
    def _make_layoutbuilder(self):
372
373
        # make a TransformerLayoutBuilder and save it on the translator
        # where it can be fished and reused by the FrameworkGCTransformer
374
        from rpython.memory.gctransform import framework
Armin Rigo's avatar
Armin Rigo committed
375
        translator = self.translator
376
        self.layoutbuilder = framework.TransformerLayoutBuilder(translator)
Armin Rigo's avatar
Armin Rigo committed
377
        self.layoutbuilder.delay_encoding()
378
379
380
        if not hasattr(translator, '_jit2gc'):
            translator._jit2gc = {}
        translator._jit2gc['layoutbuilder'] = self.layoutbuilder
381

382
    def _setup_gcclass(self):
383
        from rpython.memory.gcheader import GCHeaderBuilder
384
        self.GCClass = self.layoutbuilder.GCClass
385
        self.moving_gc = self.GCClass.moving_gc
386
        self.malloc_zero_filled = self.GCClass.malloc_zero_filled
387
        self.HDRPTR = lltype.Ptr(self.GCClass.HDR)
388
        self.gcheaderbuilder = GCHeaderBuilder(self.HDRPTR.TO)
Armin Rigo's avatar
Armin Rigo committed
389
        self.max_size_of_young_obj = self.GCClass.JIT_max_size_of_young_obj()
390
        self.minimal_size_in_nursery=self.GCClass.JIT_minimal_size_in_nursery()
391

392
393
394
395
        # for the fast path of mallocs, the following must be true, at least
        assert self.GCClass.inline_simple_malloc
        assert self.GCClass.inline_simple_malloc_varsize

Armin Rigo's avatar
Armin Rigo committed
396
397
    def _setup_tid(self):
        self.fielddescr_tid = get_field_descr(self, self.GCClass.HDR, 'tid')
398
399
        frame_tid = self.layoutbuilder.get_type_id(jitframe.JITFRAME)
        self.translator._jit2gc['frame_tid'] = frame_tid
Armin Rigo's avatar
Armin Rigo committed
400
401

    def _setup_write_barrier(self):
402
        self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType(
403
            [llmemory.Address], lltype.Void))
404
        self.write_barrier_descr = WriteBarrierDescr(self)
Armin Rigo's avatar
Armin Rigo committed
405
406

    def _make_functions(self, really_not_translated):
407
        from rpython.memory.gctypelayout import check_typeid
Armin Rigo's avatar
Armin Rigo committed
408
        llop1 = self.llop1
Armin Rigo's avatar
Armin Rigo committed
409
410
411
        (self.standard_array_basesize, _, self.standard_array_length_ofs) = \
             symbolic.get_array_token(lltype.GcArray(lltype.Signed),
                                      not really_not_translated)
Armin Rigo's avatar
Armin Rigo committed
412

413
        def malloc_nursery_slowpath(size):
Armin Rigo's avatar
Armin Rigo committed
414
            """Allocate 'size' null bytes out of the nursery.
415
            Note that the fast path is typically inlined by the backend."""
David Schneider's avatar
David Schneider committed
416
            assert size >= self.minimal_size_in_nursery
Armin Rigo's avatar
Armin Rigo committed
417
418
            if self.DEBUG:
                self._random_usage_of_xmm_registers()
Armin Rigo's avatar
Armin Rigo committed
419
            type_id = rffi.cast(llgroup.HALFWORD, 0)    # missing here
420
            return llop1.do_malloc_fixedsize(llmemory.GCREF,
421
422
                                             type_id, size,
                                             False, False, False)
423

424
        self.generate_function('malloc_nursery', malloc_nursery_slowpath,
Armin Rigo's avatar
Armin Rigo committed
425
426
                               [lltype.Signed])

427
        def malloc_array(itemsize, tid, num_elem):
428
429
            """Allocate an array with a variable-size num_elem.
            Only works for standard arrays."""
David Schneider's avatar
David Schneider committed
430
            assert num_elem >= 0, 'num_elem should be >= 0'
431
            type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
Armin Rigo's avatar
Armin Rigo committed
432
            check_typeid(type_id)
433
434
            return llop1.do_malloc_varsize_clear(
                llmemory.GCREF,
Armin Rigo's avatar
Armin Rigo committed
435
436
                type_id, num_elem, self.standard_array_basesize, itemsize,
                self.standard_array_length_ofs)
Armin Rigo's avatar
Armin Rigo committed
437
438
439
        self.generate_function('malloc_array', malloc_array,
                               [lltype.Signed] * 3)

Armin Rigo's avatar
Armin Rigo committed
440
441
        def malloc_array_nonstandard(basesize, itemsize, lengthofs, tid,
                                     num_elem):
Armin Rigo's avatar
Armin Rigo committed
442
443
444
445
446
447
448
            """For the rare case of non-standard arrays, i.e. arrays where
            self.standard_array_{basesize,length_ofs} is wrong.  It can
            occur e.g. with arrays of floats on Win32."""
            type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
            check_typeid(type_id)
            return llop1.do_malloc_varsize_clear(
                llmemory.GCREF,
Armin Rigo's avatar
Armin Rigo committed
449
                type_id, num_elem, basesize, itemsize, lengthofs)
Armin Rigo's avatar
Armin Rigo committed
450
451
        self.generate_function('malloc_array_nonstandard',
                               malloc_array_nonstandard,
Armin Rigo's avatar
Armin Rigo committed
452
                               [lltype.Signed] * 5)
Armin Rigo's avatar
Armin Rigo committed
453

Armin Rigo's avatar
Armin Rigo committed
454
455
456
457
458
459
460
461
462
        str_type_id    = self.str_descr.tid
        str_basesize   = self.str_descr.basesize
        str_itemsize   = self.str_descr.itemsize
        str_ofs_length = self.str_descr.lendescr.offset
        unicode_type_id    = self.unicode_descr.tid
        unicode_basesize   = self.unicode_descr.basesize
        unicode_itemsize   = self.unicode_descr.itemsize
        unicode_ofs_length = self.unicode_descr.lendescr.offset

463
        def malloc_str(length):
464
            type_id = llop.extract_ushort(llgroup.HALFWORD, str_type_id)
465
            return llop1.do_malloc_varsize(
466
                llmemory.GCREF,
467
                type_id, length, str_basesize, str_itemsize,
Armin Rigo's avatar
Armin Rigo committed
468
                str_ofs_length)
469
470
471
        self.generate_function('malloc_str', malloc_str,
                               [lltype.Signed])

472
        def malloc_unicode(length):
473
            type_id = llop.extract_ushort(llgroup.HALFWORD, unicode_type_id)
474
            return llop1.do_malloc_varsize(
475
                llmemory.GCREF,
476
                type_id, length, unicode_basesize, unicode_itemsize,
Armin Rigo's avatar
Armin Rigo committed
477
                unicode_ofs_length)
478
479
480
        self.generate_function('malloc_unicode', malloc_unicode,
                               [lltype.Signed])

Armin Rigo's avatar
Armin Rigo committed
481
482
483
484
485
486
487
488
489
490
491
492
493
        # Never called as far as I can tell, but there for completeness:
        # allocate a fixed-size object, but not in the nursery, because
        # it is too big.
        def malloc_big_fixedsize(size, tid):
            if self.DEBUG:
                self._random_usage_of_xmm_registers()
            type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
            check_typeid(type_id)
            return llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
                                                   type_id, size,
                                                   False, False, False)
        self.generate_function('malloc_big_fixedsize', malloc_big_fixedsize,
                               [lltype.Signed] * 2)
494

Armin Rigo's avatar
Armin Rigo committed
495
    def _bh_malloc(self, sizedescr):
496
        from rpython.memory.gctypelayout import check_typeid
Armin Rigo's avatar
Armin Rigo committed
497
498
499
500
501
502
503
        llop1 = self.llop1
        type_id = llop.extract_ushort(llgroup.HALFWORD, sizedescr.tid)
        check_typeid(type_id)
        return llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
                                               type_id, sizedescr.size,
                                               False, False, False)

504
    def _bh_malloc_array(self, num_elem, arraydescr):
505
        from rpython.memory.gctypelayout import check_typeid
Armin Rigo's avatar
Armin Rigo committed
506
507
508
509
510
511
512
513
514
        llop1 = self.llop1
        type_id = llop.extract_ushort(llgroup.HALFWORD, arraydescr.tid)
        check_typeid(type_id)
        return llop1.do_malloc_varsize_clear(llmemory.GCREF,
                                             type_id, num_elem,
                                             arraydescr.basesize,
                                             arraydescr.itemsize,
                                             arraydescr.lendescr.offset)

Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
515

Armin Rigo's avatar
Armin Rigo committed
516
517
518
519
520
521
522
523
524
525
526
    class ForTestOnly:
        pass
    for_test_only = ForTestOnly()
    for_test_only.x = 1.23

    def _random_usage_of_xmm_registers(self):
        x0 = self.for_test_only.x
        x1 = x0 * 0.1
        x2 = x0 * 0.2
        x3 = x0 * 0.3
        self.for_test_only.x = x0 + x1 + x2 + x3
Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
527
528
529
530
531
532
533
534
535

    def get_nursery_free_addr(self):
        nurs_addr = llop.gc_adr_of_nursery_free(llmemory.Address)
        return rffi.cast(lltype.Signed, nurs_addr)

    def get_nursery_top_addr(self):
        nurs_top_addr = llop.gc_adr_of_nursery_top(llmemory.Address)
        return rffi.cast(lltype.Signed, nurs_top_addr)

536
    def initialize(self):
Maciej Fijalkowski's avatar
Maciej Fijalkowski committed
537
538
        pass
        #self.gcrootmap.initialize()
539
540

    def init_size_descr(self, S, descr):
541
542
        if not isinstance(S, lltype.GcStruct):
            return
543
544
545
        if self.layoutbuilder is not None:
            type_id = self.layoutbuilder.get_type_id(S)
            descr.tid = llop.combine_ushort(lltype.Signed, type_id, 0)
546
547

    def init_array_descr(self, A, descr):
Maciej Fijalkowski's avatar
fixes    
Maciej Fijalkowski committed
548
        if not isinstance(A, (lltype.GcArray, lltype.GcStruct)):
549
            return
550
551
552
        if self.layoutbuilder is not None:
            type_id = self.layoutbuilder.get_type_id(A)
            descr.tid = llop.combine_ushort(lltype.Signed, type_id, 0)
553

Armin Rigo's avatar
Armin Rigo committed
554
555
    def can_use_nursery_malloc(self, size):
        return size < self.max_size_of_young_obj
556

557
558
559
    def has_write_barrier_class(self):
        return WriteBarrierDescr

560
    def get_malloc_slowpath_addr(self):
Armin Rigo's avatar
Armin Rigo committed
561
        return self.get_malloc_fn_addr('malloc_nursery')
562

563
564
    def get_malloc_slowpath_array_addr(self):
        return self.get_malloc_fn_addr('malloc_array')
565

Armin Rigo's avatar
Armin Rigo committed
566
567
568
569
570
571
    def get_typeid_from_classptr_if_gcremovetypeptr(self, classptr):
        """Returns the typeid corresponding from a vtable pointer 'classptr'.
        This function only works if cpu.vtable_offset is None, i.e. in
        a translation with --gcremovetypeptr.
         """
        from rpython.memory.gctypelayout import GCData
572
        assert self.gcdescr.config.translation.gcremovetypeptr
Armin Rigo's avatar
Armin Rigo committed
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590

        # hard-coded assumption: to go from an object to its class
        # we would use the following algorithm:
        #   - read the typeid from mem(locs[0]), i.e. at offset 0;
        #     this is a complete word (N=4 bytes on 32-bit, N=8 on
        #     64-bits)
        #   - keep the lower half of what is read there (i.e.
        #     truncate to an unsigned 'N / 2' bytes value)
        #   - multiply by 4 (on 32-bits only) and use it as an
        #     offset in type_info_group
        #   - add 16/32 bytes, to go past the TYPE_INFO structure
        # here, we have to go back from 'classptr' back to the typeid,
        # so we do (part of) these computations in reverse.

        sizeof_ti = rffi.sizeof(GCData.TYPE_INFO)
        type_info_group = llop.gc_get_type_info_group(llmemory.Address)
        type_info_group = rffi.cast(lltype.Signed, type_info_group)
        expected_typeid = classptr - sizeof_ti - type_info_group
591
        if WORD == 4:
Armin Rigo's avatar
Armin Rigo committed
592
593
594
            expected_typeid >>= 2
        return expected_typeid

595
596
597
598
599
600
601
602
603
604
605
    def get_translated_info_for_typeinfo(self):
        from rpython.memory.gctypelayout import GCData
        type_info_group = llop.gc_get_type_info_group(llmemory.Address)
        type_info_group = rffi.cast(lltype.Signed, type_info_group)
        if WORD == 4:
            shift_by = 2
        elif WORD == 8:
            shift_by = 0
        sizeof_ti = rffi.sizeof(GCData.TYPE_INFO)
        return (type_info_group, shift_by, sizeof_ti)

Armin Rigo's avatar
Armin Rigo committed
606
607
    def _setup_guard_is_object(self):
        from rpython.memory.gctypelayout import GCData, T_IS_RPYTHON_INSTANCE
608
609
610
611
612
613
614
615
616
617
618
619
620
        import struct
        infobits_offset, _ = symbolic.get_field_token(GCData.TYPE_INFO,
                                                      'infobits', True)
        # compute the offset to the actual *byte*, and the byte mask
        mask = struct.pack("l", T_IS_RPYTHON_INSTANCE)
        assert mask.count('\x00') == len(mask) - 1
        infobits_offset_plus = 0
        while mask.startswith('\x00'):
            infobits_offset_plus += 1
            mask = mask[1:]
        self._infobits_offset = infobits_offset
        self._infobits_offset_plus = infobits_offset_plus
        self._T_IS_RPYTHON_INSTANCE_BYTE = ord(mask[0])
Armin Rigo's avatar
Armin Rigo committed
621
622
623

    def get_translated_info_for_guard_is_object(self):
        infobits_offset = rffi.cast(lltype.Signed, self._infobits_offset)
624
625
        infobits_offset += self._infobits_offset_plus
        return (infobits_offset, self._T_IS_RPYTHON_INSTANCE_BYTE)
Armin Rigo's avatar
Armin Rigo committed
626

627
    def get_actual_typeid(self, gcptr):
628
629
        # Read the whole GC header word.  Return the typeid from the
        # lower half-word.
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
        hdr = rffi.cast(self.HDRPTR, gcptr)
        type_id = llop.extract_ushort(llgroup.HALFWORD, hdr.tid)
        return llop.combine_ushort(lltype.Signed, type_id, 0)

    def check_is_object(self, gcptr):
        # read the typeid, fetch one byte of the field 'infobits' from
        # the big typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'.
        typeid = self.get_actual_typeid(gcptr)
        #
        base_type_info, shift_by, sizeof_ti = (
            self.get_translated_info_for_typeinfo())
        infobits_offset, IS_OBJECT_FLAG = (
            self.get_translated_info_for_guard_is_object())
        p = base_type_info + (typeid << shift_by) + infobits_offset
        p = rffi.cast(rffi.CCHARP, p)
        return (ord(p[0]) & IS_OBJECT_FLAG) != 0
Armin Rigo's avatar
Armin Rigo committed
646

647
648
649
650
651
652
653
    def make_gcref_tracer(self, array_base_addr, gcrefs):
        from rpython.jit.backend.llsupport import gcreftracer
        return gcreftracer.make_framework_tracer(array_base_addr, gcrefs)

    def clear_gcref_tracer(self, tracer):
        tracer.array_length = 0

654

John Zhang's avatar
John Zhang committed
655
class GcLLDescr_mu(GcLLDescr_framework):
656
657
658
659
660
661
662
663
664
665
    def __init__(self, gcdescr, translator, rtyper, llop1=llop,
                 really_not_translated=False):
        from rpython.translator.mu.ll2mu import LL2MuMapper
        GcLLDescr_framework.__init__(self, gcdescr, translator, rtyper, llop1, really_not_translated)
        self.ll2mu = LL2MuMapper(rtyper)

    def init_size_descr(self, S, descr):
        MuT = self.ll2mu.map_type(S)
        self.ll2mu.resolve_ptr_types()
        descr.mu_typedescr_str = self.ll2mu.get_typedescr_str(MuT)
666
667
# ____________________________________________________________

668
def get_ll_description(gcdescr, translator=None, rtyper=None):
669
    # translator is None if translate_support_code is False.
670
671
672
673
674
    if gcdescr is not None:
        name = gcdescr.config.translation.gctransformer
    else:
        name = "boehm"
    try:
675
        cls = globals()['GcLLDescr_' + name]
676
677
    except KeyError:
        raise NotImplementedError("GC transformer %r not supported by "
678
                                  "the JIT backend" % (name,))
679
    return cls(gcdescr, translator, rtyper)