Skip to content

Commit

Permalink
Improve proxying type computation
Browse files Browse the repository at this point in the history
  • Loading branch information
Gene Gleyzer committed Jul 17, 2023
1 parent bce1cc4 commit 7776632
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 26 deletions.
107 changes: 94 additions & 13 deletions javatools/src/main/java/org/xvm/runtime/ServiceContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,20 @@

import java.util.concurrent.atomic.AtomicLong;

import java.util.function.Supplier;

import org.xvm.asm.ConstantPool;
import org.xvm.asm.GenericTypeResolver;
import org.xvm.asm.LinkerContext;
import org.xvm.asm.MethodStructure;
import org.xvm.asm.Op;

import org.xvm.asm.constants.FormalConstant;
import org.xvm.asm.constants.MethodConstant;
import org.xvm.asm.constants.PropertyConstant;
import org.xvm.asm.constants.SingletonConstant;
import org.xvm.asm.constants.TypeConstant;
import org.xvm.asm.constants.TypeParameterConstant;

import org.xvm.asm.op.Return_0;

Expand Down Expand Up @@ -1196,7 +1202,7 @@ public int sendOp1Request(Frame frame, Op op, int iReturn, TypeConstant... typeR
{
assert iReturn != Op.A_IGNORE_ASYNC;

OpRequest request = new OpRequest(frame, op, iReturn == Op.A_IGNORE ? 0 : 1, typeRet);
OpRequest request = new OpRequest(frame, op, iReturn == Op.A_IGNORE ? 0 : 1, () -> typeRet);

addRequest(request, frame.isDynamicVar(iReturn));

Expand Down Expand Up @@ -1329,8 +1335,11 @@ public String toString()
}
};

TypeConstant[] atypeRet = cReturns == 0 ? TypeConstant.NO_TYPES : hFunction.getReturnTypes();
OpRequest request = new OpRequest(frame, opCall, cReturns, atypeRet);

Supplier<TypeConstant[]> supplier = cReturns == 0
? null
: () -> resolveFormalReturnTypes(hFunction, ahArg);
OpRequest request = new OpRequest(frame, opCall, cReturns, supplier);

boolean fOverwhelmed = addRequest(request, fAsync);

Expand Down Expand Up @@ -1395,8 +1404,8 @@ public String toString()
}
};

TypeConstant[] atypeRet = hFunction.getReturnTypes();
OpRequest request = new OpRequest(frame, opCall, cReturns, atypeRet);
Supplier<TypeConstant[]> supplier = () -> resolveFormalReturnTypes(hFunction, ahArg);
OpRequest request = new OpRequest(frame, opCall, cReturns, supplier);
CompletableFuture<ObjectHandle[]> future = request.f_future;

boolean fOverwhelmed = addRequest(request, false);
Expand All @@ -1422,6 +1431,71 @@ public String toString()
return frame.call(frame.createWaitFrame(future, aiReturn));
}

/**
* Helper method to resolve the formal type parameters in the function's return type.
*
* This method is only called if the value returned by the service is not immutable and needs
* to be proxied. In that case the actual return value type could be used to resolve generic
* return types (see ClassTemplate.createProxyHandle), but formal type parameters can only be
* resolved using the type parameters types that are passed in by the caller.
*/
private TypeConstant[] resolveFormalReturnTypes(FunctionHandle hFunction, ObjectHandle[] ahArg)
{
TypeConstant[] atype = hFunction.getReturnTypes();
int cTypes = atype.length;

if (cTypes > 0)
{
GenericTypeResolver resolver = new GenericTypeResolver()
{
@Override
public TypeConstant resolveGenericType(String sFormalName)
{
return null;
}

@Override
public TypeConstant resolveFormalType(FormalConstant constFormal)
{
if (constFormal instanceof TypeParameterConstant constTypeParam)
{
int nRegister = constTypeParam.getRegister();
MethodConstant idMethod = hFunction.getMethodId();
MethodStructure method = idMethod == null
? null
: (MethodStructure) idMethod.getComponent();
if (method != null && nRegister < method.getTypeParamCount() &&
method.getParam(nRegister).getName().equals(constTypeParam.getName()))
{
return ahArg[nRegister].getType().getParamType(0);
}
}

return null;
}
};

boolean fClone = true;
for (int i = 0; i < cTypes; i++)
{
TypeConstant type = atype[i];
if (type.containsTypeParameter(true))
{
TypeConstant typeResolved = type.resolveGenerics(f_pool, resolver);
if (typeResolved != type)
{
if (fClone)
{
atype = atype.clone();
}
atype[i] = typeResolved;
}
}
}
};
return atype;
}

