1238106Sdes/** 2238106Sdes * Exception allocation, cloning, and release compiler support routines. 3238106Sdes * 4238106Sdes * Copyright: Copyright (c) 2017 by D Language Foundation 5238106Sdes * License: Distributed under the 6238106Sdes * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). 7238106Sdes * (See accompanying file LICENSE) 8238106Sdes * Authors: Walter Bright 9238106Sdes * Source: $(DRUNTIMESRC rt/_ehalloc.d) 10238106Sdes */ 11238106Sdes 12238106Sdesmodule rt.ehalloc; 13238106Sdes 14238106Sdes//debug = PRINTF; 15238106Sdes 16238106Sdesdebug(PRINTF) 17238106Sdes{ 18238106Sdes import core.stdc.stdio; 19238106Sdes} 20238106Sdes 21238106Sdes/********************************************** 22238106Sdes * Allocate an exception of type `ci` from the exception pool. 23238106Sdes * It has the same interface as `rt.lifetime._d_newclass()`. 24266114Sdes * The class type must be Throwable or derived from it, 25266114Sdes * and cannot be a COM or C++ class. The compiler must enforce 26266114Sdes * this. 27266114Sdes * Returns: 28266114Sdes * default initialized instance of the type 29266114Sdes */ 30266114Sdes 31266114Sdesextern (C) Throwable _d_newThrowable(const TypeInfo_Class ci) 32266114Sdes{ 33266114Sdes debug(PRINTF) printf("_d_newThrowable(ci = %p, %s)\n", ci, cast(char *)ci.name); 34238106Sdes 35238106Sdes assert(!(ci.m_flags & TypeInfo_Class.ClassFlags.isCOMclass)); 36238106Sdes assert(!(ci.m_flags & TypeInfo_Class.ClassFlags.isCPPclass)); 37238106Sdes 38238106Sdes import core.stdc.stdlib : malloc; 39238106Sdes auto init = ci.initializer; 40238106Sdes void* p = malloc(init.length); 41238106Sdes if (!p) 42238106Sdes { 43266114Sdes import core.exception : onOutOfMemoryError; 44266114Sdes onOutOfMemoryError(); 45266114Sdes } 46266114Sdes 47266114Sdes debug(PRINTF) printf(" p = %p\n", p); 48238106Sdes 49238106Sdes // initialize it 50238106Sdes p[0 .. init.length] = init[]; 51238106Sdes 52238106Sdes if (!(ci.m_flags & TypeInfo_Class.ClassFlags.noPointers)) 53287917Sdes { 54238106Sdes // Inform the GC about the pointers in the object instance 55238106Sdes import core.memory : GC; 56238106Sdes 57238106Sdes GC.addRange(p, init.length, ci); 58238106Sdes } 59287917Sdes 60276605Sdes debug(PRINTF) printf("initialization done\n"); 61276605Sdes Throwable t = cast(Throwable)p; 62276605Sdes t.refcount() = 1; 63238106Sdes return t; 64238106Sdes} 65238106Sdes 66238106Sdes 67238106Sdes/******************************************** 68238106Sdes * Delete exception instance `t` from the exception pool. 69238106Sdes * Must have been allocated with `_d_newThrowable()`. 70238106Sdes * This is meant to be called at the close of a catch block. 71238106Sdes * It's nothrow because otherwise any function with a catch block could 72238106Sdes * not be nothrow. 73238106Sdes * Input: 74238106Sdes * t = Throwable 75238106Sdes */ 76238106Sdes 77238106Sdesnothrow extern (C) void _d_delThrowable(Throwable t) 78238106Sdes{ 79238106Sdes if (t) 80238106Sdes { 81238106Sdes debug(PRINTF) printf("_d_delThrowable(%p)\n", t); 82238106Sdes 83238106Sdes /* If allocated by the GC, don't free it. 84238106Sdes * Let the GC handle it. 85238106Sdes * Supporting this is necessary while transitioning 86238106Sdes * to this new scheme for allocating exceptions. 87238106Sdes */ 88238106Sdes auto refcount = t.refcount(); 89238106Sdes if (refcount == 0) 90238106Sdes return; // it was allocated by the GC 91238106Sdes 92238106Sdes if (refcount == 1) 93238106Sdes assert(0); // no zombie objects 94238106Sdes 95238106Sdes t.refcount() = --refcount; 96238106Sdes if (refcount > 1) 97238106Sdes return; 98238106Sdes 99238106Sdes TypeInfo_Class **pc = cast(TypeInfo_Class **)t; 100238106Sdes if (*pc) 101238106Sdes { 102238106Sdes TypeInfo_Class ci = **pc; 103238106Sdes 104238106Sdes if (!(ci.m_flags & TypeInfo_Class.ClassFlags.noPointers)) 105238106Sdes { 106238106Sdes // Inform the GC about the pointers in the object instance 107238106Sdes import core.memory : GC; 108238106Sdes GC.removeRange(cast(void*) t); 109238106Sdes } 110238106Sdes } 111238106Sdes 112238106Sdes try 113238106Sdes { 114238106Sdes import rt.lifetime : rt_finalize; 115238106Sdes rt_finalize(cast(void*) t); 116238106Sdes } 117238106Sdes catch (Throwable t) 118238106Sdes { 119238106Sdes assert(0); // should never happen since Throwable.~this() is nothrow 120238106Sdes } 121238106Sdes import core.stdc.stdlib : free; 122238106Sdes debug(PRINTF) printf("free(%p)\n", t); 123238106Sdes free(cast(void*) t); 124238106Sdes } 125238106Sdes} 126238106Sdes