changeset 3527:68b65652a8d0

7158807: Revise stack management with volatile call sites Summary: Add missing stack banging into method handle assebly code and throw a StackOverflowError. Reviewed-by: jrose, twisti
author kvn
date Mon, 18 Jun 2012 09:50:43 -0700
parents 680f32d8cb81
children 13a7c97f9e9a
files src/cpu/sparc/vm/methodHandles_sparc.cpp src/cpu/x86/vm/methodHandles_x86.cpp test/compiler/7158807/Test7158807.java
diffstat 3 files changed, 132 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/sparc/vm/methodHandles_sparc.cpp	Fri Jun 08 12:49:52 2012 -0400
+++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp	Mon Jun 18 09:50:43 2012 -0700
@@ -698,6 +698,17 @@
   if (arg_slots.is_constant() && arg_slots.as_constant() == 0)
     return;
 
+  // We have to insert at least one word, so bang the stack.
+  if (UseStackBanging) {
+    // Save G3_method_handle since bang_stack_with_offset uses it as a temp register
+    __ mov(G3_method_handle, temp_reg);
+    int frame_size = (arg_slots.is_constant() ? -1 * arg_slots.as_constant() * wordSize : 0);
+    if (frame_size <= 0)
+      frame_size = 256 * Interpreter::stackElementSize;  // conservative
+    __ generate_stack_overflow_check(frame_size);
+    __ mov(temp_reg, G3_method_handle);
+  }
+
   assert_different_registers(argslot_reg, temp_reg, temp2_reg, temp3_reg,
                              (!arg_slots.is_register() ? Gargs : arg_slots.as_register()));
 
@@ -1702,6 +1713,14 @@
                         "copied argument(s) must fall within current frame");
       }
 
+      if (UseStackBanging) {
+        // Save G3_method_handle since bang_stack_with_offset uses it as a temp register
+        __ mov(G3_method_handle, O3_scratch);
+         // Bang the stack before pushing args.
+        int frame_size = 256 * Interpreter::stackElementSize;  // conservative
+        __ generate_stack_overflow_check(frame_size + sizeof(RicochetFrame));
+        __ mov(O3_scratch, G3_method_handle);
+      }
       // insert location is always the bottom of the argument list:
       __ neg(O1_stack_move);
       push_arg_slots(_masm, O0_argslot, O1_stack_move, O2_scratch, O3_scratch);
@@ -2118,6 +2137,18 @@
       // The return handler will further cut back the stack when it takes
       // down the RF.  Perhaps there is a way to streamline this further.
 
+      if (UseStackBanging) {
+        // Save G3_method_handle since bang_stack_with_offset uses it as a temp register
+        __ mov(G3_method_handle, O4_scratch);
+        // Bang the stack before recursive call.
+        // Even if slots == 0, we are inside a RicochetFrame.
+        int frame_size = collect_count.is_constant() ? collect_count.as_constant() * wordSize : -1;
+        if (frame_size < 0) {
+          frame_size = 256 * Interpreter::stackElementSize;  // conservative
+        }
+        __ generate_stack_overflow_check(frame_size + sizeof(RicochetFrame));
+        __ mov(O4_scratch, G3_method_handle);
+      }
       // State during recursive call:
       // ... keep1 | dest | dest=42 | keep3 | RF... | collect | bounce_pc |
       __ jump_to_method_handle_entry(G3_method_handle, O1_scratch);
--- a/src/cpu/x86/vm/methodHandles_x86.cpp	Fri Jun 08 12:49:52 2012 -0400
+++ b/src/cpu/x86/vm/methodHandles_x86.cpp	Mon Jun 18 09:50:43 2012 -0700
@@ -691,6 +691,14 @@
   if (VerifyMethodHandles)
     verify_stack_move(_masm, arg_slots, -1);
 
+  // We have to insert at least one word, so bang the stack.
+  if (UseStackBanging) {
+    int frame_size = (arg_slots.is_constant() ? -1 * arg_slots.as_constant() * wordSize : 0);
+    if (frame_size <= 0)
+      frame_size = 256 * Interpreter::stackElementSize;  // conservative
+    __ generate_stack_overflow_check(frame_size);
+  }
+
   // Make space on the stack for the inserted argument(s).
   // Then pull down everything shallower than rax_argslot.
   // The stacked return address gets pulled down with everything else.
