/** * Exception allocation, cloning, and release compiler support routines. * * Copyright: Copyright (c) 2017 by D Language Foundation * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright * Source: $(DRUNTIMESRC rt/_ehalloc.d) */ module rt.ehalloc; //debug = PRINTF; debug(PRINTF) { import core.stdc.stdio; } /********************************************** * Allocate an exception of type `ci` from the exception pool. * It has the same interface as `rt.lifetime._d_newclass()`. * The class type must be Throwable or derived from it, * and cannot be a COM or C++ class. The compiler must enforce * this. * Returns: * default initialized instance of the type */ extern (C) Throwable _d_newThrowable(const TypeInfo_Class ci) { debug(PRINTF) printf("_d_newThrowable(ci = %p, %s)\n", ci, cast(char *)ci.name); assert(!(ci.m_flags & TypeInfo_Class.ClassFlags.isCOMclass)); assert(!(ci.m_flags & TypeInfo_Class.ClassFlags.isCPPclass)); import core.stdc.stdlib : malloc; auto init = ci.initializer; void* p = malloc(init.length); if (!p) { import core.exception : onOutOfMemoryError; onOutOfMemoryError(); } debug(PRINTF) printf(" p = %p\n", p); // initialize it p[0 .. init.length] = init[]; if (!(ci.m_flags & TypeInfo_Class.ClassFlags.noPointers)) { // Inform the GC about the pointers in the object instance import core.memory : GC; GC.addRange(p, init.length, ci); } debug(PRINTF) printf("initialization done\n"); Throwable t = cast(Throwable)p; t.refcount() = 1; return t; } /******************************************** * Delete exception instance `t` from the exception pool. * Must have been allocated with `_d_newThrowable()`. * This is meant to be called at the close of a catch block. * It's nothrow because otherwise any function with a catch block could * not be nothrow. * Input: * t = Throwable */ nothrow extern (C) void _d_delThrowable(Throwable t) { if (t) { debug(PRINTF) printf("_d_delThrowable(%p)\n", t); /* If allocated by the GC, don't free it. * Let the GC handle it. * Supporting this is necessary while transitioning * to this new scheme for allocating exceptions. */ auto refcount = t.refcount(); if (refcount == 0) return; // it was allocated by the GC if (refcount == 1) assert(0); // no zombie objects t.refcount() = --refcount; if (refcount > 1) return; TypeInfo_Class **pc = cast(TypeInfo_Class **)t; if (*pc) { TypeInfo_Class ci = **pc; if (!(ci.m_flags & TypeInfo_Class.ClassFlags.noPointers)) { // Inform the GC about the pointers in the object instance import core.memory : GC; GC.removeRange(cast(void*) t); } } try { import rt.lifetime : rt_finalize; rt_finalize(cast(void*) t); } catch (Throwable t) { assert(0); // should never happen since Throwable.~this() is nothrow } import core.stdc.stdlib : free; debug(PRINTF) printf("free(%p)\n", t); free(cast(void*) t); } }