OSDN Git Service

Fix FOUR_ARG_DOWNCALL assembly stubs on arm and x86.
authorNicolas Geoffray <ngeoffray@google.com>
Wed, 8 Jun 2016 17:01:22 +0000 (18:01 +0100)
committerNicolas Geoffray <ngeoffray@google.com>
Thu, 9 Jun 2016 10:34:11 +0000 (11:34 +0100)
They were creating a stack that the runtime did not understand.

bug:28348339

(cherry picked from commit 0f838aa279a296b5f14c231065bb2f96b02d9caf)

Change-Id: Iecaa274512b42ad76fccb48c11a0076d0292c240

runtime/arch/arm/quick_entrypoints_arm.S
runtime/arch/x86/quick_entrypoints_x86.S
test/605-new-string-from-bytes/expected.txt [new file with mode: 0644]
test/605-new-string-from-bytes/info.txt [new file with mode: 0644]
test/605-new-string-from-bytes/src/Main.java [new file with mode: 0644]

index 10b8747..733c727 100644 (file)
 #endif
 .endm
 
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kRefsOnly)
+     * and preserves the value of rTemp2 at entry.
+     */
+.macro SETUP_REFS_ONLY_CALLEE_SAVE_FRAME_PRESERVE_RTEMP2 rTemp1, rTemp2
+    push {r5-r8, r10-r11, lr}                     @ 7 words of callee saves
+    .cfi_adjust_cfa_offset 28
+    .cfi_rel_offset r5, 0
+    .cfi_rel_offset r6, 4
+    .cfi_rel_offset r7, 8
+    .cfi_rel_offset r8, 12
+    .cfi_rel_offset r10, 16
+    .cfi_rel_offset r11, 20
+    .cfi_rel_offset lr, 24
+    sub sp, #4                                    @ bottom word will hold Method*
+    .cfi_adjust_cfa_offset 4
+    str \rTemp2, [sp, #0]                         @ save rTemp2
+    RUNTIME_CURRENT2 \rTemp1, \rTemp2             @ Load Runtime::Current into rTemp1.
+    ldr \rTemp1, [\rTemp1, #RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET] @ rTemp1 is kRefsOnly Method*.
+    ldr \rTemp2, [sp, #0]                         @ restore rTemp2
+    str \rTemp1, [sp, #0]                         @ Place Method* at bottom of stack.
+    str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
+
+    // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 28 + 4)
+#error "REFS_ONLY_CALLEE_SAVE_FRAME(ARM) size not as expected."
+#endif
+.endm
+
 .macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     add sp, #4               @ bottom word holds Method*
     .cfi_adjust_cfa_offset -4
@@ -831,23 +861,13 @@ END \name
 .macro FOUR_ARG_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
-    sub    sp, #12                    @ alignment padding
-    .cfi_adjust_cfa_offset 12
-    push   {r3}                       @ Save r3 as is it used as a temp register in the
-    .cfi_adjust_cfa_offset 4          @   expansion of the SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
-    .cfi_rel_offset r3, 0             @   macro below, which clobbers its arguments.
-    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r3, r12  @ save callee saves in case of GC
-    ldr    r3, [sp, 32]               @ restore r3
-    .cfi_restore r3
-
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME_PRESERVE_RTEMP2  r12, r3  @ save callee saves in case of GC
     str    r9, [sp, #-16]!            @ expand the frame and pass Thread::Current
     .cfi_adjust_cfa_offset 16
     bl     \entrypoint
     add    sp, #16                    @ strip the extra frame
     .cfi_adjust_cfa_offset -16
     RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
-    add    sp, #16                    @ pop r3 + padding
-    .cfi_adjust_cfa_offset -16
     \return
 END \name
 .endm
index 229601b..3f2abfe 100644 (file)
@@ -73,6 +73,38 @@ MACRO2(SETUP_REFS_ONLY_CALLEE_SAVE_FRAME, got_reg, temp_reg)
 #endif
 END_MACRO
 
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kRefsOnly)
+     * and preserves the value of got_reg at entry.
+     */
+MACRO2(SETUP_REFS_ONLY_CALLEE_SAVE_FRAME_PRESERVE_GOT_REG, got_reg, temp_reg)
+    PUSH edi  // Save callee saves (ebx is saved/restored by the upcall)
+    PUSH esi
+    PUSH ebp
+    pushl REG_VAR(got_reg)  // Save got_reg
+    subl MACRO_LITERAL(8), %esp  // Grow stack by 2 words.
+    CFI_ADJUST_CFA_OFFSET(8)
+
+    SETUP_GOT_NOSAVE RAW_VAR(got_reg)
+    // Load Runtime::instance_ from GOT.
+    movl SYMBOL(_ZN3art7Runtime9instance_E)@GOT(REG_VAR(got_reg)), REG_VAR(temp_reg)
+    movl (REG_VAR(temp_reg)), REG_VAR(temp_reg)
+    // Push save all callee-save method.
+    pushl RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET(REG_VAR(temp_reg))
+    CFI_ADJUST_CFA_OFFSET(4)
+    // Store esp as the top quick frame.
+    movl %esp, %fs:THREAD_TOP_QUICK_FRAME_OFFSET
+    // Restore got_reg.
+    movl 12(%esp), REG_VAR(got_reg)
+
+    // Ugly compile-time check, but we only have the preprocessor.
+    // Last +4: implicit return address pushed on stack when caller made call.
+#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 3*4 + 16 + 4)
+#error "REFS_ONLY_CALLEE_SAVE_FRAME(X86) size not as expected."
+#endif
+END_MACRO
+
 MACRO0(RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME)
     addl MACRO_LITERAL(16), %esp  // Unwind stack up to saved values
     CFI_ADJUST_CFA_OFFSET(-16)
@@ -686,14 +718,7 @@ END_MACRO
 
 MACRO3(FOUR_ARG_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION VAR(c_name)
-    subl MACRO_LITERAL(12), %esp                 // alignment padding
-    CFI_ADJUST_CFA_OFFSET(12)
-    PUSH ebx                                     // Save ebx as the expansion of the
-                                                 //   SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
-                                                 //   macro below clobbers it.
-    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  ebx, ebx  // save ref containing registers for GC
-    movl 28(%esp), %ebx                          // restore ebx
-    CFI_RESTORE_REG ebx
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME_PRESERVE_GOT_REG  ebx, ebx  // save ref containing registers for GC
 
     // Outgoing argument set up
     subl MACRO_LITERAL(12), %esp                 // alignment padding
@@ -708,8 +733,6 @@ MACRO3(FOUR_ARG_DOWNCALL, c_name, cxx_name, return_macro)
     addl MACRO_LITERAL(32), %esp                 // pop arguments
     CFI_ADJUST_CFA_OFFSET(-32)
     RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME          // restore frame up to return address
-    addl MACRO_LITERAL(16), %esp                 // pop ebx + padding
-    CFI_ADJUST_CFA_OFFSET(-16)
     CALL_MACRO(return_macro)                     // return or deliver exception
     END_FUNCTION VAR(c_name)
 END_MACRO
diff --git a/test/605-new-string-from-bytes/expected.txt b/test/605-new-string-from-bytes/expected.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/605-new-string-from-bytes/info.txt b/test/605-new-string-from-bytes/info.txt
new file mode 100644 (file)
index 0000000..be02c43
--- /dev/null
@@ -0,0 +1,2 @@
+Regression test for the newStringFromBytes entrypoint,
+which used to wrongly setup the stack.
diff --git a/test/605-new-string-from-bytes/src/Main.java b/test/605-new-string-from-bytes/src/Main.java
new file mode 100644 (file)
index 0000000..bd24b50
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class Main {
+
+  public static void main(String[] args) throws Exception {
+    Class c = Class.forName("java.lang.StringFactory");
+    Method m = c.getDeclaredMethod("newStringFromBytes", byte[].class, int.class);
+
+    // Loop over allocations to get more chances of doing GC while in the
+    // newStringFromBytes intrinsic.
+    for (int i = 0; i < 10; i++) {
+      try {
+        byte[] f = new byte[100000000];
+        f[0] = (byte)i;
+        f[1] = (byte)i;
+        m.invoke(null, f, 0);
+      } catch (InvocationTargetException e) {
+        if (e.getCause() instanceof OutOfMemoryError) {
+          // Ignore, this is a stress test.
+        } else {
+          throw e;
+        }
+      }
+    }
+  }
+}