From bfe1db727243b84489cfc5fe5ef3533ad7e22dc9 Mon Sep 17 00:00:00 2001 From: Marek Lipert Date: Mon, 30 Mar 2026 17:11:02 +0200 Subject: [PATCH] Throw Node. --- backend-v2/CMakeLists.txt | 3 +- backend-v2/bridge/Exceptions.cpp | 38 ++++++-- backend-v2/bridge/Exceptions.h | 6 ++ backend-v2/codegen/CodeGen.cpp | 16 ++-- backend-v2/codegen/CodeGen.h | 4 + backend-v2/codegen/ops/IfNode.cpp | 9 +- backend-v2/codegen/ops/ThrowNode.cpp | 34 +++++++ backend-v2/jit/JITEngine.cpp | 7 ++ backend-v2/runtime/CMakeLists.txt | 2 + backend-v2/runtime/Exception.c | 33 +++++++ backend-v2/runtime/Exception.h | 27 ++++++ backend-v2/runtime/Exceptions.h | 6 +- backend-v2/runtime/Object.h | 11 ++- backend-v2/runtime/ObjectProto.h | 1 + backend-v2/runtime/tests/BridgeMocks.c | 22 ++++- backend-v2/runtime/tests/Exception_test.c | 38 ++++++++ backend-v2/tests/CMakeLists.txt | 1 + backend-v2/tests/codegen/ThrowNode_test.cpp | 99 +++++++++++++++++++++ backend-v2/types/ObjectTypeSet.h | 10 ++- compile.sh | 2 +- frontend/resources/rt-classes.edn | 7 ++ 21 files changed, 350 insertions(+), 26 deletions(-) create mode 100644 backend-v2/codegen/ops/ThrowNode.cpp create mode 100644 backend-v2/runtime/Exception.c create mode 100644 backend-v2/runtime/Exception.h create mode 100644 backend-v2/runtime/tests/Exception_test.c create mode 100644 backend-v2/tests/codegen/ThrowNode_test.cpp diff --git a/backend-v2/CMakeLists.txt b/backend-v2/CMakeLists.txt index af8aaec3..5025685d 100644 --- a/backend-v2/CMakeLists.txt +++ b/backend-v2/CMakeLists.txt @@ -143,7 +143,8 @@ set(BACKEND_SOURCES codegen/ops/InstanceCallNode.cpp codegen/ops/HostInteropNode.cpp codegen/ops/NewNode.cpp - codegen/ops/IsInstanceNode.cpp) + codegen/ops/IsInstanceNode.cpp + codegen/ops/ThrowNode.cpp) add_subdirectory(runtime) diff --git a/backend-v2/bridge/Exceptions.cpp b/backend-v2/bridge/Exceptions.cpp index 0903b584..4449d5cd 100644 --- a/backend-v2/bridge/Exceptions.cpp +++ b/backend-v2/bridge/Exceptions.cpp @@ -1,5 +1,7 @@ #include "Exceptions.h" +#include "../runtime/Exception.h" #include "bytecode.pb.h" +#include "runtime/ObjectProto.h" #include "llvm/DebugInfo/Symbolize/Symbolize.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Object/ObjectFile.h" @@ -664,11 +666,9 @@ void throwInternalInconsistencyException(const std::string &errorMessage) { RT_boxPtr(::String_createDynamicStr(errorMessage.c_str())), RT_boxNil()); } -extern "C" void -throwInternalInconsistencyException_C(const char *errorMessage) { - throw rt::LanguageException( - "InternalInconsistencyException", - RT_boxPtr(::String_createDynamicStr(errorMessage)), RT_boxNil()); +extern "C" void throwInternalInconsistencyException_C(String *errorMessage) { + throw rt::LanguageException("InternalInconsistencyException", + RT_boxPtr(errorMessage), RT_boxNil()); } extern "C" [[noreturn]] void @@ -759,4 +759,32 @@ void throwCodeGenerationException( throwCodeGenerationException(errorMessage, node.form(), file, line, column); } +extern "C" String *exceptionToString_C(void *exception) { + rt::LanguageException *ex = (rt::LanguageException *)exception; + auto str = getExceptionString(*ex, StackTraceMode::Friendly, true); + return ::String_createDynamicStr(str.c_str()); +} + +extern "C" void *createException_C(const char *className, String *message, + RTValue payload) { + return new rt::LanguageException(className, RT_boxPtr(message), payload); +} + +extern "C" [[noreturn]] void throwException_C(RTValue exceptionBoxed) { + if (getType(exceptionBoxed) != exceptionType) { + release(exceptionBoxed); + throwInternalInconsistencyException( + "throwException_C called with non-exception object"); + } + Exception *ex = (Exception *)RT_unboxPtr(exceptionBoxed); + rt::LanguageException *le = (rt::LanguageException *)ex->bridgedData; + rt::LanguageException toThrow = *le; + release(exceptionBoxed); + throw toThrow; +} + +extern "C" void deleteException_C(void *exception) { + delete (rt::LanguageException *)exception; +} + } // namespace rt diff --git a/backend-v2/bridge/Exceptions.h b/backend-v2/bridge/Exceptions.h index 0acc97bd..fc0e51a1 100644 --- a/backend-v2/bridge/Exceptions.h +++ b/backend-v2/bridge/Exceptions.h @@ -110,4 +110,10 @@ extern "C" [[noreturn]] void throwNoMatchingOverloadException_C(const char *className, const char *methodName); +extern "C" String *exceptionToString_C(void *exception); +extern "C" void *createException_C(const char *className, String *message, + RTValue payload); +extern "C" [[noreturn]] void throwException_C(RTValue exceptionBoxed); +extern "C" void deleteException_C(void *exception); + #endif diff --git a/backend-v2/codegen/CodeGen.cpp b/backend-v2/codegen/CodeGen.cpp index 879745fb..896cce13 100644 --- a/backend-v2/codegen/CodeGen.cpp +++ b/backend-v2/codegen/CodeGen.cpp @@ -277,9 +277,9 @@ TypedValue CodeGen::codegen(const Node &node, return codegen(node, node.subnode().staticfield(), typeRestrictions); case opTheVar: return codegen(node, node.subnode().thevar(), typeRestrictions); - // case opThrow: - // return codegen(node, node.subnode().throw_(), typeRestrictions); - // case opTry: + case opThrow: + return this->codegen(node, static_cast(node.subnode().throw_()), typeRestrictions); + case opTry: // return codegen(node, node.subnode().try_(), typeRestrictions); case opVar: return codegen(node, node.subnode().var(), typeRestrictions); @@ -379,9 +379,9 @@ ObjectTypeSet CodeGen::getType(const Node &node, return getType(node, node.subnode().staticfield(), typeRestrictions); case opTheVar: return getType(node, node.subnode().thevar(), typeRestrictions); - // case opThrow: - // return getType(node, node.subnode().throw_(), typeRestrictions); - // case opTry: + case opThrow: + return this->getType(node, static_cast(node.subnode().throw_()), typeRestrictions); + case opTry: // return getType(node, node.subnode().try_(), typeRestrictions); case opVar: return getType(node, node.subnode().var(), typeRestrictions); @@ -492,8 +492,10 @@ bool CodeGen::canThrow(const Node &node) { case opHostInterop: return true; + case opThrow: + case opInvoke: + return true; default: - // Safer to assume it can throw if we don't know the node type return true; } } diff --git a/backend-v2/codegen/CodeGen.h b/backend-v2/codegen/CodeGen.h index f8af0dc6..29775ebb 100644 --- a/backend-v2/codegen/CodeGen.h +++ b/backend-v2/codegen/CodeGen.h @@ -142,6 +142,8 @@ class CodeGen { const ObjectTypeSet &typeRestrictions); TypedValue codegen(const Node &node, const IsInstanceNode &subnode, const ObjectTypeSet &typeRestrictions); + TypedValue codegen(const Node &node, const ThrowNode &subnode, + const ObjectTypeSet &typeRestrictions); ObjectTypeSet getType(const Node &node, const ObjectTypeSet &typeRestrictions); @@ -182,6 +184,8 @@ class CodeGen { const ObjectTypeSet &typeRestrictions); ObjectTypeSet getType(const Node &node, const IsInstanceNode &subnode, const ObjectTypeSet &typeRestrictions); + ObjectTypeSet getType(const Node &node, const ThrowNode &subnode, + const ObjectTypeSet &typeRestrictions); Var *getOrCreateVar(std::string_view name); bool canThrow(const clojure::rt::protobuf::bytecode::Node &node); diff --git a/backend-v2/codegen/ops/IfNode.cpp b/backend-v2/codegen/ops/IfNode.cpp index 790b53e3..7c088040 100644 --- a/backend-v2/codegen/ops/IfNode.cpp +++ b/backend-v2/codegen/ops/IfNode.cpp @@ -1,4 +1,5 @@ #include "../CodeGen.h" +#include using namespace std; using namespace llvm; @@ -246,9 +247,9 @@ TypedValue CodeGen::codegen(const Node &node, const IfNode &subnode, "value that does not match allowed types: ") + typeRestrictions.toString(); TypedValue msg = dynamicConstructor.createString(errMsg.c_str()); - TypedValue rawPtr = valueEncoder.unboxPointer(msg); + memoryManagement.dynamicRetain(msg); invokeManager.invokeRuntime("throwInternalInconsistencyException_C", - nullptr, {ObjectTypeSet::all()}, {rawPtr}); + nullptr, {ObjectTypeSet(stringType)}, {msg}); Builder.CreateUnreachable(); @@ -271,9 +272,9 @@ TypedValue CodeGen::codegen(const Node &node, const IfNode &subnode, "value that does not match allowed types: ") + typeRestrictions.toString(); TypedValue msg = dynamicConstructor.createString(errMsg.c_str()); - TypedValue rawPtr = valueEncoder.unboxPointer(msg); + memoryManagement.dynamicRetain(msg); invokeManager.invokeRuntime("throwInternalInconsistencyException_C", - nullptr, {ObjectTypeSet::all()}, {rawPtr}); + nullptr, {ObjectTypeSet(stringType)}, {msg}); Builder.CreateUnreachable(); diff --git a/backend-v2/codegen/ops/ThrowNode.cpp b/backend-v2/codegen/ops/ThrowNode.cpp new file mode 100644 index 00000000..48fc0721 --- /dev/null +++ b/backend-v2/codegen/ops/ThrowNode.cpp @@ -0,0 +1,34 @@ +#include "../CodeGen.h" +#include "bridge/Exceptions.h" +#include "runtime/ObjectProto.h" + +using namespace std; +using namespace llvm; + +namespace rt { + +TypedValue CodeGen::codegen(const Node &node, const ThrowNode &subnode, + const ObjectTypeSet &typeRestrictions) { + TypedValue ex = codegen(subnode.exception(), ObjectTypeSet::all().boxed()); + TypedValue boxedEx = valueEncoder.box(ex); + + if (ex.type.isDetermined() && ex.type.determinedType() != exceptionType) { + throwCodeGenerationException( + "class " + ex.type.toString() + + " cannot be cast to class java.lang.Throwable", + node); + } + + invokeManager.invokeRuntime("throwException_C", nullptr, + {ObjectTypeSet::all().boxed()}, {boxedEx}); + + // This point is unreachable because throwException_C is [[noreturn]] + return dynamicConstructor.createNil(); +} + +ObjectTypeSet CodeGen::getType(const Node &node, const ThrowNode &subnode, + const ObjectTypeSet &typeRestrictions) { + return ObjectTypeSet(nilType); +} + +} // namespace rt diff --git a/backend-v2/jit/JITEngine.cpp b/backend-v2/jit/JITEngine.cpp index c0acbfb2..9013d6d7 100644 --- a/backend-v2/jit/JITEngine.cpp +++ b/backend-v2/jit/JITEngine.cpp @@ -574,6 +574,13 @@ void JITEngine::registerRuntimeSymbols() { runtimeSymbols.insert(absoluteSymbol("JITEngine_slowPath_leave", (void *)JITEngine_slowPath_leave)); + runtimeSymbols.insert( + absoluteSymbol("exceptionToString_C", (void *)exceptionToString_C)); + runtimeSymbols.insert( + absoluteSymbol("createException_C", (void *)createException_C)); + runtimeSymbols.insert( + absoluteSymbol("deleteException_C", (void *)deleteException_C)); + cantFail(jit->getMainJITDylib().define( absoluteSymbols(std::move(runtimeSymbols)))); } diff --git a/backend-v2/runtime/CMakeLists.txt b/backend-v2/runtime/CMakeLists.txt index 61150dc8..eb40e7fd 100644 --- a/backend-v2/runtime/CMakeLists.txt +++ b/backend-v2/runtime/CMakeLists.txt @@ -37,6 +37,7 @@ set(SOURCES PersistentArrayMap.c Var.c Numbers.c + Exception.c JITSafety.c) add_library(runtime STATIC ${SOURCES}) @@ -142,6 +143,7 @@ set(TEST_MODULES Var_Race_test RefcountPerf_test Numbers_test + Exception_test ) foreach(TEST_MODULE ${TEST_MODULES}) diff --git a/backend-v2/runtime/Exception.c b/backend-v2/runtime/Exception.c new file mode 100644 index 00000000..0160e622 --- /dev/null +++ b/backend-v2/runtime/Exception.c @@ -0,0 +1,33 @@ +#include "Exception.h" +#include "Object.h" +#include "RTValue.h" +#include "String.h" +#include + +String *exceptionToString_C(void *exception); +void *createException_C(const char *className, String *message, + RTValue payload); +void deleteException_C(void *exception); + +Exception *Exception_createAssertionErrorWithMessage(String *message) { + Exception *self = (Exception *)allocate(sizeof(Exception)); + Object_create((Object *)self, exceptionType); + self->bridgedData = createException_C("AssertionError", message, RT_boxNil()); + return self; +} + +void Exception_destroy(Exception *self) { + deleteException_C(self->bridgedData); +} + +uword_t Exception_hash(Exception *self) { return (uword_t)self->bridgedData; } + +bool Exception_equals(Exception *self, Exception *other) { + return self->bridgedData == other->bridgedData; +} + +String *Exception_toString(Exception *self) { + String *retVal = exceptionToString_C(self->bridgedData); + Ptr_release(self); + return retVal; +} diff --git a/backend-v2/runtime/Exception.h b/backend-v2/runtime/Exception.h new file mode 100644 index 00000000..bf10f822 --- /dev/null +++ b/backend-v2/runtime/Exception.h @@ -0,0 +1,27 @@ +#ifndef RT_EXCEPTION_H +#define RT_EXCEPTION_H + +#include "ObjectProto.h" +#include "String.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Exception { + Object header; + void *bridgedData; +} Exception; + +Exception *Exception_createAssertionErrorWithMessage(String *message); + +void Exception_destroy(Exception *self); +uword_t Exception_hash(Exception *self); +bool Exception_equals(Exception *self, Exception *other); +String *Exception_toString(Exception *self); + +#ifdef __cplusplus +} +#endif + +#endif // RT_EXCEPTION_H diff --git a/backend-v2/runtime/Exceptions.h b/backend-v2/runtime/Exceptions.h index caccba99..0ba15584 100644 --- a/backend-v2/runtime/Exceptions.h +++ b/backend-v2/runtime/Exceptions.h @@ -6,11 +6,14 @@ #ifdef __cplusplus extern "C" { +#include "runtime/String.h" + #endif // Base throw function compatible with LanguageException [[noreturn]] void throwLanguageException_C(const char *name, RTValue message, RTValue payload); +[[noreturn]] void throwException_C(RTValue exceptionBoxed); // Standard Clojure-like exceptions [[noreturn]] void throwArityException_C(int expected, int actual); @@ -20,8 +23,7 @@ extern "C" { [[noreturn]] void throwArithmeticException_C(const char *message); [[noreturn]] void throwIndexOutOfBoundsException_C(uword_t index, uword_t count); -[[noreturn]] void -throwInternalInconsistencyException_C(const char *errorMessage); +[[noreturn]] void throwInternalInconsistencyException_C(String *errorMessage); #ifdef __cplusplus } diff --git a/backend-v2/runtime/Object.h b/backend-v2/runtime/Object.h index 3085740f..b4b6def6 100644 --- a/backend-v2/runtime/Object.h +++ b/backend-v2/runtime/Object.h @@ -105,6 +105,7 @@ inline bool Ptr_isReusable(void* ptr); #include "BigInteger.h" #include "Boolean.h" #include "Class.h" +#include "Exception.h" #include "ConcurrentHashMap.h" #include "Double.h" #include "Function.h" @@ -285,6 +286,9 @@ inline void Object_destroy(Object *restrict self, bool deallocateChildren) { case varType: Var_destroy((Var *)self); break; + case exceptionType: + Exception_destroy((Exception *)self); + break; default: break; @@ -455,6 +459,8 @@ inline uword_t Object_hash(Object *restrict self) { return PersistentArrayMap_hash((PersistentArrayMap *)self); case varType: return Var_hash((Var *)self); + case exceptionType: + return Exception_hash((Exception *)self); default: assert(false && "Internal error: hash computation for NaN tagged types " "should be computed earlier."); @@ -534,7 +540,8 @@ inline bool Object_equals(Object *self, Object *other) { case varType: return Var_equals((Var *)self, (Var *)other); break; - + case exceptionType: + return Exception_equals((Exception *)self, (Exception *)other); default: assert(false && "Internal error: hash computation for NaN tagged types " "should be computed earlier."); @@ -594,6 +601,8 @@ inline String *Object_toString(Object *restrict self) { return PersistentArrayMap_toString((PersistentArrayMap *)self); case varType: return Var_toString((Var *)self); + case exceptionType: + return Exception_toString((Exception *)self); default: assert(false && "Internal error: Object_toString got an unsupported type"); } diff --git a/backend-v2/runtime/ObjectProto.h b/backend-v2/runtime/ObjectProto.h index 4bed216d..593b5ad5 100644 --- a/backend-v2/runtime/ObjectProto.h +++ b/backend-v2/runtime/ObjectProto.h @@ -40,6 +40,7 @@ enum objectType { persistentArrayMapType, // 16 varType, // 17 objectRootType, // 18 + exceptionType, // 19 }; typedef enum objectType objectType; diff --git a/backend-v2/runtime/tests/BridgeMocks.c b/backend-v2/runtime/tests/BridgeMocks.c index b1ea1470..c58e8e0e 100644 --- a/backend-v2/runtime/tests/BridgeMocks.c +++ b/backend-v2/runtime/tests/BridgeMocks.c @@ -1,4 +1,6 @@ #include "TestTools.h" +#include "runtime/Object.h" +#include "runtime/String.h" jmp_buf exception_env; char *last_exception_name = NULL; @@ -63,10 +65,11 @@ __attribute__((weak)) void throwIndexOutOfBoundsException_C(uword_t index, abort(); } -__attribute__((weak)) void -throwInternalInconsistencyException_C(const char *errorMessage) { +__attribute__((weak)) void throwInternalInconsistencyException_C(String *msg) { handle_exception("InternalInconsistencyException"); - fprintf(stderr, "InternalInconsistencyException: %s\n", errorMessage); + String *s = String_compactify(msg); + fprintf(stderr, "InternalInconsistencyException: %s\n", String_c_str(s)); + Ptr_release(s); abort(); } @@ -90,3 +93,16 @@ __attribute__((weak)) Class *ClassLookupByRegisterId(int32_t registerId, fprintf(stderr, "Mock ClassLookup called for: %d\n", registerId); abort(); } + +__attribute__((weak)) String *exceptionToString_C(void *exception) { + return String_createStatic("Exception"); +} + +__attribute__((weak)) void * +createException_C(const char *className, String *message, RTValue payload) { + Ptr_release(message); + release(payload); + return (void *)0x1; +} + +__attribute__((weak)) void deleteException_C(void *exception) {} \ No newline at end of file diff --git a/backend-v2/runtime/tests/Exception_test.c b/backend-v2/runtime/tests/Exception_test.c new file mode 100644 index 00000000..8fb85d74 --- /dev/null +++ b/backend-v2/runtime/tests/Exception_test.c @@ -0,0 +1,38 @@ +#include "../Exception.h" +#include "../Object.h" +#include "../String.h" +#include "TestTools.h" +#include + +static void test_exception_creation(void **state) { + (void)state; + ASSERT_MEMORY_ALL_BALANCED({ + String *msg = String_createStatic("Test error message"); + Exception *exc = Exception_createAssertionErrorWithMessage(msg); + + assert_non_null(exc); + assert_int_equal(exceptionType, getType(RT_boxPtr(exc))); + assert_non_null(exc->bridgedData); + + // Test equals and hash + assert_true(equals(RT_boxPtr(exc), RT_boxPtr(exc))); + assert_int_equal(Exception_hash(exc), hash(RT_boxPtr(exc))); + + // Test toString + String *excStr = toString(RT_boxPtr(exc)); + assert_non_null(excStr); + assert_string_equal("Exception", String_c_str(excStr)); + release(RT_boxPtr(excStr)); + }); +} + +int main(void) { + initialise_memory(); + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_exception_creation), + }; + + int result = cmocka_run_group_tests(tests, NULL, NULL); + RuntimeInterface_cleanup(); + return result; +} diff --git a/backend-v2/tests/CMakeLists.txt b/backend-v2/tests/CMakeLists.txt index 6787c3fe..0ab60d4c 100644 --- a/backend-v2/tests/CMakeLists.txt +++ b/backend-v2/tests/CMakeLists.txt @@ -28,6 +28,7 @@ set(TEST_MODULES codegen/ExceptionColor_test codegen/NewNode_test codegen/IsInstanceNode_test + codegen/ThrowNode_test state/ClassRegistration_test VarUAF_repro_test JITSafety_test diff --git a/backend-v2/tests/codegen/ThrowNode_test.cpp b/backend-v2/tests/codegen/ThrowNode_test.cpp new file mode 100644 index 00000000..40e27cff --- /dev/null +++ b/backend-v2/tests/codegen/ThrowNode_test.cpp @@ -0,0 +1,99 @@ +#include "../../RuntimeHeaders.h" +#include "../../jit/JITEngine.h" +#include "../../state/ThreadsafeCompilerState.h" +#include "bytecode.pb.h" +#include +#include + +extern "C" { +#include "../../runtime/Exception.h" +#include "../../runtime/RuntimeInterface.h" +#include "../../runtime/tests/TestTools.h" +#include +} + +#include "../../bridge/Exceptions.h" + +using namespace std; +using namespace rt; +using namespace clojure::rt::protobuf::bytecode; + +static void test_throw_exception_bridge(void **state) { + (void)state; + ASSERT_MEMORY_ALL_BALANCED({ + RTValue msg = RT_boxPtr(String_createDynamicStr("test message")); + + // In our runtime, Exception objects wrap LanguageException + LanguageException *lePtr = + new LanguageException("AssertionError", msg, RT_boxNil()); + + Exception *ex = (Exception *)malloc(sizeof(Exception)); + Object_create((Object *)ex, exceptionType); + ex->bridgedData = lePtr; + + RTValue boxedEx = RT_boxPtr(ex); + + bool caught = false; + try { + throwException_C(boxedEx); + } catch (const LanguageException &e) { + caught = true; + assert_string_equal("AssertionError", e.getName().c_str()); + } catch (...) { + assert_true(false); // Should not catch other types + } + + assert_true(caught); + }); +} + +static void test_codegen_throw(void **state) { + (void)state; + ASSERT_MEMORY_ALL_BALANCED({ + rt::ThreadsafeCompilerState compState; + rt::JITEngine engine(compState); + + // (throw "error") + Node throwNode; + throwNode.set_op(opThrow); + auto *tr = throwNode.mutable_subnode()->mutable_throw_(); + + auto *ex = tr->mutable_exception(); + ex->set_op(opConst); + ex->mutable_subnode()->mutable_const_()->set_type( + ConstNode_ConstType_constTypeString); + ex->mutable_subnode()->mutable_const_()->set_val("error"); + + bool caught = false; + try { + // We expect this to throw an "InternalInconsistencyException" (as a + // LanguageException) because "error" is a String, not an Exception + // object. + auto resThrow = engine + .compileAST(throwNode, "__test_codegen_throw", + llvm::OptimizationLevel::O0, false) + .get() + .address; + + resThrow.toPtr()(); + } catch (const LanguageException &e) { + caught = true; + assert_string_equal("CodeGenerationException", e.getName().c_str()); + } catch (...) { + caught = true; + } + assert_true(caught); + }); +} + +int main(void) { + initialise_memory(); + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_throw_exception_bridge), + cmocka_unit_test(test_codegen_throw), + }; + + int result = cmocka_run_group_tests(tests, NULL, NULL); + RuntimeInterface_cleanup(); + return result; +} diff --git a/backend-v2/types/ObjectTypeSet.h b/backend-v2/types/ObjectTypeSet.h index 98c88c7c..5cc0e0c0 100644 --- a/backend-v2/types/ObjectTypeSet.h +++ b/backend-v2/types/ObjectTypeSet.h @@ -3,8 +3,8 @@ #include "../runtime/ObjectProto.h" #include "../runtime/defines.h" -#include #include +#include #include #include @@ -56,7 +56,8 @@ class ObjectTypeSet { } ObjectTypeSet(const ObjectTypeSet &other) - : internal(other.internal), isBoxed(other.isBoxed), allTypes(other.allTypes) { + : internal(other.internal), isBoxed(other.isBoxed), + allTypes(other.allTypes) { if (other.constant) constant = other.constant->copy(); else @@ -253,6 +254,7 @@ class ObjectTypeSet { retVal.insert(persistentArrayMapType); retVal.insert(varType); retVal.insert(objectRootType); + retVal.insert(exceptionType); retVal.allTypes = true; retVal.isBoxed = true; return retVal; @@ -309,6 +311,8 @@ class ObjectTypeSet { return "LQ"; case objectRootType: return "LO"; + case exceptionType: + return "LE"; default: return "LR"; } @@ -373,6 +377,8 @@ class ObjectTypeSet { return ":var"; case objectRootType: return ":any"; + case exceptionType: + return ":exception"; default: return ":custom(" + std::to_string(type) + ")"; } diff --git a/compile.sh b/compile.sh index 4ef1d6d7..4780b483 100755 --- a/compile.sh +++ b/compile.sh @@ -49,7 +49,7 @@ else fi mv $BINARY ../$BACKEND cd ../$BACKEND -make -j 8 +make -j 8 clojure-rt echo "Executing..." # lldb ./clojure-rt ./clojure-rt $BINARY diff --git a/frontend/resources/rt-classes.edn b/frontend/resources/rt-classes.edn index 4f7f60dc..e20202ef 100644 --- a/frontend/resources/rt-classes.edn +++ b/frontend/resources/rt-classes.edn @@ -8,6 +8,13 @@ {:object-type 15 :extends java.lang.Object} + +;; Assertion error is here just to enable assert. + java.lang.AssertionError + {:object-type 19 + :extends java.lang.Object + :constructor [{:args [java.lang.String] :type :call :symbol "Exception_createAssertionErrorWithMessage"}]} + java.lang.Nil {:object-type 3 :extends java.lang.Object}