diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt index 1f06fd558fe..b5e82c2decf 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt @@ -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) { - 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 diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt index ec6e4351582..d04e4764f6b 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt @@ -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)) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt index ed6791b5876..3a7a5d302b7 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt @@ -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 -> { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt index f2e34fe2b63..48f2a27d179 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt @@ -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. */ diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/exceptions/ExceptionUtils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/exceptions/ExceptionUtils.kt new file mode 100644 index 00000000000..74f199e8c41 --- /dev/null +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/exceptions/ExceptionUtils.kt @@ -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() +} \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/exceptions/InterpreterError.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/exceptions/InterpreterError.kt index 9ff2c2fbbbb..7037d1d842e 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/exceptions/InterpreterError.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/exceptions/InterpreterError.kt @@ -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") \ No newline at end of file +class InterpreterEmptyReturnStackError : InterpreterError("Return values stack is empty") + +class InterpreterAssertionError(message: String) : InterpreterError(message) \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt index 45a369caa55..a6aaa79619a 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt @@ -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 diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt index 8886e8df61c..97354e4cb50 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt @@ -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() diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt index f0315d50b43..0190a6542e4 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt @@ -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