Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Mark some GC functions pure and/or nothrow. #198

Merged
merged 1 commit into from almost 2 years ago

4 participants

Alex Rønne Petersen Steven Schveighoffer David Nadlinger Denis Shelomovskij
Alex Rønne Petersen
Collaborator

A few things worth noting:

  • These functions actually can be nothrow, because the only exceptions they can throw are Errors.
  • Yes, marking the functions with these modifiers means future implementations have to follow them. I don't think this is a problem, however, and the current situation (no modifiers at all) is very annoying.
  • I haven't marked the actual functions inside the GC with these modifiers. I didn't feel that cascading them all the way to the GC implementation was necessary; the GC is a low-level component of the runtime and thus deserves as much freedom as it can get. That said, I did verify that none of the functions marked nothrow can throw.
  • I'm not sure if the application of pure is entirely correct. I think it makes sense in terms of weak purity, but please correct me if I'm wrong.
Alex Rønne Petersen
Collaborator
alexrp commented May 11, 2012

Ping?

Alex Rønne Petersen
Collaborator
alexrp commented May 22, 2012

I've been thinking about the application of pure to some of the functions here. While the getAttr, clrAttr, and setAttr functions (and the likes) do rely on the GC's global state, I think it could be argued that this state is an implicit parameter to all functions in the core.memory module. Anyone who calls these functions will know that they rely on fetching information from the garbage collector instance. As such, marking those functions pure is fine IMHO, since their purity only depends on two inputs: The GC itself and the memory address.

Besides, there's no good alternative to doing it this way, and this module is currently not very usable in pure/nothrow code. We need to fix that silly situation.

Thoughts?

Steven Schveighoffer
Collaborator

I think most of these can be marked pure as well.

As long as it's weak purity, it can be marked pure. What we don't want is someone for instance doing:

void *p1 = gc_malloc(10);
void *p2 = gc_malloc(10);

and having the compiler rewrite as:

void *p2 = p1;

Given that most of these return mutable data, they should be weakly pure, right?

Alex Rønne Petersen
Collaborator
alexrp commented May 22, 2012

Makes sense. But this brings up the question: Should free be pure? I find that one tough, since it may seem weakly pure, but it can have all sorts of arbitrary side-effects. For example, a GC implementation might choose to run the finalizer when the data is freed, or whatever.

Steven Schveighoffer
Collaborator
Alex Rønne Petersen
Collaborator
alexrp commented May 22, 2012

Speaking of which, we probably should fix the docs: http://dlang.org/phobos/core_memory.html#free

But I'm honestly not sure what's the preferred construct these days.

Anyway, as long as free is guaranteed to not call arbitrary functions with side-effects, then it's fine I guess.

What about the enable, disable, minimize, and collect functions? I think making the latter two pure would be very, very wrong, since they on the other hand can result in finalizers being enqueued.

Steven Schveighoffer
Collaborator
Alex Rønne Petersen
Collaborator
alexrp commented May 22, 2012

a) running a collect cycle or not running one shouldn't alter the logical execution of the program. So if a call to collect is optimized out, no big deal.

I think this is a big deal: It is very common to force collections in order to reduce memory use and force finalizers to be run ASAP. We need to account for this case, and under no circumstances optimize it out. Also, keep in mind that finalizers can run arbitrary code, so if a collection causes finalizers to be fired off, this operation is by no means pure. Ideally, finalizers should be programmed to not access state outside of the object they belong to, but making this assumption is not pragmatic IMHO (just because finalization order is undefined doesn't mean accessing global state is useless - think a simple scenario like atomically decreasing a global counter).

b) the collection cycle runs in its own context, it's almost like it's on its own thread, but it's "borrowing" the current running thread's stack for execution. It really doesn't affect the current-running thread's data whatsoever (except for things the pure function isn't legally allowed to see, such as global data).

That depends. In order to implement weak references, I've used a very dirty trick where I store a GC pointer into a NO_SCAN area. This means that a collection actually can have side-effects in that it'll render weak references collected. You could argue that this is how weak references are supposed to work, but it's a side-effect no less.

As far as enable/disable, I think they should not be pure, because you don't want to optimize out a call to one of those! However, my gut tells me we should be able to build a way to call these in pairs inside a pure scope.

Yeah, it could probably be useful for certain optimized algorithms. Unfortunately, I can't think of a good way to do this.

Steven Schveighoffer
Collaborator
Steven Schveighoffer
Collaborator

Speaking of which, we probably should fix the docs: http://dlang.org/phobos/core_memory.html#free

From that page:

The block will not be finalized regardless of whether the FINALIZE attribute is set.

Seems correct to me...

Alex Rønne Petersen
Collaborator
alexrp commented May 22, 2012

I was getting at it recommending using delete.

Steven Schveighoffer
Collaborator
Alex Rønne Petersen
Collaborator
alexrp commented May 22, 2012

Well, anyway, you make a good point: We already allow pure functions to cause GC allocations, so this should be no different. But I have to admit I don't like it... it seems... dirty.

Well, I'll make the changes and rebase.

Steven Schveighoffer
Collaborator

Well, don't mark gc_enable and gc_disable pure, because they have no parameters/return value, they will be interpreted as strong-pure and might be optimized out. We need to find a way to make these weak-pure. I'll post a NG message querying on how to do it.

I guess same thing for gc_collect and gc_minimize.

Alex Rønne Petersen
Collaborator
alexrp commented May 23, 2012

Rebased. I'm not sure what to do about the range management functions, though. Do we want those to be pure?

Steven Schveighoffer
Collaborator

I'm not sure what to do about the range management functions, though. Do we want those to be pure?

I think these should be pure, but we can hold off for now. Adding ranges and roots is done when you allocate outside of the GC, and I don't think any of those functions (i.e. C's malloc and free) are marked pure yet.