@@ -1769,6 +1777,11 @@
                         "copied argument(s) must fall within current frame");
       }
 
+      if (UseStackBanging) {
+        // Bang the stack before pushing args.
+        int frame_size = 256 * Interpreter::stackElementSize;  // conservative
+        __ generate_stack_overflow_check(frame_size + sizeof(RicochetFrame));
+      }
       // insert location is always the bottom of the argument list:
       Address insert_location = __ argument_address(constant(0));
       int pre_arg_words = insert_location.disp() / wordSize;   // return PC is pushed
@@ -2206,6 +2219,15 @@
       // The return handler will further cut back the stack when it takes
       // down the RF.  Perhaps there is a way to streamline this further.
 
+      if (UseStackBanging) {
+        // Bang the stack before recursive call.
+        // Even if slots == 0, we are inside a RicochetFrame.
+        int frame_size = collect_count.is_constant() ? collect_count.as_constant() * wordSize : -1;
+        if (frame_size < 0) {
+          frame_size = 256 * Interpreter::stackElementSize;  // conservative
+        }
+        __ generate_stack_overflow_check(frame_size + sizeof(RicochetFrame));
+      }
       // State during recursive call:
       // ... keep1 | dest | dest=42 | keep3 | RF... | collect | bounce_pc |
       __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
@@ -2366,10 +2388,15 @@
         // case in a 32-bit version of the VM) we have to save 'rsi'
         // on the stack because later on (at 'L_array_is_empty') 'rsi'
         // will be overwritten.
-        { if (rsi_temp == saved_last_sp)  __ push(saved_last_sp); }
+        if (rsi_temp == saved_last_sp) {
+          __ push(saved_last_sp);
+          // Need to re-push return PC to keep it on stack top.
+          __ lea(saved_last_sp, ExternalAddress(SharedRuntime::ricochet_blob()->bounce_addr()).addr());
+          __ push(saved_last_sp);
+        }
         // Also prepare a handy macro which restores 'rsi' if required.
 #define UNPUSH_RSI                                                      \
-        { if (rsi_temp == saved_last_sp)  __ pop(saved_last_sp); }
+        { if (rsi_temp == saved_last_sp) { __ pop(saved_last_sp); __ pop(saved_last_sp); } }
 
         __ jmp(L_array_is_empty);
         __ bind(L_skip);
@@ -2382,7 +2409,12 @@
       // called in the case of a null pointer exception will not be
       // confused by the extra value on the stack (it expects the
       // return pointer on top of the stack)
-      { if (rsi_temp == saved_last_sp)  __ push(saved_last_sp); }
+      if (rsi_temp == saved_last_sp) {
+        __ push(saved_last_sp);
+        // Need to re-push return PC to keep it on stack top.
+        __ lea(saved_last_sp, ExternalAddress(SharedRuntime::ricochet_blob()->bounce_addr()).addr());
+        __ push(saved_last_sp);
+      }
 
       // Check the array type.
       Register rbx_klass = rbx_temp;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/7158807/Test7158807.java	Mon Jun 18 09:50:43 2012 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/**
+ * @test
+ * @bug 7158807
+ * @summary Revise stack management with volatile call sites
+ * @author Marc Schonefeld
+ *
+ * @run main/othervm -XX:CompileThreshold=100 -Xbatch -Xss248k Test7158807
+ */
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.VolatileCallSite;
+
+public class Test7158807 {
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) throws Throwable {
+        for (int i = 0; i < 25600; i++) {
+            MethodType mt = MethodType.methodType(java.lang.String.class);
+            System.out.println(mt);
+            MethodType mt3 = null;
+            try {
+              mt3 = MethodType.genericMethodType(i);
+            } catch (IllegalArgumentException e) {
+              System.out.println("Passed");
+              System.exit(95);
+            }
+            System.out.println(i+":");
+            try {
+                VolatileCallSite vcs = new VolatileCallSite(mt3);
+                System.out.println(vcs);
+                MethodHandle mh = vcs.dynamicInvoker();
+                vcs.setTarget(mh);
+                // System.out.println(mh);
+                mh.invoke(mt, mh);
+            } catch (Throwable e) {
+            }
+        }
+    }
+}
+