1.1 --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Wed Feb 01 07:59:01 2012 -0800 1.2 +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Wed Feb 01 16:57:08 2012 -0800 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -1091,12 +1091,238 @@ 1.11 } 1.12 } 1.13 1.14 + 1.15 +static void save_or_restore_arguments(MacroAssembler* masm, 1.16 + const int stack_slots, 1.17 + const int total_in_args, 1.18 + const int arg_save_area, 1.19 + OopMap* map, 1.20 + VMRegPair* in_regs, 1.21 + BasicType* in_sig_bt) { 1.22 + // if map is non-NULL then the code should store the values, 1.23 + // otherwise it should load them. 1.24 + int handle_index = 0; 1.25 + // Save down double word first 1.26 + for ( int i = 0; i < total_in_args; i++) { 1.27 + if (in_regs[i].first()->is_XMMRegister() && in_sig_bt[i] == T_DOUBLE) { 1.28 + int slot = handle_index * VMRegImpl::slots_per_word + arg_save_area; 1.29 + int offset = slot * VMRegImpl::stack_slot_size; 1.30 + handle_index += 2; 1.31 + assert(handle_index <= stack_slots, "overflow"); 1.32 + if (map != NULL) { 1.33 + __ movdbl(Address(rsp, offset), in_regs[i].first()->as_XMMRegister()); 1.34 + } else { 1.35 + __ movdbl(in_regs[i].first()->as_XMMRegister(), Address(rsp, offset)); 1.36 + } 1.37 + } 1.38 + if (in_regs[i].first()->is_Register() && in_sig_bt[i] == T_LONG) { 1.39 + int slot = handle_index * VMRegImpl::slots_per_word + arg_save_area; 1.40 + int offset = slot * VMRegImpl::stack_slot_size; 1.41 + handle_index += 2; 1.42 + assert(handle_index <= stack_slots, "overflow"); 1.43 + if (map != NULL) { 1.44 + __ movl(Address(rsp, offset), in_regs[i].first()->as_Register()); 1.45 + if (in_regs[i].second()->is_Register()) { 1.46 + __ movl(Address(rsp, offset + 4), in_regs[i].second()->as_Register()); 1.47 + } 1.48 + } else { 1.49 + __ movl(in_regs[i].first()->as_Register(), Address(rsp, offset)); 1.50 + if (in_regs[i].second()->is_Register()) { 1.51 + __ movl(in_regs[i].second()->as_Register(), Address(rsp, offset + 4)); 1.52 + } 1.53 + } 1.54 + } 1.55 + } 1.56 + // Save or restore single word registers 1.57 + for ( int i = 0; i < total_in_args; i++) { 1.58 + if (in_regs[i].first()->is_Register()) { 1.59 + int slot = handle_index++ * VMRegImpl::slots_per_word + arg_save_area; 1.60 + int offset = slot * VMRegImpl::stack_slot_size; 1.61 + assert(handle_index <= stack_slots, "overflow"); 1.62 + if (in_sig_bt[i] == T_ARRAY && map != NULL) { 1.63 + map->set_oop(VMRegImpl::stack2reg(slot));; 1.64 + } 1.65 + 1.66 + // Value is in an input register pass we must flush it to the stack 1.67 + const Register reg = in_regs[i].first()->as_Register(); 1.68 + switch (in_sig_bt[i]) { 1.69 + case T_ARRAY: 1.70 + if (map != NULL) { 1.71 + __ movptr(Address(rsp, offset), reg); 1.72 + } else { 1.73 + __ movptr(reg, Address(rsp, offset)); 1.74 + } 1.75 + break; 1.76 + case T_BOOLEAN: 1.77 + case T_CHAR: 1.78 + case T_BYTE: 1.79 + case T_SHORT: 1.80 + case T_INT: 1.81 + if (map != NULL) { 1.82 + __ movl(Address(rsp, offset), reg); 1.83 + } else { 1.84 + __ movl(reg, Address(rsp, offset)); 1.85 + } 1.86 + break; 1.87 + case T_OBJECT: 1.88 + default: ShouldNotReachHere(); 1.89 + } 1.90 + } else if (in_regs[i].first()->is_XMMRegister()) { 1.91 + if (in_sig_bt[i] == T_FLOAT) { 1.92 + int slot = handle_index++ * VMRegImpl::slots_per_word + arg_save_area; 1.93 + int offset = slot * VMRegImpl::stack_slot_size; 1.94 + assert(handle_index <= stack_slots, "overflow"); 1.95 + if (map != NULL) { 1.96 + __ movflt(Address(rsp, offset), in_regs[i].first()->as_XMMRegister()); 1.97 + } else { 1.98 + __ movflt(in_regs[i].first()->as_XMMRegister(), Address(rsp, offset)); 1.99 + } 1.100 + } 1.101 + } else if (in_regs[i].first()->is_stack()) { 1.102 + if (in_sig_bt[i] == T_ARRAY && map != NULL) { 1.103 + int offset_in_older_frame = in_regs[i].first()->reg2stack() + SharedRuntime::out_preserve_stack_slots(); 1.104 + map->set_oop(VMRegImpl::stack2reg(offset_in_older_frame + stack_slots)); 1.105 + } 1.106 + } 1.107 + } 1.108 +} 1.109 + 1.110 +// Check GC_locker::needs_gc and enter the runtime if it's true. This 1.111 +// keeps a new JNI critical region from starting until a GC has been 1.112 +// forced. Save down any oops in registers and describe them in an 1.113 +// OopMap. 1.114 +static void check_needs_gc_for_critical_native(MacroAssembler* masm, 1.115 + Register thread, 1.116 + int stack_slots, 1.117 + int total_c_args, 1.118 + int total_in_args, 1.119 + int arg_save_area, 1.120 + OopMapSet* oop_maps, 1.121 + VMRegPair* in_regs, 1.122 + BasicType* in_sig_bt) { 1.123 + __ block_comment("check GC_locker::needs_gc"); 1.124 + Label cont; 1.125 + __ cmp8(ExternalAddress((address)GC_locker::needs_gc_address()), false); 1.126 + __ jcc(Assembler::equal, cont); 1.127 + 1.128 + // Save down any incoming oops and call into the runtime to halt for a GC 1.129 + 1.130 + OopMap* map = new OopMap(stack_slots * 2, 0 /* arg_slots*/); 1.131 + 1.132 + save_or_restore_arguments(masm, stack_slots, total_in_args, 1.133 + arg_save_area, map, in_regs, in_sig_bt); 1.134 + 1.135 + address the_pc = __ pc(); 1.136 + oop_maps->add_gc_map( __ offset(), map); 1.137 + __ set_last_Java_frame(thread, rsp, noreg, the_pc); 1.138 + 1.139 + __ block_comment("block_for_jni_critical"); 1.140 + __ push(thread); 1.141 + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::block_for_jni_critical))); 1.142 + __ increment(rsp, wordSize); 1.143 + 1.144 + __ get_thread(thread); 1.145 + __ reset_last_Java_frame(thread, false, true); 1.146 + 1.147 + save_or_restore_arguments(masm, stack_slots, total_in_args, 1.148 + arg_save_area, NULL, in_regs, in_sig_bt); 1.149 + 1.150 + __ bind(cont); 1.151 +#ifdef ASSERT 1.152 + if (StressCriticalJNINatives) { 1.153 + // Stress register saving 1.154 + OopMap* map = new OopMap(stack_slots * 2, 0 /* arg_slots*/); 1.155 + save_or_restore_arguments(masm, stack_slots, total_in_args, 1.156 + arg_save_area, map, in_regs, in_sig_bt); 1.157 + // Destroy argument registers 1.158 + for (int i = 0; i < total_in_args - 1; i++) { 1.159 + if (in_regs[i].first()->is_Register()) { 1.160 + const Register reg = in_regs[i].first()->as_Register(); 1.161 + __ xorptr(reg, reg); 1.162 + } else if (in_regs[i].first()->is_XMMRegister()) { 1.163 + __ xorpd(in_regs[i].first()->as_XMMRegister(), in_regs[i].first()->as_XMMRegister()); 1.164 + } else if (in_regs[i].first()->is_FloatRegister()) { 1.165 + ShouldNotReachHere(); 1.166 + } else if (in_regs[i].first()->is_stack()) { 1.167 + // Nothing to do 1.168 + } else { 1.169 + ShouldNotReachHere(); 1.170 + } 1.171 + if (in_sig_bt[i] == T_LONG || in_sig_bt[i] == T_DOUBLE) { 1.172 + i++; 1.173 + } 1.174 + } 1.175 + 1.176 + save_or_restore_arguments(masm, stack_slots, total_in_args, 1.177 + arg_save_area, NULL, in_regs, in_sig_bt); 1.178 + } 1.179 +#endif 1.180 +} 1.181 + 1.182 +// Unpack an array argument into a pointer to the body and the length 1.183 +// if the array is non-null, otherwise pass 0 for both. 1.184 +static void unpack_array_argument(MacroAssembler* masm, VMRegPair reg, BasicType in_elem_type, VMRegPair body_arg, VMRegPair length_arg) { 1.185 + Register tmp_reg = rax; 1.186 + assert(!body_arg.first()->is_Register() || body_arg.first()->as_Register() != tmp_reg, 1.187 + "possible collision"); 1.188 + assert(!length_arg.first()->is_Register() || length_arg.first()->as_Register() != tmp_reg, 1.189 + "possible collision"); 1.190 + 1.191 + // Pass the length, ptr pair 1.192 + Label is_null, done; 1.193 + VMRegPair tmp(tmp_reg->as_VMReg()); 1.194 + if (reg.first()->is_stack()) { 1.195 + // Load the arg up from the stack 1.196 + simple_move32(masm, reg, tmp); 1.197 + reg = tmp; 1.198 + } 1.199 + __ testptr(reg.first()->as_Register(), reg.first()->as_Register()); 1.200 + __ jccb(Assembler::equal, is_null); 1.201 + __ lea(tmp_reg, Address(reg.first()->as_Register(), arrayOopDesc::base_offset_in_bytes(in_elem_type))); 1.202 + simple_move32(masm, tmp, body_arg); 1.203 + // load the length relative to the body. 1.204 + __ movl(tmp_reg, Address(tmp_reg, arrayOopDesc::length_offset_in_bytes() - 1.205 + arrayOopDesc::base_offset_in_bytes(in_elem_type))); 1.206 + simple_move32(masm, tmp, length_arg); 1.207 + __ jmpb(done); 1.208 + __ bind(is_null); 1.209 + // Pass zeros 1.210 + __ xorptr(tmp_reg, tmp_reg); 1.211 + simple_move32(masm, tmp, body_arg); 1.212 + simple_move32(masm, tmp, length_arg); 1.213 + __ bind(done); 1.214 +} 1.215 + 1.216 + 1.217 // --------------------------------------------------------------------------- 1.218 // Generate a native wrapper for a given method. The method takes arguments 1.219 // in the Java compiled code convention, marshals them to the native 1.220 // convention (handlizes oops, etc), transitions to native, makes the call, 1.221 // returns to java state (possibly blocking), unhandlizes any result and 1.222 // returns. 1.223 +// 1.224 +// Critical native functions are a shorthand for the use of 1.225 +// GetPrimtiveArrayCritical and disallow the use of any other JNI 1.226 +// functions. The wrapper is expected to unpack the arguments before 1.227 +// passing them to the callee and perform checks before and after the 1.228 +// native call to ensure that they GC_locker 1.229 +// lock_critical/unlock_critical semantics are followed. Some other 1.230 +// parts of JNI setup are skipped like the tear down of the JNI handle 1.231 +// block and the check for pending exceptions it's impossible for them 1.232 +// to be thrown. 1.233 +// 1.234 +// They are roughly structured like this: 1.235 +// if (GC_locker::needs_gc()) 1.236 +// SharedRuntime::block_for_jni_critical(); 1.237 +// tranistion to thread_in_native 1.238 +// unpack arrray arguments and call native entry point 1.239 +// check for safepoint in progress 1.240 +// check if any thread suspend flags are set 1.241 +// call into JVM and possible unlock the JNI critical 1.242 +// if a GC was suppressed while in the critical native. 1.243 +// transition back to thread_in_Java 1.244 +// return to caller 1.245 +// 1.246 nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, 1.247 methodHandle method, 1.248 int compile_id, 1.249 @@ -1105,6 +1331,13 @@ 1.250 BasicType *in_sig_bt, 1.251 VMRegPair *in_regs, 1.252 BasicType ret_type) { 1.253 + bool is_critical_native = true; 1.254 + address native_func = method->critical_native_function(); 1.255 + if (native_func == NULL) { 1.256 + native_func = method->native_function(); 1.257 + is_critical_native = false; 1.258 + } 1.259 + assert(native_func != NULL, "must have function"); 1.260 1.261 // An OopMap for lock (and class if static) 1.262 OopMapSet *oop_maps = new OopMapSet(); 1.263 @@ -1115,30 +1348,72 @@ 1.264 // we convert the java signature to a C signature by inserting 1.265 // the hidden arguments as arg[0] and possibly arg[1] (static method) 1.266 1.267 - int total_c_args = total_in_args + 1; 1.268 - if (method->is_static()) { 1.269 - total_c_args++; 1.270 + int total_c_args = total_in_args; 1.271 + if (!is_critical_native) { 1.272 + total_c_args += 1; 1.273 + if (method->is_static()) { 1.274 + total_c_args++; 1.275 + } 1.276 + } else { 1.277 + for (int i = 0; i < total_in_args; i++) { 1.278 + if (in_sig_bt[i] == T_ARRAY) { 1.279 + total_c_args++; 1.280 + } 1.281 + } 1.282 } 1.283 1.284 BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_c_args); 1.285 - VMRegPair* out_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_c_args); 1.286 + VMRegPair* out_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_c_args); 1.287 + BasicType* in_elem_bt = NULL; 1.288 1.289 int argc = 0; 1.290 - out_sig_bt[argc++] = T_ADDRESS; 1.291 - if (method->is_static()) { 1.292 - out_sig_bt[argc++] = T_OBJECT; 1.293 + if (!is_critical_native) { 1.294 + out_sig_bt[argc++] = T_ADDRESS; 1.295 + if (method->is_static()) { 1.296 + out_sig_bt[argc++] = T_OBJECT; 1.297 + } 1.298 + 1.299 + for (int i = 0; i < total_in_args ; i++ ) { 1.300 + out_sig_bt[argc++] = in_sig_bt[i]; 1.301 + } 1.302 + } else { 1.303 + Thread* THREAD = Thread::current(); 1.304 + in_elem_bt = NEW_RESOURCE_ARRAY(BasicType, total_in_args); 1.305 + SignatureStream ss(method->signature()); 1.306 + for (int i = 0; i < total_in_args ; i++ ) { 1.307 + if (in_sig_bt[i] == T_ARRAY) { 1.308 + // Arrays are passed as int, elem* pair 1.309 + out_sig_bt[argc++] = T_INT; 1.310 + out_sig_bt[argc++] = T_ADDRESS; 1.311 + Symbol* atype = ss.as_symbol(CHECK_NULL); 1.312 + const char* at = atype->as_C_string(); 1.313 + if (strlen(at) == 2) { 1.314 + assert(at[0] == '[', "must be"); 1.315 + switch (at[1]) { 1.316 + case 'B': in_elem_bt[i] = T_BYTE; break; 1.317 + case 'C': in_elem_bt[i] = T_CHAR; break; 1.318 + case 'D': in_elem_bt[i] = T_DOUBLE; break; 1.319 + case 'F': in_elem_bt[i] = T_FLOAT; break; 1.320 + case 'I': in_elem_bt[i] = T_INT; break; 1.321 + case 'J': in_elem_bt[i] = T_LONG; break; 1.322 + case 'S': in_elem_bt[i] = T_SHORT; break; 1.323 + case 'Z': in_elem_bt[i] = T_BOOLEAN; break; 1.324 + default: ShouldNotReachHere(); 1.325 + } 1.326 + } 1.327 + } else { 1.328 + out_sig_bt[argc++] = in_sig_bt[i]; 1.329 + in_elem_bt[i] = T_VOID; 1.330 + } 1.331 + if (in_sig_bt[i] != T_VOID) { 1.332 + assert(in_sig_bt[i] == ss.type(), "must match"); 1.333 + ss.next(); 1.334 + } 1.335 + } 1.336 } 1.337 1.338 - int i; 1.339 - for (i = 0; i < total_in_args ; i++ ) { 1.340 - out_sig_bt[argc++] = in_sig_bt[i]; 1.341 - } 1.342 - 1.343 - 1.344 // Now figure out where the args must be stored and how much stack space 1.345 - // they require (neglecting out_preserve_stack_slots but space for storing 1.346 - // the 1st six register arguments). It's weird see int_stk_helper. 1.347 - // 1.348 + // they require. 1.349 int out_arg_slots; 1.350 out_arg_slots = c_calling_convention(out_sig_bt, out_regs, total_c_args); 1.351 1.352 @@ -1151,9 +1426,44 @@ 1.353 int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots; 1.354 1.355 // Now the space for the inbound oop handle area 1.356 + int total_save_slots = 2 * VMRegImpl::slots_per_word; // 2 arguments passed in registers 1.357 + if (is_critical_native) { 1.358 + // Critical natives may have to call out so they need a save area 1.359 + // for register arguments. 1.360 + int double_slots = 0; 1.361 + int single_slots = 0; 1.362 + for ( int i = 0; i < total_in_args; i++) { 1.363 + if (in_regs[i].first()->is_Register()) { 1.364 + const Register reg = in_regs[i].first()->as_Register(); 1.365 + switch (in_sig_bt[i]) { 1.366 + case T_ARRAY: 1.367 + case T_BOOLEAN: 1.368 + case T_BYTE: 1.369 + case T_SHORT: 1.370 + case T_CHAR: 1.371 + case T_INT: single_slots++; break; 1.372 + case T_LONG: double_slots++; break; 1.373 + default: ShouldNotReachHere(); 1.374 + } 1.375 + } else if (in_regs[i].first()->is_XMMRegister()) { 1.376 + switch (in_sig_bt[i]) { 1.377 + case T_FLOAT: single_slots++; break; 1.378 + case T_DOUBLE: double_slots++; break; 1.379 + default: ShouldNotReachHere(); 1.380 + } 1.381 + } else if (in_regs[i].first()->is_FloatRegister()) { 1.382 + ShouldNotReachHere(); 1.383 + } 1.384 + } 1.385 + total_save_slots = double_slots * 2 + single_slots; 1.386 + // align the save area 1.387 + if (double_slots != 0) { 1.388 + stack_slots = round_to(stack_slots, 2); 1.389 + } 1.390 + } 1.391 1.392 int oop_handle_offset = stack_slots; 1.393 - stack_slots += 2*VMRegImpl::slots_per_word; 1.394 + stack_slots += total_save_slots; 1.395 1.396 // Now any space we need for handlizing a klass if static method 1.397 1.398 @@ -1161,7 +1471,6 @@ 1.399 int klass_offset = -1; 1.400 int lock_slot_offset = 0; 1.401 bool is_static = false; 1.402 - int oop_temp_slot_offset = 0; 1.403 1.404 if (method->is_static()) { 1.405 klass_slot_offset = stack_slots; 1.406 @@ -1221,7 +1530,7 @@ 1.407 // First thing make an ic check to see if we should even be here 1.408 1.409 // We are free to use all registers as temps without saving them and 1.410 - // restoring them except rbp,. rbp, is the only callee save register 1.411 + // restoring them except rbp. rbp is the only callee save register 1.412 // as far as the interpreter and the compiler(s) are concerned. 1.413 1.414 1.415 @@ -1230,7 +1539,6 @@ 1.416 Label hit; 1.417 Label exception_pending; 1.418 1.419 - 1.420 __ verify_oop(receiver); 1.421 __ cmpptr(ic_reg, Address(receiver, oopDesc::klass_offset_in_bytes())); 1.422 __ jcc(Assembler::equal, hit); 1.423 @@ -1292,11 +1600,10 @@ 1.424 1.425 // Generate a new frame for the wrapper. 1.426 __ enter(); 1.427 - // -2 because return address is already present and so is saved rbp, 1.428 + // -2 because return address is already present and so is saved rbp 1.429 __ subptr(rsp, stack_size - 2*wordSize); 1.430 1.431 - // Frame is now completed as far a size and linkage. 1.432 - 1.433 + // Frame is now completed as far as size and linkage. 1.434 int frame_complete = ((intptr_t)__ pc()) - start; 1.435 1.436 // Calculate the difference between rsp and rbp,. We need to know it 1.437 @@ -1319,7 +1626,6 @@ 1.438 // Compute the rbp, offset for any slots used after the jni call 1.439 1.440 int lock_slot_rbp_offset = (lock_slot_offset*VMRegImpl::stack_slot_size) - fp_adjustment; 1.441 - int oop_temp_slot_rbp_offset = (oop_temp_slot_offset*VMRegImpl::stack_slot_size) - fp_adjustment; 1.442 1.443 // We use rdi as a thread pointer because it is callee save and 1.444 // if we load it once it is usable thru the entire wrapper 1.445 @@ -1332,6 +1638,10 @@ 1.446 1.447 __ get_thread(thread); 1.448 1.449 + if (is_critical_native) { 1.450 + check_needs_gc_for_critical_native(masm, thread, stack_slots, total_c_args, total_in_args, 1.451 + oop_handle_offset, oop_maps, in_regs, in_sig_bt); 1.452 + } 1.453 1.454 // 1.455 // We immediately shuffle the arguments so that any vm call we have to 1.456 @@ -1353,7 +1663,7 @@ 1.457 // vectors we have in our possession. We simply walk the java vector to 1.458 // get the source locations and the c vector to get the destinations. 1.459 1.460 - int c_arg = method->is_static() ? 2 : 1 ; 1.461 + int c_arg = is_critical_native ? 0 : (method->is_static() ? 2 : 1 ); 1.462 1.463 // Record rsp-based slot for receiver on stack for non-static methods 1.464 int receiver_offset = -1; 1.465 @@ -1373,10 +1683,16 @@ 1.466 // Are free to temporaries if we have to do stack to steck moves. 1.467 // All inbound args are referenced based on rbp, and all outbound args via rsp. 1.468 1.469 - for (i = 0; i < total_in_args ; i++, c_arg++ ) { 1.470 + for (int i = 0; i < total_in_args ; i++, c_arg++ ) { 1.471 switch (in_sig_bt[i]) { 1.472 case T_ARRAY: 1.473 + if (is_critical_native) { 1.474 + unpack_array_argument(masm, in_regs[i], in_elem_bt[i], out_regs[c_arg + 1], out_regs[c_arg]); 1.475 + c_arg++; 1.476 + break; 1.477 + } 1.478 case T_OBJECT: 1.479 + assert(!is_critical_native, "no oop arguments"); 1.480 object_move(masm, map, oop_handle_offset, stack_slots, in_regs[i], out_regs[c_arg], 1.481 ((i == 0) && (!is_static)), 1.482 &receiver_offset); 1.483 @@ -1408,7 +1724,7 @@ 1.484 1.485 // Pre-load a static method's oop into rsi. Used both by locking code and 1.486 // the normal JNI call code. 1.487 - if (method->is_static()) { 1.488 + if (method->is_static() && !is_critical_native) { 1.489 1.490 // load opp into a register 1.491 __ movoop(oop_handle_reg, JNIHandles::make_local(Klass::cast(method->method_holder())->java_mirror())); 1.492 @@ -1463,6 +1779,7 @@ 1.493 1.494 // Lock a synchronized method 1.495 if (method->is_synchronized()) { 1.496 + assert(!is_critical_native, "unhandled"); 1.497 1.498 1.499 const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes(); 1.500 @@ -1529,14 +1846,15 @@ 1.501 1.502 1.503 // get JNIEnv* which is first argument to native 1.504 - 1.505 - __ lea(rdx, Address(thread, in_bytes(JavaThread::jni_environment_offset()))); 1.506 - __ movptr(Address(rsp, 0), rdx); 1.507 + if (!is_critical_native) { 1.508 + __ lea(rdx, Address(thread, in_bytes(JavaThread::jni_environment_offset()))); 1.509 + __ movptr(Address(rsp, 0), rdx); 1.510 + } 1.511 1.512 // Now set thread in native 1.513 __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_native); 1.514 1.515 - __ call(RuntimeAddress(method->native_function())); 1.516 + __ call(RuntimeAddress(native_func)); 1.517 1.518 // WARNING - on Windows Java Natives use pascal calling convention and pop the 1.519 // arguments off of the stack. We could just re-adjust the stack pointer here 1.520 @@ -1591,6 +1909,8 @@ 1.521 __ fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std())); 1.522 } 1.523 1.524 + Label after_transition; 1.525 + 1.526 // check for safepoint operation in progress and/or pending suspend requests 1.527 { Label Continue; 1.528 1.529 @@ -1611,17 +1931,29 @@ 1.530 // 1.531 save_native_result(masm, ret_type, stack_slots); 1.532 __ push(thread); 1.533 - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, 1.534 - JavaThread::check_special_condition_for_native_trans))); 1.535 + if (!is_critical_native) { 1.536 + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, 1.537 + JavaThread::check_special_condition_for_native_trans))); 1.538 + } else { 1.539 + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, 1.540 + JavaThread::check_special_condition_for_native_trans_and_transition))); 1.541 + } 1.542 __ increment(rsp, wordSize); 1.543 // Restore any method result value 1.544 restore_native_result(masm, ret_type, stack_slots); 1.545 1.546 + if (is_critical_native) { 1.547 + // The call above performed the transition to thread_in_Java so 1.548 + // skip the transition logic below. 1.549 + __ jmpb(after_transition); 1.550 + } 1.551 + 1.552 __ bind(Continue); 1.553 } 1.554 1.555 // change thread state 1.556 __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_Java); 1.557 + __ bind(after_transition); 1.558 1.559 Label reguard; 1.560 Label reguard_done; 1.561 @@ -1710,15 +2042,15 @@ 1.562 __ verify_oop(rax); 1.563 } 1.564 1.565 - // reset handle block 1.566 - __ movptr(rcx, Address(thread, JavaThread::active_handles_offset())); 1.567 - 1.568 - __ movptr(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD); 1.569 - 1.570 - // Any exception pending? 1.571 - __ cmpptr(Address(thread, in_bytes(Thread::pending_exception_offset())), (int32_t)NULL_WORD); 1.572 - __ jcc(Assembler::notEqual, exception_pending); 1.573 - 1.574 + if (!is_critical_native) { 1.575 + // reset handle block 1.576 + __ movptr(rcx, Address(thread, JavaThread::active_handles_offset())); 1.577 + __ movptr(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD); 1.578 + 1.579 + // Any exception pending? 1.580 + __ cmpptr(Address(thread, in_bytes(Thread::pending_exception_offset())), (int32_t)NULL_WORD); 1.581 + __ jcc(Assembler::notEqual, exception_pending); 1.582 + } 1.583 1.584 // no exception, we're almost done 1.585 1.586 @@ -1829,16 +2161,18 @@ 1.587 1.588 // BEGIN EXCEPTION PROCESSING 1.589 1.590 - // Forward the exception 1.591 - __ bind(exception_pending); 1.592 - 1.593 - // remove possible return value from FPU register stack 1.594 - __ empty_FPU_stack(); 1.595 - 1.596 - // pop our frame 1.597 - __ leave(); 1.598 - // and forward the exception 1.599 - __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); 1.600 + if (!is_critical_native) { 1.601 + // Forward the exception 1.602 + __ bind(exception_pending); 1.603 + 1.604 + // remove possible return value from FPU register stack 1.605 + __ empty_FPU_stack(); 1.606 + 1.607 + // pop our frame 1.608 + __ leave(); 1.609 + // and forward the exception 1.610 + __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); 1.611 + } 1.612 1.613 __ flush(); 1.614 1.615 @@ -1851,6 +2185,11 @@ 1.616 (is_static ? in_ByteSize(klass_offset) : in_ByteSize(receiver_offset)), 1.617 in_ByteSize(lock_slot_offset*VMRegImpl::stack_slot_size), 1.618 oop_maps); 1.619 + 1.620 + if (is_critical_native) { 1.621 + nm->set_lazy_critical_native(true); 1.622 + } 1.623 + 1.624 return nm; 1.625 1.626 }