src/cpu/x86/vm/sharedRuntime_x86_32.cpp

changeset 3500
0382d2b469b2
parent 3130
5432047c7db7
child 3969
1d7922586cf6
     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  }

mercurial