Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mak/SRCS
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ SRCS=\
src\rt\deh_win64_posix.d \
src\rt\dmain2.d \
src\rt\dwarfeh.d \
src\rt\ehalloc.d \
src\rt\invariant.d \
src\rt\lifetime.d \
src\rt\llmath.d \
Expand Down
4 changes: 4 additions & 0 deletions src/core/thread.d
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ version( Windows )

void append( Throwable t )
{
if (t.refcount())
++t.refcount();
if( obj.m_unhandled is null )
obj.m_unhandled = t;
else
Expand Down Expand Up @@ -377,6 +379,8 @@ else version( Posix )

void append( Throwable t )
{
if (t.refcount())
++t.refcount();
if( obj.m_unhandled is null )
obj.m_unhandled = t;
else
Expand Down
20 changes: 20 additions & 0 deletions src/object.d
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ private
extern (C) void rt_finalize(void *data, bool det=true);
}

public @trusted @nogc nothrow pure extern (C) void _d_delThrowable(scope Throwable);

// NOTE: For some reason, this declaration method doesn't work
// in this particular file (and this file only). It must
// be a DMD thing.
Expand Down Expand Up @@ -1704,6 +1706,18 @@ class Throwable : Object
*/
Throwable next;

private uint _refcount; // 0 : allocated by GC
// 1 : allocated by _d_newThrowable()
// 2.. : reference count + 1

/**
* Returns:
* mutable reference to the reference count, which is
* 0 - allocated by the GC, 1 - allocated by _d_newThrowable(),
* and >=2 which is the reference count + 1
*/
@system @nogc final pure nothrow ref uint refcount() return scope { return _refcount; }

@nogc @safe pure nothrow this(string msg, Throwable next = null)
{
this.msg = msg;
Expand All @@ -1719,6 +1733,12 @@ class Throwable : Object
//this.info = _d_traceContext();
}

@trusted nothrow ~this()
{
if (next && next._refcount)
_d_delThrowable(next);
}

/**
* Overrides $(D Object.toString) and returns the error message.
* Internally this forwards to the $(D toString) overload that
Expand Down
20 changes: 16 additions & 4 deletions src/rt/deh_win32.d
Original file line number Diff line number Diff line change
Expand Up @@ -611,21 +611,33 @@ int _d_exception_filter(EXCEPTION_POINTERS *eptrs,
}

/***********************************
* Throw a D object.
* Throw a D instance of Throwable.
*/

private void throwImpl(Object h)
private void throwImpl(Throwable h)
{
// @@@ TODO @@@ Signature should change: h will always be a Throwable.
//printf("_d_throw(h = %p, &h = %p)\n", h, &h);
//printf("\tvptr = %p\n", *(void **)h);

/* Increment reference count if `h` is a refcounted Throwable
*/
auto refcount = h.refcount();
if (refcount) // non-zero means it's refcounted
h.refcount() = refcount + 1;

_d_createTrace(h, null);
RaiseException(STATUS_DIGITAL_MARS_D_EXCEPTION,
EXCEPTION_NONCONTINUABLE,
1, cast(void *)&h);
}

extern(C) void _d_throwc(Object h)
/***************************************
* The compiler converts:
* throw h;
* into a call to:
* _d_throwc(h);
*/
extern(C) void _d_throwc(Throwable h)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your also forgetting to update dwarfeh?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to check it in. Done.

{
// set up a stack frame for trace unwinding
version (AsmX86)
Expand Down
8 changes: 7 additions & 1 deletion src/rt/deh_win64_posix.d
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ size_t __eh_find_caller(size_t regbp, size_t *pretaddr)
* Throw a D object.
*/

extern (C) void _d_throwc(Object h)
extern (C) void _d_throwc(Throwable h)
{
size_t regebp;

Expand All @@ -242,6 +242,12 @@ extern (C) void _d_throwc(Object h)
else
static assert(0);

/* Increment reference count if `h` is a refcounted Throwable
*/
auto refcount = h.refcount();
if (refcount) // non-zero means it's refcounted
h.refcount() = refcount + 1;

_d_createTrace(h, null);

//static uint abc;
Expand Down
6 changes: 6 additions & 0 deletions src/rt/dwarfeh.d
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ extern(C) void _d_throwdwarf(Throwable o)
eh.push(); // add to thrown exception stack
//printf("_d_throwdwarf: eh = %p, eh.next = %p\n", eh, eh.next);

/* Increment reference count if `o` is a refcounted Throwable
*/
auto refcount = o.refcount();
if (refcount) // non-zero means it's refcounted
o.refcount() = refcount + 1;

/* Called by unwinder when exception object needs destruction by other than our code.
*/
extern (C) static void exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* eo)
Expand Down
125 changes: 125 additions & 0 deletions src/rt/ehalloc.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/**
* 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 src/rt/_dwarfeh.d)
*/

module rt.ehalloc;

//debug = PRINTF;

debug(PRINTF)
{
import core.stdc.stdio;
}

/**********************************************
* Allocate an exception of type `ci` from the exception pool.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from the exception pool - There is no pool in this implementation, isn't there?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. But there could be - without changing the interface.

* 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;
void* p = malloc(ci.initializer.length);
if (!p)
{
import core.exception : onOutOfMemoryError;
onOutOfMemoryError();
}

debug(PRINTF) printf(" p = %p\n", p);

// initialize it
p[0 .. ci.initializer.length] = ci.initializer[];

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, ci.initializer.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);
}
}