Make native class object members delegate to static methods in the outer class
This commit is contained in:
@@ -189,6 +189,11 @@ public class AsmUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (AnnotationsPackage.isPlatformStaticInClassObject(functionDescriptor)) {
|
||||||
|
// Native method will be a member of the class, the class object method will be delegated to it
|
||||||
|
flags &= ~Opcodes.ACC_NATIVE;
|
||||||
|
}
|
||||||
|
|
||||||
if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) {
|
if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) {
|
||||||
DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
|
DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
|
||||||
if (!(containingDeclaration instanceof ClassDescriptor) ||
|
if (!(containingDeclaration instanceof ClassDescriptor) ||
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin;
|
|||||||
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterKind;
|
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterKind;
|
||||||
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterSignature;
|
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterSignature;
|
||||||
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature;
|
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature;
|
||||||
|
import org.jetbrains.jet.lang.resolve.kotlin.nativeDeclarations.NativeDeclarationsPackage;
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
import org.jetbrains.jet.lang.types.Approximation;
|
import org.jetbrains.jet.lang.types.Approximation;
|
||||||
import org.jetbrains.jet.lang.types.TypesPackage;
|
import org.jetbrains.jet.lang.types.TypesPackage;
|
||||||
@@ -129,6 +130,8 @@ public class FunctionCodegen extends ParentCodegenAware {
|
|||||||
Method asmMethod = jvmSignature.getAsmMethod();
|
Method asmMethod = jvmSignature.getAsmMethod();
|
||||||
|
|
||||||
int flags = getMethodAsmFlags(functionDescriptor, methodContextKind);
|
int flags = getMethodAsmFlags(functionDescriptor, methodContextKind);
|
||||||
|
boolean isNative = NativeDeclarationsPackage.hasNativeAnnotation(functionDescriptor);
|
||||||
|
|
||||||
MethodVisitor mv = v.newMethod(origin,
|
MethodVisitor mv = v.newMethod(origin,
|
||||||
flags,
|
flags,
|
||||||
asmMethod.getName(),
|
asmMethod.getName(),
|
||||||
@@ -154,8 +157,9 @@ public class FunctionCodegen extends ParentCodegenAware {
|
|||||||
|
|
||||||
generateBridges(functionDescriptor);
|
generateBridges(functionDescriptor);
|
||||||
|
|
||||||
|
boolean staticInClassObject = AnnotationsPackage.isPlatformStaticInClassObject(functionDescriptor);
|
||||||
|
|
||||||
if (AnnotationsPackage.isPlatformStaticInClassObject(functionDescriptor)) {
|
if (staticInClassObject) {
|
||||||
MemberCodegen<?> codegen = getParentCodegen().getParentCodegen();
|
MemberCodegen<?> codegen = getParentCodegen().getParentCodegen();
|
||||||
((ImplementationBodyCodegen) codegen).addAdditionalTask(new PlatformStaticGenerator(functionDescriptor, origin, state));
|
((ImplementationBodyCodegen) codegen).addAdditionalTask(new PlatformStaticGenerator(functionDescriptor, origin, state));
|
||||||
}
|
}
|
||||||
@@ -175,9 +179,17 @@ public class FunctionCodegen extends ParentCodegenAware {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & Opcodes.ACC_NATIVE) == 0) {
|
if (!isNative) {
|
||||||
generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, getParentCodegen());
|
generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, getParentCodegen());
|
||||||
}
|
}
|
||||||
|
else if (staticInClassObject) {
|
||||||
|
// native platformStatic foo() in class object should delegate to the static native function moved to the outer class
|
||||||
|
mv.visitCode();
|
||||||
|
ClassifierDescriptor outerClassDescriptor =
|
||||||
|
(ClassifierDescriptor) functionDescriptor.getContainingDeclaration().getContainingDeclaration();
|
||||||
|
assert outerClassDescriptor != null : "Class object has no outer class: " + functionDescriptor.getContainingDeclaration();
|
||||||
|
generateDelegateToMethodBody(false, mv, asmMethod, typeMapper.mapClass(outerClassDescriptor).getInternalName());
|
||||||
|
}
|
||||||
|
|
||||||
endVisit(mv, null, origin.getElement());
|
endVisit(mv, null, origin.getElement());
|
||||||
|
|
||||||
@@ -304,7 +316,7 @@ public class FunctionCodegen extends ParentCodegenAware {
|
|||||||
JetTypeMapper typeMapper = parentCodegen.typeMapper;
|
JetTypeMapper typeMapper = parentCodegen.typeMapper;
|
||||||
|
|
||||||
if (context.getParentContext() instanceof PackageFacadeContext) {
|
if (context.getParentContext() instanceof PackageFacadeContext) {
|
||||||
generateStaticDelegateMethodBody(mv, signature.getAsmMethod(), (PackageFacadeContext) context.getParentContext());
|
generatePackageDelegateMethodBody(mv, signature.getAsmMethod(), (PackageFacadeContext) context.getParentContext());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
FrameMap frameMap = createFrameMap(parentCodegen.state, functionDescriptor, signature, isStaticMethod(context.getContextKind(),
|
FrameMap frameMap = createFrameMap(parentCodegen.state, functionDescriptor, signature, isStaticMethod(context.getContextKind(),
|
||||||
@@ -374,10 +386,19 @@ public class FunctionCodegen extends ParentCodegenAware {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void generateStaticDelegateMethodBody(
|
private static void generatePackageDelegateMethodBody(
|
||||||
@NotNull MethodVisitor mv,
|
@NotNull MethodVisitor mv,
|
||||||
@NotNull Method asmMethod,
|
@NotNull Method asmMethod,
|
||||||
@NotNull PackageFacadeContext context
|
@NotNull PackageFacadeContext context
|
||||||
|
) {
|
||||||
|
generateDelegateToMethodBody(true, mv, asmMethod, context.getDelegateToClassType().getInternalName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void generateDelegateToMethodBody(
|
||||||
|
boolean isStatic,
|
||||||
|
@NotNull MethodVisitor mv,
|
||||||
|
@NotNull Method asmMethod,
|
||||||
|
@NotNull String classToDelegateTo
|
||||||
) {
|
) {
|
||||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||||
Type[] argTypes = asmMethod.getArgumentTypes();
|
Type[] argTypes = asmMethod.getArgumentTypes();
|
||||||
@@ -388,12 +409,12 @@ public class FunctionCodegen extends ParentCodegenAware {
|
|||||||
iv.visitLabel(label);
|
iv.visitLabel(label);
|
||||||
iv.visitLineNumber(1, label);
|
iv.visitLineNumber(1, label);
|
||||||
|
|
||||||
int k = 0;
|
int k = isStatic ? 0 : 1;
|
||||||
for (Type argType : argTypes) {
|
for (Type argType : argTypes) {
|
||||||
iv.load(k, argType);
|
iv.load(k, argType);
|
||||||
k += argType.getSize();
|
k += argType.getSize();
|
||||||
}
|
}
|
||||||
iv.invokestatic(context.getDelegateToClassType().getInternalName(), asmMethod.getName(), asmMethod.getDescriptor(), false);
|
iv.invokestatic(classToDelegateTo, asmMethod.getName(), asmMethod.getDescriptor(), false);
|
||||||
iv.areturn(asmMethod.getReturnType());
|
iv.areturn(asmMethod.getReturnType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,7 +614,7 @@ public class FunctionCodegen extends ParentCodegenAware {
|
|||||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||||
if (this.owner instanceof PackageFacadeContext) {
|
if (this.owner instanceof PackageFacadeContext) {
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
generateStaticDelegateMethodBody(mv, defaultMethod, (PackageFacadeContext) this.owner);
|
generatePackageDelegateMethodBody(mv, defaultMethod, (PackageFacadeContext) this.owner);
|
||||||
endVisit(mv, "default method delegation", callableDescriptorToDeclaration(functionDescriptor));
|
endVisit(mv, "default method delegation", callableDescriptorToDeclaration(functionDescriptor));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
import kotlin.jvm.*
|
import kotlin.jvm.*
|
||||||
|
|
||||||
class WithNative {
|
class WithNative {
|
||||||
|
|||||||
@@ -1,27 +1,34 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
import kotlin.jvm.*
|
import kotlin.jvm.*
|
||||||
import kotlin.platform.*
|
import kotlin.platform.*
|
||||||
|
|
||||||
class WithNative {
|
class WithNative {
|
||||||
class object {
|
class object {
|
||||||
platformStatic native fun bar() {}
|
platformStatic native fun bar(l: Long, s: String): Double = null!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ObjWithNative {
|
object ObjWithNative {
|
||||||
platformStatic native fun bar() {}
|
platformStatic native fun bar(l: Long, s: String): Double = null!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
var d = 0.0
|
||||||
try {
|
try {
|
||||||
WithNative.bar()
|
d = WithNative.bar(1, "")
|
||||||
return "Link error expected"
|
return "Link error expected"
|
||||||
}
|
}
|
||||||
catch (e: java.lang.UnsatisfiedLinkError) {}
|
catch (e: java.lang.UnsatisfiedLinkError) {
|
||||||
|
if (e.getMessage() != "foo.WithNative.bar(JLjava/lang/String;)D") return "Fail 1: " + e.getMessage()
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ObjWithNative.bar()
|
d = ObjWithNative.bar(1, "")
|
||||||
return "Link error expected on object"
|
return "Link error expected on object"
|
||||||
}
|
}
|
||||||
catch (e: java.lang.UnsatisfiedLinkError) {}
|
catch (e: java.lang.UnsatisfiedLinkError) {
|
||||||
|
if (e.getMessage() != "foo.ObjWithNative.bar(JLjava/lang/String;)D") return "Fail 2: " + e.getMessage()
|
||||||
|
}
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user