Skip to content

Commit

Permalink
support ref attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
jll63 committed May 6, 2018
1 parent 810dc95 commit 2402e9d
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 59 deletions.
210 changes: 151 additions & 59 deletions source/openmethods.d
Original file line number Diff line number Diff line change
Expand Up @@ -301,21 +301,25 @@ mixin(registerMethods);

auto registerMethods(string moduleName = __MODULE__)
{
return format("static import openmethods;"
~ "mixin(openmethods._registerMethods!(%s));"
~ "mixin openmethods._registerSpecs!(%s);\n",
moduleName, moduleName);
return `static import openmethods;
import std.traits : FunctionAttribute;
mixin(openmethods._registerMethods!(%s));
mixin openmethods._registerSpecs!(%s);`.format(moduleName, moduleName);
}

mixin template declareMethod(string index, ReturnType, string name, ParameterType...)
{
mixin(openmethods._declareMethod!(index, ReturnType, name, ParameterType));
mixin(openmethods.Method!(index, ReturnType, name,
FunctionAttribute.none, ParameterType)
.code);
}

mixin template declareMethod(ReturnType, string name, ParameterType...)
{
mixin openmethods.declareMethod!(openmethods.MptrInDeallocator, ReturnType, name,
ParameterType);
import std.traits;
mixin(openmethods.Method!(openmethods.MptrInDeallocator, ReturnType, name,
FunctionAttribute.none, ParameterType)
.code);
}

mixin template defineMethod(alias Dispatcher, alias Fun)
Expand Down Expand Up @@ -468,9 +472,9 @@ setMethodErrorHandler(void function(MethodError error) handler)
enum IsVirtual(T) = false;
enum IsVirtual(T : virtual!U, U) = true;

private alias VirtualType(T : virtual!U, U) = U;
alias VirtualType(T : virtual!U, U) = U;

