1/** 2 * Exception allocation, cloning, and release compiler support routines. 3 * 4 * Copyright: Copyright (c) 2017 by D Language Foundation 5 * License: Distributed under the 6 * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). 7 * (See accompanying file LICENSE) 8 * Authors: Walter Bright 9 * Source: $(DRUNTIMESRC rt/_ehalloc.d) 10 */ 11 12module rt.ehalloc; 13 14//debug = PRINTF; 15 16debug(PRINTF) 17{ 18 import core.stdc.stdio; 19} 20 21/********************************************** 22 * Allocate an exception of type `ci` from the exception pool. 23 * It has the same interface as `rt.lifetime._d_newclass()`. 24 * The class type must be Throwable or derived from it, 25 * and cannot be a COM or C++ class. The compiler must enforce 26 * this. 27 * Returns: 28 * default initialized instance of the type 29 */ 30 31extern (C) Throwable _d_newThrowable(const TypeInfo_Class ci) 32{ 33 debug(PRINTF) printf("_d_newThrowable(ci = %p, %s)\n", ci, cast(char *)ci.name); 34 35 assert(!(ci.m_flags & TypeInfo_Class.ClassFlags.isCOMclass)); 36 assert(!(ci.m_flags & TypeInfo_Class.ClassFlags.isCPPclass)); 37 38 import core.stdc.stdlib : malloc; 39 auto init = ci.initializer; 40 void* p = malloc(init.length); 41 if (!p) 42 { 43 import core.exception : onOutOfMemoryError; 44 onOutOfMemoryError(); 45 } 46 47 debug(PRINTF) printf(" p = %p\n", p); 48 49 // initialize it 50 p[0 .. init.length] = init[]; 51 52 if (!(ci.m_flags & TypeInfo_Class.ClassFlags.noPointers)) 53 { 54 // Inform the GC about the pointers in the object instance 55 import core.memory : GC; 56 57 GC.addRange(p, init.length, ci); 58 } 59 60 debug(PRINTF) printf("initialization done\n"); 61 Throwable t = cast(Throwable)p; 62 t.refcount() = 1; 63 return t; 64} 65 66 67/******************************************** 68 * Delete exception instance `t` from the exception pool. 69 * Must have been allocated with `_d_newThrowable()`. 70 * This is meant to be called at the close of a catch block. 71 * It's nothrow because otherwise any function with a catch block could 72 * not be nothrow. 73 * Input: 74 * t = Throwable 75 */ 76 77nothrow extern (C) void _d_delThrowable(Throwable t) 78{ 79 if (t) 80 { 81 debug(PRINTF) printf("_d_delThrowable(%p)\n", t); 82 83 /* If allocated by the GC, don't free it. 84 * Let the GC handle it. 85 * Supporting this is necessary while transitioning 86 * to this new scheme for allocating exceptions. 87 */ 88 auto refcount = t.refcount(); 89 if (refcount == 0) 90 return; // it was allocated by the GC 91 92 if (refcount == 1) 93 assert(0); // no zombie objects 94 95 t.refcount() = --refcount; 96 if (refcount > 1) 97 return; 98 99 TypeInfo_Class **pc = cast(TypeInfo_Class **)t; 100 if (*pc) 101 { 102 TypeInfo_Class ci = **pc; 103 104 if (!(ci.m_flags & TypeInfo_Class.ClassFlags.noPointers)) 105 { 106 // Inform the GC about the pointers in the object instance 107 import core.memory : GC; 108 GC.removeRange(cast(void*) t); 109 } 110 } 111 112 try 113 { 114 import rt.lifetime : rt_finalize; 115 rt_finalize(cast(void*) t); 116 } 117 catch (Throwable t) 118 { 119 assert(0); // should never happen since Throwable.~this() is nothrow 120 } 121 import core.stdc.stdlib : free; 122 debug(PRINTF) printf("free(%p)\n", t); 123 free(cast(void*) t); 124 } 125} 126