001/* 002 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.hotspot.stubs; 024 025import jdk.internal.jvmci.code.*; 026import jdk.internal.jvmci.hotspot.*; 027import static com.oracle.graal.hotspot.nodes.JumpToExceptionHandlerNode.*; 028import static com.oracle.graal.hotspot.nodes.PatchReturnAddressNode.*; 029import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; 030import static com.oracle.graal.hotspot.stubs.StubUtil.*; 031 032import com.oracle.graal.api.replacements.*; 033import com.oracle.graal.compiler.common.spi.*; 034import com.oracle.graal.graph.Node.ConstantNodeParameter; 035import com.oracle.graal.graph.Node.NodeIntrinsic; 036import com.oracle.graal.hotspot.*; 037import com.oracle.graal.hotspot.meta.*; 038import com.oracle.graal.hotspot.nodes.*; 039import com.oracle.graal.replacements.*; 040import com.oracle.graal.replacements.Snippet.ConstantParameter; 041import com.oracle.graal.word.*; 042 043/** 044 * Stub called by the {@linkplain HotSpotVMConfig#MARKID_EXCEPTION_HANDLER_ENTRY exception handler 045 * entry point} in a compiled method. This entry point is used when returning to a method to handle 046 * an exception thrown by a callee. It is not used for routing implicit exceptions. Therefore, it 047 * does not need to save any registers as HotSpot uses a caller save convention. 048 * <p> 049 * The descriptor for a call to this stub is {@link HotSpotBackend#EXCEPTION_HANDLER}. 050 */ 051public class ExceptionHandlerStub extends SnippetStub { 052 053 public ExceptionHandlerStub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { 054 super("exceptionHandler", providers, linkage); 055 } 056 057 /** 058 * This stub is called when returning to a method to handle an exception thrown by a callee. It 059 * is not used for routing implicit exceptions. Therefore, it does not need to save any 060 * registers as HotSpot uses a caller save convention. 061 */ 062 @Override 063 public boolean preservesRegisters() { 064 return false; 065 } 066 067 @Override 068 protected Object getConstantParameterValue(int index, String name) { 069 assert index == 2; 070 return providers.getRegisters().getThreadRegister(); 071 } 072 073 @Snippet 074 private static void exceptionHandler(Object exception, Word exceptionPc, @ConstantParameter Register threadRegister) { 075 Word thread = registerAsWord(threadRegister); 076 checkNoExceptionInThread(thread, assertionsEnabled()); 077 checkExceptionNotNull(assertionsEnabled(), exception); 078 writeExceptionOop(thread, exception); 079 writeExceptionPc(thread, exceptionPc); 080 if (logging()) { 081 printf("handling exception %p (", Word.fromObject(exception).rawValue()); 082 decipher(Word.fromObject(exception).rawValue()); 083 printf(") at %p (", exceptionPc.rawValue()); 084 decipher(exceptionPc.rawValue()); 085 printf(")\n"); 086 } 087 088 // patch throwing pc into return address so that deoptimization finds the right debug info 089 patchReturnAddress(exceptionPc); 090 091 Word handlerPc = exceptionHandlerForPc(EXCEPTION_HANDLER_FOR_PC, thread); 092 093 if (logging()) { 094 printf("handler for exception %p at %p is at %p (", Word.fromObject(exception).rawValue(), exceptionPc.rawValue(), handlerPc.rawValue()); 095 decipher(handlerPc.rawValue()); 096 printf(")\n"); 097 } 098 099 // patch the return address so that this stub returns to the exception handler 100 jumpToExceptionHandler(handlerPc); 101 } 102 103 static void checkNoExceptionInThread(Word thread, boolean enabled) { 104 if (enabled) { 105 Object currentException = readExceptionOop(thread); 106 if (currentException != null) { 107 fatal("exception object in thread must be null, not %p", Word.fromObject(currentException).rawValue()); 108 } 109 if (cAssertionsEnabled()) { 110 // This thread-local is only cleared in DEBUG builds of the VM 111 // (see OptoRuntime::generate_exception_blob) 112 Word currentExceptionPc = readExceptionPc(thread); 113 if (currentExceptionPc.notEqual(Word.zero())) { 114 fatal("exception PC in thread must be zero, not %p", currentExceptionPc.rawValue()); 115 } 116 } 117 } 118 } 119 120 static void checkExceptionNotNull(boolean enabled, Object exception) { 121 if (enabled && exception == null) { 122 fatal("exception must not be null"); 123 } 124 } 125 126 @Fold 127 private static boolean logging() { 128 return Boolean.getBoolean("graal.logExceptionHandlerStub"); 129 } 130 131 /** 132 * Determines if either Java assertions are enabled for {@link ExceptionHandlerStub} or if this 133 * is a HotSpot build where the ASSERT mechanism is enabled. 134 * <p> 135 * This first check relies on the per-class assertion status which is why this method must be in 136 * this class. 137 */ 138 @Fold 139 @SuppressWarnings("all") 140 private static boolean assertionsEnabled() { 141 boolean enabled = false; 142 assert enabled = true; 143 return enabled || cAssertionsEnabled(); 144 } 145 146 public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = newDescriptor(ExceptionHandlerStub.class, "exceptionHandlerForPc", Word.class, Word.class); 147 148 @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true) 149 public static native Word exceptionHandlerForPc(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForPc, Word thread); 150}