Skip to content

Commit

Permalink
Make fields/methods always use fast calls
Browse files Browse the repository at this point in the history
  • Loading branch information
thecodewarrior committed Feb 4, 2021
1 parent 0b2391e commit e44e90e
Show file tree
Hide file tree
Showing 14 changed files with 132 additions and 384 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
library_version=1.0.0b1
library_version=1.0.0b2
Original file line number Diff line number Diff line change
Expand Up @@ -46,29 +46,17 @@ public class ConstructorMirror internal constructor(
}

/**
* Create a new instance using this constructor. If performance is of the essence use [callFast], which should be
* near-native speed, but will provide somewhat less helpful exceptions.
* Create a new instance using this constructor. After the one-time cost of creating the
* [MethodHandle][java.lang.invoke.MethodHandle], the access should be near-native speed.
*/
@Suppress("UNCHECKED_CAST")
public fun <T : Any?> call(vararg args: Any?): T {
if(args.size != parameters.size)
throw IllegalArgumentException("Incorrect argument count (${args.size}) for constructor `$this`")
return raw.wrapper(args as Array<Any?>) as T
}

@JvmSynthetic
public operator fun <T> invoke(vararg args: Any?): T = call(*args)

/**
* Create a new instance using this constructor. After the one-time cost of creating the
* [MethodHandle][java.lang.invoke.MethodHandle], the access should be near-native speed. This method, while faster
* than [call], will provide somewhat less helpful exceptions.
*/
@Suppress("UNCHECKED_CAST")
public fun <T : Any?> callFast(vararg args: Any?): T {
return raw.wrapper(args as Array<Any?>) as T
}