Alex Rønne Petersen
Collaborator
alexrp commented May 23, 2012

It will have to be eventually, otherwise writing a pure allocator interface is going to suck...

Steven Schveighoffer
Collaborator

Reviewing your new version:

gc_setAttr, gc_getAttr, gc_clrAttr cannot be marked pure as-is, because they could be interpreted as strong-pure if called with immutable pointer. I'm pretty sure the current compiler does not optimize this, but we don't want to leave a bomb there for when it does optimize it.

It would make sense, actually, for those to be marked without 'in' (since a GC implementation might actually store the bits inside the block), but that would likely break some existing code.

gc_reserve does not have any mutable reference parameters or return values, so it will be interpreted as strong pure. It cannot be marked pure without a solution as we are discussing in the NG, but I think this is no big loss for now.

Continuing review...

Steven Schveighoffer
Collaborator

OK, so other than those, I think it looks good.

Alex Rønne Petersen
Collaborator
alexrp commented May 23, 2012

It would make sense, actually, for those to be marked without 'in' (since a GC implementation might actually store the bits inside the block), but that would likely break some existing code.

Then we should do that breakage sooner rather than later. I agree that these pointers really should not be marked with 'in' at all.

gc_reserve does not have any mutable reference parameters or return values, so it will be interpreted as strong pure. It cannot be marked pure without a solution as we are discussing in the NG, but I think this is no big loss for now.

I think for both gc_reserve and the attribute functions, we can just mark them pure for now and and add a TODO comment as a reminder that it should be fixed when we get proper weak purity (or whatever we want to call it).

Alex Rønne Petersen
Collaborator
alexrp commented May 25, 2012

Is this good to go?

Steven Schveighoffer
Collaborator

gc_reserve will be marked strong pure today. I think we can't make it pure, or it will not work properly.

The attribute functions I think should not be marked pure, but add a TODO: these should be pure when forced weak purity is possible at the top of the function list.

Alex Rønne Petersen
Collaborator
alexrp commented May 25, 2012

Why can't the attribute ones be pure? We just make the arguments not 'in' (as they really should be) and they will be weakly pure by definition.

Steven Schveighoffer
Collaborator

Because it would break code. The bar has to be set very high to be break existing code, and there just isn't enough benefit, seeing as how the adverse behavior won't happen without an improved optimizer in the compiler.

We have two choices:

  1. mark them as pure and leave in specified on the void*. This should work today, as I don't think the compiler will optimize out any calls based on this. Then "remember" to fix it if the compiler does start optimizing.
  2. Do not mark them as pure, and change it properly when it is possible to mark something as explicitly weak pure.

My vote is for option 2, because the chances we remember some time in the future to come back and fix it for option 1 is pretty slim.

What is the fallout if we use option 2? That is, if we can't mark those functions pure, what other functions now cannot be marked pure?

Alex Rønne Petersen
Collaborator
alexrp commented May 25, 2012

There is the fallout that writing pure allocators against the GC interface would basically be impossible (in particular, I suspect that setting NO_SCAN will be very common).

Steven Schveighoffer
Collaborator
Alex Rønne Petersen
Collaborator
alexrp commented May 25, 2012

I really wish more people would weigh in here, but they seem busier arguing about the language's purity design than giving input here. ;)

Create setAttrPure which does exactly the same thing, but just doesn't mark the parameter as in (and of course, is marked pure). When we can force weak purity, we can replace it with an alias.

Can't we simply overload it? Keep in mind, it's a D linkage function, not C. So, we overload it and deprecate the old overload?

Steven Schveighoffer
Collaborator
Alex Rønne Petersen
Collaborator
alexrp commented May 25, 2012