/**
* Send an asynchronous property "read" operation request.
*
Expand Down Expand Up @@ -1547,7 +1621,7 @@ public String toString()
}
};

OpRequest request = new OpRequest(frame, opInit, 1);
OpRequest request = new OpRequest(frame, opInit, 1, null);

addRequest(request, false);

Expand Down Expand Up @@ -1740,13 +1814,17 @@ protected void sendResponse(Fiber fiberCaller, Frame frame, CompletableFuture fu
public static class OpRequest
extends Request
{
protected OpRequest(Frame frameCaller, Op op, int cReturns, TypeConstant... typeRet)
/**
* @param supplierRet (optional) the supplier of return types to be used *only* if the
* request's return values need to be proxied
*/
protected OpRequest(Frame frameCaller, Op op, int cReturns, Supplier<TypeConstant[]> supplierRet)
{
super(frameCaller);

f_op = op;
f_atypeReturn = typeRet;
f_cReturns = cReturns;
f_supplierRet = supplierRet;
}

@Override
Expand Down Expand Up @@ -1803,7 +1881,8 @@ protected int checkResponse(Fiber fiberCaller, Frame frame, int cReturns, int in
if (frame.m_hException == null)
{
int iResult = ctxSrc.validatePassThrough(frame, ctxDst,
f_atypeReturn, frame.f_ahVar, 1);
f_supplierRet == null ? null : f_supplierRet.get(),
frame.f_ahVar, 1);
if (iResult == Op.R_EXCEPTION)
{
Arrays.fill(frame.f_ahVar, null);
Expand Down Expand Up @@ -1873,7 +1952,9 @@ protected int checkResponse(Fiber fiberCaller, Frame frame, int cReturns, int in
}
}

int iResult = ctxSrc.validatePassThrough(frame, ctxDst, null, ahReturn, cReturns);
int iResult = ctxSrc.validatePassThrough(frame, ctxDst,
f_supplierRet == null ? null : f_supplierRet.get(),
ahReturn, cReturns);
if (iResult == Op.R_EXCEPTION)
{
Arrays.fill(ahReturn, null);
Expand All @@ -1892,9 +1973,9 @@ public String toString()
return f_op.toString();
}

private final Op f_op;
private final int f_cReturns;
private final TypeConstant[] f_atypeReturn;
private final Op f_op;
private final int f_cReturns;
private final Supplier<TypeConstant[]> f_supplierRet;
}

/**
Expand Down
23 changes: 10 additions & 13 deletions manualTests/src/main/x/TestSimple.x
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
module TestSimple {
module TestSimple.examples.org {
@Inject Console console;

package json import json.xtclang.org;
void run() {
String[] strings = ["abc", "def"];

import json.*;
Test<String> t = new Test(strings);
String[] filtered = t.filter(s -> s.indexOf("e")).toArray(Constant); // that used to fail at RT
console.print(filtered);
}

void run() {
String str = \|{
|"host":"admin.xqiz.it",
|"http":8080,
|"https":8090
|}
;
Doc doc = new Parser(str.toReader()).parseDoc(); // used to fail to compile (unknown type "Doc")
assert doc.is(Map<String, Doc>);
console.print(doc);
service Test<Element>(Collection<Element> underlying)
implements Collection<Element>
delegates Collection(underlying) {
}
}

0 comments on commit 7776632

Please sign in to comment.