Replace all assert calls in interpreter with internal verify

This swap of methods allow us to handle all asserted errors as
critical and not to process them inside interpreter
This commit is contained in:
Ivan Kylchik
2021-05-31 21:44:45 +03:00
committed by TeamCityServer
parent 23392b73a9
commit af67e950c4
9 changed files with 55 additions and 27 deletions
@@ -16,6 +16,8 @@ import org.jetbrains.kotlin.ir.interpreter.builtins.interpretBinaryFunction
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretTernaryFunction
import org.jetbrains.kotlin.ir.interpreter.builtins.interpretUnaryFunction
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
import org.jetbrains.kotlin.ir.interpreter.exceptions.verify
import org.jetbrains.kotlin.ir.interpreter.exceptions.withExceptionHandler
import org.jetbrains.kotlin.ir.interpreter.intrinsics.IntrinsicEvaluator
import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
@@ -141,7 +143,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
irClass.defaultType.isArray() || irClass.defaultType.isPrimitiveArray() -> {
// array constructor doesn't have body so must be treated separately
callStack.addVariable(Variable(irConstructor.symbol, KTypeState(constructorCall.type, irBuiltIns.anyClass.owner)))
assert(handleIntrinsicMethods(irConstructor)) { "Unsupported intrinsic constructor: ${irConstructor.render()}" }
verify(handleIntrinsicMethods(irConstructor)) { "Unsupported intrinsic constructor: ${irConstructor.render()}" }
}
irClass.defaultType.isUnsignedType() -> {
val propertySymbol = irClass.declarations.single { it is IrProperty }.symbol
@@ -178,13 +180,13 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
override fun interceptJavaStaticField(expression: IrGetField) {
val field = expression.symbol.owner
assert(field.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && field.isStatic)
assert(field.initializer?.expression !is IrConst<*>)
verify(field.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && field.isStatic)
verify(field.initializer?.expression !is IrConst<*>)
callStack.pushState(Wrapper.getStaticGetter(field).invokeWithArguments().toState(field.type))
}
private fun MethodHandle?.invokeMethod(irFunction: IrFunction, args: List<State>) {
this ?: return assert(handleIntrinsicMethods(irFunction)) { "Unsupported intrinsic function: ${irFunction.render()}" }
this ?: return verify(handleIntrinsicMethods(irFunction)) { "Unsupported intrinsic function: ${irFunction.render()}" }
val argsForMethodInvocation = irFunction.getArgsForMethodInvocation(this@DefaultCallInterceptor, this.type(), args)
withExceptionHandler(environment) {
val result = this.invokeWithArguments(argsForMethodInvocation) // TODO if null return Unit
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException
import org.jetbrains.kotlin.ir.interpreter.exceptions.verify
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.interpreter.state.*
@@ -214,8 +216,7 @@ private fun unfoldReturn(expression: IrReturn, callStack: CallStack) {
}
private fun unfoldSetField(expression: IrSetField, callStack: CallStack) {
// receiver is null, for example, for top level fields; cannot interpret set on top level var
if (expression.accessesTopLevelOrObjectField()) error("Cannot interpret set method on top level properties")
verify(!expression.accessesTopLevelOrObjectField()) { "Cannot interpret set method on top level properties" }
callStack.addInstruction(SimpleInstruction(expression))
callStack.addInstruction(CompoundInstruction(expression.value))
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterTimeOutError
import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException
import org.jetbrains.kotlin.ir.interpreter.exceptions.verify
import org.jetbrains.kotlin.ir.interpreter.proxy.CommonProxy.Companion.asProxy
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
@@ -90,7 +92,6 @@ class IrInterpreter private constructor(
while (!callStack.hasNoInstructions()) {
callStack.popInstruction().handle()
incrementAndCheckCommands()
}
callStack.popState().apply { callStack.dropFrame() }
@@ -386,7 +387,7 @@ class IrInterpreter private constructor(
expression.accessesTopLevelOrObjectField() -> {
val propertyOwner = field.correspondingPropertySymbol?.owner
val isConst = propertyOwner?.isConst == true || propertyOwner?.backingField?.initializer?.expression is IrConst<*>
assert(isConst) { "Cannot interpret get method on top level non const properties" }
verify(isConst) { "Cannot interpret get method on top level non const properties" }
callStack.addInstruction(CompoundInstruction(field.initializer?.expression))
}
else -> {
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
import org.jetbrains.kotlin.ir.interpreter.state.*
@@ -222,22 +223,6 @@ internal fun IrClass.internalName(): String {
return internalName.toString()
}
internal inline fun withExceptionHandler(environment: IrInterpreterEnvironment, block: () -> Unit) {
try {
block()
} catch (e: Throwable) {
e.handleUserException(environment)
}
}
internal fun Throwable.handleUserException(environment: IrInterpreterEnvironment) {
val exceptionName = this::class.java.simpleName
val irExceptionClass = environment.irExceptions.firstOrNull { it.name.asString() == exceptionName }
?: environment.irBuiltIns.throwableClass.owner
environment.callStack.pushState(ExceptionState(this, irExceptionClass, environment.callStack.getStackTrace()))
environment.callStack.dropFramesUntilTryCatch()
}
/**
* This method is analog of `checkcast` jvm bytecode operation. Throw exception whenever actual type is not a subtype of expected.
*/
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.ir.interpreter.exceptions
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
import org.jetbrains.kotlin.ir.interpreter.state.ExceptionState
internal fun verify(value: Boolean) {
verify(value) { "Assertion failed" }
}
internal inline fun verify(value: Boolean, lazyMessage: () -> Any) {
if (!value) throw InterpreterAssertionError(lazyMessage().toString())
}
internal inline fun withExceptionHandler(environment: IrInterpreterEnvironment, block: () -> Unit) {
try {
block()
} catch (e: InterpreterException) {
throw e
} catch (e: Throwable) {
e.handleUserException(environment)
}
}
internal fun Throwable.handleUserException(environment: IrInterpreterEnvironment) {
val exceptionName = this::class.java.simpleName
val irExceptionClass = environment.irExceptions.firstOrNull { it.name.asString() == exceptionName }
?: environment.irBuiltIns.throwableClass.owner
environment.callStack.pushState(ExceptionState(this, irExceptionClass, environment.callStack.getStackTrace()))
environment.callStack.dropFramesUntilTryCatch()
}
@@ -11,4 +11,6 @@ class InterpreterMethodNotFoundError(message: String) : InterpreterError(message
class InterpreterTimeOutError : InterpreterError("Exceeded execution limit of constexpr expression")
class InterpreterEmptyReturnStackError : InterpreterError("Return values stack is empty")
class InterpreterEmptyReturnStackError : InterpreterError("Return values stack is empty")
class InterpreterAssertionError(message: String) : InterpreterError(message)
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.interpreter.*
import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException
import org.jetbrains.kotlin.ir.interpreter.state.*
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.ir.interpreter.proxy.reflection
import org.jetbrains.kotlin.ir.interpreter.CallInterceptor
import org.jetbrains.kotlin.ir.interpreter.exceptions.verify
import org.jetbrains.kotlin.ir.interpreter.getDispatchReceiver
import org.jetbrains.kotlin.ir.interpreter.getExtensionReceiver
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
@@ -64,7 +65,7 @@ internal class KMutableProperty0Proxy(
override fun call(vararg args: Any?) {
checkArguments(1, args.size)
// null receiver <=> property is on top level
assert(state.receiver != null) { "Cannot interpret set method on top level non const properties" }
verify(state.receiver != null) { "Cannot interpret set method on top level properties" }
val receiver = state.receiver!!
val newValue = args.single().toState(propertyType)
setter.getExtensionReceiver()
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
import org.jetbrains.kotlin.ir.interpreter.handleUserException
import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.defaultType