gc_getAttr is a completely internal function. We just change it to accept void*. Then we make an extra set of overloads inside the GC struct, and, in the ones that take an in void*, we just use a cast hack (this isn't problematic because we're dealing with const, not immutable).

Steven Schveighoffer
Collaborator
David Nadlinger
Collaborator

@schveiguy: Cue Walter complaining that his private DLL tests don't work any longer… ;)

Alex Rønne Petersen
Collaborator
alexrp commented May 25, 2012

if you are dealing with const you are dealing with possibly immutable.

I posted a long rant on the NG on why this really doesn't matter in real world compilers: http://forum.dlang.org/thread/jooo4k$shb$2@digitalmars.com?page=4#post-joq5hk:24bit:241:40digitalmars.com

But we can make pure versions if you prefer.

Steven Schveighoffer
Collaborator

Cue Walter complaining that his private DLL tests don't work any longer… ;)

ooooh good point! @alexrp any changes we make to the private functions have to be made to the gcstub directory as well.

Steven Schveighoffer
Collaborator

if you are dealing with const you are dealing with possibly immutable.

I posted a long rant on the NG on why this is really doesn't matter in real world compilers

No, that's not what I'm talking about. But in any case, I think actually, we are easily able to cast away const for the prototype because the actual function is const. So here's now what I think we can do:

gc_getAttr(in void *) -> gc_getAttr(void *) pure
GC.getAttr(in void *) -> leave as is (but insert a cast to void * for passing to gc_getAttr)
add GC.getAttr(void *) pure

Then when weakpure is markable, fix things back, we won't need to deprecate anything.

Alex Rønne Petersen
Collaborator
alexrp commented June 01, 2012

@schveiguy I've rebased with the changes we discussed, and have added FIXME notes that we should attend to once weak purity can be properly marked. Can you please review?

Steven Schveighoffer
Collaborator

addrOf can be pure outright, it returns a mutable void * (though this might not be the best idea, maybe it should be fixed to return const(void)* )

Don't forget to update gcstub!

Alex Rønne Petersen
Collaborator
alexrp commented June 01, 2012

addrOf can be pure outright, it returns a mutable void * (though this might not be the best idea, maybe it should be fixed to return const(void)* )

Too restrictive IMO; addrOf is often used to get from an interior pointer in an array or structure to the base, so forcing it to be const would be unreasonable.

Don't forget to update gcstub!

What is there to update? The functions I modified have C linkage, so all these attribute and storage class changes shouldn't affect linking (I think... doesn't on Linux, anyway).

Note also that I didn't change the GC implementation either.

Steven Schveighoffer
Collaborator
Alex Rønne Petersen
Collaborator
alexrp commented June 01, 2012

Should be inout then.

Can you clarify how it should be declared? I'm not too familiar with inout yet, to be honest.

No idea, all I know is that Walter goes on a rampage whenever It doesn't get updated ;) Maybe that's only when functions are added/removed...

I think so. For C linkage functions, this stuff really shouldn't matter, since all the D 'annotations' are removed from the mangling.

Steven Schveighoffer
Collaborator

Can you clarify how it should be declared? I'm not too familiar with inout yet, to be honest.

inout(void)* addrOf(inout(void)* p)

I think so. For C linkage functions, this stuff really shouldn't matter, since all the D 'annotations' are removed from the mangling.

Just checked, yes you need to update gcstub, because it duplicates the GC struct, which is D linkage.

Alex Rønne Petersen
Collaborator
alexrp commented June 01, 2012

Just checked, yes you need to update gcstub, because it duplicates the GC struct, which is D linkage.

I don't see it... only occurrence of struct GC is in core.memory.

Steven Schveighoffer
Collaborator

Yes, you are right, I am wrong. Sorry.

Alex Rønne Petersen
Collaborator
alexrp commented June 01, 2012

Well, just pushed the inout change. All good?

Steven Schveighoffer
Collaborator

Almost right. We still need the overloads, because inout is like const, so could potentially be treated as optimizable on a pure function if called with immutable arguments.

Sorry :( should have mentioned that when I said it could be pure outright!

Alex Rønne Petersen
Collaborator
alexrp commented June 01, 2012

Done.

Steven Schveighoffer
Collaborator

Still not right.

Should be like this:

static inout(void)* addrOf( inout(void)* p ) /*pure*/ nothrow
{
   return cast(inout(void)*)addrOf(cast()p);
}
Alex Rønne Petersen
Collaborator
alexrp commented June 01, 2012

OK, how about this time? :)

Steven Schveighoffer
Collaborator

OK, looks good! Let's wait and see how the pull tester does with it.

Steven Schveighoffer
Collaborator

Indeed, it looks good to merge.

