Wed, 27 Nov 2013 16:16:21 -0800
8029015: PPC64 (part 216): opto: trap based null and range checks
Summary: On PPC64 use tdi instruction that does a compare and raises SIGTRAP for NULL and range checks.
Reviewed-by: kvn
goetz@6458 | 1 | /* |
goetz@6458 | 2 | * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. |
goetz@6458 | 3 | * Copyright 2012, 2013 SAP AG. All rights reserved. |
goetz@6458 | 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
goetz@6458 | 5 | * |
goetz@6458 | 6 | * This code is free software; you can redistribute it and/or modify it |
goetz@6458 | 7 | * under the terms of the GNU General Public License version 2 only, as |
goetz@6458 | 8 | * published by the Free Software Foundation. |
goetz@6458 | 9 | * |
goetz@6458 | 10 | * This code is distributed in the hope that it will be useful, but WITHOUT |
goetz@6458 | 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
goetz@6458 | 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
goetz@6458 | 13 | * version 2 for more details (a copy is included in the LICENSE file that |
goetz@6458 | 14 | * accompanied this code). |
goetz@6458 | 15 | * |
goetz@6458 | 16 | * You should have received a copy of the GNU General Public License version |
goetz@6458 | 17 | * 2 along with this work; if not, write to the Free Software Foundation, |
goetz@6458 | 18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
goetz@6458 | 19 | * |
goetz@6458 | 20 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
goetz@6458 | 21 | * or visit www.oracle.com if you need additional information or have any |
goetz@6458 | 22 | * questions. |
goetz@6458 | 23 | * |
goetz@6458 | 24 | */ |
goetz@6458 | 25 | |
goetz@6458 | 26 | #include "precompiled.hpp" |
goetz@6458 | 27 | #include "interpreter/interpreter.hpp" |
goetz@6458 | 28 | #include "memory/resourceArea.hpp" |
goetz@6458 | 29 | #include "oops/markOop.hpp" |
goetz@6458 | 30 | #include "oops/method.hpp" |
goetz@6458 | 31 | #include "oops/oop.inline.hpp" |
goetz@6458 | 32 | #include "runtime/frame.inline.hpp" |
goetz@6458 | 33 | #include "runtime/handles.inline.hpp" |
goetz@6458 | 34 | #include "runtime/javaCalls.hpp" |
goetz@6458 | 35 | #include "runtime/monitorChunk.hpp" |
goetz@6458 | 36 | #include "runtime/signature.hpp" |
goetz@6458 | 37 | #include "runtime/stubCodeGenerator.hpp" |
goetz@6458 | 38 | #include "runtime/stubRoutines.hpp" |
goetz@6458 | 39 | #include "vmreg_ppc.inline.hpp" |
goetz@6458 | 40 | #ifdef COMPILER1 |
goetz@6458 | 41 | #include "c1/c1_Runtime1.hpp" |
goetz@6458 | 42 | #include "runtime/vframeArray.hpp" |
goetz@6458 | 43 | #endif |
goetz@6458 | 44 | |
goetz@6458 | 45 | #ifndef CC_INTERP |
goetz@6458 | 46 | #error "CC_INTERP must be defined on PPC64" |
goetz@6458 | 47 | #endif |
goetz@6458 | 48 | |
goetz@6458 | 49 | #ifdef ASSERT |
goetz@6458 | 50 | void RegisterMap::check_location_valid() { |
goetz@6458 | 51 | } |
goetz@6458 | 52 | #endif // ASSERT |
goetz@6458 | 53 | |
goetz@6458 | 54 | bool frame::safe_for_sender(JavaThread *thread) { |
goetz@6458 | 55 | bool safe = false; |
goetz@6458 | 56 | address cursp = (address)sp(); |
goetz@6458 | 57 | address curfp = (address)fp(); |
goetz@6458 | 58 | if ((cursp != NULL && curfp != NULL && |
goetz@6458 | 59 | (cursp <= thread->stack_base() && cursp >= thread->stack_base() - thread->stack_size())) && |
goetz@6458 | 60 | (curfp <= thread->stack_base() && curfp >= thread->stack_base() - thread->stack_size())) { |
goetz@6458 | 61 | safe = true; |
goetz@6458 | 62 | } |
goetz@6458 | 63 | return safe; |
goetz@6458 | 64 | } |
goetz@6458 | 65 | |
goetz@6458 | 66 | bool frame::is_interpreted_frame() const { |
goetz@6458 | 67 | return Interpreter::contains(pc()); |
goetz@6458 | 68 | } |
goetz@6458 | 69 | |
goetz@6458 | 70 | frame frame::sender_for_entry_frame(RegisterMap *map) const { |
goetz@6458 | 71 | assert(map != NULL, "map must be set"); |
goetz@6458 | 72 | // Java frame called from C; skip all C frames and return top C |
goetz@6458 | 73 | // frame of that chunk as the sender. |
goetz@6458 | 74 | JavaFrameAnchor* jfa = entry_frame_call_wrapper()->anchor(); |
goetz@6458 | 75 | assert(!entry_frame_is_first(), "next Java fp must be non zero"); |
goetz@6458 | 76 | assert(jfa->last_Java_sp() > _sp, "must be above this frame on stack"); |
goetz@6458 | 77 | map->clear(); |
goetz@6458 | 78 | assert(map->include_argument_oops(), "should be set by clear"); |
goetz@6458 | 79 | |
goetz@6458 | 80 | if (jfa->last_Java_pc() != NULL) { |
goetz@6458 | 81 | frame fr(jfa->last_Java_sp(), jfa->last_Java_pc()); |
goetz@6458 | 82 | return fr; |
goetz@6458 | 83 | } |
goetz@6458 | 84 | // Last_java_pc is not set, if we come here from compiled code. The |
goetz@6458 | 85 | // constructor retrieves the PC from the stack. |
goetz@6458 | 86 | frame fr(jfa->last_Java_sp()); |
goetz@6458 | 87 | return fr; |
goetz@6458 | 88 | } |
goetz@6458 | 89 | |
goetz@6458 | 90 | frame frame::sender_for_interpreter_frame(RegisterMap *map) const { |
goetz@6458 | 91 | // Pass callers initial_caller_sp as unextended_sp. |
goetz@6458 | 92 | return frame(sender_sp(), sender_pc(), (intptr_t*)((parent_ijava_frame_abi *)callers_abi())->initial_caller_sp); |
goetz@6458 | 93 | } |
goetz@6458 | 94 | |
goetz@6458 | 95 | frame frame::sender_for_compiled_frame(RegisterMap *map) const { |
goetz@6458 | 96 | assert(map != NULL, "map must be set"); |
goetz@6458 | 97 | |
goetz@6458 | 98 | // Frame owned by compiler. |
goetz@6458 | 99 | address pc = *compiled_sender_pc_addr(_cb); |
goetz@6458 | 100 | frame caller(compiled_sender_sp(_cb), pc); |
goetz@6458 | 101 | |
goetz@6458 | 102 | // Now adjust the map. |
goetz@6458 | 103 | |
goetz@6458 | 104 | // Get the rest. |
goetz@6458 | 105 | if (map->update_map()) { |
goetz@6458 | 106 | // Tell GC to use argument oopmaps for some runtime stubs that need it. |
goetz@6458 | 107 | map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread())); |
goetz@6458 | 108 | if (_cb->oop_maps() != NULL) { |
goetz@6458 | 109 | OopMapSet::update_register_map(this, map); |
goetz@6458 | 110 | } |
goetz@6458 | 111 | } |
goetz@6458 | 112 | |
goetz@6458 | 113 | return caller; |
goetz@6458 | 114 | } |
goetz@6458 | 115 | |
goetz@6458 | 116 | intptr_t* frame::compiled_sender_sp(CodeBlob* cb) const { |
goetz@6458 | 117 | return sender_sp(); |
goetz@6458 | 118 | } |
goetz@6458 | 119 | |
goetz@6458 | 120 | address* frame::compiled_sender_pc_addr(CodeBlob* cb) const { |
goetz@6458 | 121 | return sender_pc_addr(); |
goetz@6458 | 122 | } |
goetz@6458 | 123 | |
goetz@6458 | 124 | frame frame::sender(RegisterMap* map) const { |
goetz@6458 | 125 | // Default is we do have to follow them. The sender_for_xxx will |
goetz@6458 | 126 | // update it accordingly. |
goetz@6458 | 127 | map->set_include_argument_oops(false); |
goetz@6458 | 128 | |
goetz@6458 | 129 | if (is_entry_frame()) return sender_for_entry_frame(map); |
goetz@6458 | 130 | if (is_interpreted_frame()) return sender_for_interpreter_frame(map); |
goetz@6458 | 131 | assert(_cb == CodeCache::find_blob(pc()),"Must be the same"); |
goetz@6458 | 132 | |
goetz@6458 | 133 | if (_cb != NULL) { |
goetz@6458 | 134 | return sender_for_compiled_frame(map); |
goetz@6458 | 135 | } |
goetz@6458 | 136 | // Must be native-compiled frame, i.e. the marshaling code for native |
goetz@6458 | 137 | // methods that exists in the core system. |
goetz@6458 | 138 | return frame(sender_sp(), sender_pc()); |
goetz@6458 | 139 | } |
goetz@6458 | 140 | |
goetz@6458 | 141 | void frame::patch_pc(Thread* thread, address pc) { |
goetz@6458 | 142 | if (TracePcPatching) { |
goetz@6458 | 143 | tty->print_cr("patch_pc at address " PTR_FORMAT " [" PTR_FORMAT " -> " PTR_FORMAT "]", |
goetz@6458 | 144 | &((address*) _sp)[-1], ((address*) _sp)[-1], pc); |
goetz@6458 | 145 | } |
goetz@6458 | 146 | own_abi()->lr = (uint64_t)pc; |
goetz@6458 | 147 | _cb = CodeCache::find_blob(pc); |
goetz@6458 | 148 | if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) { |
goetz@6458 | 149 | address orig = (((nmethod*)_cb)->get_original_pc(this)); |
goetz@6458 | 150 | assert(orig == _pc, "expected original to be stored before patching"); |
goetz@6458 | 151 | _deopt_state = is_deoptimized; |
goetz@6458 | 152 | // Leave _pc as is. |
goetz@6458 | 153 | } else { |
goetz@6458 | 154 | _deopt_state = not_deoptimized; |
goetz@6458 | 155 | _pc = pc; |
goetz@6458 | 156 | } |
goetz@6458 | 157 | } |
goetz@6458 | 158 | |
goetz@6458 | 159 | void frame::pd_gc_epilog() { |
goetz@6458 | 160 | if (is_interpreted_frame()) { |
goetz@6458 | 161 | // Set constant pool cache entry for interpreter. |
goetz@6458 | 162 | Method* m = interpreter_frame_method(); |
goetz@6458 | 163 | |
goetz@6458 | 164 | *interpreter_frame_cpoolcache_addr() = m->constants()->cache(); |
goetz@6458 | 165 | } |
goetz@6458 | 166 | } |
goetz@6458 | 167 | |
goetz@6458 | 168 | bool frame::is_interpreted_frame_valid(JavaThread* thread) const { |
goetz@6458 | 169 | // Is there anything to do? |
goetz@6458 | 170 | assert(is_interpreted_frame(), "Not an interpreted frame"); |
goetz@6458 | 171 | return true; |
goetz@6458 | 172 | } |
goetz@6458 | 173 | |
goetz@6458 | 174 | BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) { |
goetz@6458 | 175 | assert(is_interpreted_frame(), "interpreted frame expected"); |
goetz@6458 | 176 | Method* method = interpreter_frame_method(); |
goetz@6458 | 177 | BasicType type = method->result_type(); |
goetz@6458 | 178 | |
goetz@6458 | 179 | #ifdef CC_INTERP |
goetz@6458 | 180 | if (method->is_native()) { |
goetz@6458 | 181 | // Prior to calling into the runtime to notify the method exit the possible |
goetz@6458 | 182 | // result value is saved into the interpreter frame. |
goetz@6458 | 183 | interpreterState istate = get_interpreterState(); |
goetz@6458 | 184 | address lresult = (address)istate + in_bytes(BytecodeInterpreter::native_lresult_offset()); |
goetz@6458 | 185 | address fresult = (address)istate + in_bytes(BytecodeInterpreter::native_fresult_offset()); |
goetz@6458 | 186 | |
goetz@6458 | 187 | switch (method->result_type()) { |
goetz@6458 | 188 | case T_OBJECT: |
goetz@6458 | 189 | case T_ARRAY: { |
goetz@6458 | 190 | oop* obj_p = *(oop**)lresult; |
simonis@6483 | 191 | oop obj = (obj_p == NULL) ? (oop)NULL : *obj_p; |
goetz@6458 | 192 | assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check"); |
goetz@6458 | 193 | *oop_result = obj; |
goetz@6458 | 194 | break; |
goetz@6458 | 195 | } |
goetz@6458 | 196 | // We use std/stfd to store the values. |
goetz@6458 | 197 | case T_BOOLEAN : value_result->z = (jboolean) *(unsigned long*)lresult; break; |
goetz@6458 | 198 | case T_INT : value_result->i = (jint) *(long*)lresult; break; |
goetz@6458 | 199 | case T_CHAR : value_result->c = (jchar) *(unsigned long*)lresult; break; |
goetz@6458 | 200 | case T_SHORT : value_result->s = (jshort) *(long*)lresult; break; |
goetz@6458 | 201 | case T_BYTE : value_result->z = (jbyte) *(long*)lresult; break; |
goetz@6458 | 202 | case T_LONG : value_result->j = (jlong) *(long*)lresult; break; |
goetz@6458 | 203 | case T_FLOAT : value_result->f = (jfloat) *(double*)fresult; break; |
goetz@6458 | 204 | case T_DOUBLE : value_result->d = (jdouble) *(double*)fresult; break; |
goetz@6458 | 205 | case T_VOID : /* Nothing to do */ break; |
goetz@6458 | 206 | default : ShouldNotReachHere(); |
goetz@6458 | 207 | } |
goetz@6458 | 208 | } else { |
goetz@6458 | 209 | intptr_t* tos_addr = interpreter_frame_tos_address(); |
goetz@6458 | 210 | switch (method->result_type()) { |
goetz@6458 | 211 | case T_OBJECT: |
goetz@6458 | 212 | case T_ARRAY: { |
goetz@6458 | 213 | oop obj = *(oop*)tos_addr; |
goetz@6458 | 214 | assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check"); |
goetz@6458 | 215 | *oop_result = obj; |
goetz@6458 | 216 | } |
goetz@6458 | 217 | case T_BOOLEAN : value_result->z = (jboolean) *(jint*)tos_addr; break; |
goetz@6458 | 218 | case T_BYTE : value_result->b = (jbyte) *(jint*)tos_addr; break; |
goetz@6458 | 219 | case T_CHAR : value_result->c = (jchar) *(jint*)tos_addr; break; |
goetz@6458 | 220 | case T_SHORT : value_result->s = (jshort) *(jint*)tos_addr; break; |
goetz@6458 | 221 | case T_INT : value_result->i = *(jint*)tos_addr; break; |
goetz@6458 | 222 | case T_LONG : value_result->j = *(jlong*)tos_addr; break; |
goetz@6458 | 223 | case T_FLOAT : value_result->f = *(jfloat*)tos_addr; break; |
goetz@6458 | 224 | case T_DOUBLE : value_result->d = *(jdouble*)tos_addr; break; |
goetz@6458 | 225 | case T_VOID : /* Nothing to do */ break; |
goetz@6458 | 226 | default : ShouldNotReachHere(); |
goetz@6458 | 227 | } |
goetz@6458 | 228 | } |
goetz@6458 | 229 | #else |
goetz@6458 | 230 | Unimplemented(); |
goetz@6458 | 231 | #endif |
goetz@6458 | 232 | return type; |
goetz@6458 | 233 | } |
goetz@6458 | 234 | |
goetz@6458 | 235 | #ifndef PRODUCT |
goetz@6458 | 236 | |
goetz@6458 | 237 | void frame::describe_pd(FrameValues& values, int frame_no) { |
goetz@6458 | 238 | if (is_interpreted_frame()) { |
goetz@6458 | 239 | #ifdef CC_INTERP |
goetz@6458 | 240 | interpreterState istate = get_interpreterState(); |
goetz@6458 | 241 | values.describe(frame_no, (intptr_t*)istate, "istate"); |
goetz@6458 | 242 | values.describe(frame_no, (intptr_t*)&(istate->_thread), " thread"); |
goetz@6458 | 243 | values.describe(frame_no, (intptr_t*)&(istate->_bcp), " bcp"); |
goetz@6458 | 244 | values.describe(frame_no, (intptr_t*)&(istate->_locals), " locals"); |
goetz@6458 | 245 | values.describe(frame_no, (intptr_t*)&(istate->_constants), " constants"); |
goetz@6458 | 246 | values.describe(frame_no, (intptr_t*)&(istate->_method), err_msg(" method = %s", istate->_method->name_and_sig_as_C_string())); |
goetz@6458 | 247 | values.describe(frame_no, (intptr_t*)&(istate->_mdx), " mdx"); |
goetz@6458 | 248 | values.describe(frame_no, (intptr_t*)&(istate->_stack), " stack"); |
goetz@6458 | 249 | values.describe(frame_no, (intptr_t*)&(istate->_msg), err_msg(" msg = %s", BytecodeInterpreter::C_msg(istate->_msg))); |
goetz@6458 | 250 | values.describe(frame_no, (intptr_t*)&(istate->_result), " result"); |
goetz@6458 | 251 | values.describe(frame_no, (intptr_t*)&(istate->_prev_link), " prev_link"); |
goetz@6458 | 252 | values.describe(frame_no, (intptr_t*)&(istate->_oop_temp), " oop_temp"); |
goetz@6458 | 253 | values.describe(frame_no, (intptr_t*)&(istate->_stack_base), " stack_base"); |
goetz@6458 | 254 | values.describe(frame_no, (intptr_t*)&(istate->_stack_limit), " stack_limit"); |
goetz@6458 | 255 | values.describe(frame_no, (intptr_t*)&(istate->_monitor_base), " monitor_base"); |
goetz@6458 | 256 | values.describe(frame_no, (intptr_t*)&(istate->_frame_bottom), " frame_bottom"); |
goetz@6458 | 257 | values.describe(frame_no, (intptr_t*)&(istate->_last_Java_pc), " last_Java_pc"); |
goetz@6458 | 258 | values.describe(frame_no, (intptr_t*)&(istate->_last_Java_fp), " last_Java_fp"); |
goetz@6458 | 259 | values.describe(frame_no, (intptr_t*)&(istate->_last_Java_sp), " last_Java_sp"); |
goetz@6458 | 260 | values.describe(frame_no, (intptr_t*)&(istate->_self_link), " self_link"); |
goetz@6458 | 261 | values.describe(frame_no, (intptr_t*)&(istate->_native_fresult), " native_fresult"); |
goetz@6458 | 262 | values.describe(frame_no, (intptr_t*)&(istate->_native_lresult), " native_lresult"); |
goetz@6458 | 263 | #else |
goetz@6458 | 264 | Unimplemented(); |
goetz@6458 | 265 | #endif |
goetz@6458 | 266 | } |
goetz@6458 | 267 | } |
goetz@6458 | 268 | #endif |
goetz@6458 | 269 | |
goetz@6458 | 270 | void frame::adjust_unextended_sp() { |
goetz@6458 | 271 | // If we are returning to a compiled MethodHandle call site, the |
goetz@6458 | 272 | // saved_fp will in fact be a saved value of the unextended SP. The |
goetz@6458 | 273 | // simplest way to tell whether we are returning to such a call site |
goetz@6458 | 274 | // is as follows: |
goetz@6458 | 275 | |
goetz@6458 | 276 | if (is_compiled_frame() && false /*is_at_mh_callsite()*/) { // TODO PPC port |
goetz@6458 | 277 | // If the sender PC is a deoptimization point, get the original |
goetz@6458 | 278 | // PC. For MethodHandle call site the unextended_sp is stored in |
goetz@6458 | 279 | // saved_fp. |
goetz@6458 | 280 | _unextended_sp = _fp - _cb->frame_size(); |
goetz@6458 | 281 | |
goetz@6458 | 282 | #ifdef ASSERT |
goetz@6458 | 283 | nmethod *sender_nm = _cb->as_nmethod_or_null(); |
goetz@6458 | 284 | assert(sender_nm && *_sp == *_unextended_sp, "backlink changed"); |
goetz@6458 | 285 | |
goetz@6458 | 286 | intptr_t* sp = _unextended_sp; // check if stack can be walked from here |
goetz@6458 | 287 | for (int x = 0; x < 5; ++x) { // check up to a couple of backlinks |
goetz@6458 | 288 | intptr_t* prev_sp = *(intptr_t**)sp; |
goetz@6458 | 289 | if (prev_sp == 0) break; // end of stack |
goetz@6458 | 290 | assert(prev_sp>sp, "broken stack"); |
goetz@6458 | 291 | sp = prev_sp; |
goetz@6458 | 292 | } |
goetz@6458 | 293 | |
goetz@6458 | 294 | if (sender_nm->is_deopt_mh_entry(_pc)) { // checks for deoptimization |
goetz@6458 | 295 | address original_pc = sender_nm->get_original_pc(this); |
goetz@6458 | 296 | assert(sender_nm->insts_contains(original_pc), "original PC must be in nmethod"); |
goetz@6458 | 297 | assert(sender_nm->is_method_handle_return(original_pc), "must be"); |
goetz@6458 | 298 | } |
goetz@6458 | 299 | #endif |
goetz@6458 | 300 | } |
goetz@6458 | 301 | } |
goetz@6458 | 302 | |
goetz@6458 | 303 | intptr_t *frame::initial_deoptimization_info() { |
goetz@6458 | 304 | // unused... but returns fp() to minimize changes introduced by 7087445 |
goetz@6458 | 305 | return fp(); |
goetz@6458 | 306 | } |