private template VirtualArity(QP...)
template VirtualArity(QP...)
{
static if (QP.length == 0) {
enum VirtualArity = 0;
Expand Down Expand Up @@ -550,14 +554,22 @@ template castArgs(T...)
immutable MptrInDeallocator = "deallocator";
immutable MptrViaHash = "hash";

struct Method(string Mptr, R, string id, T...)
struct Method(string Mptr, R, string id, FunctionAttribute functionAttributes_, T...)
{
alias QualParams = T;
alias Params = CallParams!T;
alias R function(Params) Spec;
alias ReturnType = R;
alias Word = Runtime.Word;
enum name = id;
alias functionAttributes = functionAttributes_;
alias This = Method!(Mptr, R, id, functionAttributes, T);


static if (functionAttributes & FunctionAttribute.ref_) {
alias ref R function(Params) Spec;
} else {
alias R function(Params) Spec;
}

static __gshared Runtime.MethodInfo info;

Expand Down Expand Up @@ -679,32 +691,81 @@ struct Method(string Mptr, R, string id, T...)
}
}

static auto dispatcher(CallParams!T args)
{
debug(traceCalls) {
stderr.write(info.name);
}
enum code = discriminatorCode ~ dispatcherCode;

alias Word = Runtime.Word;
assert(info.slotStride);
enum discriminatorCode = `openmethods.%s %s(openmethods.MethodTag, %s);
`.format(This.stringof,
name,
Params.stringof[1..$-1]
);

static if (VirtualArity!QualParams == 1) {
auto mptr = Indexer!(QualParams).unary(args);
debug(traceCalls) {
stderr.writef("%s %s", mptr, info.slotStride[0].i);
}
auto pf = cast(Spec) mptr[info.slotStride[0].i].p;
} else {
auto pf =
cast(Spec) Indexer!(QualParams).move(info.slotStride, args).p;
enum refAttribute = functionAttributes & FunctionAttribute.ref_ ? "ref " : "";

enum string nonRefAttributes= `%s%s%s%s%s%s`
.format(
functionAttributes & FunctionAttribute.pure_ ? " pure" : "",
functionAttributes & FunctionAttribute.nothrow_ ? " nothrow" : "",
functionAttributes & FunctionAttribute.trusted ? " @trusted" : "",
functionAttributes & FunctionAttribute.safe ? " @safe" : "",
functionAttributes & FunctionAttribute.nogc ? " @nogc" : "",
functionAttributes & FunctionAttribute.system ? " @system" : "");

static string dispatcherCode() {
string params;
string args;
string sep = "";

foreach (i, p; Params) {
args ~= `%sarg%d`.format(sep, i);
params ~= `%s%s arg%d`.format(sep, p.stringof, i);
sep = ", ";
}

return `
%s%s %s(%s)%s%s%s%s%s%s
{
import std.traits, openmethods;
debug(traceCalls) {
import std.stdio;
stderr.write(info.name);
}
alias Word = Runtime.Word;
alias Method = openmethods.%s;
assert(Method.info.slotStride);
static if (openmethods.VirtualArity!(Method.QualParams) == 1) {
auto mptr = Method.Indexer!(Method.QualParams).unary(%s);
debug(traceCalls) {
writefln(" pf = %s", pf);
stderr.writef("%%s %%s", mptr, Method.info.slotStride[0].i);
}
auto pf = cast(Method.Spec) mptr[Method.info.slotStride[0].i].p;
} else {
auto pf =
cast(Method.Spec) Method.Indexer!(Method.QualParams).move(Method.info.slotStride, %s).p;
}
debug(traceCalls) {
import std.stdio;
writefln(" pf = %%s", pf);
}
assert(pf);
return pf(args);
assert(pf);
return pf(%s);
}
`.format(functionAttributes & FunctionAttribute.ref_ ? "ref " : "",
ReturnType.stringof,
name,
params,
functionAttributes & FunctionAttribute.pure_ ? " pure" : "",
functionAttributes & FunctionAttribute.nothrow_ ? " nothrow" : "",
functionAttributes & FunctionAttribute.trusted ? " @trusted" : "",
functionAttributes & FunctionAttribute.safe ? " @safe" : "",
functionAttributes & FunctionAttribute.nogc ? " @nogc" : "",
functionAttributes & FunctionAttribute.system ? " @system" : "",
This.stringof,
args, args, args);
}

shared static this() {
Expand Down Expand Up @@ -879,16 +940,16 @@ struct Runtime

Metrics update()
{
// Create a Method object for each method. Create a Class object for all
// the classes or interfaces that occur as virtual parameters in a method,
// or were registered explicitly with 'registerClasses'.

seed();

foreach (ci; additionalClasses) {
if (ci !in classMap) {
auto c = classMap[ci] = new Class(ci);
debug(explain) {
writefln(" %s", c.name);
}
}
}
// Create a Class object for all the classes or interfaces that derive from
// a class or interface that occur as virtual parameters in a method,
// or were registered explicitly with 'registerClasses'. Also record in
// each Class object all the method parameters that target it.

debug(explain) {
writefln("Scooping...");
Expand All @@ -900,11 +961,32 @@ struct Runtime
}
}

// Fill the 'directBases' and 'directDerived' arrays in the Class objects.

initClasses();

// Copy the Class objects to the 'classes' array, ensuring that derived
// classes and interface come after their base class and interfaces, but as
// close to them as possible.
layer();

// Fill the 'conforming' arrays, i.e. for each class record all the classes
// and interfaces that are type compatible with it. Note that every class
// is in its own 'conforming' array.

calculateInheritanceRelationships();

// Check if there are classes that define the 'delete' operator.

checkDeallocatorConflicts();

// For each method, reserve one slot per virtual parameter in the target
// Class.

allocateSlots();

// Build dispatch tables and install the global vectors.

buildTables();

if (methodsUsingHash) {
Expand Down Expand Up @@ -958,6 +1040,15 @@ struct Runtime
debug(explain) {
writeln();
}

foreach (ci; additionalClasses) {
if (ci !in classMap) {
auto c = classMap[ci] = new Class(ci);
debug(explain) {
writefln(" %s", c.name);
}
}
}
}

bool scoop(ClassInfo ci)
Expand Down Expand Up @@ -1607,6 +1698,7 @@ struct Runtime
}
}
}

foreach (spec; m.specs) {
auto nextSpec = findNext(spec, m.specs);
*spec.info.nextPtr = nextSpec ? nextSpec.info.pf : null;
Expand Down Expand Up @@ -1680,7 +1772,9 @@ version (GNU) {
string _registerMethods(alias MODULE)()
{
import std.array;

string[] code;

foreach (m; __traits(allMembers, MODULE)) {
static if (is(typeof(__traits(getOverloads, MODULE, m)))) {
foreach (o; __traits(getOverloads, MODULE, m)) {
Expand All @@ -1694,13 +1788,19 @@ string _registerMethods(alias MODULE)()
}

auto meth =
format(`openmethods.Method!("%s", %s, "%s", %s)`,
format(`openmethods.Method!("%s", %s, "%s", %s, %s)`,
index,
ReturnType!o.stringof,
m,
functionAttributes!o,
Parameters!o.stringof[1..$-1]);
code ~= format(`alias %s = %s.dispatcher;`, m, meth);
code ~= format(`alias %s = %s.discriminator;`, m, meth);
//code ~= format(`alias %s = %s.dispatcher;`, m, meth);
// alias Method = openmethods.Method!(index, ReturnType, m, functionAttributes!o, Parameters!o);
alias Method = openmethods.Method!(index, ReturnType!o, m, functionAttributes!o, Parameters!o);
//code ~= `mixin(%s.code);`.format(meth);
code ~= Method.dispatcherCode;
code ~= Method.discriminatorCode;
//code ~= format(`alias %s = %s.discriminator;`, m, meth);
}
}
}
Expand All @@ -1716,14 +1816,20 @@ mixin template _registerSpecs(alias MODULE)
{
static struct Register {

static wrapper = function Meth.ReturnType(Meth.Params args) {
return Fun(openmethods.castArgs!(Meth.QualParams).To!(Parameters!Fun).arglist(args).expand);
};
static if (Meth.functionAttributes & FunctionAttribute.ref_) {
static ref Meth.ReturnType wrapper(Meth.Params args) {
return Fun(openmethods.castArgs!(Meth.QualParams).To!(Parameters!Fun).arglist(args).expand);
}
} else {
static Meth.ReturnType wrapper(Meth.Params args) {
return Fun(openmethods.castArgs!(Meth.QualParams).To!(Parameters!Fun).arglist(args).expand);
}
}

static __gshared Runtime.SpecInfo si;

shared static this() {
si.pf = cast(void*) wrapper;
si.pf = cast(void*) &wrapper;

debug(explain) {
import std.stdio;
Expand Down Expand Up @@ -1798,17 +1904,3 @@ mixin template _registerSpecs(alias MODULE)
}
}
}

string _declareMethod(string index, ReturnType, string name, ParameterType...)()
{
import std.format;

enum meth =
format(`openmethods.Method!("%s", %s, "%s", %s)`,
index,
ReturnType.stringof,
name,
ParameterType.stringof[1..$-1]);
return format(`alias %s = %s.dispatcher;`, name, meth)
~ format(`alias %s = %s.discriminator;`, name, meth);
}
2 changes: 2 additions & 0 deletions tests/manualregistration.d
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
}
+/

// EXCLUDE_GDC

static import openmethods;
import openmethods : virtual, declareMethod, defineMethod;

Expand Down

0 comments on commit 2402e9d

Please sign in to comment.