Steven Schveighoffer schveiguy merged commit ef8b2a6 into from June 01, 2012
Steven Schveighoffer schveiguy closed this June 01, 2012
Denis Shelomovskij

WTF?! Sorry, but these breakes everything I know about pure functions in D. They are compiler checkable, not user checkable. E.g. strlen can't be pure because it's argument is a pointer, not an array (or we have to consider that if a pure function accepts a pointer the function result depends on all process memory).

All gc_* functions depends on global GC state and can't be pure unless this state is passed as an argument (such change will break binary compatibility but we can also leave old functions and add new ones).

Do you understand that you don't understand what is argument value and what is returned value of a pure function when we are dealing with pointers? I just filled Issue 8185 - Pure functions and pointers.

Revert it as soon as possible, please!

David Nadlinger
Collaborator

@denis-sh: You might want to get your facts straight first – pure functions in D can take/return pointers just fine. See the spec, and I recently wrote an article about it. As for the GC state, managing garbage collected memory is allowed in pure functions (making it possible to e.g. use new). This change gives some low-level functions the same treatment.

Denis Shelomovskij

@klickverbot:

You might want to get your facts straight first – pure functions in D can take/return pointers just fine. See the spec, and I recently wrote an article about it.

OK, I'm a human and can make a mistake. But I still doesn't see this. If my mistake is obvious, just quote me some sentences from specs etc.

As for the GC state, managing garbage collected memory is allowed in pure functions (making it possible to e.g. use new).

According to specs new is clearly stated as an exception. An arbitrary C function isn't stated as an exception (even a C function from a specific module).

@klickverbot, have you seen my Issue 8185 - Pure functions and pointers?

Alex Rønne Petersen
Collaborator
alexrp commented June 02, 2012

@denis-sh As discussed above in this pull request, we decided to do what we did here because the GC is a special case. Yes, in an ideal world, all purity would be compiler-checkable, but then pure would be next to useless. You would be unable to write a pure generic allocator using the GC as allocation mechanism for example. These changes are made because we've taken a pragmatic stance on the matter. Even Haskell, for example, has to call low-level functions in its runtime that aren't quite pure.

You are correct in saying that in reality, the GC functions operate on global state. But conceptually they operate on the GC class instance inside the gc.gcx module, and that can be considered a hidden parameter. Yes, it could be made an actual parameter, but there's no point. Further, there's no point in trying to actually enforce pure and nothrow inside the GC implementation; in fact, it would be impossible due to some of the functions it uses.

The GC (or more generally, druntime) is a very low-level aspect of the language. What we've done here is a faith-based approach where we assume people who hack on the GC know what they're doing and don't break the guarantees made in the core.memory module.

Denis Shelomovskij

@alexrp I'm not against any hacking with hidden global state in pure functions. My point is that a compiler can do some unexpected things if a function is pure because it assumes that pure functions produces the same results for the same arguments and doesn't read/write global state. And I doesn't see anywhere a definition of same arguments/same results for pointers (see Comment 3 on Issue 8185).

But at least the following example has to be considered:

Example 1

int res = gc_reserve(100);
  • Expectations: Reserve some memory.
  • Reality: Will (may) not be actually called if gc_reserve have ever been called with this argument.
  • Note: This even violates gc_reserve documentation, because it can return any amount of memory for the same argument.

Example 2

if(!gc_reserve(400 * MiB))
    return false; // This is assumed to be a common case
  • Expectations: We will tell the user to stop allocating such big buffers.
  • Reality: Same as above.

Example 3

gc_reserve(100);
  • Expectations: Reserve some memory.
  • Reality: Will (may) produce a compilation error/warning and never ever be called.

Example 4

immutable(void)*[] pArr;
for(; ;) {
    immutable p = gc_malloc(100 * MiB);
    if(!p) break;
    pArr ~= p;
    size_t random = 0;
    foreach(b; cast(immutable(ubyte)[])p[0 .. 100 * MiB])
        random += b;
    writeln("random: ", random);
}
  • Expectations: Prints memory hashes until break.
  • Reality: Will (may) call gc_malloc once so the random will always be the same and it will be an infinite loop.

P.S.

I hope this my post is constructive enough.

Alex Rønne Petersen
Collaborator
alexrp commented June 02, 2012

Example 1
Example 2
Example 3

You are right. gc_reserve should only be nothrow until we can mark weak purity. @schveiguy Do you agree?

Example 4

Wrong. gc_malloc returns a pointer with mutable indirection, so it is weakly pure. The compiler is not allowed to optimize it. It may only use the purity information for the type system.

Denis Shelomovskij

I forgot to mention that Example 2 leads to OOM error because one can think a system just gave him lots of memory and than try to use it with gc_malloc.

Denis Shelomovskij

Example 4

Wrong.

