70 public ExceptionHandlerStub(OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { 71 super("exceptionHandler", options, providers, linkage); 72 } 73 74 /** 75 * This stub is called when returning to a method to handle an exception thrown by a callee. It 76 * is not used for routing implicit exceptions. Therefore, it does not need to save any 77 * registers as HotSpot uses a caller save convention. 78 */ 79 @Override 80 public boolean preservesRegisters() { 81 return false; 82 } 83 84 @Override 85 protected Object getConstantParameterValue(int index, String name) { 86 if (index == 2) { 87 return providers.getRegisters().getThreadRegister(); 88 } 89 assert index == 3; 90 return options; 91 } 92 93 @Snippet 94 private static void exceptionHandler(Object exception, Word exceptionPc, @ConstantParameter Register threadRegister, @ConstantParameter OptionValues options) { 95 Word thread = registerAsWord(threadRegister); 96 checkNoExceptionInThread(thread, assertionsEnabled(INJECTED_VMCONFIG)); 97 checkExceptionNotNull(assertionsEnabled(INJECTED_VMCONFIG), exception); 98 writeExceptionOop(thread, exception); 99 writeExceptionPc(thread, exceptionPc); 100 if (logging(options)) { 101 printf("handling exception %p (", Word.objectToTrackedPointer(exception).rawValue()); 102 decipher(Word.objectToTrackedPointer(exception).rawValue()); 103 printf(") at %p (", exceptionPc.rawValue()); 104 decipher(exceptionPc.rawValue()); 105 printf(")\n"); 106 } 107 108 // patch throwing pc into return address so that deoptimization finds the right debug info 109 patchReturnAddress(exceptionPc); 110 111 Word handlerPc = exceptionHandlerForPc(EXCEPTION_HANDLER_FOR_PC, thread); 112 113 if (logging(options)) { 114 printf("handler for exception %p at %p is at %p (", Word.objectToTrackedPointer(exception).rawValue(), exceptionPc.rawValue(), handlerPc.rawValue()); 115 decipher(handlerPc.rawValue()); 116 printf(")\n"); 117 } 118 119 // patch the return address so that this stub returns to the exception handler 120 jumpToExceptionHandler(handlerPc); 121 } 122 123 static void checkNoExceptionInThread(Word thread, boolean enabled) { 124 if (enabled) { 125 Object currentException = readExceptionOop(thread); 126 if (currentException != null) { 127 fatal("exception object in thread must be null, not %p", Word.objectToTrackedPointer(currentException).rawValue()); 128 } 129 if (cAssertionsEnabled(INJECTED_VMCONFIG)) { 130 // This thread-local is only cleared in DEBUG builds of the VM 131 // (see OptoRuntime::generate_exception_blob) 132 Word currentExceptionPc = readExceptionPc(thread); 133 if (currentExceptionPc.notEqual(WordFactory.zero())) { 134 fatal("exception PC in thread must be zero, not %p", currentExceptionPc.rawValue()); 135 } 136 } 137 } 138 } 139 140 static void checkExceptionNotNull(boolean enabled, Object exception) { 141 if (enabled && exception == null) { 142 fatal("exception must not be null"); 143 } 144 } 145 146 @Fold 147 static boolean logging(OptionValues options) { 148 return StubOptions.TraceExceptionHandlerStub.getValue(options); 149 } 150 151 /** 152 * Determines if either Java assertions are enabled for Graal or if this is a HotSpot build 153 * where the ASSERT mechanism is enabled. 154 */ 155 @Fold 156 @SuppressWarnings("all") 157 static boolean assertionsEnabled(@InjectedParameter GraalHotSpotVMConfig config) { 158 return Assertions.assertionsEnabled() || cAssertionsEnabled(config); 159 } 160 161 public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = newDescriptor(ExceptionHandlerStub.class, "exceptionHandlerForPc", Word.class, Word.class); 162 163 @NodeIntrinsic(value = StubForeignCallNode.class) 164 public static native Word exceptionHandlerForPc(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForPc, Word thread); 165 } | 70 public ExceptionHandlerStub(OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { 71 super("exceptionHandler", options, providers, linkage); 72 } 73 74 /** 75 * This stub is called when returning to a method to handle an exception thrown by a callee. It 76 * is not used for routing implicit exceptions. Therefore, it does not need to save any 77 * registers as HotSpot uses a caller save convention. 78 */ 79 @Override 80 public boolean preservesRegisters() { 81 return false; 82 } 83 84 @Override 85 protected Object getConstantParameterValue(int index, String name) { 86 if (index == 2) { 87 return providers.getRegisters().getThreadRegister(); 88 } 89 assert index == 3; 90 return StubOptions.TraceExceptionHandlerStub.getValue(options); 91 } 92 93 @Snippet 94 private static void exceptionHandler(Object exception, Word exceptionPc, @ConstantParameter Register threadRegister, @ConstantParameter boolean logging) { 95 Word thread = registerAsWord(threadRegister); 96 checkNoExceptionInThread(thread, assertionsEnabled(INJECTED_VMCONFIG)); 97 checkExceptionNotNull(assertionsEnabled(INJECTED_VMCONFIG), exception); 98 writeExceptionOop(thread, exception); 99 writeExceptionPc(thread, exceptionPc); 100 if (logging) { 101 printf("handling exception %p (", Word.objectToTrackedPointer(exception).rawValue()); 102 decipher(Word.objectToTrackedPointer(exception).rawValue()); 103 printf(") at %p (", exceptionPc.rawValue()); 104 decipher(exceptionPc.rawValue()); 105 printf(")\n"); 106 } 107 108 // patch throwing pc into return address so that deoptimization finds the right debug info 109 patchReturnAddress(exceptionPc); 110 111 Word handlerPc = exceptionHandlerForPc(EXCEPTION_HANDLER_FOR_PC, thread); 112 113 if (logging) { 114 printf("handler for exception %p at %p is at %p (", Word.objectToTrackedPointer(exception).rawValue(), exceptionPc.rawValue(), handlerPc.rawValue()); 115 decipher(handlerPc.rawValue()); 116 printf(")\n"); 117 } 118 119 // patch the return address so that this stub returns to the exception handler 120 jumpToExceptionHandler(handlerPc); 121 } 122 123 static void checkNoExceptionInThread(Word thread, boolean enabled) { 124 if (enabled) { 125 Object currentException = readExceptionOop(thread); 126 if (currentException != null) { 127 fatal("exception object in thread must be null, not %p", Word.objectToTrackedPointer(currentException).rawValue()); 128 } 129 if (cAssertionsEnabled(INJECTED_VMCONFIG)) { 130 // This thread-local is only cleared in DEBUG builds of the VM 131 // (see OptoRuntime::generate_exception_blob) 132 Word currentExceptionPc = readExceptionPc(thread); 133 if (currentExceptionPc.notEqual(WordFactory.zero())) { 134 fatal("exception PC in thread must be zero, not %p", currentExceptionPc.rawValue()); 135 } 136 } 137 } 138 } 139 140 static void checkExceptionNotNull(boolean enabled, Object exception) { 141 if (enabled && exception == null) { 142 fatal("exception must not be null"); 143 } 144 } 145 146 /** 147 * Determines if either Java assertions are enabled for Graal or if this is a HotSpot build 148 * where the ASSERT mechanism is enabled. 149 */ 150 @Fold 151 @SuppressWarnings("all") 152 static boolean assertionsEnabled(@InjectedParameter GraalHotSpotVMConfig config) { 153 return Assertions.assertionsEnabled() || cAssertionsEnabled(config); 154 } 155 156 public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = newDescriptor(ExceptionHandlerStub.class, "exceptionHandlerForPc", Word.class, Word.class); 157 158 @NodeIntrinsic(value = StubForeignCallNode.class) 159 public static native Word exceptionHandlerForPc(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForPc, Word thread); 160 } |