override fun toString(): String {
var str = ""
if(access != Modifier.Access.DEFAULT) {
Expand Down
48 changes: 4 additions & 44 deletions src/main/kotlin/dev/thecodewarrior/mirror/member/FieldMirror.kt
Original file line number Diff line number Diff line change
Expand Up @@ -125,33 +125,13 @@ public class FieldMirror internal constructor(
MethodHandleHelper.wrapperForStaticGetter(java)
}

/**
* Get the value of this field in the passed instance. If this is a static field, `null` should be used for the
* instance. If performance is of the essence however, use [getFast], which should be near-native speed, but will
* have somewhat less helpful exceptions.
*/
@Suppress("UNCHECKED_CAST")
public fun <T : Any?> get(receiver: Any?): T {
if(isStatic) {
if(receiver != null)
throw IllegalArgumentException("Invalid receiver for static field `${declaringClass.java.simpleName}.$name`. Expected null.")
return raw.staticGetWrapper() as T
} else {
if (receiver == null)
throw NullPointerException("Null receiver for instance field `${declaringClass.java.simpleName}.$name`")
if(!declaringClass.java.isAssignableFrom(receiver.javaClass))
throw IllegalArgumentException("Invalid receiver type `${receiver.javaClass.simpleName}` for instance field `${declaringClass.java.simpleName}.$name`")
return raw.instanceGetWrapper(receiver) as T
}
}

/**
* Get the value of this field in the passed instance. If this is a static field, `null` should be used for the
* instance. After the one-time cost of creating the [MethodHandle][java.lang.invoke.MethodHandle], the access should
* be near-native speed. This method, while faster than [get], will provide somewhat less helpful exceptions.
* be near-native speed.
*/
@Suppress("UNCHECKED_CAST")
public fun <T : Any?> getFast(receiver: Any?): T {
public fun <T : Any?> get(receiver: Any?): T {
if(isStatic) {
return raw.staticGetWrapper() as T
} else {
Expand All @@ -168,33 +148,13 @@ public class FieldMirror internal constructor(
MethodHandleHelper.wrapperForStaticSetter(java)
}

/**
* Set the value of this field in the passed instance. If this is a static field, `null` should be used for the
* instance. If performance is of the essence however, use [setFast], which should be near-native speed, but will
* have somewhat less helpful exceptions.
*/
@Suppress("UNCHECKED_CAST")
public fun set(receiver: Any?, value: Any?) {
if(isStatic) {
if(receiver != null)
throw IllegalArgumentException("Invalid receiver for static field `${declaringClass.java.simpleName}.$name`. Expected null.")
raw.staticSetWrapper(value)
} else {
if (receiver == null)
throw NullPointerException("Null receiver for instance field `${declaringClass.java.simpleName}.$name`")
if(!declaringClass.java.isAssignableFrom(receiver.javaClass))
throw IllegalArgumentException("Invalid receiver type `${receiver.javaClass.simpleName}` for instance field `${declaringClass.java.simpleName}.$name`")
raw.instanceSetWrapper(receiver, value)
}
}

/**
* Set the value of this field in the passed instance. If this is a static field, `null` should be used for the
* instance. After the one-time cost of creating the [MethodHandle][java.lang.invoke.MethodHandle], the access
* should be near-native speed. This method, while faster than [set], will provide somewhat less helpful exceptions.
* should be near-native speed.
*/
@Suppress("UNCHECKED_CAST")
public fun setFast(receiver: Any?, value: Any?) {
public fun set(receiver: Any?, value: Any?) {
if(isStatic) {
raw.staticSetWrapper(value)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public abstract class MemberMirror internal constructor(
*/
public abstract fun withDeclaringClass(enclosing: ClassMirror?): MemberMirror

override fun <T: Annotation?> getAnnotation(annotationClass: Class<T>): T {
override fun <T: Annotation> getAnnotation(annotationClass: Class<T>): T? {
return annotatedElement.getAnnotation(annotationClass)
}

Expand Down
34 changes: 4 additions & 30 deletions src/main/kotlin/dev/thecodewarrior/mirror/member/MethodMirror.kt
Original file line number Diff line number Diff line change
Expand Up @@ -175,49 +175,23 @@ public class MethodMirror internal constructor(
}

/**
* Call this method on the passed instance. If this is a static method, `null` should be used for the instance. If
* performance is of the essence use [callFast], which should be near-native speed, but will provide somewhat less
* helpful exceptions.
* Call this method on the passed instance. If this is a static method, `null` should be used for the instance.
* After the one-time cost of creating the [MethodHandle][java.lang.invoke.MethodHandle], the access should be
* near-native speed.
*/
@Suppress("UNCHECKED_CAST")
@Throws(Throwable::class)
public fun <T> call(receiver: Any?, vararg args: Any?): T {
if(isStatic) {
if(receiver != null)
throw IllegalArgumentException("Invalid receiver for static method `${declaringClass.java.simpleName}.$name`. Expected null.")
if(args.size != parameters.size)
throw IllegalArgumentException("Incorrect argument count (${args.size}) for static method `$this`")

return raw.staticWrapper(args as Array<Any?>) as T
} else {
if(receiver == null)
throw NullPointerException("Null receiver for instance method `${declaringClass.java.simpleName}.$name`")
if(!declaringClass.java.isAssignableFrom(receiver.javaClass))
throw IllegalArgumentException("Invalid receiver type `${receiver.javaClass.simpleName}` for instance method `${declaringClass.java.simpleName}.$name`")
if(args.size != parameters.size)
throw IllegalArgumentException("Incorrect argument count (${args.size}) for instance method `$this`")

return raw.instanceWrapper(receiver, args as Array<Any?>) as T
return raw.instanceWrapper(receiver!!, args as Array<Any?>) as T
}
}

@JvmSynthetic
public operator fun <T> invoke(receiver: Any?, vararg args: Any?): T = call(receiver, *args)

/**
* Call this method on the passed instance. If this is a static method, `null` should be used for the instance.
* After the one-time cost of creating the [MethodHandle][java.lang.invoke.MethodHandle], the access should be
* near-native speed. This method, while faster than [call], will provide somewhat less helpful exceptions.
*/
@Suppress("UNCHECKED_CAST")
public fun <T : Any?> callFast(receiver: Any?, vararg args: Any?): T {
if(isStatic) {
return raw.staticWrapper(args as Array<Any?>) as T
} else {
return raw.instanceWrapper(receiver!!, args as Array<Any?>) as T
}
}

override fun toString(): String {
var str = ""
str += modifiers.joinToString("") { "$it " }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,59 +64,4 @@ internal class Constructors: MTest() {
Mirror.reflect(X._constructor()).call<Any>(0)
}
}

@Test
fun `fast calling a constructor should correctly return an instance`() {
val X by sources.add("X", "class X { int field; X() { field = 20; } }")
sources.compile()
val instance = Mirror.reflect(X._constructor()).callFast<Any>()
assertEquals(X, instance.javaClass)
assertEquals(20, instance._get<Any>("field"))
}

@Test
fun `fast calling a private constructor should not throw`() {
val X by sources.add("X", "class X { int field; private X() { field = 20; } }")
sources.compile()
assertDoesNotThrow {
Mirror.reflect(X._constructor()).callFast<Any>()
}
}

@Test
fun `fast calling a constructor with arguments should pass them`() {
val X by sources.add("X", "class X { int field; X(int param) { field = param; } }")
sources.compile()
val instance = Mirror.reflect(X._constructor()).callFast<Any>(20)
assertEquals(X, instance.javaClass)
assertEquals(20, instance._get<Any>("field"))
}

@Test
fun `fast calling a constructor with arguments and no parameters should not throw`() {
val X by sources.add("X", "class X { X() { } }")
sources.compile()
// for some reason passing arguments to a zero-arg method is fine, but not constructors?
assertThrows<IllegalArgumentException> {
Mirror.reflect(X._constructor()).callFast<Any>(0)
}
}

@Test
fun `fast calling a constructor with too many arguments should throw`() {
val X by sources.add("X", "class X { X(int a) { } }")
sources.compile()
assertThrows<IllegalArgumentException> {
Mirror.reflect(X._constructor()).callFast<Any>(0, 1)
}
}

@Test
fun `fast calling a constructor with too few arguments should throw`() {
val X by sources.add("X", "class X { X(int a, int b) { } }")
sources.compile()
assertThrows<IllegalArgumentException> {
Mirror.reflect(X._constructor()).callFast<Any>(0)
}
}
}
105 changes: 0 additions & 105 deletions src/test/kotlin/dev/thecodewarrior/mirror/methodhandles/FastCall.kt

This file was deleted.

Loading

0 comments on commit e44e90e

Please sign in to comment.