Have you noticed there is no cast(immutable)? You probably have to look at @klickverbot's Purity in D article "pure and immutable – again?" section

Steven Schveighoffer
Collaborator
Alex Rønne Petersen
Collaborator
alexrp commented June 02, 2012

I actually did (if you look at the diff) - either of us must have missed fixing/reviewing that at some point. Anyway, I'll make a pull request to revert it to just nothrow.

Alex Rønne Petersen
Collaborator
alexrp commented June 02, 2012

See #237.

David Nadlinger
Collaborator

@denis-sh: Sorry if my earlier post sounded like a personal attack, it certainly wasn't intended that way. I thought you were implying that pure functions taking pointers are a problem in general, and Alex/Steven were stupid for not seeing that – even though the issues were discussed at length before the request was merged. ;)

Steven Schveighoffer
Collaborator
Denis Shelomovskij

That doesn't matter. The fact that it returns mutable makes it weak pure (the optimizer cannot remove any calls to gc_malloc)

Than I have no idea how does pure work. Why this

immutable int[] arr1 = pureFunction(1);
...
immutable int[] arr2 = pureFunction(1);

can't be optimized to this

immutable int[] arr1 = pureFunction(1);
...
immutable int[] arr2 = arr1;

? The only answer I see is that compiler knows that pureFunction can depend on some global state but I've never heard about such "feature" of pure functions and it looks inconsistent.

Steven Schveighoffer
Collaborator

It's a new concept D has embraced. Since such a function that takes or returns mutable data cannot be pure optimized, it normally cannot be pure. But, if it doesn't access global variables, or shared data, then it still can't be optimized, but it can be called by an optimizable pure function!

So a pure function that created an immutable(int)[] with the numbers 1 to n could be pure and call malloc with no issues. The call to malloc could not be optimized, but the call to the number generating function could.

Of course, malloc DOES modify global shared state, but in an independent and thread safe way. So we must force malloc to be weakpure.

In fact , it might be reasonable to detect the implicit immutable cast, and optimize out calls to malloc, since you cannot change the data returned anyway. So the example might not work like you expect, but that's because your expectations are wrong.

Denis Shelomovskij

It's a new concept D has embraced. ....

I completely agree and thank you for doing this. My point is that some functions you calls pure aren't logically pure.

In fact , it might be reasonable to detect the implicit immutable cast, and optimize out calls to malloc, since you cannot change the data returned anyway. So the example might not work like you expect, but that's because your expectations are wrong.

Looks like it contradicts to your previous post. Does it? Doesn't matter. Anyway, at least I'm still very confused with pure and request participation in Issue 8185 - Pure functions and pointers understanding and than converting the conclusion into docs and/or @klickverbot's article.

Steven Schveighoffer
Collaborator
Deleted user Unknown referenced this pull request from a commit December 24, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 2 authors.

Jun 01, 2012
Mark some GC functions pure and/or nothrow. d4e8beb
This page is out of date. Refresh to see the latest.

Showing 1 changed file with 99 additions and 54 deletions. Show diff stats Hide diff stats

  1. 153  src/core/memory.d
153  src/core/memory.d
@@ -21,25 +21,25 @@ private
21 21
     extern (C) void gc_init();
22 22
     extern (C) void gc_term();
23 23
 
24  
-    extern (C) void gc_enable();
25  
-    extern (C) void gc_disable();
26  
-    extern (C) void gc_collect();
27  
-    extern (C) void gc_minimize();
28  
-
29  
-    extern (C) uint gc_getAttr( in void* p );
30  
-    extern (C) uint gc_setAttr( in void* p, uint a );
31  
-    extern (C) uint gc_clrAttr( in void* p, uint a );
32  
-
33  
-    extern (C) void*    gc_malloc( size_t sz, uint ba = 0 );
34  
-    extern (C) void*    gc_calloc( size_t sz, uint ba = 0 );
35  
-    extern (C) BlkInfo_ gc_qalloc( size_t sz, uint ba = 0 );
36  
-    extern (C) void*    gc_realloc( void* p, size_t sz, uint ba = 0 );
37  
-    extern (C) size_t   gc_extend( void* p, size_t mx, size_t sz );
38  
-    extern (C) size_t   gc_reserve( size_t sz );
39  
-    extern (C) void     gc_free( void* p );
40  
-
41  
-    extern (C) void*   gc_addrOf( in void* p );
42  
-    extern (C) size_t  gc_sizeOf( in void* p );
  24
+    extern (C) void gc_enable() nothrow;
  25
+    extern (C) void gc_disable() nothrow;
  26
+    extern (C) void gc_collect() nothrow;
  27
+    extern (C) void gc_minimize() nothrow;
  28
+
  29
+    extern (C) uint gc_getAttr( void* p ) pure nothrow;
  30
