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:
committed by
TeamCityServer
parent
23392b73a9
commit
af67e950c4
+6
-4
@@ -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
|
||||
|
||||
+3
-2
@@ -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.
|
||||
*/
|
||||
|
||||
+35
@@ -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()
|
||||
}
|
||||
+3
-1
@@ -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)
|
||||
+1
@@ -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
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user