+    extern (C) uint gc_setAttr( void* p, uint a ) pure nothrow;
  31
+    extern (C) uint gc_clrAttr( void* p, uint a ) pure nothrow;
  32
+
  33
+    extern (C) void*    gc_malloc( size_t sz, uint ba = 0 ) pure nothrow;
  34
+    extern (C) void*    gc_calloc( size_t sz, uint ba = 0 ) pure nothrow;
  35
+    extern (C) BlkInfo_ gc_qalloc( size_t sz, uint ba = 0 ) pure nothrow;
  36
+    extern (C) void*    gc_realloc( void* p, size_t sz, uint ba = 0 ) pure nothrow;
  37
+    extern (C) size_t   gc_extend( void* p, size_t mx, size_t sz ) pure nothrow;
  38
+    extern (C) size_t   gc_reserve( size_t sz ) pure nothrow;
  39
+    extern (C) void     gc_free( void* p ) pure nothrow;
  40
+
  41
+    extern (C) void*   gc_addrOf( void* p ) pure nothrow;
  42
+    extern (C) size_t  gc_sizeOf( void* p ) pure nothrow;
43 43
 
44 44
     struct BlkInfo_
45 45
     {
@@ -48,13 +48,13 @@ private
48 48
         uint   attr;
49 49
     }
50 50
 
51  
-    extern (C) BlkInfo_ gc_query( in void* p );
  51
+    extern (C) BlkInfo_ gc_query( void* p ) pure nothrow;
52 52
 
53  
-    extern (C) void gc_addRoot( in void* p );
54  
-    extern (C) void gc_addRange( in void* p, size_t sz );
  53
+    extern (C) void gc_addRoot( in void* p ) nothrow;
  54
+    extern (C) void gc_addRange( in void* p, size_t sz ) nothrow;
55 55
 
56  
-    extern (C) void gc_removeRoot( in void* p );
57  
-    extern (C) void gc_removeRange( in void* p );
  56
+    extern (C) void gc_removeRoot( in void* p ) nothrow;
  57
+    extern (C) void gc_removeRange( in void* p ) nothrow;
58 58
 }
59 59
 
60 60
 
@@ -64,13 +64,15 @@ private
64 64
  */
65 65
 struct GC
66 66
 {
  67
+    @disable this();
  68
+
67 69
     /**
68 70
      * Enables automatic garbage collection behavior if collections have
69 71
      * previously been suspended by a call to disable.  This function is
70 72
      * reentrant, and must be called once for every call to disable before
71 73
      * automatic collections are enabled.
72 74
      */
73  
-    static void enable()
  75
+    static void enable() nothrow /* FIXME pure */
74 76
     {
75 77
         gc_enable();
76 78
     }
@@ -83,7 +85,7 @@ struct GC
83 85
      * such as during an out of memory condition.  This function is reentrant,
84 86
      * but enable must be called once for each call to disable.
85 87
      */
86  
-    static void disable()
  88
+    static void disable() nothrow /* FIXME pure */
87 89
     {
88 90
         gc_disable();
89 91
     }
@@ -96,7 +98,7 @@ struct GC
96 98
      * and then to reclaim free space.  This action may need to suspend all
97 99
      * running threads for at least part of the collection process.
98 100
      */
99  
-    static void collect()
  101
+    static void collect() nothrow /* FIXME pure */
100 102
     {
101 103
         gc_collect();
102 104
     }
@@ -106,7 +108,7 @@ struct GC
106 108
      * physical memory to the operating system.  The amount of free memory
107 109
      * returned depends on the allocator design and on program behavior.
108 110
      */
109  
-    static void minimize()
  111
+    static void minimize() nothrow /* FIXME pure */
110 112
     {
111 113
         gc_minimize();
112 114
     }
@@ -159,7 +161,14 @@ struct GC
159 161
      *  A bit field containing any bits set for the memory block referenced by
160 162
      *  p or zero on error.
161 163
      */
162  
-    static uint getAttr( in void* p )
  164
+    static uint getAttr( in void* p ) nothrow
  165
+    {
  166
+        return getAttr(cast()p);
  167
+    }
  168
+
  169
+
  170
+    /// ditto
  171
+    static uint getAttr(void* p) pure nothrow
163 172
     {
164 173
         return gc_getAttr( p );
165 174
     }
@@ -175,10 +184,18 @@ struct GC
175 184
      *  p = A pointer to the root of a valid memory block or to null.
176 185
      *  a = A bit field containing any bits to set for this memory block.
177 186
      *
  187
+     * Returns:
178 188
      *  The result of a call to getAttr after the specified bits have been
179 189
      *  set.
180 190
      */
181  
-    static uint setAttr( in void* p, uint a )
  191
+    static uint setAttr( in void* p, uint a ) nothrow
  192
+    {
  193
+        return setAttr(cast()p, a);
  194
+    }
  195
+
  196
+
  197
+    /// ditto
  198
+    static uint setAttr(void* p, uint a) pure nothrow
182 199
     {
183 200
         return gc_setAttr( p, a );
184 201
     }
@@ -198,7 +215,14 @@ struct GC
198 215
      *  The result of a call to getAttr after the specified bits have been
199 216
      *  cleared.
200 217
      */
201  
-    static uint clrAttr( in void* p, uint a )
  218
+    static uint clrAttr( in void* p, uint a ) nothrow
  219
+    {
  220
+        return clrAttr(cast()p, a);
  221
+    }
  222
+
  223
+
  224
+    /// ditto
  225
+    static uint clrAttr(void* p, uint a) pure nothrow
202 226
     {
203 227
         return gc_clrAttr( p, a );
204 228
     }
@@ -209,7 +233,7 @@ struct GC
209 233
      * This memory may be deleted at will with a call to free, or it may be
210 234
      * discarded and cleaned up automatically during a collection run.  If
211 235
      * allocation fails, this function will call onOutOfMemory which is
212  
-     * expected to throw an OutOfMemoryException.
  236
+     * expected to throw an OutOfMemoryError.
213 237
      *
214 238
      * Params:
215 239
      *  sz = The desired allocation size in bytes.
@@ -220,9 +244,9 @@ struct GC
220 244
      *  is available.
221 245
      *
222 246
      * Throws:
223  
-     *  OutOfMemoryException on allocation failure.
  247
+     *  OutOfMemoryError on allocation failure.
224 248
      */
225  
-    static void* malloc( size_t sz, uint ba = 0 )
  249
+    static void* malloc( size_t sz, uint ba = 0 ) pure nothrow
226 250
     {
227 251
         return gc_malloc( sz, ba );
228 252
     }
@@ -233,7 +257,7 @@ struct GC
233 257
      * This memory may be deleted at will with a call to free, or it may be
234 258
      * discarded and cleaned up automatically during a collection run.  If
235 259
      * allocation fails, this function will call onOutOfMemory which is
236  
-     * expected to throw an OutOfMemoryException.
  260
+     * expected to throw an OutOfMemoryError.
237 261
      *
238 262
      * Params:
239 263
      *  sz = The desired allocation size in bytes.
@@ -244,9 +268,9 @@ struct GC
244 268
      *  error.
245 269
      *
246 270
      * Throws:
247  
-     *  OutOfMemoryException on allocation failure.
  271
+     *  OutOfMemoryError on allocation failure.
248 272
      */
249  
-    static BlkInfo qalloc( size_t sz, uint ba = 0 )
  273
+    static BlkInfo qalloc( size_t sz, uint ba = 0 ) pure nothrow
250 274
     {
251 275
         return gc_qalloc( sz, ba );
252 276
     }
@@ -258,7 +282,7 @@ struct GC
258 282
      * deleted at will with a call to free, or it may be discarded and cleaned
259 283
      * up automatically during a collection run.  If allocation fails, this
260 284
      * function will call onOutOfMemory which is expected to throw an
261  
-     * OutOfMemoryException.
  285
+     * OutOfMemoryError.
262 286
      *
263 287
      * Params:
264 288
      *  sz = The desired allocation size in bytes.
@@ -269,9 +293,9 @@ struct GC
269 293
      *  is available.
270 294
      *
271 295
      * Throws:
272  
-     *  OutOfMemoryException on allocation failure.
  296
+     *  OutOfMemoryError on allocation failure.
273 297
      */
274  
-    static void* calloc( size_t sz, uint ba = 0 )
  298
+    static void* calloc( size_t sz, uint ba = 0 ) pure nothrow
275 299
     {
276 300
         return gc_calloc( sz, ba );
277 301
     }
@@ -287,7 +311,7 @@ struct GC
287 311
      * be freed by realloc if sz is equal to zero.  The garbage collector is
288 312
      * otherwise expected to later reclaim the memory block if it is unused.
289 313
      * If allocation fails, this function will call onOutOfMemory which is
290  
-     * expected to throw an OutOfMemoryException.  If p references memory not
  314
+     * expected to throw an OutOfMemoryError.  If p references memory not
291 315
      * originally allocated by this garbage collector, or if it points to the
292 316
      * interior of a memory block, no action will be taken.  If ba is zero
293 317
      * (the default) and p references the head of a valid, known memory block
@@ -307,9 +331,9 @@ struct GC
307 331
      *  zero.  On failure, the original value of p is returned.
308 332
      *
309 333
      * Throws:
310  
-     *  OutOfMemoryException on allocation failure.
  334
+     *  OutOfMemoryError on allocation failure.
311 335
      */
312  
-    static void* realloc( void* p, size_t sz, uint ba = 0 )
  336
+    static void* realloc( void* p, size_t sz, uint ba = 0 ) pure nothrow
313 337
     {
314 338
         return gc_realloc( p, sz, ba );
315 339
     }
@@ -330,7 +354,7 @@ struct GC
330 354
      *  The size in bytes of the extended memory block referenced by p or zero
331 355
      *  if no extension occurred.
332 356
      */
333  
-    static size_t extend( void* p, size_t mx, size_t sz )
  357
+    static size_t extend( void* p, size_t mx, size_t sz ) pure nothrow
334 358
     {
335 359
         return gc_extend( p, mx, sz );
336 360
     }
@@ -346,7 +370,7 @@ struct GC
346 370
      * Returns:
347 371
      *  The actual number of bytes reserved or zero on error.
348 372
      */
349  
-    static size_t reserve( size_t sz )
  373
+    static size_t reserve( size_t sz ) pure nothrow
350 374
     {
351 375
         return gc_reserve( sz );
352 376
     }
@@ -363,7 +387,7 @@ struct GC
363 387
      * Params:
364 388
      *  p = A pointer to the root of a valid memory block or to null.
365 389
      */
366  
-    static void free( void* p )
  390
+    static void free( void* p ) pure nothrow
367 391
     {
368 392
         gc_free( p );
369 393
     }
@@ -384,9 +408,16 @@ struct GC
384 408
      * Returns:
385 409
      *  The base address of the memory block referenced by p or null on error.
386 410
      */
387  
-    static void* addrOf( in void* p )
  411
+    static inout(void)* addrOf( inout(void)* p ) nothrow /* FIXME pure */
388 412
     {
389  
-        return gc_addrOf( p );
  413
+        return cast(inout(void)*)addrOf(cast()p);
  414
+    }
  415
+
  416
+
  417
+    /// ditto
  418
+    static void* addrOf(void* p) pure nothrow
  419
+    {
  420
+        return gc_addrOf(p);
390 421
     }
391 422
 
392 423
 
@@ -403,7 +434,14 @@ struct GC
403 434
      * Returns:
404 435
      *  The size in bytes of the memory block referenced by p or zero on error.
405 436
      */
406  
-    static size_t sizeOf( in void* p )
  437
+    static size_t sizeOf( in void* p ) nothrow
  438
+    {
  439
+        return sizeOf(cast(const)p);
  440
+    }
  441
+
  442
+
  443
+    /// ditto
  444
+    static size_t sizeOf(void* p) pure nothrow
407 445
     {
408 446
         return gc_sizeOf( p );
409 447
     }
@@ -424,7 +462,14 @@ struct GC
424 462
      *  Information regarding the memory block referenced by p or BlkInfo.init
425 463
      *  on error.
426 464
      */
427  
-    static BlkInfo query( in void* p )
  465
+    static BlkInfo query( in void* p ) nothrow
  466
+    {
  467
+        return query(cast(const)p);
  468
+    }
  469
+
  470
+
  471
+    /// ditto
  472
+    static BlkInfo query(void* p) pure nothrow
428 473
     {
429 474
         return gc_query( p );
430 475
     }
@@ -438,7 +483,7 @@ struct GC
438 483
      * Params:
439 484
      *  p = A pointer to a valid memory address or to null.
440 485
      */
441  
-    static void addRoot( in void* p )
  486
+    static void addRoot( in void* p ) nothrow /* FIXME pure */
442 487
     {
443 488
         gc_addRoot( p );
444 489
     }
@@ -454,7 +499,7 @@ struct GC
454 499
      *  sz = The size in bytes of the block to add.  If sz is zero then the
455 500
      *       no operation will occur.  If p is null then sz must be zero.
456 501
      */
457  
-    static void addRange( in void* p, size_t sz )
  502
+    static void addRange( in void* p, size_t sz ) nothrow /* FIXME pure */
458 503
     {
459 504
         gc_addRange( p, sz );
460 505
     }
@@ -467,7 +512,7 @@ struct GC
467 512
      *
468 513
      *  p  = A pointer to a valid memory address or to null.
469 514
      */
470  
-    static void removeRoot( in void* p )
  515
+    static void removeRoot( in void* p ) nothrow /* FIXME pure */
471 516
     {
472 517
         gc_removeRoot( p );
473 518
     }
@@ -482,7 +527,7 @@ struct GC
482 527
      * Params:
483 528
      *  p  = A pointer to a valid memory address or to null.
484 529
      */
485  
-    static void removeRange( in void* p )
  530
+    static void removeRange( in void* p ) nothrow /* FIXME pure */
486 531
     {
487 532
         gc_removeRange( p );
488 533
     }
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.