mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-13 01:13:10 +00:00
Merge
This commit is contained in:
commit
5f8d6ce7b6
@ -345,7 +345,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo
|
||||
return (err == PS_OK)? array : 0;
|
||||
}
|
||||
|
||||
#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) | defined(ppc64)
|
||||
#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) | defined(ppc64) || defined(aarch64)
|
||||
JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0
|
||||
(JNIEnv *env, jobject this_obj, jint lwp_id) {
|
||||
|
||||
@ -367,6 +367,9 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo
|
||||
#ifdef amd64
|
||||
#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG
|
||||
#endif
|
||||
#ifdef aarch64
|
||||
#define NPRGREG 32
|
||||
#endif
|
||||
#if defined(sparc) || defined(sparcv9)
|
||||
#define NPRGREG sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_NPRGREG
|
||||
#endif
|
||||
@ -466,6 +469,12 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo
|
||||
regs[REG_INDEX(R_O7)] = gregs.u_regs[14];
|
||||
#endif /* sparc */
|
||||
|
||||
#if defined(aarch64)
|
||||
|
||||
#define REG_INDEX(reg) sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_##reg
|
||||
|
||||
#endif /* aarch64 */
|
||||
|
||||
#ifdef ppc64
|
||||
#define REG_INDEX(reg) sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_##reg
|
||||
|
||||
|
||||
@ -71,6 +71,9 @@ combination of ptrace and /proc calls.
|
||||
#if defined(sparc) || defined(sparcv9) || defined(ppc64)
|
||||
#define user_regs_struct pt_regs
|
||||
#endif
|
||||
#if defined(aarch64)
|
||||
#define user_regs_struct user_pt_regs
|
||||
#endif
|
||||
|
||||
// This C bool type must be int for compatibility with Linux calls and
|
||||
// it would be a mistake to equivalence it to C++ bool on many platforms
|
||||
|
||||
@ -34,6 +34,7 @@ import sun.jvm.hotspot.debugger.JVMDebugger;
|
||||
import sun.jvm.hotspot.debugger.MachineDescription;
|
||||
import sun.jvm.hotspot.debugger.MachineDescriptionAMD64;
|
||||
import sun.jvm.hotspot.debugger.MachineDescriptionPPC64;
|
||||
import sun.jvm.hotspot.debugger.MachineDescriptionAArch64;
|
||||
import sun.jvm.hotspot.debugger.MachineDescriptionIA64;
|
||||
import sun.jvm.hotspot.debugger.MachineDescriptionIntelX86;
|
||||
import sun.jvm.hotspot.debugger.MachineDescriptionSPARC32Bit;
|
||||
@ -591,6 +592,8 @@ public class HotSpotAgent {
|
||||
machDesc = new MachineDescriptionAMD64();
|
||||
} else if (cpu.equals("ppc64")) {
|
||||
machDesc = new MachineDescriptionPPC64();
|
||||
} else if (cpu.equals("aarch64")) {
|
||||
machDesc = new MachineDescriptionAArch64();
|
||||
} else if (cpu.equals("sparc")) {
|
||||
if (LinuxDebuggerLocal.getAddressSize()==8) {
|
||||
machDesc = new MachineDescriptionSPARC64Bit();
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2014, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.debugger;
|
||||
|
||||
public class MachineDescriptionAArch64 extends MachineDescriptionTwosComplement implements MachineDescription {
|
||||
public long getAddressSize() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
public boolean isLP64() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isBigEndian() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -61,7 +61,7 @@ public class PlatformInfo {
|
||||
return "x86";
|
||||
} else if (cpu.equals("sparc") || cpu.equals("sparcv9")) {
|
||||
return "sparc";
|
||||
} else if (cpu.equals("ia64") || cpu.equals("amd64") || cpu.equals("x86_64") || cpu.equals("ppc64")) {
|
||||
} else if (cpu.equals("ia64") || cpu.equals("amd64") || cpu.equals("x86_64") || cpu.equals("ppc64") || cpu.equals("aarch64")) {
|
||||
return cpu;
|
||||
} else {
|
||||
try {
|
||||
|
||||
@ -286,7 +286,7 @@ ifneq ($(OSNAME),windows)
|
||||
|
||||
# Use uname output for SRCARCH, but deal with platform differences. If ARCH
|
||||
# is not explicitly listed below, it is treated as x86.
|
||||
SRCARCH = $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 arm ppc ppc64 zero,$(ARCH)))
|
||||
SRCARCH = $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 arm ppc ppc64 aarch64 zero,$(ARCH)))
|
||||
ARCH/ = x86
|
||||
ARCH/sparc = sparc
|
||||
ARCH/sparc64= sparc
|
||||
@ -296,6 +296,7 @@ ifneq ($(OSNAME),windows)
|
||||
ARCH/ppc64 = ppc
|
||||
ARCH/ppc = ppc
|
||||
ARCH/arm = arm
|
||||
ARCH/aarch64= aarch64
|
||||
ARCH/zero = zero
|
||||
|
||||
# BUILDARCH is usually the same as SRCARCH, except for sparcv9
|
||||
@ -326,11 +327,12 @@ ifneq ($(OSNAME),windows)
|
||||
LIBARCH/sparcv9 = sparcv9
|
||||
LIBARCH/ia64 = ia64
|
||||
LIBARCH/ppc64 = ppc64
|
||||
LIBARCH/aarch64 = aarch64
|
||||
LIBARCH/ppc = ppc
|
||||
LIBARCH/arm = arm
|
||||
LIBARCH/zero = $(ZERO_LIBARCH)
|
||||
|
||||
LP64_ARCH = sparcv9 amd64 ia64 ppc64 zero
|
||||
LP64_ARCH = sparcv9 amd64 ia64 ppc64 aarch64 zero
|
||||
endif
|
||||
|
||||
# Required make macro settings for all platforms
|
||||
|
||||
32
hotspot/make/linux/makefiles/aarch64.make
Normal file
32
hotspot/make/linux/makefiles/aarch64.make
Normal file
@ -0,0 +1,32 @@
|
||||
#
|
||||
# Copyright (c) 2003, 2013, 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.
|
||||
#
|
||||
#
|
||||
|
||||
# The copied fdlibm routines in sharedRuntimeTrig.o must not be optimized
|
||||
OPT_CFLAGS/sharedRuntimeTrig.o = $(OPT_CFLAGS/NOOPT)
|
||||
# The copied fdlibm routines in sharedRuntimeTrans.o must not be optimized
|
||||
OPT_CFLAGS/sharedRuntimeTrans.o = $(OPT_CFLAGS/NOOPT)
|
||||
# Must also specify if CPU is little endian
|
||||
CFLAGS += -DVM_LITTLE_ENDIAN
|
||||
|
||||
CFLAGS += -D_LP64=1
|
||||
@ -194,6 +194,7 @@ DATA_MODE/sparc = 32
|
||||
DATA_MODE/sparcv9 = 64
|
||||
DATA_MODE/amd64 = 64
|
||||
DATA_MODE/ppc64 = 64
|
||||
DATA_MODE/aarch64 = 64
|
||||
|
||||
DATA_MODE = $(DATA_MODE/$(BUILDARCH))
|
||||
|
||||
|
||||
@ -130,6 +130,15 @@ ifneq (,$(findstring $(ARCH), ppc ppc64))
|
||||
HS_ARCH = ppc
|
||||
endif
|
||||
|
||||
# AARCH64
|
||||
ifeq ($(ARCH), aarch64)
|
||||
ARCH_DATA_MODEL = 64
|
||||
MAKE_ARGS += LP64=1
|
||||
PLATFORM = linux-aarch64
|
||||
VM_PLATFORM = linux_aarch64
|
||||
HS_ARCH = aarch64
|
||||
endif
|
||||
|
||||
# On 32 bit linux we build server and client, on 64 bit just server.
|
||||
ifeq ($(JVM_VARIANTS),)
|
||||
ifeq ($(ARCH_DATA_MODEL), 32)
|
||||
|
||||
@ -172,6 +172,7 @@ endif
|
||||
ARCHFLAG = $(ARCHFLAG/$(BUILDARCH))
|
||||
ARCHFLAG/i486 = -m32 -march=i586
|
||||
ARCHFLAG/amd64 = -m64 $(STACK_ALIGNMENT_OPT)
|
||||
ARCHFLAG/aarch64 =
|
||||
ARCHFLAG/ia64 =
|
||||
ARCHFLAG/sparc = -m32 -mcpu=v9
|
||||
ARCHFLAG/sparcv9 = -m64 -mcpu=v9
|
||||
|
||||
15
hotspot/make/linux/platform_aarch64
Normal file
15
hotspot/make/linux/platform_aarch64
Normal file
@ -0,0 +1,15 @@
|
||||
os_family = linux
|
||||
|
||||
arch = aarch64
|
||||
|
||||
arch_model = aarch64
|
||||
|
||||
os_arch = linux_aarch64
|
||||
|
||||
os_arch_model = linux_aarch64
|
||||
|
||||
lib_arch = aarch64
|
||||
|
||||
compiler = gcc
|
||||
|
||||
sysdefs = -DLINUX -D_GNU_SOURCE -DAARCH64
|
||||
12255
hotspot/src/cpu/aarch64/vm/aarch64.ad
Normal file
12255
hotspot/src/cpu/aarch64/vm/aarch64.ad
Normal file
File diff suppressed because it is too large
Load Diff
41
hotspot/src/cpu/aarch64/vm/aarch64Test.cpp
Normal file
41
hotspot/src/cpu/aarch64/vm/aarch64Test.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "code/codeBlob.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
|
||||
// hook routine called during JVM bootstrap to test AArch64 assembler
|
||||
|
||||
extern "C" void entry(CodeBuffer*);
|
||||
|
||||
void aarch64TestHook()
|
||||
{
|
||||
BufferBlob* b = BufferBlob::create("aarch64Test", 500000);
|
||||
CodeBuffer code(b);
|
||||
MacroAssembler _masm(&code);
|
||||
entry(&code);
|
||||
}
|
||||
365
hotspot/src/cpu/aarch64/vm/aarch64_ad.m4
Normal file
365
hotspot/src/cpu/aarch64/vm/aarch64_ad.m4
Normal file
@ -0,0 +1,365 @@
|
||||
dnl Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
dnl DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
dnl
|
||||
dnl This code is free software; you can redistribute it and/or modify it
|
||||
dnl under the terms of the GNU General Public License version 2 only, as
|
||||
dnl published by the Free Software Foundation.
|
||||
dnl
|
||||
dnl This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
dnl version 2 for more details (a copy is included in the LICENSE file that
|
||||
dnl accompanied this code).
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License version
|
||||
dnl 2 along with this work; if not, write to the Free Software Foundation,
|
||||
dnl Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
dnl
|
||||
dnl Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
dnl or visit www.oracle.com if you need additional information or have any
|
||||
dnl questions.
|
||||
dnl
|
||||
dnl
|
||||
dnl Process this file with m4 aarch64_ad.m4 to generate the arithmetic
|
||||
dnl and shift patterns patterns used in aarch64.ad.
|
||||
dnl
|
||||
// BEGIN This section of the file is automatically generated. Do not edit --------------
|
||||
|
||||
define(`BASE_SHIFT_INSN',
|
||||
`
|
||||
instruct $2$1_reg_$4_reg(iReg$1NoSp dst,
|
||||
iReg$1 src1, iReg$1 src2,
|
||||
immI src3, rFlagsReg cr) %{
|
||||
match(Set dst ($2$1 src1 ($4$1 src2 src3)));
|
||||
|
||||
ins_cost(1.9 * INSN_COST);
|
||||
format %{ "$3 $dst, $src1, $src2, $5 $src3" %}
|
||||
|
||||
ins_encode %{
|
||||
__ $3(as_Register($dst$$reg),
|
||||
as_Register($src1$$reg),
|
||||
as_Register($src2$$reg),
|
||||
Assembler::$5,
|
||||
$src3$$constant & 0x3f);
|
||||
%}
|
||||
|
||||
ins_pipe(ialu_reg_reg_shift);
|
||||
%}')dnl
|
||||
define(`BASE_INVERTED_INSN',
|
||||
`
|
||||
instruct $2$1_reg_not_reg(iReg$1NoSp dst,
|
||||
iReg$1 src1, iReg$1 src2, imm$1_M1 m1,
|
||||
rFlagsReg cr) %{
|
||||
dnl This ifelse is because hotspot reassociates (xor (xor ..)..)
|
||||
dnl into this canonical form.
|
||||
ifelse($2,Xor,
|
||||
match(Set dst (Xor$1 m1 (Xor$1 src2 src1)));,
|
||||
match(Set dst ($2$1 src1 (Xor$1 src2 m1)));)
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "$3 $dst, $src1, $src2" %}
|
||||
|
||||
ins_encode %{
|
||||
__ $3(as_Register($dst$$reg),
|
||||
as_Register($src1$$reg),
|
||||
as_Register($src2$$reg),
|
||||
Assembler::LSL, 0);
|
||||
%}
|
||||
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}')dnl
|
||||
define(`INVERTED_SHIFT_INSN',
|
||||
`
|
||||
instruct $2$1_reg_$4_not_reg(iReg$1NoSp dst,
|
||||
iReg$1 src1, iReg$1 src2,
|
||||
immI src3, imm$1_M1 src4, rFlagsReg cr) %{
|
||||
dnl This ifelse is because hotspot reassociates (xor (xor ..)..)
|
||||
dnl into this canonical form.
|
||||
ifelse($2,Xor,
|
||||
match(Set dst ($2$1 src4 (Xor$1($4$1 src2 src3) src1)));,
|
||||
match(Set dst ($2$1 src1 (Xor$1($4$1 src2 src3) src4)));)
|
||||
ins_cost(1.9 * INSN_COST);
|
||||
format %{ "$3 $dst, $src1, $src2, $5 $src3" %}
|
||||
|
||||
ins_encode %{
|
||||
__ $3(as_Register($dst$$reg),
|
||||
as_Register($src1$$reg),
|
||||
as_Register($src2$$reg),
|
||||
Assembler::$5,
|
||||
$src3$$constant & 0x3f);
|
||||
%}
|
||||
|
||||
ins_pipe(ialu_reg_reg_shift);
|
||||
%}')dnl
|
||||
define(`NOT_INSN',
|
||||
`instruct reg$1_not_reg(iReg$1NoSp dst,
|
||||
iReg$1 src1, imm$1_M1 m1,
|
||||
rFlagsReg cr) %{
|
||||
match(Set dst (Xor$1 src1 m1));
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "$2 $dst, $src1, zr" %}
|
||||
|
||||
ins_encode %{
|
||||
__ $2(as_Register($dst$$reg),
|
||||
as_Register($src1$$reg),
|
||||
zr,
|
||||
Assembler::LSL, 0);
|
||||
%}
|
||||
|
||||
ins_pipe(ialu_reg);
|
||||
%}')dnl
|
||||
dnl
|
||||
define(`BOTH_SHIFT_INSNS',
|
||||
`BASE_SHIFT_INSN(I, $1, ifelse($2,andr,andw,$2w), $3, $4)
|
||||
BASE_SHIFT_INSN(L, $1, $2, $3, $4)')dnl
|
||||
dnl
|
||||
define(`BOTH_INVERTED_INSNS',
|
||||
`BASE_INVERTED_INSN(I, $1, $2, $3, $4)
|
||||
BASE_INVERTED_INSN(L, $1, $2, $3, $4)')dnl
|
||||
dnl
|
||||
define(`BOTH_INVERTED_SHIFT_INSNS',
|
||||
`INVERTED_SHIFT_INSN(I, $1, $2w, $3, $4, ~0, int)
|
||||
INVERTED_SHIFT_INSN(L, $1, $2, $3, $4, ~0l, long)')dnl
|
||||
dnl
|
||||
define(`ALL_SHIFT_KINDS',
|
||||
`BOTH_SHIFT_INSNS($1, $2, URShift, LSR)
|
||||
BOTH_SHIFT_INSNS($1, $2, RShift, ASR)
|
||||
BOTH_SHIFT_INSNS($1, $2, LShift, LSL)')dnl
|
||||
dnl
|
||||
define(`ALL_INVERTED_SHIFT_KINDS',
|
||||
`BOTH_INVERTED_SHIFT_INSNS($1, $2, URShift, LSR)
|
||||
BOTH_INVERTED_SHIFT_INSNS($1, $2, RShift, ASR)
|
||||
BOTH_INVERTED_SHIFT_INSNS($1, $2, LShift, LSL)')dnl
|
||||
dnl
|
||||
NOT_INSN(L, eon)
|
||||
NOT_INSN(I, eonw)
|
||||
BOTH_INVERTED_INSNS(And, bic)
|
||||
BOTH_INVERTED_INSNS(Or, orn)
|
||||
BOTH_INVERTED_INSNS(Xor, eon)
|
||||
ALL_INVERTED_SHIFT_KINDS(And, bic)
|
||||
ALL_INVERTED_SHIFT_KINDS(Xor, eon)
|
||||
ALL_INVERTED_SHIFT_KINDS(Or, orn)
|
||||
ALL_SHIFT_KINDS(And, andr)
|
||||
ALL_SHIFT_KINDS(Xor, eor)
|
||||
ALL_SHIFT_KINDS(Or, orr)
|
||||
ALL_SHIFT_KINDS(Add, add)
|
||||
ALL_SHIFT_KINDS(Sub, sub)
|
||||
dnl
|
||||
dnl EXTEND mode, rshift_op, src, lshift_count, rshift_count
|
||||
define(`EXTEND', `($2$1 (LShift$1 $3 $4) $5)')
|
||||
define(`BFM_INSN',`
|
||||
// Shift Left followed by Shift Right.
|
||||
// This idiom is used by the compiler for the i2b bytecode etc.
|
||||
instruct $4$1(iReg$1NoSp dst, iReg$1 src, immI lshift_count, immI rshift_count)
|
||||
%{
|
||||
match(Set dst EXTEND($1, $3, src, lshift_count, rshift_count));
|
||||
// Make sure we are not going to exceed what $4 can do.
|
||||
predicate((unsigned int)n->in(2)->get_int() <= $2
|
||||
&& (unsigned int)n->in(1)->in(2)->get_int() <= $2);
|
||||
|
||||
ins_cost(INSN_COST * 2);
|
||||
format %{ "$4 $dst, $src, $rshift_count - $lshift_count, #$2 - $lshift_count" %}
|
||||
ins_encode %{
|
||||
int lshift = $lshift_count$$constant, rshift = $rshift_count$$constant;
|
||||
int s = $2 - lshift;
|
||||
int r = (rshift - lshift) & $2;
|
||||
__ $4(as_Register($dst$$reg),
|
||||
as_Register($src$$reg),
|
||||
r, s);
|
||||
%}
|
||||
|
||||
ins_pipe(ialu_reg_shift);
|
||||
%}')
|
||||
BFM_INSN(L, 63, RShift, sbfm)
|
||||
BFM_INSN(I, 31, RShift, sbfmw)
|
||||
BFM_INSN(L, 63, URShift, ubfm)
|
||||
BFM_INSN(I, 31, URShift, ubfmw)
|
||||
dnl
|
||||
// Bitfield extract with shift & mask
|
||||
define(`BFX_INSN',
|
||||
`instruct $3$1(iReg$1NoSp dst, iReg$1 src, immI rshift, imm$1_bitmask mask)
|
||||
%{
|
||||
match(Set dst (And$1 ($2$1 src rshift) mask));
|
||||
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "$3 $dst, $src, $mask" %}
|
||||
ins_encode %{
|
||||
int rshift = $rshift$$constant;
|
||||
long mask = $mask$$constant;
|
||||
int width = exact_log2(mask+1);
|
||||
__ $3(as_Register($dst$$reg),
|
||||
as_Register($src$$reg), rshift, width);
|
||||
%}
|
||||
ins_pipe(ialu_reg_shift);
|
||||
%}')
|
||||
BFX_INSN(I,URShift,ubfxw)
|
||||
BFX_INSN(L,URShift,ubfx)
|
||||
|
||||
// We can use ubfx when extending an And with a mask when we know mask
|
||||
// is positive. We know that because immI_bitmask guarantees it.
|
||||
instruct ubfxIConvI2L(iRegLNoSp dst, iRegIorL2I src, immI rshift, immI_bitmask mask)
|
||||
%{
|
||||
match(Set dst (ConvI2L (AndI (URShiftI src rshift) mask)));
|
||||
|
||||
ins_cost(INSN_COST * 2);
|
||||
format %{ "ubfx $dst, $src, $mask" %}
|
||||
ins_encode %{
|
||||
int rshift = $rshift$$constant;
|
||||
long mask = $mask$$constant;
|
||||
int width = exact_log2(mask+1);
|
||||
__ ubfx(as_Register($dst$$reg),
|
||||
as_Register($src$$reg), rshift, width);
|
||||
%}
|
||||
ins_pipe(ialu_reg_shift);
|
||||
%}
|
||||
|
||||
// Rotations
|
||||
|
||||
define(`EXTRACT_INSN',
|
||||
`instruct extr$3$1(iReg$1NoSp dst, iReg$1 src1, iReg$1 src2, immI lshift, immI rshift, rFlagsReg cr)
|
||||
%{
|
||||
match(Set dst ($3$1 (LShift$1 src1 lshift) (URShift$1 src2 rshift)));
|
||||
predicate(0 == ((n->in(1)->in(2)->get_int() + n->in(2)->in(2)->get_int()) & $2));
|
||||
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "extr $dst, $src1, $src2, #$rshift" %}
|
||||
|
||||
ins_encode %{
|
||||
__ $4(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg),
|
||||
$rshift$$constant & $2);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg_extr);
|
||||
%}
|
||||
')dnl
|
||||
EXTRACT_INSN(L, 63, Or, extr)
|
||||
EXTRACT_INSN(I, 31, Or, extrw)
|
||||
EXTRACT_INSN(L, 63, Add, extr)
|
||||
EXTRACT_INSN(I, 31, Add, extrw)
|
||||
define(`ROL_EXPAND', `
|
||||
// $2 expander
|
||||
|
||||
instruct $2$1_rReg(iReg$1 dst, iReg$1 src, iRegI shift, rFlagsReg cr)
|
||||
%{
|
||||
effect(DEF dst, USE src, USE shift);
|
||||
|
||||
format %{ "$2 $dst, $src, $shift" %}
|
||||
ins_cost(INSN_COST * 3);
|
||||
ins_encode %{
|
||||
__ subw(rscratch1, zr, as_Register($shift$$reg));
|
||||
__ $3(as_Register($dst$$reg), as_Register($src$$reg),
|
||||
rscratch1);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg_vshift);
|
||||
%}')dnl
|
||||
define(`ROR_EXPAND', `
|
||||
// $2 expander
|
||||
|
||||
instruct $2$1_rReg(iReg$1 dst, iReg$1 src, iRegI shift, rFlagsReg cr)
|
||||
%{
|
||||
effect(DEF dst, USE src, USE shift);
|
||||
|
||||
format %{ "$2 $dst, $src, $shift" %}
|
||||
ins_cost(INSN_COST);
|
||||
ins_encode %{
|
||||
__ $3(as_Register($dst$$reg), as_Register($src$$reg),
|
||||
as_Register($shift$$reg));
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg_vshift);
|
||||
%}')dnl
|
||||
define(ROL_INSN, `
|
||||
instruct $3$1_rReg_Var_C$2(iRegL dst, iRegL src, iRegI shift, immI$2 c$2, rFlagsReg cr)
|
||||
%{
|
||||
match(Set dst (Or$1 (LShift$1 src shift) (URShift$1 src (SubI c$2 shift))));
|
||||
|
||||
expand %{
|
||||
$3L_rReg(dst, src, shift, cr);
|
||||
%}
|
||||
%}')dnl
|
||||
define(ROR_INSN, `
|
||||
instruct $3$1_rReg_Var_C$2(iRegL dst, iRegL src, iRegI shift, immI$2 c$2, rFlagsReg cr)
|
||||
%{
|
||||
match(Set dst (Or$1 (URShift$1 src shift) (LShift$1 src (SubI c$2 shift))));
|
||||
|
||||
expand %{
|
||||
$3L_rReg(dst, src, shift, cr);
|
||||
%}
|
||||
%}')dnl
|
||||
ROL_EXPAND(L, rol, rorv)
|
||||
ROL_EXPAND(I, rol, rorvw)
|
||||
ROL_INSN(L, _64, rol)
|
||||
ROL_INSN(L, 0, rol)
|
||||
ROL_INSN(I, _32, rol)
|
||||
ROL_INSN(I, 0, rol)
|
||||
ROR_EXPAND(L, ror, rorv)
|
||||
ROR_EXPAND(I, ror, rorvw)
|
||||
ROR_INSN(L, _64, ror)
|
||||
ROR_INSN(L, 0, ror)
|
||||
ROR_INSN(I, _32, ror)
|
||||
ROR_INSN(I, 0, ror)
|
||||
|
||||
// Add/subtract (extended)
|
||||
dnl ADD_SUB_EXTENDED(mode, size, add node, shift node, insn, shift type, wordsize
|
||||
define(`ADD_SUB_CONV', `
|
||||
instruct $3Ext$1(iReg$2NoSp dst, iReg$2 src1, iReg$1orL2I src2, rFlagsReg cr)
|
||||
%{
|
||||
match(Set dst ($3$2 src1 (ConvI2L src2)));
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "$4 $dst, $src1, $5 $src2" %}
|
||||
|
||||
ins_encode %{
|
||||
__ $4(as_Register($dst$$reg), as_Register($src1$$reg),
|
||||
as_Register($src2$$reg), ext::$5);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}')dnl
|
||||
ADD_SUB_CONV(I,L,Add,add,sxtw);
|
||||
ADD_SUB_CONV(I,L,Sub,sub,sxtw);
|
||||
dnl
|
||||
define(`ADD_SUB_EXTENDED', `
|
||||
instruct $3Ext$1_$6(iReg$1NoSp dst, iReg$1 src1, iReg$1 src2, immI_`'eval($7-$2) lshift, immI_`'eval($7-$2) rshift, rFlagsReg cr)
|
||||
%{
|
||||
match(Set dst ($3$1 src1 EXTEND($1, $4, src2, lshift, rshift)));
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "$5 $dst, $src1, $6 $src2" %}
|
||||
|
||||
ins_encode %{
|
||||
__ $5(as_Register($dst$$reg), as_Register($src1$$reg),
|
||||
as_Register($src2$$reg), ext::$6);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}')
|
||||
ADD_SUB_EXTENDED(I,16,Add,RShift,add,sxth,32)
|
||||
ADD_SUB_EXTENDED(I,8,Add,RShift,add,sxtb,32)
|
||||
ADD_SUB_EXTENDED(I,8,Add,URShift,add,uxtb,32)
|
||||
ADD_SUB_EXTENDED(L,16,Add,RShift,add,sxth,64)
|
||||
ADD_SUB_EXTENDED(L,32,Add,RShift,add,sxtw,64)
|
||||
ADD_SUB_EXTENDED(L,8,Add,RShift,add,sxtb,64)
|
||||
ADD_SUB_EXTENDED(L,8,Add,URShift,add,uxtb,64)
|
||||
dnl
|
||||
dnl ADD_SUB_ZERO_EXTEND(mode, size, add node, insn, shift type)
|
||||
define(`ADD_SUB_ZERO_EXTEND', `
|
||||
instruct $3Ext$1_$5_and(iReg$1NoSp dst, iReg$1 src1, iReg$1 src2, imm$1_$2 mask, rFlagsReg cr)
|
||||
%{
|
||||
match(Set dst ($3$1 src1 (And$1 src2 mask)));
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "$4 $dst, $src1, $src2, $5" %}
|
||||
|
||||
ins_encode %{
|
||||
__ $4(as_Register($dst$$reg), as_Register($src1$$reg),
|
||||
as_Register($src2$$reg), ext::$5);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}')
|
||||
dnl
|
||||
ADD_SUB_ZERO_EXTEND(I,255,Add,addw,uxtb)
|
||||
ADD_SUB_ZERO_EXTEND(I,65535,Add,addw,uxth)
|
||||
ADD_SUB_ZERO_EXTEND(L,255,Add,add,uxtb)
|
||||
ADD_SUB_ZERO_EXTEND(L,65535,Add,add,uxth)
|
||||
ADD_SUB_ZERO_EXTEND(L,4294967295,Add,add,uxtw)
|
||||
dnl
|
||||
ADD_SUB_ZERO_EXTEND(I,255,Sub,subw,uxtb)
|
||||
ADD_SUB_ZERO_EXTEND(I,65535,Sub,subw,uxth)
|
||||
ADD_SUB_ZERO_EXTEND(L,255,Sub,sub,uxtb)
|
||||
ADD_SUB_ZERO_EXTEND(L,65535,Sub,sub,uxth)
|
||||
ADD_SUB_ZERO_EXTEND(L,4294967295,Sub,sub,uxtw)
|
||||
|
||||
// END This section of the file is automatically generated. Do not edit --------------
|
||||
200
hotspot/src/cpu/aarch64/vm/aarch64_call.cpp
Normal file
200
hotspot/src/cpu/aarch64/vm/aarch64_call.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef BUILTIN_SIM
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "../../../../../../simulator/cpustate.hpp"
|
||||
#include "../../../../../../simulator/simulator.hpp"
|
||||
|
||||
/*
|
||||
* a routine to initialise and enter ARM simulator execution when
|
||||
* calling into ARM code from x86 code.
|
||||
*
|
||||
* we maintain a simulator per-thread and provide it with 8 Mb of
|
||||
* stack space
|
||||
*/
|
||||
#define SIM_STACK_SIZE (1024 * 1024) // in units of u_int64_t
|
||||
|
||||
extern "C" u_int64_t get_alt_stack()
|
||||
{
|
||||
return AArch64Simulator::altStack();
|
||||
}
|
||||
|
||||
extern "C" void setup_arm_sim(void *sp, u_int64_t calltype)
|
||||
{
|
||||
// n.b. this function runs on the simulator stack so as to avoid
|
||||
// simulator frames appearing in between VM x86 and ARM frames. note
|
||||
// that arfgument sp points to the old (VM) stack from which the
|
||||
// call into the sim was made. The stack switch and entry into this
|
||||
// routine is handled by x86 prolog code planted in the head of the
|
||||
// ARM code buffer which the sim is about to start executing (see
|
||||
// aarch64_linkage.S).
|
||||
//
|
||||
// The first ARM instruction in the buffer is identified by fnptr
|
||||
// stored at the top of the old stack. x86 register contents precede
|
||||
// fnptr. preceding that are the fp and return address of the VM
|
||||
// caller into ARM code. any extra, non-register arguments passed to
|
||||
// the linkage routine precede the fp (this is as per any normal x86
|
||||
// call wirth extra args).
|
||||
//
|
||||
// note that the sim creates Java frames on the Java stack just
|
||||
// above sp (i.e. directly above fnptr). it sets the sim FP register
|
||||
// to the pushed fp for the caller effectively eliding the register
|
||||
// data saved by the linkage routine.
|
||||
//
|
||||
// x86 register call arguments are loaded from the stack into ARM
|
||||
// call registers. if extra arguments occur preceding the x86
|
||||
// caller's fp then they are copied either into extra ARM registers
|
||||
// (ARM has 8 rather than 6 gp call registers) or up the stack
|
||||
// beyond the saved x86 registers so that they immediately precede
|
||||
// the ARM frame where the ARM calling convention expects them to
|
||||
// be.
|
||||
//
|
||||
// n.b. the number of register/stack values passed to the ARM code
|
||||
// is determined by calltype
|
||||
//
|
||||
// +--------+
|
||||
// | fnptr | <--- argument sp points here
|
||||
// +--------+ |
|
||||
// | rax | | return slot if we need to return a value
|
||||
// +--------+ |
|
||||
// | rdi | increasing
|
||||
// +--------+ address
|
||||
// | rsi | |
|
||||
// +--------+ V
|
||||
// | rdx |
|
||||
// +--------+
|
||||
// | rcx |
|
||||
// +--------+
|
||||
// | r8 |
|
||||
// +--------+
|
||||
// | r9 |
|
||||
// +--------+
|
||||
// | xmm0 |
|
||||
// +--------+
|
||||
// | xmm1 |
|
||||
// +--------+
|
||||
// | xmm2 |
|
||||
// +--------+
|
||||
// | xmm3 |
|
||||
// +--------+
|
||||
// | xmm4 |
|
||||
// +--------+
|
||||
// | xmm5 |
|
||||
// +--------+
|
||||
// | xmm6 |
|
||||
// +--------+
|
||||
// | xmm7 |
|
||||
// +--------+
|
||||
// | fp |
|
||||
// +--------+
|
||||
// | caller |
|
||||
// | ret ip |
|
||||
// +--------+
|
||||
// | arg0 | <-- any extra call args start here
|
||||
// +--------+ offset = 18 * wordSize
|
||||
// | . . . | (i.e. 1 * calladdr + 1 * rax + 6 * gp call regs
|
||||
// + 8 * fp call regs + 2 * frame words)
|
||||
//
|
||||
// we use a unique sim/stack per thread
|
||||
const int cursor2_offset = 18;
|
||||
const int fp_offset = 16;
|
||||
u_int64_t *cursor = (u_int64_t *)sp;
|
||||
u_int64_t *cursor2 = ((u_int64_t *)sp) + cursor2_offset;
|
||||
u_int64_t *fp = ((u_int64_t *)sp) + fp_offset;
|
||||
int gp_arg_count = calltype & 0xf;
|
||||
int fp_arg_count = (calltype >> 4) & 0xf;
|
||||
int return_type = (calltype >> 8) & 0x3;
|
||||
AArch64Simulator *sim = AArch64Simulator::get_current(UseSimulatorCache, DisableBCCheck);
|
||||
// save previous cpu state in case this is a recursive entry
|
||||
CPUState saveState = sim->getCPUState();
|
||||
// set up initial sim pc, sp and fp registers
|
||||
sim->init(*cursor++, (u_int64_t)sp, (u_int64_t)fp);
|
||||
u_int64_t *return_slot = cursor++;
|
||||
|
||||
// if we need to pass the sim extra args on the stack then bump
|
||||
// the stack pointer now
|
||||
u_int64_t *cursor3 = (u_int64_t *)sim->getCPUState().xreg(SP, 1);
|
||||
if (gp_arg_count > 8) {
|
||||
cursor3 -= gp_arg_count - 8;
|
||||
}
|
||||
if (fp_arg_count > 8) {
|
||||
cursor3 -= fp_arg_count - 8;
|
||||
}
|
||||
sim->getCPUState().xreg(SP, 1) = (u_int64_t)(cursor3++);
|
||||
|
||||
for (int i = 0; i < gp_arg_count; i++) {
|
||||
if (i < 6) {
|
||||
// copy saved register to sim register
|
||||
GReg reg = (GReg)i;
|
||||
sim->getCPUState().xreg(reg, 0) = *cursor++;
|
||||
} else if (i < 8) {
|
||||
// copy extra int arg to sim register
|
||||
GReg reg = (GReg)i;
|
||||
sim->getCPUState().xreg(reg, 0) = *cursor2++;
|
||||
} else {
|
||||
// copy extra fp arg to sim stack
|
||||
*cursor3++ = *cursor2++;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < fp_arg_count; i++) {
|
||||
if (i < 8) {
|
||||
// copy saved register to sim register
|
||||
GReg reg = (GReg)i;
|
||||
sim->getCPUState().xreg(reg, 0) = *cursor++;
|
||||
} else {
|
||||
// copy extra arg to sim stack
|
||||
*cursor3++ = *cursor2++;
|
||||
}
|
||||
}
|
||||
AArch64Simulator::status_t return_status = sim->run();
|
||||
if (return_status != AArch64Simulator::STATUS_RETURN){
|
||||
sim->simPrint0();
|
||||
fatal("invalid status returned from simulator.run()\n");
|
||||
}
|
||||
switch (return_type) {
|
||||
case MacroAssembler::ret_type_void:
|
||||
default:
|
||||
break;
|
||||
case MacroAssembler::ret_type_integral:
|
||||
// this overwrites the saved r0
|
||||
*return_slot = sim->getCPUState().xreg(R0, 0);
|
||||
break;
|
||||
case MacroAssembler::ret_type_float:
|
||||
*(float *)return_slot = sim->getCPUState().sreg(V0);
|
||||
break;
|
||||
case MacroAssembler::ret_type_double:
|
||||
*(double *)return_slot = sim->getCPUState().dreg(V0);
|
||||
break;
|
||||
}
|
||||
// restore incoimng cpu state
|
||||
sim->getCPUState() = saveState;
|
||||
}
|
||||
|
||||
#endif
|
||||
167
hotspot/src/cpu/aarch64/vm/aarch64_linkage.S
Normal file
167
hotspot/src/cpu/aarch64/vm/aarch64_linkage.S
Normal file
@ -0,0 +1,167 @@
|
||||
#
|
||||
# Copyright (c) 2012, Red Hat. 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.
|
||||
|
||||
# Routines used to enable x86 VM C++ code to invoke JIT-compiled ARM code
|
||||
# -- either Java methods or generated stub -- and to allow JIT-compiled
|
||||
# ARM code to invoke x86 VM C++ code
|
||||
#
|
||||
# the code for aarch64_stub_prolog below can be copied into the start
|
||||
# of the ARM code buffer and patched with a link to the
|
||||
# C++ routine which starts execution on the simulator. the ARM
|
||||
# code can be generated immediately following the copied code.
|
||||
|
||||
#ifdef BUILTIN_SIM
|
||||
|
||||
.data
|
||||
.globl setup_arm_sim,
|
||||
.type setup_arm_sim,@function
|
||||
.globl get_alt_stack,
|
||||
.type get_alt_stack,@function
|
||||
.globl aarch64_stub_prolog
|
||||
.p2align 4
|
||||
aarch64_stub_prolog:
|
||||
// entry point
|
||||
4: lea 1f(%rip), %r11
|
||||
mov (%r11), %r10
|
||||
mov (%r10), %r10
|
||||
jmp *%r10
|
||||
.p2align 4
|
||||
1:
|
||||
.set entry_offset, . - 1b
|
||||
.quad aarch64_prolog_ptr
|
||||
// 64 bit int used to idenitfy called fn arg/return types
|
||||
.set calltype_offset, . - 1b
|
||||
.quad 0
|
||||
// arm JIT code follows the stub
|
||||
.set arm_code_offset, . - 1b
|
||||
.size aarch64_stub_prolog, .-aarch64_stub_prolog
|
||||
aarch64_stub_prolog_end:
|
||||
|
||||
.text
|
||||
aarch64_prolog_ptr:
|
||||
.quad aarch64_prolog
|
||||
|
||||
.globl aarch64_prolog
|
||||
aarch64_prolog:
|
||||
.cfi_startproc
|
||||
pushq %rbp
|
||||
.cfi_def_cfa_offset 16
|
||||
.cfi_offset 6, -16
|
||||
movq %rsp, %rbp
|
||||
.cfi_def_cfa_register 6
|
||||
// save all registers used to pass args
|
||||
sub $8, %rsp
|
||||
movd %xmm7, (%rsp)
|
||||
sub $8, %rsp
|
||||
movd %xmm6, (%rsp)
|
||||
sub $8, %rsp
|
||||
movd %xmm5, (%rsp)
|
||||
sub $8, %rsp
|
||||
movd %xmm4, (%rsp)
|
||||
sub $8, %rsp
|
||||
movd %xmm3, (%rsp)
|
||||
sub $8, %rsp
|
||||
movd %xmm2, (%rsp)
|
||||
sub $8, %rsp
|
||||
movd %xmm1, (%rsp)
|
||||
sub $8, %rsp
|
||||
movd %xmm0, (%rsp)
|
||||
push %r9
|
||||
push %r8
|
||||
push %rcx
|
||||
push %rdx
|
||||
push %rsi
|
||||
push %rdi
|
||||
// save rax -- this stack slot will be rewritten with a
|
||||
// return value if needed
|
||||
push %rax
|
||||
// temporarily save r11 while we find the other stack
|
||||
push %r11
|
||||
// retrieve alt stack
|
||||
call get_alt_stack@PLT
|
||||
pop %r11
|
||||
// push start of arm code
|
||||
lea (arm_code_offset)(%r11), %rsi
|
||||
push %rsi
|
||||
// load call type code in arg reg 1
|
||||
mov (calltype_offset)(%r11), %rsi
|
||||
// load current stack pointer in arg reg 0
|
||||
mov %rsp, %rdi
|
||||
// switch to alt stack
|
||||
mov %rax, %rsp
|
||||
// save previous stack pointer on new stack
|
||||
push %rdi
|
||||
// 16-align the new stack pointer
|
||||
push %rdi
|
||||
// call sim setup routine
|
||||
call setup_arm_sim@PLT
|
||||
// switch back to old stack
|
||||
pop %rsp
|
||||
// pop start of arm code
|
||||
pop %rdi
|
||||
// pop rax -- either restores old value or installs return value
|
||||
pop %rax
|
||||
// pop arg registers
|
||||
pop %rdi
|
||||
pop %rsi
|
||||
pop %rdx
|
||||
pop %rcx
|
||||
pop %r8
|
||||
pop %r9
|
||||
movd (%rsp), %xmm0
|
||||
add $8, %rsp
|
||||
movd (%rsp), %xmm1
|
||||
add $8, %rsp
|
||||
movd (%rsp), %xmm2
|
||||
add $8, %rsp
|
||||
movd (%rsp), %xmm3
|
||||
add $8, %rsp
|
||||
movd (%rsp), %xmm4
|
||||
add $8, %rsp
|
||||
movd (%rsp), %xmm5
|
||||
add $8, %rsp
|
||||
movd (%rsp), %xmm6
|
||||
add $8, %rsp
|
||||
movd (%rsp), %xmm7
|
||||
add $8, %rsp
|
||||
leave
|
||||
.cfi_def_cfa 7, 8
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
|
||||
.p2align 4
|
||||
get_pc:
|
||||
// get return pc in rdi and then push it back
|
||||
pop %rdi
|
||||
push %rdi
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
.long
|
||||
.globl aarch64_stub_prolog_size
|
||||
.type aarch64_stub_prolog_size,@function
|
||||
aarch64_stub_prolog_size:
|
||||
leaq aarch64_stub_prolog_end - aarch64_stub_prolog, %rax
|
||||
ret
|
||||
|
||||
#endif
|
||||
98
hotspot/src/cpu/aarch64/vm/ad_encode.m4
Normal file
98
hotspot/src/cpu/aarch64/vm/ad_encode.m4
Normal file
@ -0,0 +1,98 @@
|
||||
dnl Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
dnl DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
dnl
|
||||
dnl This code is free software; you can redistribute it and/or modify it
|
||||
dnl under the terms of the GNU General Public License version 2 only, as
|
||||
dnl published by the Free Software Foundation.
|
||||
dnl
|
||||
dnl This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
dnl version 2 for more details (a copy is included in the LICENSE file that
|
||||
dnl accompanied this code).
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License version
|
||||
dnl 2 along with this work; if not, write to the Free Software Foundation,
|
||||
dnl Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
dnl
|
||||
dnl Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
dnl or visit www.oracle.com if you need additional information or have any
|
||||
dnl questions.
|
||||
dnl
|
||||
dnl
|
||||
dnl Process this file with m4 ad_encode.m4 to generate the load/store
|
||||
dnl patterns used in aarch64.ad.
|
||||
dnl
|
||||
define(choose, `loadStore($1, &MacroAssembler::$3, $2, $4,
|
||||
$5, $6, $7, $8);dnl
|
||||
|
||||
%}')dnl
|
||||
define(access, `
|
||||
$3Register $1_reg = as_$3Register($$1$$reg);
|
||||
$4choose(MacroAssembler(&cbuf), $1_reg,$2,$mem->opcode(),
|
||||
as_Register($mem$$base),$mem$$index,$mem$$scale,$mem$$disp)')dnl
|
||||
define(load,`
|
||||
enc_class aarch64_enc_$2($1 dst, memory mem) %{dnl
|
||||
access(dst,$2,$3)')dnl
|
||||
load(iRegI,ldrsbw)
|
||||
load(iRegI,ldrsb)
|
||||
load(iRegI,ldrb)
|
||||
load(iRegL,ldrb)
|
||||
load(iRegI,ldrshw)
|
||||
load(iRegI,ldrsh)
|
||||
load(iRegI,ldrh)
|
||||
load(iRegL,ldrh)
|
||||
load(iRegI,ldrw)
|
||||
load(iRegL,ldrw)
|
||||
load(iRegL,ldrsw)
|
||||
load(iRegL,ldr)
|
||||
load(vRegF,ldrs,Float)
|
||||
load(vRegD,ldrd,Float)
|
||||
define(STORE,`
|
||||
enc_class aarch64_enc_$2($1 src, memory mem) %{dnl
|
||||
access(src,$2,$3,$4)')dnl
|
||||
define(STORE0,`
|
||||
enc_class aarch64_enc_$2`'0(memory mem) %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
choose(_masm,zr,$2,$mem->opcode(),
|
||||
as_$3Register($mem$$base),$mem$$index,$mem$$scale,$mem$$disp)')dnl
|
||||
STORE(iRegI,strb)
|
||||
STORE0(iRegI,strb)
|
||||
STORE(iRegI,strh)
|
||||
STORE0(iRegI,strh)
|
||||
STORE(iRegI,strw)
|
||||
STORE0(iRegI,strw)
|
||||
STORE(iRegL,str,,
|
||||
`// we sometimes get asked to store the stack pointer into the
|
||||
// current thread -- we cannot do that directly on AArch64
|
||||
if (src_reg == r31_sp) {
|
||||
MacroAssembler _masm(&cbuf);
|
||||
assert(as_Register($mem$$base) == rthread, "unexpected store for sp");
|
||||
__ mov(rscratch2, sp);
|
||||
src_reg = rscratch2;
|
||||
}
|
||||
')
|
||||
STORE0(iRegL,str)
|
||||
STORE(vRegF,strs,Float)
|
||||
STORE(vRegD,strd,Float)
|
||||
|
||||
enc_class aarch64_enc_strw_immn(immN src, memory mem) %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
address con = (address)$src$$constant;
|
||||
// need to do this the hard way until we can manage relocs
|
||||
// for 32 bit constants
|
||||
__ movoop(rscratch2, (jobject)con);
|
||||
if (con) __ encode_heap_oop_not_null(rscratch2);
|
||||
choose(_masm,rscratch2,strw,$mem->opcode(),
|
||||
as_Register($mem$$base),$mem$$index,$mem$$scale,$mem$$disp)
|
||||
|
||||
enc_class aarch64_enc_strw_immnk(immN src, memory mem) %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
address con = (address)$src$$constant;
|
||||
// need to do this the hard way until we can manage relocs
|
||||
// for 32 bit constants
|
||||
__ movoop(rscratch2, (jobject)con);
|
||||
__ encode_klass_not_null(rscratch2);
|
||||
choose(_masm,rscratch2,strw,$mem->opcode(),
|
||||
as_Register($mem$$base),$mem$$index,$mem$$scale,$mem$$disp)
|
||||
|
||||
1526
hotspot/src/cpu/aarch64/vm/assembler_aarch64.cpp
Normal file
1526
hotspot/src/cpu/aarch64/vm/assembler_aarch64.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2340
hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp
Normal file
2340
hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp
Normal file
File diff suppressed because it is too large
Load Diff
33
hotspot/src/cpu/aarch64/vm/assembler_aarch64.inline.hpp
Normal file
33
hotspot/src/cpu/aarch64/vm/assembler_aarch64.inline.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_ASSEMBLER_AARCH64_INLINE_HPP
|
||||
#define CPU_AARCH64_VM_ASSEMBLER_AARCH64_INLINE_HPP
|
||||
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
|
||||
#endif // CPU_AARCH64_VM_ASSEMBLER_AARCH64_INLINE_HPP
|
||||
48
hotspot/src/cpu/aarch64/vm/bytecodeInterpreter_aarch64.cpp
Normal file
48
hotspot/src/cpu/aarch64/vm/bytecodeInterpreter_aarch64.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/assembler.hpp"
|
||||
#include "interpreter/bytecodeInterpreter.hpp"
|
||||
#include "interpreter/bytecodeInterpreter.inline.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/interpreterRuntime.hpp"
|
||||
#include "oops/methodData.hpp"
|
||||
#include "oops/method.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "prims/jvmtiThreadState.hpp"
|
||||
#include "runtime/deoptimization.hpp"
|
||||
#include "runtime/frame.inline.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
#include "runtime/synchronizer.hpp"
|
||||
#include "runtime/vframeArray.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "interp_masm_aarch64.hpp"
|
||||
|
||||
#ifdef CC_INTERP
|
||||
|
||||
#endif // CC_INTERP (all)
|
||||
116
hotspot/src/cpu/aarch64/vm/bytecodeInterpreter_aarch64.hpp
Normal file
116
hotspot/src/cpu/aarch64/vm/bytecodeInterpreter_aarch64.hpp
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_BYTECODEINTERPRETER_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_BYTECODEINTERPRETER_AARCH64_HPP
|
||||
|
||||
// Platform specific for C++ based Interpreter
|
||||
|
||||
private:
|
||||
|
||||
interpreterState _self_link; /* Previous interpreter state */ /* sometimes points to self??? */
|
||||
address _result_handler; /* temp for saving native result handler */
|
||||
intptr_t* _sender_sp; /* sender's sp before stack (locals) extension */
|
||||
|
||||
address _extra_junk1; /* temp to save on recompiles */
|
||||
address _extra_junk2; /* temp to save on recompiles */
|
||||
address _extra_junk3; /* temp to save on recompiles */
|
||||
// address dummy_for_native2; /* a native frame result handler would be here... */
|
||||
// address dummy_for_native1; /* native result type stored here in a interpreter native frame */
|
||||
address _extra_junk4; /* temp to save on recompiles */
|
||||
address _extra_junk5; /* temp to save on recompiles */
|
||||
address _extra_junk6; /* temp to save on recompiles */
|
||||
public:
|
||||
// we have an interpreter frame...
|
||||
inline intptr_t* sender_sp() {
|
||||
return _sender_sp;
|
||||
}
|
||||
|
||||
// The interpreter always has the frame anchor fully setup so we don't
|
||||
// have to do anything going to vm from the interpreter. On return
|
||||
// we do have to clear the flags in case they we're modified to
|
||||
// maintain the stack walking invariants.
|
||||
//
|
||||
#define SET_LAST_JAVA_FRAME()
|
||||
|
||||
#define RESET_LAST_JAVA_FRAME()
|
||||
|
||||
/*
|
||||
* Macros for accessing the stack.
|
||||
*/
|
||||
#undef STACK_INT
|
||||
#undef STACK_FLOAT
|
||||
#undef STACK_ADDR
|
||||
#undef STACK_OBJECT
|
||||
#undef STACK_DOUBLE
|
||||
#undef STACK_LONG
|
||||
|
||||
// JavaStack Implementation
|
||||
|
||||
#define GET_STACK_SLOT(offset) (*((intptr_t*) &topOfStack[-(offset)]))
|
||||
#define STACK_SLOT(offset) ((address) &topOfStack[-(offset)])
|
||||
#define STACK_ADDR(offset) (*((address *) &topOfStack[-(offset)]))
|
||||
#define STACK_INT(offset) (*((jint*) &topOfStack[-(offset)]))
|
||||
#define STACK_FLOAT(offset) (*((jfloat *) &topOfStack[-(offset)]))
|
||||
#define STACK_OBJECT(offset) (*((oop *) &topOfStack [-(offset)]))
|
||||
#define STACK_DOUBLE(offset) (((VMJavaVal64*) &topOfStack[-(offset)])->d)
|
||||
#define STACK_LONG(offset) (((VMJavaVal64 *) &topOfStack[-(offset)])->l)
|
||||
|
||||
#define SET_STACK_SLOT(value, offset) (*(intptr_t*)&topOfStack[-(offset)] = *(intptr_t*)(value))
|
||||
#define SET_STACK_ADDR(value, offset) (*((address *)&topOfStack[-(offset)]) = (value))
|
||||
#define SET_STACK_INT(value, offset) (*((jint *)&topOfStack[-(offset)]) = (value))
|
||||
#define SET_STACK_FLOAT(value, offset) (*((jfloat *)&topOfStack[-(offset)]) = (value))
|
||||
#define SET_STACK_OBJECT(value, offset) (*((oop *)&topOfStack[-(offset)]) = (value))
|
||||
#define SET_STACK_DOUBLE(value, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->d = (value))
|
||||
#define SET_STACK_DOUBLE_FROM_ADDR(addr, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->d = \
|
||||
((VMJavaVal64*)(addr))->d)
|
||||
#define SET_STACK_LONG(value, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->l = (value))
|
||||
#define SET_STACK_LONG_FROM_ADDR(addr, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->l = \
|
||||
((VMJavaVal64*)(addr))->l)
|
||||
// JavaLocals implementation
|
||||
|
||||
#define LOCALS_SLOT(offset) ((intptr_t*)&locals[-(offset)])
|
||||
#define LOCALS_ADDR(offset) ((address)locals[-(offset)])
|
||||
#define LOCALS_INT(offset) ((jint)(locals[-(offset)]))
|
||||
#define LOCALS_FLOAT(offset) (*((jfloat*)&locals[-(offset)]))
|
||||
#define LOCALS_OBJECT(offset) ((oop)locals[-(offset)])
|
||||
#define LOCALS_DOUBLE(offset) (((VMJavaVal64*)&locals[-((offset) + 1)])->d)
|
||||
#define LOCALS_LONG(offset) (((VMJavaVal64*)&locals[-((offset) + 1)])->l)
|
||||
#define LOCALS_LONG_AT(offset) (((address)&locals[-((offset) + 1)]))
|
||||
#define LOCALS_DOUBLE_AT(offset) (((address)&locals[-((offset) + 1)]))
|
||||
|
||||
#define SET_LOCALS_SLOT(value, offset) (*(intptr_t*)&locals[-(offset)] = *(intptr_t *)(value))
|
||||
#define SET_LOCALS_ADDR(value, offset) (*((address *)&locals[-(offset)]) = (value))
|
||||
#define SET_LOCALS_INT(value, offset) (*((jint *)&locals[-(offset)]) = (value))
|
||||
#define SET_LOCALS_FLOAT(value, offset) (*((jfloat *)&locals[-(offset)]) = (value))
|
||||
#define SET_LOCALS_OBJECT(value, offset) (*((oop *)&locals[-(offset)]) = (value))
|
||||
#define SET_LOCALS_DOUBLE(value, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->d = (value))
|
||||
#define SET_LOCALS_LONG(value, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->l = (value))
|
||||
#define SET_LOCALS_DOUBLE_FROM_ADDR(addr, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->d = \
|
||||
((VMJavaVal64*)(addr))->d)
|
||||
#define SET_LOCALS_LONG_FROM_ADDR(addr, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->l = \
|
||||
((VMJavaVal64*)(addr))->l)
|
||||
|
||||
#endif // CPU_AARCH64_VM_BYTECODEINTERPRETER_AARCH64_HPP
|
||||
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_BYTECODEINTERPRETER_AARCH64_INLINE_HPP
|
||||
#define CPU_AARCH64_VM_BYTECODEINTERPRETER_AARCH64_INLINE_HPP
|
||||
|
||||
// Inline interpreter functions for IA32
|
||||
|
||||
inline jfloat BytecodeInterpreter::VMfloatAdd(jfloat op1, jfloat op2) { return op1 + op2; }
|
||||
inline jfloat BytecodeInterpreter::VMfloatSub(jfloat op1, jfloat op2) { return op1 - op2; }
|
||||
inline jfloat BytecodeInterpreter::VMfloatMul(jfloat op1, jfloat op2) { return op1 * op2; }
|
||||
inline jfloat BytecodeInterpreter::VMfloatDiv(jfloat op1, jfloat op2) { return op1 / op2; }
|
||||
inline jfloat BytecodeInterpreter::VMfloatRem(jfloat op1, jfloat op2) { return fmod(op1, op2); }
|
||||
|
||||
inline jfloat BytecodeInterpreter::VMfloatNeg(jfloat op) { return -op; }
|
||||
|
||||
inline int32_t BytecodeInterpreter::VMfloatCompare(jfloat op1, jfloat op2, int32_t direction) {
|
||||
return ( op1 < op2 ? -1 :
|
||||
op1 > op2 ? 1 :
|
||||
op1 == op2 ? 0 :
|
||||
(direction == -1 || direction == 1) ? direction : 0);
|
||||
|
||||
}
|
||||
|
||||
inline void BytecodeInterpreter::VMmemCopy64(uint32_t to[2], const uint32_t from[2]) {
|
||||
// x86 can do unaligned copies but not 64bits at a time
|
||||
to[0] = from[0]; to[1] = from[1];
|
||||
}
|
||||
|
||||
// The long operations depend on compiler support for "long long" on x86
|
||||
|
||||
inline jlong BytecodeInterpreter::VMlongAdd(jlong op1, jlong op2) {
|
||||
return op1 + op2;
|
||||
}
|
||||
|
||||
inline jlong BytecodeInterpreter::VMlongAnd(jlong op1, jlong op2) {
|
||||
return op1 & op2;
|
||||
}
|
||||
|
||||
inline jlong BytecodeInterpreter::VMlongDiv(jlong op1, jlong op2) {
|
||||
// QQQ what about check and throw...
|
||||
return op1 / op2;
|
||||
}
|
||||
|
||||
inline jlong BytecodeInterpreter::VMlongMul(jlong op1, jlong op2) {
|
||||
return op1 * op2;
|
||||
}
|
||||
|
||||
inline jlong BytecodeInterpreter::VMlongOr(jlong op1, jlong op2) {
|
||||
return op1 | op2;
|
||||
}
|
||||
|
||||
inline jlong BytecodeInterpreter::VMlongSub(jlong op1, jlong op2) {
|
||||
return op1 - op2;
|
||||
}
|
||||
|
||||
inline jlong BytecodeInterpreter::VMlongXor(jlong op1, jlong op2) {
|
||||
return op1 ^ op2;
|
||||
}
|
||||
|
||||
inline jlong BytecodeInterpreter::VMlongRem(jlong op1, jlong op2) {
|
||||
return op1 % op2;
|
||||
}
|
||||
|
||||
inline jlong BytecodeInterpreter::VMlongUshr(jlong op1, jint op2) {
|
||||
// CVM did this 0x3f mask, is the really needed??? QQQ
|
||||
return ((unsigned long long) op1) >> (op2 & 0x3F);
|
||||
}
|
||||
|
||||
inline jlong BytecodeInterpreter::VMlongShr(jlong op1, jint op2) {
|
||||
return op1 >> (op2 & 0x3F);
|
||||
}
|
||||
|
||||
inline jlong BytecodeInterpreter::VMlongShl(jlong op1, jint op2) {
|
||||
return op1 << (op2 & 0x3F);
|
||||
}
|
||||
|
||||
inline jlong BytecodeInterpreter::VMlongNeg(jlong op) {
|
||||
return -op;
|
||||
}
|
||||
|
||||
inline jlong BytecodeInterpreter::VMlongNot(jlong op) {
|
||||
return ~op;
|
||||
}
|
||||
|
||||
inline int32_t BytecodeInterpreter::VMlongLtz(jlong op) {
|
||||
return (op <= 0);
|
||||
}
|
||||
|
||||
inline int32_t BytecodeInterpreter::VMlongGez(jlong op) {
|
||||
return (op >= 0);
|
||||
}
|
||||
|
||||
inline int32_t BytecodeInterpreter::VMlongEqz(jlong op) {
|
||||
return (op == 0);
|
||||
}
|
||||
|
||||
inline int32_t BytecodeInterpreter::VMlongEq(jlong op1, jlong op2) {
|
||||
return (op1 == op2);
|
||||
}
|
||||
|
||||
inline int32_t BytecodeInterpreter::VMlongNe(jlong op1, jlong op2) {
|
||||
return (op1 != op2);
|
||||
}
|
||||
|
||||
inline int32_t BytecodeInterpreter::VMlongGe(jlong op1, jlong op2) {
|
||||
return (op1 >= op2);
|
||||
}
|
||||
|
||||
inline int32_t BytecodeInterpreter::VMlongLe(jlong op1, jlong op2) {
|
||||
return (op1 <= op2);
|
||||
}
|
||||
|
||||
inline int32_t BytecodeInterpreter::VMlongLt(jlong op1, jlong op2) {
|
||||
return (op1 < op2);
|
||||
}
|
||||
|
||||
inline int32_t BytecodeInterpreter::VMlongGt(jlong op1, jlong op2) {
|
||||
return (op1 > op2);
|
||||
}
|
||||
|
||||
inline int32_t BytecodeInterpreter::VMlongCompare(jlong op1, jlong op2) {
|
||||
return (VMlongLt(op1, op2) ? -1 : VMlongGt(op1, op2) ? 1 : 0);
|
||||
}
|
||||
|
||||
// Long conversions
|
||||
|
||||
inline jdouble BytecodeInterpreter::VMlong2Double(jlong val) {
|
||||
return (jdouble) val;
|
||||
}
|
||||
|
||||
inline jfloat BytecodeInterpreter::VMlong2Float(jlong val) {
|
||||
return (jfloat) val;
|
||||
}
|
||||
|
||||
inline jint BytecodeInterpreter::VMlong2Int(jlong val) {
|
||||
return (jint) val;
|
||||
}
|
||||
|
||||
// Double Arithmetic
|
||||
|
||||
inline jdouble BytecodeInterpreter::VMdoubleAdd(jdouble op1, jdouble op2) {
|
||||
return op1 + op2;
|
||||
}
|
||||
|
||||
inline jdouble BytecodeInterpreter::VMdoubleDiv(jdouble op1, jdouble op2) {
|
||||
// Divide by zero... QQQ
|
||||
return op1 / op2;
|
||||
}
|
||||
|
||||
inline jdouble BytecodeInterpreter::VMdoubleMul(jdouble op1, jdouble op2) {
|
||||
return op1 * op2;
|
||||
}
|
||||
|
||||
inline jdouble BytecodeInterpreter::VMdoubleNeg(jdouble op) {
|
||||
return -op;
|
||||
}
|
||||
|
||||
inline jdouble BytecodeInterpreter::VMdoubleRem(jdouble op1, jdouble op2) {
|
||||
return fmod(op1, op2);
|
||||
}
|
||||
|
||||
inline jdouble BytecodeInterpreter::VMdoubleSub(jdouble op1, jdouble op2) {
|
||||
return op1 - op2;
|
||||
}
|
||||
|
||||
inline int32_t BytecodeInterpreter::VMdoubleCompare(jdouble op1, jdouble op2, int32_t direction) {
|
||||
return ( op1 < op2 ? -1 :
|
||||
op1 > op2 ? 1 :
|
||||
op1 == op2 ? 0 :
|
||||
(direction == -1 || direction == 1) ? direction : 0);
|
||||
}
|
||||
|
||||
// Double Conversions
|
||||
|
||||
inline jfloat BytecodeInterpreter::VMdouble2Float(jdouble val) {
|
||||
return (jfloat) val;
|
||||
}
|
||||
|
||||
// Float Conversions
|
||||
|
||||
inline jdouble BytecodeInterpreter::VMfloat2Double(jfloat op) {
|
||||
return (jdouble) op;
|
||||
}
|
||||
|
||||
// Integer Arithmetic
|
||||
|
||||
inline jint BytecodeInterpreter::VMintAdd(jint op1, jint op2) {
|
||||
return op1 + op2;
|
||||
}
|
||||
|
||||
inline jint BytecodeInterpreter::VMintAnd(jint op1, jint op2) {
|
||||
return op1 & op2;
|
||||
}
|
||||
|
||||
inline jint BytecodeInterpreter::VMintDiv(jint op1, jint op2) {
|
||||
/* it's possible we could catch this special case implicitly */
|
||||
if ((juint)op1 == 0x80000000 && op2 == -1) return op1;
|
||||
else return op1 / op2;
|
||||
}
|
||||
|
||||
inline jint BytecodeInterpreter::VMintMul(jint op1, jint op2) {
|
||||
return op1 * op2;
|
||||
}
|
||||
|
||||
inline jint BytecodeInterpreter::VMintNeg(jint op) {
|
||||
return -op;
|
||||
}
|
||||
|
||||
inline jint BytecodeInterpreter::VMintOr(jint op1, jint op2) {
|
||||
return op1 | op2;
|
||||
}
|
||||
|
||||
inline jint BytecodeInterpreter::VMintRem(jint op1, jint op2) {
|
||||
/* it's possible we could catch this special case implicitly */
|
||||
if ((juint)op1 == 0x80000000 && op2 == -1) return 0;
|
||||
else return op1 % op2;
|
||||
}
|
||||
|
||||
inline jint BytecodeInterpreter::VMintShl(jint op1, jint op2) {
|
||||
return op1 << op2;
|
||||
}
|
||||
|
||||
inline jint BytecodeInterpreter::VMintShr(jint op1, jint op2) {
|
||||
return op1 >> (op2 & 0x1f);
|
||||
}
|
||||
|
||||
inline jint BytecodeInterpreter::VMintSub(jint op1, jint op2) {
|
||||
return op1 - op2;
|
||||
}
|
||||
|
||||
inline jint BytecodeInterpreter::VMintUshr(jint op1, jint op2) {
|
||||
return ((juint) op1) >> (op2 & 0x1f);
|
||||
}
|
||||
|
||||
inline jint BytecodeInterpreter::VMintXor(jint op1, jint op2) {
|
||||
return op1 ^ op2;
|
||||
}
|
||||
|
||||
inline jdouble BytecodeInterpreter::VMint2Double(jint val) {
|
||||
return (jdouble) val;
|
||||
}
|
||||
|
||||
inline jfloat BytecodeInterpreter::VMint2Float(jint val) {
|
||||
return (jfloat) val;
|
||||
}
|
||||
|
||||
inline jlong BytecodeInterpreter::VMint2Long(jint val) {
|
||||
return (jlong) val;
|
||||
}
|
||||
|
||||
inline jchar BytecodeInterpreter::VMint2Char(jint val) {
|
||||
return (jchar) val;
|
||||
}
|
||||
|
||||
inline jshort BytecodeInterpreter::VMint2Short(jint val) {
|
||||
return (jshort) val;
|
||||
}
|
||||
|
||||
inline jbyte BytecodeInterpreter::VMint2Byte(jint val) {
|
||||
return (jbyte) val;
|
||||
}
|
||||
|
||||
#endif // CPU_AARCH64_VM_BYTECODEINTERPRETER_AARCH64_INLINE_HPP
|
||||
29
hotspot/src/cpu/aarch64/vm/bytecodes_aarch64.cpp
Normal file
29
hotspot/src/cpu/aarch64/vm/bytecodes_aarch64.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "interpreter/bytecodes.hpp"
|
||||
|
||||
|
||||
31
hotspot/src/cpu/aarch64/vm/bytecodes_aarch64.hpp
Normal file
31
hotspot/src/cpu/aarch64/vm/bytecodes_aarch64.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_BYTECODES_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_BYTECODES_AARCH64_HPP
|
||||
|
||||
// No aarch64 specific bytecodes
|
||||
|
||||
#endif // CPU_AARCH64_VM_BYTECODES_AARCH64_HPP
|
||||
75
hotspot/src/cpu/aarch64/vm/bytes_aarch64.hpp
Normal file
75
hotspot/src/cpu/aarch64/vm/bytes_aarch64.hpp
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_BYTES_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_BYTES_AARCH64_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class Bytes: AllStatic {
|
||||
public:
|
||||
// Returns true if the byte ordering used by Java is different from the native byte ordering
|
||||
// of the underlying machine. For example, this is true for Intel x86, but false for Solaris
|
||||
// on Sparc.
|
||||
static inline bool is_Java_byte_ordering_different(){ return true; }
|
||||
|
||||
|
||||
// Efficient reading and writing of unaligned unsigned data in platform-specific byte ordering
|
||||
// (no special code is needed since x86 CPUs can access unaligned data)
|
||||
static inline u2 get_native_u2(address p) { return *(u2*)p; }
|
||||
static inline u4 get_native_u4(address p) { return *(u4*)p; }
|
||||
static inline u8 get_native_u8(address p) { return *(u8*)p; }
|
||||
|
||||
static inline void put_native_u2(address p, u2 x) { *(u2*)p = x; }
|
||||
static inline void put_native_u4(address p, u4 x) { *(u4*)p = x; }
|
||||
static inline void put_native_u8(address p, u8 x) { *(u8*)p = x; }
|
||||
|
||||
|
||||
// Efficient reading and writing of unaligned unsigned data in Java
|
||||
// byte ordering (i.e. big-endian ordering). Byte-order reversal is
|
||||
// needed since x86 CPUs use little-endian format.
|
||||
static inline u2 get_Java_u2(address p) { return swap_u2(get_native_u2(p)); }
|
||||
static inline u4 get_Java_u4(address p) { return swap_u4(get_native_u4(p)); }
|
||||
static inline u8 get_Java_u8(address p) { return swap_u8(get_native_u8(p)); }
|
||||
|
||||
static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, swap_u2(x)); }
|
||||
static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, swap_u4(x)); }
|
||||
static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, swap_u8(x)); }
|
||||
|
||||
|
||||
// Efficient swapping of byte ordering
|
||||
static inline u2 swap_u2(u2 x); // compiler-dependent implementation
|
||||
static inline u4 swap_u4(u4 x); // compiler-dependent implementation
|
||||
static inline u8 swap_u8(u8 x);
|
||||
};
|
||||
|
||||
|
||||
// The following header contains the implementations of swap_u2, swap_u4, and swap_u8[_base]
|
||||
|
||||
#ifdef TARGET_OS_ARCH_linux_aarch64
|
||||
# include "bytes_linux_aarch64.inline.hpp"
|
||||
#endif
|
||||
|
||||
#endif // CPU_AARCH64_VM_BYTES_AARCH64_HPP
|
||||
391
hotspot/src/cpu/aarch64/vm/c1_CodeStubs_aarch64.cpp
Normal file
391
hotspot/src/cpu/aarch64/vm/c1_CodeStubs_aarch64.cpp
Normal file
@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "c1/c1_CodeStubs.hpp"
|
||||
#include "c1/c1_FrameMap.hpp"
|
||||
#include "c1/c1_LIRAssembler.hpp"
|
||||
#include "c1/c1_MacroAssembler.hpp"
|
||||
#include "c1/c1_Runtime1.hpp"
|
||||
#include "nativeInst_aarch64.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "vmreg_aarch64.inline.hpp"
|
||||
#if INCLUDE_ALL_GCS
|
||||
#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
#define __ ce->masm()->
|
||||
|
||||
void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bind(_entry);
|
||||
ce->store_parameter(_method->as_register(), 1);
|
||||
ce->store_parameter(_bci, 0);
|
||||
__ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::counter_overflow_id)));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
__ b(_continuation);
|
||||
}
|
||||
|
||||
RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index,
|
||||
bool throw_index_out_of_bounds_exception)
|
||||
: _throw_index_out_of_bounds_exception(throw_index_out_of_bounds_exception)
|
||||
, _index(index)
|
||||
{
|
||||
assert(info != NULL, "must have info");
|
||||
_info = new CodeEmitInfo(info);
|
||||
}
|
||||
|
||||
void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bind(_entry);
|
||||
if (_info->deoptimize_on_exception()) {
|
||||
address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
|
||||
__ far_call(RuntimeAddress(a));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
return;
|
||||
}
|
||||
|
||||
if (_index->is_cpu_register()) {
|
||||
__ mov(rscratch1, _index->as_register());
|
||||
} else {
|
||||
__ mov(rscratch1, _index->as_jint());
|
||||
}
|
||||
Runtime1::StubID stub_id;
|
||||
if (_throw_index_out_of_bounds_exception) {
|
||||
stub_id = Runtime1::throw_index_exception_id;
|
||||
} else {
|
||||
stub_id = Runtime1::throw_range_check_failed_id;
|
||||
}
|
||||
__ far_call(RuntimeAddress(Runtime1::entry_for(stub_id)), NULL, rscratch2);
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
|
||||
_info = new CodeEmitInfo(info);
|
||||
}
|
||||
|
||||
void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bind(_entry);
|
||||
address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
|
||||
__ far_call(RuntimeAddress(a));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
void DivByZeroStub::emit_code(LIR_Assembler* ce) {
|
||||
if (_offset != -1) {
|
||||
ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
|
||||
}
|
||||
__ bind(_entry);
|
||||
__ far_call(Address(Runtime1::entry_for(Runtime1::throw_div0_exception_id), relocInfo::runtime_call_type));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
#ifdef ASSERT
|
||||
__ should_not_reach_here();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Implementation of NewInstanceStub
|
||||
|
||||
NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) {
|
||||
_result = result;
|
||||
_klass = klass;
|
||||
_klass_reg = klass_reg;
|
||||
_info = new CodeEmitInfo(info);
|
||||
assert(stub_id == Runtime1::new_instance_id ||
|
||||
stub_id == Runtime1::fast_new_instance_id ||
|
||||
stub_id == Runtime1::fast_new_instance_init_check_id,
|
||||
"need new_instance id");
|
||||
_stub_id = stub_id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void NewInstanceStub::emit_code(LIR_Assembler* ce) {
|
||||
assert(__ rsp_offset() == 0, "frame size should be fixed");
|
||||
__ bind(_entry);
|
||||
__ mov(r3, _klass_reg->as_register());
|
||||
__ far_call(RuntimeAddress(Runtime1::entry_for(_stub_id)));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
assert(_result->as_register() == r0, "result must in r0,");
|
||||
__ b(_continuation);
|
||||
}
|
||||
|
||||
|
||||
// Implementation of NewTypeArrayStub
|
||||
|
||||
// Implementation of NewTypeArrayStub
|
||||
|
||||
NewTypeArrayStub::NewTypeArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) {
|
||||
_klass_reg = klass_reg;
|
||||
_length = length;
|
||||
_result = result;
|
||||
_info = new CodeEmitInfo(info);
|
||||
}
|
||||
|
||||
|
||||
void NewTypeArrayStub::emit_code(LIR_Assembler* ce) {
|
||||
assert(__ rsp_offset() == 0, "frame size should be fixed");
|
||||
__ bind(_entry);
|
||||
assert(_length->as_register() == r19, "length must in r19,");
|
||||
assert(_klass_reg->as_register() == r3, "klass_reg must in r3");
|
||||
__ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_type_array_id)));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
assert(_result->as_register() == r0, "result must in r0");
|
||||
__ b(_continuation);
|
||||
}
|
||||
|
||||
|
||||
// Implementation of NewObjectArrayStub
|
||||
|
||||
NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) {
|
||||
_klass_reg = klass_reg;
|
||||
_result = result;
|
||||
_length = length;
|
||||
_info = new CodeEmitInfo(info);
|
||||
}
|
||||
|
||||
|
||||
void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
|
||||
assert(__ rsp_offset() == 0, "frame size should be fixed");
|
||||
__ bind(_entry);
|
||||
assert(_length->as_register() == r19, "length must in r19,");
|
||||
assert(_klass_reg->as_register() == r3, "klass_reg must in r3");
|
||||
__ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_object_array_id)));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
assert(_result->as_register() == r0, "result must in r0");
|
||||
__ b(_continuation);
|
||||
}
|
||||
// Implementation of MonitorAccessStubs
|
||||
|
||||
MonitorEnterStub::MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info)
|
||||
: MonitorAccessStub(obj_reg, lock_reg)
|
||||
{
|
||||
_info = new CodeEmitInfo(info);
|
||||
}
|
||||
|
||||
|
||||
void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
|
||||
assert(__ rsp_offset() == 0, "frame size should be fixed");
|
||||
__ bind(_entry);
|
||||
ce->store_parameter(_obj_reg->as_register(), 1);
|
||||
ce->store_parameter(_lock_reg->as_register(), 0);
|
||||
Runtime1::StubID enter_id;
|
||||
if (ce->compilation()->has_fpu_code()) {
|
||||
enter_id = Runtime1::monitorenter_id;
|
||||
} else {
|
||||
enter_id = Runtime1::monitorenter_nofpu_id;
|
||||
}
|
||||
__ far_call(RuntimeAddress(Runtime1::entry_for(enter_id)));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
__ b(_continuation);
|
||||
}
|
||||
|
||||
|
||||
void MonitorExitStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bind(_entry);
|
||||
if (_compute_lock) {
|
||||
// lock_reg was destroyed by fast unlocking attempt => recompute it
|
||||
ce->monitor_address(_monitor_ix, _lock_reg);
|
||||
}
|
||||
ce->store_parameter(_lock_reg->as_register(), 0);
|
||||
// note: non-blocking leaf routine => no call info needed
|
||||
Runtime1::StubID exit_id;
|
||||
if (ce->compilation()->has_fpu_code()) {
|
||||
exit_id = Runtime1::monitorexit_id;
|
||||
} else {
|
||||
exit_id = Runtime1::monitorexit_nofpu_id;
|
||||
}
|
||||
__ adr(lr, _continuation);
|
||||
__ far_jump(RuntimeAddress(Runtime1::entry_for(exit_id)));
|
||||
}
|
||||
|
||||
|
||||
// Implementation of patching:
|
||||
// - Copy the code at given offset to an inlined buffer (first the bytes, then the number of bytes)
|
||||
// - Replace original code with a call to the stub
|
||||
// At Runtime:
|
||||
// - call to stub, jump to runtime
|
||||
// - in runtime: preserve all registers (rspecially objects, i.e., source and destination object)
|
||||
// - in runtime: after initializing class, restore original code, reexecute instruction
|
||||
|
||||
int PatchingStub::_patch_info_offset = -NativeGeneralJump::instruction_size;
|
||||
|
||||
void PatchingStub::align_patch_site(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
void PatchingStub::emit_code(LIR_Assembler* ce) {
|
||||
assert(false, "AArch64 should not use C1 runtime patching");
|
||||
}
|
||||
|
||||
|
||||
void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bind(_entry);
|
||||
__ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::deoptimize_id)));
|
||||
ce->add_call_info_here(_info);
|
||||
DEBUG_ONLY(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
|
||||
void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
address a;
|
||||
if (_info->deoptimize_on_exception()) {
|
||||
// Deoptimize, do not throw the exception, because it is probably wrong to do it here.
|
||||
a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id);
|
||||
} else {
|
||||
a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id);
|
||||
}
|
||||
|
||||
ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
|
||||
__ bind(_entry);
|
||||
__ far_call(RuntimeAddress(a));
|
||||
ce->add_call_info_here(_info);
|
||||
ce->verify_oop_map(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
|
||||
void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
|
||||
assert(__ rsp_offset() == 0, "frame size should be fixed");
|
||||
|
||||
__ bind(_entry);
|
||||
// pass the object in a scratch register because all other registers
|
||||
// must be preserved
|
||||
if (_obj->is_cpu_register()) {
|
||||
__ mov(rscratch1, _obj->as_register());
|
||||
}
|
||||
__ far_call(RuntimeAddress(Runtime1::entry_for(_stub)), NULL, rscratch2);
|
||||
ce->add_call_info_here(_info);
|
||||
debug_only(__ should_not_reach_here());
|
||||
}
|
||||
|
||||
|
||||
void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
|
||||
//---------------slow case: call to native-----------------
|
||||
__ bind(_entry);
|
||||
// Figure out where the args should go
|
||||
// This should really convert the IntrinsicID to the Method* and signature
|
||||
// but I don't know how to do that.
|
||||
//
|
||||
VMRegPair args[5];
|
||||
BasicType signature[5] = { T_OBJECT, T_INT, T_OBJECT, T_INT, T_INT};
|
||||
SharedRuntime::java_calling_convention(signature, args, 5, true);
|
||||
|
||||
// push parameters
|
||||
// (src, src_pos, dest, destPos, length)
|
||||
Register r[5];
|
||||
r[0] = src()->as_register();
|
||||
r[1] = src_pos()->as_register();
|
||||
r[2] = dst()->as_register();
|
||||
r[3] = dst_pos()->as_register();
|
||||
r[4] = length()->as_register();
|
||||
|
||||
// next registers will get stored on the stack
|
||||
for (int i = 0; i < 5 ; i++ ) {
|
||||
VMReg r_1 = args[i].first();
|
||||
if (r_1->is_stack()) {
|
||||
int st_off = r_1->reg2stack() * wordSize;
|
||||
__ str (r[i], Address(sp, st_off));
|
||||
} else {
|
||||
assert(r[i] == args[i].first()->as_Register(), "Wrong register for arg ");
|
||||
}
|
||||
}
|
||||
|
||||
ce->align_call(lir_static_call);
|
||||
|
||||
ce->emit_static_call_stub();
|
||||
Address resolve(SharedRuntime::get_resolve_static_call_stub(),
|
||||
relocInfo::static_call_type);
|
||||
__ trampoline_call(resolve);
|
||||
ce->add_call_info_here(info());
|
||||
|
||||
#ifndef PRODUCT
|
||||
__ lea(rscratch2, ExternalAddress((address)&Runtime1::_arraycopy_slowcase_cnt));
|
||||
__ incrementw(Address(rscratch2));
|
||||
#endif
|
||||
|
||||
__ b(_continuation);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#if INCLUDE_ALL_GCS
|
||||
|
||||
void G1PreBarrierStub::emit_code(LIR_Assembler* ce) {
|
||||
// At this point we know that marking is in progress.
|
||||
// If do_load() is true then we have to emit the
|
||||
// load of the previous value; otherwise it has already
|
||||
// been loaded into _pre_val.
|
||||
|
||||
__ bind(_entry);
|
||||
assert(pre_val()->is_register(), "Precondition.");
|
||||
|
||||
Register pre_val_reg = pre_val()->as_register();
|
||||
|
||||
if (do_load()) {
|
||||
ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/);
|
||||
}
|
||||
__ cbz(pre_val_reg, _continuation);
|
||||
ce->store_parameter(pre_val()->as_register(), 0);
|
||||
__ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::g1_pre_barrier_slow_id)));
|
||||
__ b(_continuation);
|
||||
}
|
||||
|
||||
jbyte* G1PostBarrierStub::_byte_map_base = NULL;
|
||||
|
||||
jbyte* G1PostBarrierStub::byte_map_base_slow() {
|
||||
BarrierSet* bs = Universe::heap()->barrier_set();
|
||||
assert(bs->is_a(BarrierSet::G1SATBCTLogging),
|
||||
"Must be if we're using this.");
|
||||
return ((G1SATBCardTableModRefBS*)bs)->byte_map_base;
|
||||
}
|
||||
|
||||
|
||||
void G1PostBarrierStub::emit_code(LIR_Assembler* ce) {
|
||||
__ bind(_entry);
|
||||
assert(addr()->is_register(), "Precondition.");
|
||||
assert(new_val()->is_register(), "Precondition.");
|
||||
Register new_val_reg = new_val()->as_register();
|
||||
__ cbz(new_val_reg, _continuation);
|
||||
ce->store_parameter(addr()->as_pointer_register(), 0);
|
||||
__ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::g1_post_barrier_slow_id)));
|
||||
__ b(_continuation);
|
||||
}
|
||||
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#undef __
|
||||
81
hotspot/src/cpu/aarch64/vm/c1_Defs_aarch64.hpp
Normal file
81
hotspot/src/cpu/aarch64/vm/c1_Defs_aarch64.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_C1_DEFS_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_C1_DEFS_AARCH64_HPP
|
||||
|
||||
// native word offsets from memory address (little endian)
|
||||
enum {
|
||||
pd_lo_word_offset_in_bytes = 0,
|
||||
pd_hi_word_offset_in_bytes = BytesPerWord
|
||||
};
|
||||
|
||||
// explicit rounding operations are required to implement the strictFP mode
|
||||
enum {
|
||||
pd_strict_fp_requires_explicit_rounding = false
|
||||
};
|
||||
|
||||
// FIXME: There are no callee-saved
|
||||
|
||||
// registers
|
||||
enum {
|
||||
pd_nof_cpu_regs_frame_map = RegisterImpl::number_of_registers, // number of registers used during code emission
|
||||
pd_nof_fpu_regs_frame_map = FloatRegisterImpl::number_of_registers, // number of registers used during code emission
|
||||
|
||||
pd_nof_caller_save_cpu_regs_frame_map = 19 - 2, // number of registers killed by calls
|
||||
pd_nof_caller_save_fpu_regs_frame_map = 32, // number of registers killed by calls
|
||||
|
||||
pd_first_callee_saved_reg = 19 - 2,
|
||||
pd_last_callee_saved_reg = 26 - 2,
|
||||
|
||||
pd_last_allocatable_cpu_reg = 16,
|
||||
|
||||
pd_nof_cpu_regs_reg_alloc
|
||||
= pd_last_allocatable_cpu_reg + 1, // number of registers that are visible to register allocator
|
||||
pd_nof_fpu_regs_reg_alloc = 8, // number of registers that are visible to register allocator
|
||||
|
||||
pd_nof_cpu_regs_linearscan = 32, // number of registers visible to linear scan
|
||||
pd_nof_fpu_regs_linearscan = pd_nof_fpu_regs_frame_map, // number of registers visible to linear scan
|
||||
pd_nof_xmm_regs_linearscan = 0, // like sparc we don't have any of these
|
||||
pd_first_cpu_reg = 0,
|
||||
pd_last_cpu_reg = 16,
|
||||
pd_first_byte_reg = 0,
|
||||
pd_last_byte_reg = 16,
|
||||
pd_first_fpu_reg = pd_nof_cpu_regs_frame_map,
|
||||
pd_last_fpu_reg = pd_first_fpu_reg + 31,
|
||||
|
||||
pd_first_callee_saved_fpu_reg = 8 + pd_first_fpu_reg,
|
||||
pd_last_callee_saved_fpu_reg = 15 + pd_first_fpu_reg,
|
||||
};
|
||||
|
||||
|
||||
// Encoding of float value in debug info. This is true on x86 where
|
||||
// floats are extended to doubles when stored in the stack, false for
|
||||
// AArch64 where floats and doubles are stored in their native form.
|
||||
enum {
|
||||
pd_float_saved_as_double = false
|
||||
};
|
||||
|
||||
#endif // CPU_AARCH64_VM_C1_DEFS_AARCH64_HPP
|
||||
36
hotspot/src/cpu/aarch64/vm/c1_FpuStackSim_aarch64.cpp
Normal file
36
hotspot/src/cpu/aarch64/vm/c1_FpuStackSim_aarch64.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "c1/c1_FpuStackSim.hpp"
|
||||
#include "c1/c1_FrameMap.hpp"
|
||||
#include "utilities/array.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
//--------------------------------------------------------
|
||||
// FpuStackSim
|
||||
//--------------------------------------------------------
|
||||
|
||||
// No FPU stack on AARCH64
|
||||
32
hotspot/src/cpu/aarch64/vm/c1_FpuStackSim_aarch64.hpp
Normal file
32
hotspot/src/cpu/aarch64/vm/c1_FpuStackSim_aarch64.hpp
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_C1_FPUSTACKSIM_HPP
|
||||
#define CPU_AARCH64_VM_C1_FPUSTACKSIM_HPP
|
||||
|
||||
// No FPU stack on AARCH64
|
||||
class FpuStackSim;
|
||||
|
||||
#endif // CPU_AARCH64_VM_C1_FPUSTACKSIM_HPP
|
||||
356
hotspot/src/cpu/aarch64/vm/c1_FrameMap_aarch64.cpp
Normal file
356
hotspot/src/cpu/aarch64/vm/c1_FrameMap_aarch64.cpp
Normal file
@ -0,0 +1,356 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "c1/c1_FrameMap.hpp"
|
||||
#include "c1/c1_LIR.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "vmreg_aarch64.inline.hpp"
|
||||
|
||||
LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool) {
|
||||
LIR_Opr opr = LIR_OprFact::illegalOpr;
|
||||
VMReg r_1 = reg->first();
|
||||
VMReg r_2 = reg->second();
|
||||
if (r_1->is_stack()) {
|
||||
// Convert stack slot to an SP offset
|
||||
// The calling convention does not count the SharedRuntime::out_preserve_stack_slots() value
|
||||
// so we must add it in here.
|
||||
int st_off = (r_1->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size;
|
||||
opr = LIR_OprFact::address(new LIR_Address(sp_opr, st_off, type));
|
||||
} else if (r_1->is_Register()) {
|
||||
Register reg = r_1->as_Register();
|
||||
if (r_2->is_Register() && (type == T_LONG || type == T_DOUBLE)) {
|
||||
Register reg2 = r_2->as_Register();
|
||||
assert(reg2 == reg, "must be same register");
|
||||
opr = as_long_opr(reg);
|
||||
} else if (type == T_OBJECT || type == T_ARRAY) {
|
||||
opr = as_oop_opr(reg);
|
||||
} else if (type == T_METADATA) {
|
||||
opr = as_metadata_opr(reg);
|
||||
} else {
|
||||
opr = as_opr(reg);
|
||||
}
|
||||
} else if (r_1->is_FloatRegister()) {
|
||||
assert(type == T_DOUBLE || type == T_FLOAT, "wrong type");
|
||||
int num = r_1->as_FloatRegister()->encoding();
|
||||
if (type == T_FLOAT) {
|
||||
opr = LIR_OprFact::single_fpu(num);
|
||||
} else {
|
||||
opr = LIR_OprFact::double_fpu(num);
|
||||
}
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
return opr;
|
||||
}
|
||||
|
||||
LIR_Opr FrameMap::r0_opr;
|
||||
LIR_Opr FrameMap::r1_opr;
|
||||
LIR_Opr FrameMap::r2_opr;
|
||||
LIR_Opr FrameMap::r3_opr;
|
||||
LIR_Opr FrameMap::r4_opr;
|
||||
LIR_Opr FrameMap::r5_opr;
|
||||
LIR_Opr FrameMap::r6_opr;
|
||||
LIR_Opr FrameMap::r7_opr;
|
||||
LIR_Opr FrameMap::r8_opr;
|
||||
LIR_Opr FrameMap::r9_opr;
|
||||
LIR_Opr FrameMap::r10_opr;
|
||||
LIR_Opr FrameMap::r11_opr;
|
||||
LIR_Opr FrameMap::r12_opr;
|
||||
LIR_Opr FrameMap::r13_opr;
|
||||
LIR_Opr FrameMap::r14_opr;
|
||||
LIR_Opr FrameMap::r15_opr;
|
||||
LIR_Opr FrameMap::r16_opr;
|
||||
LIR_Opr FrameMap::r17_opr;
|
||||
LIR_Opr FrameMap::r18_opr;
|
||||
LIR_Opr FrameMap::r19_opr;
|
||||
LIR_Opr FrameMap::r20_opr;
|
||||
LIR_Opr FrameMap::r21_opr;
|
||||
LIR_Opr FrameMap::r22_opr;
|
||||
LIR_Opr FrameMap::r23_opr;
|
||||
LIR_Opr FrameMap::r24_opr;
|
||||
LIR_Opr FrameMap::r25_opr;
|
||||
LIR_Opr FrameMap::r26_opr;
|
||||
LIR_Opr FrameMap::r27_opr;
|
||||
LIR_Opr FrameMap::r28_opr;
|
||||
LIR_Opr FrameMap::r29_opr;
|
||||
LIR_Opr FrameMap::r30_opr;
|
||||
|
||||
LIR_Opr FrameMap::rfp_opr;
|
||||
LIR_Opr FrameMap::sp_opr;
|
||||
|
||||
LIR_Opr FrameMap::receiver_opr;
|
||||
|
||||
LIR_Opr FrameMap::r0_oop_opr;
|
||||
LIR_Opr FrameMap::r1_oop_opr;
|
||||
LIR_Opr FrameMap::r2_oop_opr;
|
||||
LIR_Opr FrameMap::r3_oop_opr;
|
||||
LIR_Opr FrameMap::r4_oop_opr;
|
||||
LIR_Opr FrameMap::r5_oop_opr;
|
||||
LIR_Opr FrameMap::r6_oop_opr;
|
||||
LIR_Opr FrameMap::r7_oop_opr;
|
||||
LIR_Opr FrameMap::r8_oop_opr;
|
||||
LIR_Opr FrameMap::r9_oop_opr;
|
||||
LIR_Opr FrameMap::r10_oop_opr;
|
||||
LIR_Opr FrameMap::r11_oop_opr;
|
||||
LIR_Opr FrameMap::r12_oop_opr;
|
||||
LIR_Opr FrameMap::r13_oop_opr;
|
||||
LIR_Opr FrameMap::r14_oop_opr;
|
||||
LIR_Opr FrameMap::r15_oop_opr;
|
||||
LIR_Opr FrameMap::r16_oop_opr;
|
||||
LIR_Opr FrameMap::r17_oop_opr;
|
||||
LIR_Opr FrameMap::r18_oop_opr;
|
||||
LIR_Opr FrameMap::r19_oop_opr;
|
||||
LIR_Opr FrameMap::r20_oop_opr;
|
||||
LIR_Opr FrameMap::r21_oop_opr;
|
||||
LIR_Opr FrameMap::r22_oop_opr;
|
||||
LIR_Opr FrameMap::r23_oop_opr;
|
||||
LIR_Opr FrameMap::r24_oop_opr;
|
||||
LIR_Opr FrameMap::r25_oop_opr;
|
||||
LIR_Opr FrameMap::r26_oop_opr;
|
||||
LIR_Opr FrameMap::r27_oop_opr;
|
||||
LIR_Opr FrameMap::r28_oop_opr;
|
||||
LIR_Opr FrameMap::r29_oop_opr;
|
||||
LIR_Opr FrameMap::r30_oop_opr;
|
||||
|
||||
LIR_Opr FrameMap::rscratch1_opr;
|
||||
LIR_Opr FrameMap::rscratch2_opr;
|
||||
LIR_Opr FrameMap::rscratch1_long_opr;
|
||||
LIR_Opr FrameMap::rscratch2_long_opr;
|
||||
|
||||
LIR_Opr FrameMap::r0_metadata_opr;
|
||||
LIR_Opr FrameMap::r1_metadata_opr;
|
||||
LIR_Opr FrameMap::r2_metadata_opr;
|
||||
LIR_Opr FrameMap::r3_metadata_opr;
|
||||
LIR_Opr FrameMap::r4_metadata_opr;
|
||||
LIR_Opr FrameMap::r5_metadata_opr;
|
||||
|
||||
LIR_Opr FrameMap::long0_opr;
|
||||
LIR_Opr FrameMap::long1_opr;
|
||||
LIR_Opr FrameMap::fpu0_float_opr;
|
||||
LIR_Opr FrameMap::fpu0_double_opr;
|
||||
|
||||
LIR_Opr FrameMap::_caller_save_cpu_regs[] = { 0, };
|
||||
LIR_Opr FrameMap::_caller_save_fpu_regs[] = { 0, };
|
||||
|
||||
//--------------------------------------------------------
|
||||
// FrameMap
|
||||
//--------------------------------------------------------
|
||||
|
||||
void FrameMap::initialize() {
|
||||
assert(!_init_done, "once");
|
||||
|
||||
int i=0;
|
||||
map_register(i, r0); r0_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r1); r1_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r2); r2_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r3); r3_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r4); r4_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r5); r5_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r6); r6_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r7); r7_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r10); r10_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r11); r11_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r12); r12_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r13); r13_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r14); r14_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r15); r15_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r16); r16_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r17); r17_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r18); r18_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r19); r19_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r20); r20_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r21); r21_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r22); r22_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r23); r23_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r24); r24_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r25); r25_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
map_register(i, r26); r26_opr = LIR_OprFact::single_cpu(i); i++;
|
||||
|
||||
map_register(i, r27); r27_opr = LIR_OprFact::single_cpu(i); i++; // rheapbase
|
||||
map_register(i, r28); r28_opr = LIR_OprFact::single_cpu(i); i++; // rthread
|
||||
map_register(i, r29); r29_opr = LIR_OprFact::single_cpu(i); i++; // rfp
|
||||
map_register(i, r30); r30_opr = LIR_OprFact::single_cpu(i); i++; // lr
|
||||
map_register(i, r31_sp); sp_opr = LIR_OprFact::single_cpu(i); i++; // sp
|
||||
map_register(i, r8); r8_opr = LIR_OprFact::single_cpu(i); i++; // rscratch1
|
||||
map_register(i, r9); r9_opr = LIR_OprFact::single_cpu(i); i++; // rscratch2
|
||||
|
||||
rscratch1_opr = r8_opr;
|
||||
rscratch2_opr = r9_opr;
|
||||
rscratch1_long_opr = LIR_OprFact::double_cpu(r8_opr->cpu_regnr(), r8_opr->cpu_regnr());
|
||||
rscratch2_long_opr = LIR_OprFact::double_cpu(r9_opr->cpu_regnr(), r9_opr->cpu_regnr());
|
||||
|
||||
long0_opr = LIR_OprFact::double_cpu(0, 0);
|
||||
long1_opr = LIR_OprFact::double_cpu(1, 1);
|
||||
|
||||
fpu0_float_opr = LIR_OprFact::single_fpu(0);
|
||||
fpu0_double_opr = LIR_OprFact::double_fpu(0);
|
||||
|
||||
_caller_save_cpu_regs[0] = r0_opr;
|
||||
_caller_save_cpu_regs[1] = r1_opr;
|
||||
_caller_save_cpu_regs[2] = r2_opr;
|
||||
_caller_save_cpu_regs[3] = r3_opr;
|
||||
_caller_save_cpu_regs[4] = r4_opr;
|
||||
_caller_save_cpu_regs[5] = r5_opr;
|
||||
_caller_save_cpu_regs[6] = r6_opr;
|
||||
_caller_save_cpu_regs[7] = r7_opr;
|
||||
// rscratch1, rscratch 2 not included
|
||||
_caller_save_cpu_regs[8] = r10_opr;
|
||||
_caller_save_cpu_regs[9] = r11_opr;
|
||||
_caller_save_cpu_regs[10] = r12_opr;
|
||||
_caller_save_cpu_regs[11] = r13_opr;
|
||||
_caller_save_cpu_regs[12] = r14_opr;
|
||||
_caller_save_cpu_regs[13] = r15_opr;
|
||||
_caller_save_cpu_regs[14] = r16_opr;
|
||||
_caller_save_cpu_regs[15] = r17_opr;
|
||||
_caller_save_cpu_regs[16] = r18_opr;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
_caller_save_fpu_regs[i] = LIR_OprFact::single_fpu(i);
|
||||
}
|
||||
|
||||
_init_done = true;
|
||||
|
||||
r0_oop_opr = as_oop_opr(r0);
|
||||
r1_oop_opr = as_oop_opr(r1);
|
||||
r2_oop_opr = as_oop_opr(r2);
|
||||
r3_oop_opr = as_oop_opr(r3);
|
||||
r4_oop_opr = as_oop_opr(r4);
|
||||
r5_oop_opr = as_oop_opr(r5);
|
||||
r6_oop_opr = as_oop_opr(r6);
|
||||
r7_oop_opr = as_oop_opr(r7);
|
||||
r8_oop_opr = as_oop_opr(r8);
|
||||
r9_oop_opr = as_oop_opr(r9);
|
||||
r10_oop_opr = as_oop_opr(r10);
|
||||
r11_oop_opr = as_oop_opr(r11);
|
||||
r12_oop_opr = as_oop_opr(r12);
|
||||
r13_oop_opr = as_oop_opr(r13);
|
||||
r14_oop_opr = as_oop_opr(r14);
|
||||
r15_oop_opr = as_oop_opr(r15);
|
||||
r16_oop_opr = as_oop_opr(r16);
|
||||
r17_oop_opr = as_oop_opr(r17);
|
||||
r18_oop_opr = as_oop_opr(r18);
|
||||
r19_oop_opr = as_oop_opr(r19);
|
||||
r20_oop_opr = as_oop_opr(r20);
|
||||
r21_oop_opr = as_oop_opr(r21);
|
||||
r22_oop_opr = as_oop_opr(r22);
|
||||
r23_oop_opr = as_oop_opr(r23);
|
||||
r24_oop_opr = as_oop_opr(r24);
|
||||
r25_oop_opr = as_oop_opr(r25);
|
||||
r26_oop_opr = as_oop_opr(r26);
|
||||
r27_oop_opr = as_oop_opr(r27);
|
||||
r28_oop_opr = as_oop_opr(r28);
|
||||
r29_oop_opr = as_oop_opr(r29);
|
||||
r30_oop_opr = as_oop_opr(r30);
|
||||
|
||||
r0_metadata_opr = as_metadata_opr(r0);
|
||||
r1_metadata_opr = as_metadata_opr(r1);
|
||||
r2_metadata_opr = as_metadata_opr(r2);
|
||||
r3_metadata_opr = as_metadata_opr(r3);
|
||||
r4_metadata_opr = as_metadata_opr(r4);
|
||||
r5_metadata_opr = as_metadata_opr(r5);
|
||||
|
||||
sp_opr = as_pointer_opr(r31_sp);
|
||||
rfp_opr = as_pointer_opr(rfp);
|
||||
|
||||
VMRegPair regs;
|
||||
BasicType sig_bt = T_OBJECT;
|
||||
SharedRuntime::java_calling_convention(&sig_bt, ®s, 1, true);
|
||||
receiver_opr = as_oop_opr(regs.first()->as_Register());
|
||||
|
||||
for (int i = 0; i < nof_caller_save_fpu_regs; i++) {
|
||||
_caller_save_fpu_regs[i] = LIR_OprFact::single_fpu(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Address FrameMap::make_new_address(ByteSize sp_offset) const {
|
||||
// for rbp, based address use this:
|
||||
// return Address(rbp, in_bytes(sp_offset) - (framesize() - 2) * 4);
|
||||
return Address(sp, in_bytes(sp_offset));
|
||||
}
|
||||
|
||||
|
||||
// ----------------mapping-----------------------
|
||||
// all mapping is based on rfp addressing, except for simple leaf methods where we access
|
||||
// the locals sp based (and no frame is built)
|
||||
|
||||
|
||||
// Frame for simple leaf methods (quick entries)
|
||||
//
|
||||
// +----------+
|
||||
// | ret addr | <- TOS
|
||||
// +----------+
|
||||
// | args |
|
||||
// | ...... |
|
||||
|
||||
// Frame for standard methods
|
||||
//
|
||||
// | .........| <- TOS
|
||||
// | locals |
|
||||
// +----------+
|
||||
// | old fp, | <- RFP
|
||||
// +----------+
|
||||
// | ret addr |
|
||||
// +----------+
|
||||
// | args |
|
||||
// | .........|
|
||||
|
||||
|
||||
// For OopMaps, map a local variable or spill index to an VMRegImpl name.
|
||||
// This is the offset from sp() in the frame of the slot for the index,
|
||||
// skewed by VMRegImpl::stack0 to indicate a stack location (vs.a register.)
|
||||
//
|
||||
// framesize +
|
||||
// stack0 stack0 0 <- VMReg
|
||||
// | | <registers> |
|
||||
// ...........|..............|.............|
|
||||
// 0 1 2 3 x x 4 5 6 ... | <- local indices
|
||||
// ^ ^ sp() ( x x indicate link
|
||||
// | | and return addr)
|
||||
// arguments non-argument locals
|
||||
|
||||
|
||||
VMReg FrameMap::fpu_regname (int n) {
|
||||
// Return the OptoReg name for the fpu stack slot "n"
|
||||
// A spilled fpu stack slot comprises to two single-word OptoReg's.
|
||||
return as_FloatRegister(n)->as_VMReg();
|
||||
}
|
||||
|
||||
LIR_Opr FrameMap::stack_pointer() {
|
||||
return FrameMap::sp_opr;
|
||||
}
|
||||
|
||||
|
||||
// JSR 292
|
||||
LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() {
|
||||
// assert(rfp == rbp_mh_SP_save, "must be same register");
|
||||
return rfp_opr;
|
||||
}
|
||||
|
||||
|
||||
bool FrameMap::validate_frame() {
|
||||
return true;
|
||||
}
|
||||
148
hotspot/src/cpu/aarch64/vm/c1_FrameMap_aarch64.hpp
Normal file
148
hotspot/src/cpu/aarch64/vm/c1_FrameMap_aarch64.hpp
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_C1_FRAMEMAP_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_C1_FRAMEMAP_AARCH64_HPP
|
||||
|
||||
// On AArch64 the frame looks as follows:
|
||||
//
|
||||
// +-----------------------------+---------+----------------------------------------+----------------+-----------
|
||||
// | size_arguments-nof_reg_args | 2 words | size_locals-size_arguments+numreg_args | _size_monitors | spilling .
|
||||
// +-----------------------------+---------+----------------------------------------+----------------+-----------
|
||||
|
||||
public:
|
||||
static const int pd_c_runtime_reserved_arg_size;
|
||||
|
||||
enum {
|
||||
first_available_sp_in_frame = 0,
|
||||
frame_pad_in_bytes = 16,
|
||||
nof_reg_args = 8
|
||||
};
|
||||
|
||||
public:
|
||||
static LIR_Opr receiver_opr;
|
||||
|
||||
static LIR_Opr r0_opr;
|
||||
static LIR_Opr r1_opr;
|
||||
static LIR_Opr r2_opr;
|
||||
static LIR_Opr r3_opr;
|
||||
static LIR_Opr r4_opr;
|
||||
static LIR_Opr r5_opr;
|
||||
static LIR_Opr r6_opr;
|
||||
static LIR_Opr r7_opr;
|
||||
static LIR_Opr r8_opr;
|
||||
static LIR_Opr r9_opr;
|
||||
static LIR_Opr r10_opr;
|
||||
static LIR_Opr r11_opr;
|
||||
static LIR_Opr r12_opr;
|
||||
static LIR_Opr r13_opr;
|
||||
static LIR_Opr r14_opr;
|
||||
static LIR_Opr r15_opr;
|
||||
static LIR_Opr r16_opr;
|
||||
static LIR_Opr r17_opr;
|
||||
static LIR_Opr r18_opr;
|
||||
static LIR_Opr r19_opr;
|
||||
static LIR_Opr r20_opr;
|
||||
static LIR_Opr r21_opr;
|
||||
static LIR_Opr r22_opr;
|
||||
static LIR_Opr r23_opr;
|
||||
static LIR_Opr r24_opr;
|
||||
static LIR_Opr r25_opr;
|
||||
static LIR_Opr r26_opr;
|
||||
static LIR_Opr r27_opr;
|
||||
static LIR_Opr r28_opr;
|
||||
static LIR_Opr r29_opr;
|
||||
static LIR_Opr r30_opr;
|
||||
static LIR_Opr rfp_opr;
|
||||
static LIR_Opr sp_opr;
|
||||
|
||||
static LIR_Opr r0_oop_opr;
|
||||
static LIR_Opr r1_oop_opr;
|
||||
static LIR_Opr r2_oop_opr;
|
||||
static LIR_Opr r3_oop_opr;
|
||||
static LIR_Opr r4_oop_opr;
|
||||
static LIR_Opr r5_oop_opr;
|
||||
static LIR_Opr r6_oop_opr;
|
||||
static LIR_Opr r7_oop_opr;
|
||||
static LIR_Opr r8_oop_opr;
|
||||
static LIR_Opr r9_oop_opr;
|
||||
static LIR_Opr r10_oop_opr;
|
||||
static LIR_Opr r11_oop_opr;
|
||||
static LIR_Opr r12_oop_opr;
|
||||
static LIR_Opr r13_oop_opr;
|
||||
static LIR_Opr r14_oop_opr;
|
||||
static LIR_Opr r15_oop_opr;
|
||||
static LIR_Opr r16_oop_opr;
|
||||
static LIR_Opr r17_oop_opr;
|
||||
static LIR_Opr r18_oop_opr;
|
||||
static LIR_Opr r19_oop_opr;
|
||||
static LIR_Opr r20_oop_opr;
|
||||
static LIR_Opr r21_oop_opr;
|
||||
static LIR_Opr r22_oop_opr;
|
||||
static LIR_Opr r23_oop_opr;
|
||||
static LIR_Opr r24_oop_opr;
|
||||
static LIR_Opr r25_oop_opr;
|
||||
static LIR_Opr r26_oop_opr;
|
||||
static LIR_Opr r27_oop_opr;
|
||||
static LIR_Opr r28_oop_opr;
|
||||
static LIR_Opr r29_oop_opr;
|
||||
static LIR_Opr r30_oop_opr;
|
||||
|
||||
static LIR_Opr rscratch1_opr;
|
||||
static LIR_Opr rscratch2_opr;
|
||||
static LIR_Opr rscratch1_long_opr;
|
||||
static LIR_Opr rscratch2_long_opr;
|
||||
|
||||
static LIR_Opr r0_metadata_opr;
|
||||
static LIR_Opr r1_metadata_opr;
|
||||
static LIR_Opr r2_metadata_opr;
|
||||
static LIR_Opr r3_metadata_opr;
|
||||
static LIR_Opr r4_metadata_opr;
|
||||
static LIR_Opr r5_metadata_opr;
|
||||
|
||||
static LIR_Opr long0_opr;
|
||||
static LIR_Opr long1_opr;
|
||||
static LIR_Opr fpu0_float_opr;
|
||||
static LIR_Opr fpu0_double_opr;
|
||||
|
||||
static LIR_Opr as_long_opr(Register r) {
|
||||
return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r));
|
||||
}
|
||||
static LIR_Opr as_pointer_opr(Register r) {
|
||||
return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r));
|
||||
}
|
||||
|
||||
// VMReg name for spilled physical FPU stack slot n
|
||||
static VMReg fpu_regname (int n);
|
||||
|
||||
static bool is_caller_save_register (LIR_Opr opr) { return true; }
|
||||
static bool is_caller_save_register (Register r) { return true; }
|
||||
|
||||
static int nof_caller_save_cpu_regs() { return pd_nof_caller_save_cpu_regs_frame_map; }
|
||||
static int last_cpu_reg() { return pd_last_cpu_reg; }
|
||||
static int last_byte_reg() { return pd_last_byte_reg; }
|
||||
|
||||
#endif // CPU_AARCH64_VM_C1_FRAMEMAP_AARCH64_HPP
|
||||
|
||||
3186
hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp
Normal file
3186
hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp
Normal file
File diff suppressed because it is too large
Load Diff
78
hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.hpp
Normal file
78
hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.hpp
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_X86_VM_C1_LIRASSEMBLER_X86_HPP
|
||||
#define CPU_X86_VM_C1_LIRASSEMBLER_X86_HPP
|
||||
|
||||
private:
|
||||
|
||||
int array_element_size(BasicType type) const;
|
||||
|
||||
void arith_fpu_implementation(LIR_Code code, int left_index, int right_index, int dest_index, bool pop_fpu_stack);
|
||||
|
||||
// helper functions which checks for overflow and sets bailout if it
|
||||
// occurs. Always returns a valid embeddable pointer but in the
|
||||
// bailout case the pointer won't be to unique storage.
|
||||
address float_constant(float f);
|
||||
address double_constant(double d);
|
||||
|
||||
address int_constant(jlong n);
|
||||
|
||||
bool is_literal_address(LIR_Address* addr);
|
||||
|
||||
// When we need to use something other than rscratch1 use this
|
||||
// method.
|
||||
Address as_Address(LIR_Address* addr, Register tmp);
|
||||
|
||||
// Record the type of the receiver in ReceiverTypeData
|
||||
void type_profile_helper(Register mdo,
|
||||
ciMethodData *md, ciProfileData *data,
|
||||
Register recv, Label* update_done);
|
||||
void add_debug_info_for_branch(address adr, CodeEmitInfo* info);
|
||||
|
||||
void casw(Register addr, Register newval, Register cmpval);
|
||||
void casl(Register addr, Register newval, Register cmpval);
|
||||
|
||||
void poll_for_safepoint(relocInfo::relocType rtype, CodeEmitInfo* info = NULL);
|
||||
|
||||
static const int max_tableswitches = 20;
|
||||
struct tableswitch switches[max_tableswitches];
|
||||
int tableswitch_count;
|
||||
|
||||
void init() { tableswitch_count = 0; }
|
||||
|
||||
void deoptimize_trap(CodeEmitInfo *info);
|
||||
|
||||
public:
|
||||
|
||||
void store_parameter(Register r, int offset_from_esp_in_words);
|
||||
void store_parameter(jint c, int offset_from_esp_in_words);
|
||||
void store_parameter(jobject c, int offset_from_esp_in_words);
|
||||
|
||||
enum { call_stub_size = 12 * NativeInstruction::instruction_size,
|
||||
exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
|
||||
deopt_handler_size = 7 * NativeInstruction::instruction_size };
|
||||
|
||||
#endif // CPU_X86_VM_C1_LIRASSEMBLER_X86_HPP
|
||||
1392
hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp
Normal file
1392
hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp
Normal file
File diff suppressed because it is too large
Load Diff
32
hotspot/src/cpu/aarch64/vm/c1_LinearScan_aarch64.cpp
Normal file
32
hotspot/src/cpu/aarch64/vm/c1_LinearScan_aarch64.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "c1/c1_Instruction.hpp"
|
||||
#include "c1/c1_LinearScan.hpp"
|
||||
#include "utilities/bitMap.inline.hpp"
|
||||
|
||||
void LinearScan::allocate_fpu_stack() {
|
||||
// No FPU stack on AArch64
|
||||
}
|
||||
76
hotspot/src/cpu/aarch64/vm/c1_LinearScan_aarch64.hpp
Normal file
76
hotspot/src/cpu/aarch64/vm/c1_LinearScan_aarch64.hpp
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_C1_LINEARSCAN_HPP
|
||||
#define CPU_AARCH64_VM_C1_LINEARSCAN_HPP
|
||||
|
||||
inline bool LinearScan::is_processed_reg_num(int reg_num) {
|
||||
return reg_num <= FrameMap::last_cpu_reg() || reg_num >= pd_nof_cpu_regs_frame_map;
|
||||
}
|
||||
|
||||
inline int LinearScan::num_physical_regs(BasicType type) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
inline bool LinearScan::requires_adjacent_regs(BasicType type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool LinearScan::is_caller_save(int assigned_reg) {
|
||||
assert(assigned_reg >= 0 && assigned_reg < nof_regs, "should call this only for registers");
|
||||
if (assigned_reg < pd_first_callee_saved_reg)
|
||||
return true;
|
||||
if (assigned_reg > pd_last_callee_saved_reg && assigned_reg < pd_first_callee_saved_fpu_reg)
|
||||
return true;
|
||||
if (assigned_reg > pd_last_callee_saved_fpu_reg && assigned_reg < pd_last_fpu_reg)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline void LinearScan::pd_add_temps(LIR_Op* op) {
|
||||
// FIXME ??
|
||||
}
|
||||
|
||||
|
||||
// Implementation of LinearScanWalker
|
||||
|
||||
inline bool LinearScanWalker::pd_init_regs_for_alloc(Interval* cur) {
|
||||
if (allocator()->gen()->is_vreg_flag_set(cur->reg_num(), LIRGenerator::callee_saved)) {
|
||||
assert(cur->type() != T_FLOAT && cur->type() != T_DOUBLE, "cpu regs only");
|
||||
_first_reg = pd_first_callee_saved_reg;
|
||||
_last_reg = pd_last_callee_saved_reg;
|
||||
return true;
|
||||
} else if (cur->type() == T_INT || cur->type() == T_LONG || cur->type() == T_OBJECT || cur->type() == T_ADDRESS || cur->type() == T_METADATA) {
|
||||
_first_reg = pd_first_cpu_reg;
|
||||
_last_reg = pd_last_allocatable_cpu_reg;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#endif // CPU_AARCH64_VM_C1_LINEARSCAN_HPP
|
||||
458
hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.cpp
Normal file
458
hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.cpp
Normal file
@ -0,0 +1,458 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "c1/c1_MacroAssembler.hpp"
|
||||
#include "c1/c1_Runtime1.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "gc_interface/collectedHeap.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "oops/arrayOop.hpp"
|
||||
#include "oops/markOop.hpp"
|
||||
#include "runtime/basicLock.hpp"
|
||||
#include "runtime/biasedLocking.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
|
||||
void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result,
|
||||
FloatRegister f0, FloatRegister f1,
|
||||
Register result)
|
||||
{
|
||||
Label done;
|
||||
if (is_float) {
|
||||
fcmps(f0, f1);
|
||||
} else {
|
||||
fcmpd(f0, f1);
|
||||
}
|
||||
if (unordered_result < 0) {
|
||||
// we want -1 for unordered or less than, 0 for equal and 1 for
|
||||
// greater than.
|
||||
cset(result, NE); // Not equal or unordered
|
||||
cneg(result, result, LT); // Less than or unordered
|
||||
} else {
|
||||
// we want -1 for less than, 0 for equal and 1 for unordered or
|
||||
// greater than.
|
||||
cset(result, NE); // Not equal or unordered
|
||||
cneg(result, result, LO); // Less than
|
||||
}
|
||||
}
|
||||
|
||||
int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register scratch, Label& slow_case) {
|
||||
const int aligned_mask = BytesPerWord -1;
|
||||
const int hdr_offset = oopDesc::mark_offset_in_bytes();
|
||||
assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different");
|
||||
Label done, fail;
|
||||
int null_check_offset = -1;
|
||||
|
||||
verify_oop(obj);
|
||||
|
||||
// save object being locked into the BasicObjectLock
|
||||
str(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));
|
||||
|
||||
if (UseBiasedLocking) {
|
||||
assert(scratch != noreg, "should have scratch register at this point");
|
||||
null_check_offset = biased_locking_enter(disp_hdr, obj, hdr, scratch, false, done, &slow_case);
|
||||
} else {
|
||||
null_check_offset = offset();
|
||||
}
|
||||
|
||||
// Load object header
|
||||
ldr(hdr, Address(obj, hdr_offset));
|
||||
// and mark it as unlocked
|
||||
orr(hdr, hdr, markOopDesc::unlocked_value);
|
||||
// save unlocked object header into the displaced header location on the stack
|
||||
str(hdr, Address(disp_hdr, 0));
|
||||
// test if object header is still the same (i.e. unlocked), and if so, store the
|
||||
// displaced header address in the object header - if it is not the same, get the
|
||||
// object header instead
|
||||
lea(rscratch2, Address(obj, hdr_offset));
|
||||
cmpxchgptr(hdr, disp_hdr, rscratch2, rscratch1, done, /*fallthough*/NULL);
|
||||
// if the object header was the same, we're done
|
||||
// if the object header was not the same, it is now in the hdr register
|
||||
// => test if it is a stack pointer into the same stack (recursive locking), i.e.:
|
||||
//
|
||||
// 1) (hdr & aligned_mask) == 0
|
||||
// 2) sp <= hdr
|
||||
// 3) hdr <= sp + page_size
|
||||
//
|
||||
// these 3 tests can be done by evaluating the following expression:
|
||||
//
|
||||
// (hdr - sp) & (aligned_mask - page_size)
|
||||
//
|
||||
// assuming both the stack pointer and page_size have their least
|
||||
// significant 2 bits cleared and page_size is a power of 2
|
||||
mov(rscratch1, sp);
|
||||
sub(hdr, hdr, rscratch1);
|
||||
ands(hdr, hdr, aligned_mask - os::vm_page_size());
|
||||
// for recursive locking, the result is zero => save it in the displaced header
|
||||
// location (NULL in the displaced hdr location indicates recursive locking)
|
||||
str(hdr, Address(disp_hdr, 0));
|
||||
// otherwise we don't care about the result and handle locking via runtime call
|
||||
cbnz(hdr, slow_case);
|
||||
// done
|
||||
bind(done);
|
||||
if (PrintBiasedLockingStatistics) {
|
||||
lea(rscratch2, ExternalAddress((address)BiasedLocking::fast_path_entry_count_addr()));
|
||||
addmw(Address(rscratch2, 0), 1, rscratch1);
|
||||
}
|
||||
return null_check_offset;
|
||||
}
|
||||
|
||||
|
||||
void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {
|
||||
const int aligned_mask = BytesPerWord -1;
|
||||
const int hdr_offset = oopDesc::mark_offset_in_bytes();
|
||||
assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different");
|
||||
Label done;
|
||||
|
||||
if (UseBiasedLocking) {
|
||||
// load object
|
||||
ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));
|
||||
biased_locking_exit(obj, hdr, done);
|
||||
}
|
||||
|
||||
// load displaced header
|
||||
ldr(hdr, Address(disp_hdr, 0));
|
||||
// if the loaded hdr is NULL we had recursive locking
|
||||
// if we had recursive locking, we are done
|
||||
cbz(hdr, done);
|
||||
if (!UseBiasedLocking) {
|
||||
// load object
|
||||
ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));
|
||||
}
|
||||
verify_oop(obj);
|
||||
// test if object header is pointing to the displaced header, and if so, restore
|
||||
// the displaced header in the object - if the object header is not pointing to
|
||||
// the displaced header, get the object header instead
|
||||
// if the object header was not pointing to the displaced header,
|
||||
// we do unlocking via runtime call
|
||||
if (hdr_offset) {
|
||||
lea(rscratch1, Address(obj, hdr_offset));
|
||||
cmpxchgptr(disp_hdr, hdr, rscratch1, rscratch2, done, &slow_case);
|
||||
} else {
|
||||
cmpxchgptr(disp_hdr, hdr, obj, rscratch2, done, &slow_case);
|
||||
}
|
||||
// done
|
||||
bind(done);
|
||||
}
|
||||
|
||||
|
||||
// Defines obj, preserves var_size_in_bytes
|
||||
void C1_MacroAssembler::try_allocate(Register obj, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2, Label& slow_case) {
|
||||
if (UseTLAB) {
|
||||
tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case);
|
||||
} else {
|
||||
eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case);
|
||||
incr_allocated_bytes(noreg, var_size_in_bytes, con_size_in_bytes, t1);
|
||||
}
|
||||
}
|
||||
|
||||
void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) {
|
||||
assert_different_registers(obj, klass, len);
|
||||
if (UseBiasedLocking && !len->is_valid()) {
|
||||
assert_different_registers(obj, klass, len, t1, t2);
|
||||
ldr(t1, Address(klass, Klass::prototype_header_offset()));
|
||||
} else {
|
||||
// This assumes that all prototype bits fit in an int32_t
|
||||
mov(t1, (int32_t)(intptr_t)markOopDesc::prototype());
|
||||
}
|
||||
str(t1, Address(obj, oopDesc::mark_offset_in_bytes()));
|
||||
|
||||
if (UseCompressedClassPointers) { // Take care not to kill klass
|
||||
encode_klass_not_null(t1, klass);
|
||||
strw(t1, Address(obj, oopDesc::klass_offset_in_bytes()));
|
||||
} else {
|
||||
str(klass, Address(obj, oopDesc::klass_offset_in_bytes()));
|
||||
}
|
||||
|
||||
if (len->is_valid()) {
|
||||
strw(len, Address(obj, arrayOopDesc::length_offset_in_bytes()));
|
||||
} else if (UseCompressedClassPointers) {
|
||||
store_klass_gap(obj, zr);
|
||||
}
|
||||
}
|
||||
|
||||
// Zero words; len is in bytes
|
||||
// Destroys all registers except addr
|
||||
// len must be a nonzero multiple of wordSize
|
||||
void C1_MacroAssembler::zero_memory(Register addr, Register len, Register t1) {
|
||||
assert_different_registers(addr, len, t1, rscratch1, rscratch2);
|
||||
|
||||
#ifdef ASSERT
|
||||
{ Label L;
|
||||
tst(len, BytesPerWord - 1);
|
||||
br(Assembler::EQ, L);
|
||||
stop("len is not a multiple of BytesPerWord");
|
||||
bind(L);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
block_comment("zero memory");
|
||||
#endif
|
||||
|
||||
Label loop;
|
||||
Label entry;
|
||||
|
||||
// Algorithm:
|
||||
//
|
||||
// scratch1 = cnt & 7;
|
||||
// cnt -= scratch1;
|
||||
// p += scratch1;
|
||||
// switch (scratch1) {
|
||||
// do {
|
||||
// cnt -= 8;
|
||||
// p[-8] = 0;
|
||||
// case 7:
|
||||
// p[-7] = 0;
|
||||
// case 6:
|
||||
// p[-6] = 0;
|
||||
// // ...
|
||||
// case 1:
|
||||
// p[-1] = 0;
|
||||
// case 0:
|
||||
// p += 8;
|
||||
// } while (cnt);
|
||||
// }
|
||||
|
||||
const int unroll = 8; // Number of str(zr) instructions we'll unroll
|
||||
|
||||
lsr(len, len, LogBytesPerWord);
|
||||
andr(rscratch1, len, unroll - 1); // tmp1 = cnt % unroll
|
||||
sub(len, len, rscratch1); // cnt -= unroll
|
||||
// t1 always points to the end of the region we're about to zero
|
||||
add(t1, addr, rscratch1, Assembler::LSL, LogBytesPerWord);
|
||||
adr(rscratch2, entry);
|
||||
sub(rscratch2, rscratch2, rscratch1, Assembler::LSL, 2);
|
||||
br(rscratch2);
|
||||
bind(loop);
|
||||
sub(len, len, unroll);
|
||||
for (int i = -unroll; i < 0; i++)
|
||||
str(zr, Address(t1, i * wordSize));
|
||||
bind(entry);
|
||||
add(t1, t1, unroll * wordSize);
|
||||
cbnz(len, loop);
|
||||
}
|
||||
|
||||
// preserves obj, destroys len_in_bytes
|
||||
void C1_MacroAssembler::initialize_body(Register obj, Register len_in_bytes, int hdr_size_in_bytes, Register t1) {
|
||||
Label done;
|
||||
assert(obj != len_in_bytes && obj != t1 && t1 != len_in_bytes, "registers must be different");
|
||||
assert((hdr_size_in_bytes & (BytesPerWord - 1)) == 0, "header size is not a multiple of BytesPerWord");
|
||||
Register index = len_in_bytes;
|
||||
// index is positive and ptr sized
|
||||
subs(index, index, hdr_size_in_bytes);
|
||||
br(Assembler::EQ, done);
|
||||
// note: for the remaining code to work, index must be a multiple of BytesPerWord
|
||||
#ifdef ASSERT
|
||||
{ Label L;
|
||||
tst(index, BytesPerWord - 1);
|
||||
br(Assembler::EQ, L);
|
||||
stop("index is not a multiple of BytesPerWord");
|
||||
bind(L);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Preserve obj
|
||||
if (hdr_size_in_bytes)
|
||||
add(obj, obj, hdr_size_in_bytes);
|
||||
zero_memory(obj, index, t1);
|
||||
if (hdr_size_in_bytes)
|
||||
sub(obj, obj, hdr_size_in_bytes);
|
||||
|
||||
// done
|
||||
bind(done);
|
||||
}
|
||||
|
||||
|
||||
void C1_MacroAssembler::allocate_object(Register obj, Register t1, Register t2, int header_size, int object_size, Register klass, Label& slow_case) {
|
||||
assert_different_registers(obj, t1, t2); // XXX really?
|
||||
assert(header_size >= 0 && object_size >= header_size, "illegal sizes");
|
||||
|
||||
try_allocate(obj, noreg, object_size * BytesPerWord, t1, t2, slow_case);
|
||||
|
||||
initialize_object(obj, klass, noreg, object_size * HeapWordSize, t1, t2);
|
||||
}
|
||||
|
||||
void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register var_size_in_bytes, int con_size_in_bytes, Register t1, Register t2) {
|
||||
assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0,
|
||||
"con_size_in_bytes is not multiple of alignment");
|
||||
const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize;
|
||||
|
||||
initialize_header(obj, klass, noreg, t1, t2);
|
||||
|
||||
// clear rest of allocated space
|
||||
const Register index = t2;
|
||||
const int threshold = 16 * BytesPerWord; // approximate break even point for code size (see comments below)
|
||||
if (var_size_in_bytes != noreg) {
|
||||
mov(index, var_size_in_bytes);
|
||||
initialize_body(obj, index, hdr_size_in_bytes, t1);
|
||||
} else if (con_size_in_bytes <= threshold) {
|
||||
// use explicit null stores
|
||||
int i = hdr_size_in_bytes;
|
||||
if (i < con_size_in_bytes && (con_size_in_bytes % (2 * BytesPerWord))) {
|
||||
str(zr, Address(obj, i));
|
||||
i += BytesPerWord;
|
||||
}
|
||||
for (; i < con_size_in_bytes; i += 2 * BytesPerWord)
|
||||
stp(zr, zr, Address(obj, i));
|
||||
} else if (con_size_in_bytes > hdr_size_in_bytes) {
|
||||
block_comment("zero memory");
|
||||
// use loop to null out the fields
|
||||
|
||||
int words = (con_size_in_bytes - hdr_size_in_bytes) / BytesPerWord;
|
||||
mov(index, words / 8);
|
||||
|
||||
const int unroll = 8; // Number of str(zr) instructions we'll unroll
|
||||
int remainder = words % unroll;
|
||||
lea(rscratch1, Address(obj, hdr_size_in_bytes + remainder * BytesPerWord));
|
||||
|
||||
Label entry_point, loop;
|
||||
b(entry_point);
|
||||
|
||||
bind(loop);
|
||||
sub(index, index, 1);
|
||||
for (int i = -unroll; i < 0; i++) {
|
||||
if (-i == remainder)
|
||||
bind(entry_point);
|
||||
str(zr, Address(rscratch1, i * wordSize));
|
||||
}
|
||||
if (remainder == 0)
|
||||
bind(entry_point);
|
||||
add(rscratch1, rscratch1, unroll * wordSize);
|
||||
cbnz(index, loop);
|
||||
|
||||
}
|
||||
|
||||
membar(StoreStore);
|
||||
|
||||
if (CURRENT_ENV->dtrace_alloc_probes()) {
|
||||
assert(obj == r0, "must be");
|
||||
far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));
|
||||
}
|
||||
|
||||
verify_oop(obj);
|
||||
}
|
||||
void C1_MacroAssembler::allocate_array(Register obj, Register len, Register t1, Register t2, int header_size, int f, Register klass, Label& slow_case) {
|
||||
assert_different_registers(obj, len, t1, t2, klass);
|
||||
|
||||
// determine alignment mask
|
||||
assert(!(BytesPerWord & 1), "must be a multiple of 2 for masking code to work");
|
||||
|
||||
// check for negative or excessive length
|
||||
mov(rscratch1, (int32_t)max_array_allocation_length);
|
||||
cmp(len, rscratch1);
|
||||
br(Assembler::HS, slow_case);
|
||||
|
||||
const Register arr_size = t2; // okay to be the same
|
||||
// align object end
|
||||
mov(arr_size, (int32_t)header_size * BytesPerWord + MinObjAlignmentInBytesMask);
|
||||
add(arr_size, arr_size, len, ext::uxtw, f);
|
||||
andr(arr_size, arr_size, ~MinObjAlignmentInBytesMask);
|
||||
|
||||
try_allocate(obj, arr_size, 0, t1, t2, slow_case);
|
||||
|
||||
initialize_header(obj, klass, len, t1, t2);
|
||||
|
||||
// clear rest of allocated space
|
||||
const Register len_zero = len;
|
||||
initialize_body(obj, arr_size, header_size * BytesPerWord, len_zero);
|
||||
|
||||
membar(StoreStore);
|
||||
|
||||
if (CURRENT_ENV->dtrace_alloc_probes()) {
|
||||
assert(obj == r0, "must be");
|
||||
far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)));
|
||||
}
|
||||
|
||||
verify_oop(obj);
|
||||
}
|
||||
|
||||
|
||||
void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) {
|
||||
verify_oop(receiver);
|
||||
// explicit NULL check not needed since load from [klass_offset] causes a trap
|
||||
// check against inline cache
|
||||
assert(!MacroAssembler::needs_explicit_null_check(oopDesc::klass_offset_in_bytes()), "must add explicit null check");
|
||||
|
||||
cmp_klass(receiver, iCache, rscratch1);
|
||||
}
|
||||
|
||||
|
||||
void C1_MacroAssembler::build_frame(int framesize, int bang_size_in_bytes) {
|
||||
// If we have to make this method not-entrant we'll overwrite its
|
||||
// first instruction with a jump. For this action to be legal we
|
||||
// must ensure that this first instruction is a B, BL, NOP, BKPT,
|
||||
// SVC, HVC, or SMC. Make it a NOP.
|
||||
nop();
|
||||
assert(bang_size_in_bytes >= framesize, "stack bang size incorrect");
|
||||
// Make sure there is enough stack space for this method's activation.
|
||||
// Note that we do this before doing an enter().
|
||||
generate_stack_overflow_check(bang_size_in_bytes);
|
||||
MacroAssembler::build_frame(framesize + 2 * wordSize);
|
||||
if (NotifySimulator) {
|
||||
notify(Assembler::method_entry);
|
||||
}
|
||||
}
|
||||
|
||||
void C1_MacroAssembler::remove_frame(int framesize) {
|
||||
MacroAssembler::remove_frame(framesize + 2 * wordSize);
|
||||
if (NotifySimulator) {
|
||||
notify(Assembler::method_reentry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void C1_MacroAssembler::verified_entry() {
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
void C1_MacroAssembler::verify_stack_oop(int stack_offset) {
|
||||
if (!VerifyOops) return;
|
||||
verify_oop_addr(Address(sp, stack_offset), "oop");
|
||||
}
|
||||
|
||||
void C1_MacroAssembler::verify_not_null_oop(Register r) {
|
||||
if (!VerifyOops) return;
|
||||
Label not_null;
|
||||
cbnz(r, not_null);
|
||||
stop("non-null oop required");
|
||||
bind(not_null);
|
||||
verify_oop(r);
|
||||
}
|
||||
|
||||
void C1_MacroAssembler::invalidate_registers(bool inv_r0, bool inv_r19, bool inv_r2, bool inv_r3, bool inv_r4, bool inv_r5) {
|
||||
#ifdef ASSERT
|
||||
static int nn;
|
||||
if (inv_r0) mov(r0, 0xDEAD);
|
||||
if (inv_r19) mov(r19, 0xDEAD);
|
||||
if (inv_r2) mov(r2, nn++);
|
||||
if (inv_r3) mov(r3, 0xDEAD);
|
||||
if (inv_r4) mov(r4, 0xDEAD);
|
||||
if (inv_r5) mov(r5, 0xDEAD);
|
||||
#endif
|
||||
}
|
||||
#endif // ifndef PRODUCT
|
||||
108
hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp
Normal file
108
hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_C1_MACROASSEMBLER_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_C1_MACROASSEMBLER_AARCH64_HPP
|
||||
|
||||
using MacroAssembler::build_frame;
|
||||
|
||||
// C1_MacroAssembler contains high-level macros for C1
|
||||
|
||||
private:
|
||||
int _rsp_offset; // track rsp changes
|
||||
// initialization
|
||||
void pd_init() { _rsp_offset = 0; }
|
||||
|
||||
void zero_memory(Register addr, Register len, Register t1);
|
||||
|
||||
public:
|
||||
void try_allocate(
|
||||
Register obj, // result: pointer to object after successful allocation
|
||||
Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
|
||||
int con_size_in_bytes, // object size in bytes if known at compile time
|
||||
Register t1, // temp register
|
||||
Register t2, // temp register
|
||||
Label& slow_case // continuation point if fast allocation fails
|
||||
);
|
||||
|
||||
void initialize_header(Register obj, Register klass, Register len, Register t1, Register t2);
|
||||
void initialize_body(Register obj, Register len_in_bytes, int hdr_size_in_bytes, Register t1);
|
||||
|
||||
void float_cmp(bool is_float, int unordered_result,
|
||||
FloatRegister f0, FloatRegister f1,
|
||||
Register result);
|
||||
|
||||
// locking
|
||||
// hdr : must be r0, contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// disp_hdr: must point to the displaced header location, contents preserved
|
||||
// scratch : scratch register, contents destroyed
|
||||
// returns code offset at which to add null check debug information
|
||||
int lock_object (Register swap, Register obj, Register disp_hdr, Register scratch, Label& slow_case);
|
||||
|
||||
// unlocking
|
||||
// hdr : contents destroyed
|
||||
// obj : must point to the object to lock, contents preserved
|
||||
// disp_hdr: must be r0 & must point to the displaced header location, contents destroyed
|
||||
void unlock_object(Register swap, Register obj, Register lock, Label& slow_case);
|
||||
|
||||
void initialize_object(
|
||||
Register obj, // result: pointer to object after successful allocation
|
||||
Register klass, // object klass
|
||||
Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
|
||||
int con_size_in_bytes, // object size in bytes if known at compile time
|
||||
Register t1, // temp register
|
||||
Register t2 // temp register
|
||||
);
|
||||
|
||||
// allocation of fixed-size objects
|
||||
// (can also be used to allocate fixed-size arrays, by setting
|
||||
// hdr_size correctly and storing the array length afterwards)
|
||||
// obj : will contain pointer to allocated object
|
||||
// t1, t2 : scratch registers - contents destroyed
|
||||
// header_size: size of object header in words
|
||||
// object_size: total size of object in words
|
||||
// slow_case : exit to slow case implementation if fast allocation fails
|
||||
void allocate_object(Register obj, Register t1, Register t2, int header_size, int object_size, Register klass, Label& slow_case);
|
||||
|
||||
enum {
|
||||
max_array_allocation_length = 0x00FFFFFF
|
||||
};
|
||||
|
||||
// allocation of arrays
|
||||
// obj : will contain pointer to allocated object
|
||||
// len : array length in number of elements
|
||||
// t : scratch register - contents destroyed
|
||||
// header_size: size of object header in words
|
||||
// f : element scale factor
|
||||
// slow_case : exit to slow case implementation if fast allocation fails
|
||||
void allocate_array(Register obj, Register len, Register t, Register t2, int header_size, int f, Register klass, Label& slow_case);
|
||||
|
||||
int rsp_offset() const { return _rsp_offset; }
|
||||
void set_rsp_offset(int n) { _rsp_offset = n; }
|
||||
|
||||
void invalidate_registers(bool inv_r0, bool inv_r19, bool inv_r2, bool inv_r3, bool inv_r4, bool inv_r5) PRODUCT_RETURN;
|
||||
|
||||
#endif // CPU_AARCH64_VM_C1_MACROASSEMBLER_AARCH64_HPP
|
||||
1322
hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp
Normal file
1322
hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp
Normal file
File diff suppressed because it is too large
Load Diff
81
hotspot/src/cpu/aarch64/vm/c1_globals_aarch64.hpp
Normal file
81
hotspot/src/cpu/aarch64/vm/c1_globals_aarch64.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_C1_GLOBALS_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_C1_GLOBALS_AARCH64_HPP
|
||||
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
// Sets the default values for platform dependent flags used by the client compiler.
|
||||
// (see c1_globals.hpp)
|
||||
|
||||
#ifndef TIERED
|
||||
define_pd_global(bool, BackgroundCompilation, true );
|
||||
define_pd_global(bool, UseTLAB, true );
|
||||
define_pd_global(bool, ResizeTLAB, true );
|
||||
define_pd_global(bool, InlineIntrinsics, true );
|
||||
define_pd_global(bool, PreferInterpreterNativeStubs, false);
|
||||
define_pd_global(bool, ProfileTraps, false);
|
||||
define_pd_global(bool, UseOnStackReplacement, true );
|
||||
define_pd_global(bool, TieredCompilation, false);
|
||||
#ifdef BUILTIN_SIM
|
||||
// We compile very aggressively with the builtin simulator because
|
||||
// doing so greatly reduces run times and tests more code.
|
||||
define_pd_global(intx, CompileThreshold, 150 );
|
||||
define_pd_global(intx, BackEdgeThreshold, 500);
|
||||
#else
|
||||
define_pd_global(intx, CompileThreshold, 1500 );
|
||||
define_pd_global(intx, BackEdgeThreshold, 100000);
|
||||
#endif
|
||||
|
||||
define_pd_global(intx, OnStackReplacePercentage, 933 );
|
||||
define_pd_global(intx, FreqInlineSize, 325 );
|
||||
define_pd_global(intx, NewSizeThreadIncrease, 4*K );
|
||||
define_pd_global(intx, InitialCodeCacheSize, 160*K);
|
||||
define_pd_global(intx, ReservedCodeCacheSize, 32*M );
|
||||
define_pd_global(intx, NonProfiledCodeHeapSize, 13*M );
|
||||
define_pd_global(intx, ProfiledCodeHeapSize, 14*M );
|
||||
define_pd_global(intx, NonNMethodCodeHeapSize, 5*M );
|
||||
define_pd_global(bool, ProfileInterpreter, false);
|
||||
define_pd_global(intx, CodeCacheExpansionSize, 32*K );
|
||||
define_pd_global(uintx, CodeCacheMinBlockLength, 1);
|
||||
define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
|
||||
define_pd_global(uintx, MetaspaceSize, 12*M );
|
||||
define_pd_global(bool, NeverActAsServerClassMachine, true );
|
||||
define_pd_global(uint64_t,MaxRAM, 1ULL*G);
|
||||
define_pd_global(bool, CICompileOSR, true );
|
||||
#endif // !TIERED
|
||||
define_pd_global(bool, UseTypeProfile, false);
|
||||
define_pd_global(bool, RoundFPResults, true );
|
||||
|
||||
define_pd_global(bool, LIRFillDelaySlots, false);
|
||||
define_pd_global(bool, OptimizeSinglePrecision, true );
|
||||
define_pd_global(bool, CSEArrayLength, false);
|
||||
define_pd_global(bool, TwoOperandLIRForm, false );
|
||||
|
||||
define_pd_global(intx, SafepointPollOffset, 0 );
|
||||
|
||||
#endif // CPU_AARCH64_VM_C1_GLOBALS_AARCH64_HPP
|
||||
91
hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp
Normal file
91
hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_C2_GLOBALS_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_C2_GLOBALS_AARCH64_HPP
|
||||
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
// Sets the default values for platform dependent flags used by the server compiler.
|
||||
// (see c2_globals.hpp). Alpha-sorted.
|
||||
|
||||
define_pd_global(bool, BackgroundCompilation, true);
|
||||
define_pd_global(bool, UseTLAB, true);
|
||||
define_pd_global(bool, ResizeTLAB, true);
|
||||
define_pd_global(bool, CICompileOSR, true);
|
||||
define_pd_global(bool, InlineIntrinsics, true);
|
||||
define_pd_global(bool, PreferInterpreterNativeStubs, false);
|
||||
define_pd_global(bool, ProfileTraps, true);
|
||||
define_pd_global(bool, UseOnStackReplacement, true);
|
||||
#ifdef CC_INTERP
|
||||
define_pd_global(bool, ProfileInterpreter, false);
|
||||
#else
|
||||
define_pd_global(bool, ProfileInterpreter, true);
|
||||
#endif // CC_INTERP
|
||||
define_pd_global(bool, TieredCompilation, trueInTiered);
|
||||
define_pd_global(intx, CompileThreshold, 10000);
|
||||
define_pd_global(intx, BackEdgeThreshold, 100000);
|
||||
|
||||
define_pd_global(intx, OnStackReplacePercentage, 140);
|
||||
define_pd_global(intx, ConditionalMoveLimit, 3);
|
||||
define_pd_global(intx, FLOATPRESSURE, 64);
|
||||
define_pd_global(intx, FreqInlineSize, 325);
|
||||
define_pd_global(intx, MinJumpTableSize, 10);
|
||||
define_pd_global(intx, INTPRESSURE, 25);
|
||||
define_pd_global(intx, InteriorEntryAlignment, 16);
|
||||
define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K));
|
||||
define_pd_global(intx, LoopUnrollLimit, 60);
|
||||
// InitialCodeCacheSize derived from specjbb2000 run.
|
||||
define_pd_global(intx, InitialCodeCacheSize, 2496*K); // Integral multiple of CodeCacheExpansionSize
|
||||
define_pd_global(intx, CodeCacheExpansionSize, 64*K);
|
||||
|
||||
// Ergonomics related flags
|
||||
define_pd_global(uint64_t,MaxRAM, 128ULL*G);
|
||||
define_pd_global(intx, RegisterCostAreaRatio, 16000);
|
||||
|
||||
// Peephole and CISC spilling both break the graph, and so makes the
|
||||
// scheduler sick.
|
||||
define_pd_global(bool, OptoPeephole, true);
|
||||
define_pd_global(bool, UseCISCSpill, true);
|
||||
define_pd_global(bool, OptoScheduling, false);
|
||||
define_pd_global(bool, OptoBundling, false);
|
||||
|
||||
define_pd_global(intx, ReservedCodeCacheSize, 48*M);
|
||||
define_pd_global(intx, NonProfiledCodeHeapSize, 21*M);
|
||||
define_pd_global(intx, ProfiledCodeHeapSize, 22*M);
|
||||
define_pd_global(intx, NonNMethodCodeHeapSize, 5*M );
|
||||
define_pd_global(uintx, CodeCacheMinBlockLength, 4);
|
||||
define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K);
|
||||
|
||||
// Heap related flags
|
||||
define_pd_global(uintx,MetaspaceSize, ScaleForWordSize(16*M));
|
||||
|
||||
// Ergonomics related flags
|
||||
define_pd_global(bool, NeverActAsServerClassMachine, false);
|
||||
|
||||
define_pd_global(bool, TrapBasedRangeChecks, false); // Not needed.
|
||||
|
||||
#endif // CPU_AARCH64_VM_C2_GLOBALS_AARCH64_HPP
|
||||
36
hotspot/src/cpu/aarch64/vm/c2_init_aarch64.cpp
Normal file
36
hotspot/src/cpu/aarch64/vm/c2_init_aarch64.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "opto/compile.hpp"
|
||||
#include "opto/node.hpp"
|
||||
|
||||
// processor dependent initialization for i486
|
||||
|
||||
void Compile::pd_compiler2_init() {
|
||||
guarantee(CodeEntryAlignment >= InteriorEntryAlignment, "" );
|
||||
// QQQ presumably all 64bit cpu's support this. Seems like the ifdef could
|
||||
// simply be left out.
|
||||
}
|
||||
35
hotspot/src/cpu/aarch64/vm/codeBuffer_aarch64.hpp
Normal file
35
hotspot/src/cpu/aarch64/vm/codeBuffer_aarch64.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_CODEBUFFER_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_CODEBUFFER_AARCH64_HPP
|
||||
|
||||
private:
|
||||
void pd_initialize() {}
|
||||
|
||||
public:
|
||||
void flush_bundle(bool start_new_bundle) {}
|
||||
|
||||
#endif // CPU_AARCH64_VM_CODEBUFFER_AARCH64_HPP
|
||||
152
hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp
Normal file
152
hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "code/compiledIC.hpp"
|
||||
#include "code/icBuffer.hpp"
|
||||
#include "code/nmethod.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
|
||||
// Release the CompiledICHolder* associated with this call site is there is one.
|
||||
void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) {
|
||||
// This call site might have become stale so inspect it carefully.
|
||||
NativeCall* call = nativeCall_at(call_site->addr());
|
||||
if (is_icholder_entry(call->destination())) {
|
||||
NativeMovConstReg* value = nativeMovConstReg_at(call_site->cached_value());
|
||||
InlineCacheBuffer::queue_for_release((CompiledICHolder*)value->data());
|
||||
}
|
||||
}
|
||||
|
||||
bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
|
||||
// This call site might have become stale so inspect it carefully.
|
||||
NativeCall* call = nativeCall_at(call_site->addr());
|
||||
return is_icholder_entry(call->destination());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define __ _masm.
|
||||
void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
|
||||
// Stub is fixed up when the corresponding call is converted from
|
||||
// calling compiled code to calling interpreted code.
|
||||
// mov rmethod, 0
|
||||
// jmp -4 # to self
|
||||
|
||||
address mark = cbuf.insts_mark(); // Get mark within main instrs section.
|
||||
|
||||
// Note that the code buffer's insts_mark is always relative to insts.
|
||||
// That's why we must use the macroassembler to generate a stub.
|
||||
MacroAssembler _masm(&cbuf);
|
||||
|
||||
address base = __ start_a_stub(to_interp_stub_size()*2);
|
||||
|
||||
int offset = __ offset();
|
||||
if (base == NULL) return; // CodeBuffer::expand failed
|
||||
// static stub relocation stores the instruction address of the call
|
||||
__ relocate(static_stub_Relocation::spec(mark));
|
||||
// static stub relocation also tags the Method* in the code-stream.
|
||||
__ mov_metadata(rmethod, (Metadata*)NULL);
|
||||
__ movptr(rscratch1, 0);
|
||||
__ br(rscratch1);
|
||||
|
||||
assert((__ offset() - offset) <= (int)to_interp_stub_size(), "stub too big");
|
||||
__ end_a_stub();
|
||||
}
|
||||
#undef __
|
||||
|
||||
int CompiledStaticCall::to_interp_stub_size() {
|
||||
return 7 * NativeInstruction::instruction_size;
|
||||
}
|
||||
|
||||
// Relocation entries for call stub, compiled java to interpreter.
|
||||
int CompiledStaticCall::reloc_to_interp_stub() {
|
||||
return 4; // 3 in emit_to_interp_stub + 1 in emit_call
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
|
||||
address stub = find_stub();
|
||||
guarantee(stub != NULL, "stub not found");
|
||||
|
||||
if (TraceICs) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
|
||||
p2i(instruction_address()),
|
||||
callee->name_and_sig_as_C_string());
|
||||
}
|
||||
|
||||
// Creation also verifies the object.
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
|
||||
#ifndef PRODUCT
|
||||
NativeGeneralJump* jump = nativeGeneralJump_at(method_holder->next_instruction_address());
|
||||
|
||||
assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(),
|
||||
"a) MT-unsafe modification of inline cache");
|
||||
assert(method_holder->data() == 0 || jump->jump_destination() == entry,
|
||||
"b) MT-unsafe modification of inline cache");
|
||||
#endif
|
||||
// Update stub.
|
||||
method_holder->set_data((intptr_t)callee());
|
||||
NativeGeneralJump::insert_unconditional(method_holder->next_instruction_address(), entry);
|
||||
ICache::invalidate_range(stub, to_interp_stub_size());
|
||||
// Update jump to call.
|
||||
set_destination_mt_safe(stub);
|
||||
}
|
||||
|
||||
void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
|
||||
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
|
||||
// Reset stub.
|
||||
address stub = static_stub->addr();
|
||||
assert(stub != NULL, "stub not found");
|
||||
// Creation also verifies the object.
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
|
||||
method_holder->set_data(0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Non-product mode code
|
||||
#ifndef PRODUCT
|
||||
|
||||
void CompiledStaticCall::verify() {
|
||||
// Verify call.
|
||||
NativeCall::verify();
|
||||
if (os::is_MP()) {
|
||||
verify_alignment();
|
||||
}
|
||||
|
||||
// Verify stub.
|
||||
address stub = find_stub();
|
||||
assert(stub != NULL, "no stub found for static call");
|
||||
// Creation also verifies the object.
|
||||
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
|
||||
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());
|
||||
|
||||
// Verify state.
|
||||
assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
|
||||
}
|
||||
|
||||
#endif // !PRODUCT
|
||||
61
hotspot/src/cpu/aarch64/vm/copy_aarch64.hpp
Normal file
61
hotspot/src/cpu/aarch64/vm/copy_aarch64.hpp
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_COPY_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_COPY_AARCH64_HPP
|
||||
|
||||
// Inline functions for memory copy and fill.
|
||||
|
||||
// Contains inline asm implementations
|
||||
#ifdef TARGET_OS_ARCH_linux_aarch64
|
||||
# include "copy_linux_aarch64.inline.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
static void pd_fill_to_words(HeapWord* tohw, size_t count, juint value) {
|
||||
julong* to = (julong*) tohw;
|
||||
julong v = ((julong) value << 32) | value;
|
||||
while (count-- > 0) {
|
||||
*to++ = v;
|
||||
}
|
||||
}
|
||||
|
||||
static void pd_fill_to_aligned_words(HeapWord* tohw, size_t count, juint value) {
|
||||
pd_fill_to_words(tohw, count, value);
|
||||
}
|
||||
|
||||
static void pd_fill_to_bytes(void* to, size_t count, jubyte value) {
|
||||
(void)memset(to, value, count);
|
||||
}
|
||||
|
||||
static void pd_zero_to_words(HeapWord* tohw, size_t count) {
|
||||
pd_fill_to_words(tohw, count, 0);
|
||||
}
|
||||
|
||||
static void pd_zero_to_bytes(void* to, size_t count) {
|
||||
(void)memset(to, 0, count);
|
||||
}
|
||||
|
||||
#endif // CPU_AARCH64_VM_COPY_AARCH64_HPP
|
||||
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_CPPINTERPRETERGENERATOR_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_CPPINTERPRETERGENERATOR_AARCH64_HPP
|
||||
|
||||
protected:
|
||||
|
||||
void generate_more_monitors();
|
||||
void generate_deopt_handling();
|
||||
|
||||
#endif // CPU_AARCH64_VM_CPPINTERPRETERGENERATOR_AARCH64_HPP
|
||||
595
hotspot/src/cpu/aarch64/vm/cpustate_aarch64.hpp
Normal file
595
hotspot/src/cpu/aarch64/vm/cpustate_aarch64.hpp
Normal file
@ -0,0 +1,595 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CPU_STATE_H
|
||||
#define _CPU_STATE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/*
|
||||
* symbolic names used to identify general registers which also match
|
||||
* the registers indices in machine code
|
||||
*
|
||||
* We have 32 general registers which can be read/written as 32 bit or
|
||||
* 64 bit sources/sinks and are appropriately referred to as Wn or Xn
|
||||
* in the assembly code. Some instructions mix these access modes
|
||||
* (e.g. ADD X0, X1, W2) so the implementation of the instruction
|
||||
* needs to *know* which type of read or write access is required.
|
||||
*/
|
||||
enum GReg {
|
||||
R0,
|
||||
R1,
|
||||
R2,
|
||||
R3,
|
||||
R4,
|
||||
R5,
|
||||
R6,
|
||||
R7,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R12,
|
||||
R13,
|
||||
R14,
|
||||
R15,
|
||||
R16,
|
||||
R17,
|
||||
R18,
|
||||
R19,
|
||||
R20,
|
||||
R21,
|
||||
R22,
|
||||
R23,
|
||||
R24,
|
||||
R25,
|
||||
R26,
|
||||
R27,
|
||||
R28,
|
||||
R29,
|
||||
R30,
|
||||
R31,
|
||||
// and now the aliases
|
||||
RSCRATCH1=R8,
|
||||
RSCRATCH2=R9,
|
||||
RMETHOD=R12,
|
||||
RESP=R20,
|
||||
RDISPATCH=R21,
|
||||
RBCP=R22,
|
||||
RLOCALS=R24,
|
||||
RMONITORS=R25,
|
||||
RCPOOL=R26,
|
||||
RHEAPBASE=R27,
|
||||
RTHREAD=R28,
|
||||
FP = R29,
|
||||
LR = R30,
|
||||
SP = R31,
|
||||
ZR = R31
|
||||
};
|
||||
|
||||
/*
|
||||
* symbolic names used to refer to floating point registers which also
|
||||
* match the registers indices in machine code
|
||||
*
|
||||
* We have 32 FP registers which can be read/written as 8, 16, 32, 64
|
||||
* and 128 bit sources/sinks and are appropriately referred to as Bn,
|
||||
* Hn, Sn, Dn and Qn in the assembly code. Some instructions mix these
|
||||
* access modes (e.g. FCVT S0, D0) so the implementation of the
|
||||
* instruction needs to *know* which type of read or write access is
|
||||
* required.
|
||||
*/
|
||||
|
||||
enum VReg {
|
||||
V0,
|
||||
V1,
|
||||
V2,
|
||||
V3,
|
||||
V4,
|
||||
V5,
|
||||
V6,
|
||||
V7,
|
||||
V8,
|
||||
V9,
|
||||
V10,
|
||||
V11,
|
||||
V12,
|
||||
V13,
|
||||
V14,
|
||||
V15,
|
||||
V16,
|
||||
V17,
|
||||
V18,
|
||||
V19,
|
||||
V20,
|
||||
V21,
|
||||
V22,
|
||||
V23,
|
||||
V24,
|
||||
V25,
|
||||
V26,
|
||||
V27,
|
||||
V28,
|
||||
V29,
|
||||
V30,
|
||||
V31,
|
||||
};
|
||||
|
||||
/**
|
||||
* all the different integer bit patterns for the components of a
|
||||
* general register are overlaid here using a union so as to allow all
|
||||
* reading and writing of the desired bits.
|
||||
*
|
||||
* n.b. the ARM spec says that when you write a 32 bit register you
|
||||
* are supposed to write the low 32 bits and zero the high 32
|
||||
* bits. But we don't actually have to care about this because Java
|
||||
* will only ever consume the 32 bits value as a 64 bit quantity after
|
||||
* an explicit extend.
|
||||
*/
|
||||
union GRegisterValue
|
||||
{
|
||||
int8_t s8;
|
||||
int16_t s16;
|
||||
int32_t s32;
|
||||
int64_t s64;
|
||||
u_int8_t u8;
|
||||
u_int16_t u16;
|
||||
u_int32_t u32;
|
||||
u_int64_t u64;
|
||||
};
|
||||
|
||||
class GRegister
|
||||
{
|
||||
public:
|
||||
GRegisterValue value;
|
||||
};
|
||||
|
||||
/*
|
||||
* float registers provide for storage of a single, double or quad
|
||||
* word format float in the same register. single floats are not
|
||||
* paired within each double register as per 32 bit arm. instead each
|
||||
* 128 bit register Vn embeds the bits for Sn, and Dn in the lower
|
||||
* quarter and half, respectively, of the bits for Qn.
|
||||
*
|
||||
* The upper bits can also be accessed as single or double floats by
|
||||
* the float vector operations using indexing e.g. V1.D[1], V1.S[3]
|
||||
* etc and, for SIMD operations using a horrible index range notation.
|
||||
*
|
||||
* The spec also talks about accessing float registers as half words
|
||||
* and bytes with Hn and Bn providing access to the low 16 and 8 bits
|
||||
* of Vn but it is not really clear what these bits represent. We can
|
||||
* probably ignore this for Java anyway. However, we do need to access
|
||||
* the raw bits at 32 and 64 bit resolution to load to/from integer
|
||||
* registers.
|
||||
*/
|
||||
|
||||
union FRegisterValue
|
||||
{
|
||||
float s;
|
||||
double d;
|
||||
long double q;
|
||||
// eventually we will need to be able to access the data as a vector
|
||||
// the integral array elements allow us to access the bits in s, d,
|
||||
// q, vs and vd at an appropriate level of granularity
|
||||
u_int8_t vb[16];
|
||||
u_int16_t vh[8];
|
||||
u_int32_t vw[4];
|
||||
u_int64_t vx[2];
|
||||
float vs[4];
|
||||
double vd[2];
|
||||
};
|
||||
|
||||
class FRegister
|
||||
{
|
||||
public:
|
||||
FRegisterValue value;
|
||||
};
|
||||
|
||||
/*
|
||||
* CPSR register -- this does not exist as a directly accessible
|
||||
* register but we need to store the flags so we can implement
|
||||
* flag-seting and flag testing operations
|
||||
*
|
||||
* we can possibly use injected x86 asm to report the outcome of flag
|
||||
* setting operations. if so we will need to grab the flags
|
||||
* immediately after the operation in order to ensure we don't lose
|
||||
* them because of the actions of the simulator. so we still need
|
||||
* somewhere to store the condition codes.
|
||||
*/
|
||||
|
||||
class CPSRRegister
|
||||
{
|
||||
public:
|
||||
u_int32_t value;
|
||||
|
||||
/*
|
||||
* condition register bit select values
|
||||
*
|
||||
* the order of bits here is important because some of
|
||||
* the flag setting conditional instructions employ a
|
||||
* bit field to populate the flags when a false condition
|
||||
* bypasses execution of the operation and we want to
|
||||
* be able to assign the flags register using the
|
||||
* supplied value.
|
||||
*/
|
||||
|
||||
enum CPSRIdx {
|
||||
V_IDX,
|
||||
C_IDX,
|
||||
Z_IDX,
|
||||
N_IDX
|
||||
};
|
||||
|
||||
enum CPSRMask {
|
||||
V = 1 << V_IDX,
|
||||
C = 1 << C_IDX,
|
||||
Z = 1 << Z_IDX,
|
||||
N = 1 << N_IDX
|
||||
};
|
||||
|
||||
static const int CPSR_ALL_FLAGS = (V | C | Z | N);
|
||||
};
|
||||
|
||||
// auxiliary function to assemble the relevant bits from
|
||||
// the x86 EFLAGS register into an ARM CPSR value
|
||||
|
||||
#define X86_V_IDX 11
|
||||
#define X86_C_IDX 0
|
||||
#define X86_Z_IDX 6
|
||||
#define X86_N_IDX 7
|
||||
|
||||
#define X86_V (1 << X86_V_IDX)
|
||||
#define X86_C (1 << X86_C_IDX)
|
||||
#define X86_Z (1 << X86_Z_IDX)
|
||||
#define X86_N (1 << X86_N_IDX)
|
||||
|
||||
inline u_int32_t convertX86Flags(u_int32_t x86flags)
|
||||
{
|
||||
u_int32_t flags;
|
||||
// set N flag
|
||||
flags = ((x86flags & X86_N) >> X86_N_IDX);
|
||||
// shift then or in Z flag
|
||||
flags <<= 1;
|
||||
flags |= ((x86flags & X86_Z) >> X86_Z_IDX);
|
||||
// shift then or in C flag
|
||||
flags <<= 1;
|
||||
flags |= ((x86flags & X86_C) >> X86_C_IDX);
|
||||
// shift then or in V flag
|
||||
flags <<= 1;
|
||||
flags |= ((x86flags & X86_V) >> X86_V_IDX);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
inline u_int32_t convertX86FlagsFP(u_int32_t x86flags)
|
||||
{
|
||||
// x86 flags set by fcomi(x,y) are ZF:PF:CF
|
||||
// (yes, that's PF for parity, WTF?)
|
||||
// where
|
||||
// 0) 0:0:0 means x > y
|
||||
// 1) 0:0:1 means x < y
|
||||
// 2) 1:0:0 means x = y
|
||||
// 3) 1:1:1 means x and y are unordered
|
||||
// note that we don't have to check PF so
|
||||
// we really have a simple 2-bit case switch
|
||||
// the corresponding ARM64 flags settings
|
||||
// in hi->lo bit order are
|
||||
// 0) --C-
|
||||
// 1) N---
|
||||
// 2) -ZC-
|
||||
// 3) --CV
|
||||
|
||||
static u_int32_t armFlags[] = {
|
||||
0b0010,
|
||||
0b1000,
|
||||
0b0110,
|
||||
0b0011
|
||||
};
|
||||
// pick out the ZF and CF bits
|
||||
u_int32_t zc = ((x86flags & X86_Z) >> X86_Z_IDX);
|
||||
zc <<= 1;
|
||||
zc |= ((x86flags & X86_C) >> X86_C_IDX);
|
||||
|
||||
return armFlags[zc];
|
||||
}
|
||||
|
||||
/*
|
||||
* FPSR register -- floating point status register
|
||||
|
||||
* this register includes IDC, IXC, UFC, OFC, DZC, IOC and QC bits,
|
||||
* and the floating point N, Z, C, V bits but the latter are unused in
|
||||
* aarch64 mode. the sim ignores QC for now.
|
||||
*
|
||||
* bit positions are as per the ARMv7 FPSCR register
|
||||
*
|
||||
* IDC : 7 ==> Input Denormal (cumulative exception bit)
|
||||
* IXC : 4 ==> Inexact
|
||||
* UFC : 3 ==> Underflow
|
||||
* OFC : 2 ==> Overflow
|
||||
* DZC : 1 ==> Division by Zero
|
||||
* IOC : 0 ==> Invalid Operation
|
||||
*/
|
||||
|
||||
class FPSRRegister
|
||||
{
|
||||
public:
|
||||
u_int32_t value;
|
||||
// indices for bits in the FPSR register value
|
||||
enum FPSRIdx {
|
||||
IO_IDX = 0,
|
||||
DZ_IDX = 1,
|
||||
OF_IDX = 2,
|
||||
UF_IDX = 3,
|
||||
IX_IDX = 4,
|
||||
ID_IDX = 7
|
||||
};
|
||||
// corresponding bits as numeric values
|
||||
enum FPSRMask {
|
||||
IO = (1 << IO_IDX),
|
||||
DZ = (1 << DZ_IDX),
|
||||
OF = (1 << OF_IDX),
|
||||
UF = (1 << UF_IDX),
|
||||
IX = (1 << IX_IDX),
|
||||
ID = (1 << ID_IDX)
|
||||
};
|
||||
static const int FPSR_ALL_FPSRS = (IO | DZ | OF | UF | IX | ID);
|
||||
};
|
||||
|
||||
// debugger support
|
||||
|
||||
enum PrintFormat
|
||||
{
|
||||
FMT_DECIMAL,
|
||||
FMT_HEX,
|
||||
FMT_SINGLE,
|
||||
FMT_DOUBLE,
|
||||
FMT_QUAD,
|
||||
FMT_MULTI
|
||||
};
|
||||
|
||||
/*
|
||||
* model of the registers and other state associated with the cpu
|
||||
*/
|
||||
class CPUState
|
||||
{
|
||||
friend class AArch64Simulator;
|
||||
private:
|
||||
// this is the PC of the instruction being executed
|
||||
u_int64_t pc;
|
||||
// this is the PC of the instruction to be executed next
|
||||
// it is defaulted to pc + 4 at instruction decode but
|
||||
// execute may reset it
|
||||
|
||||
u_int64_t nextpc;
|
||||
GRegister gr[33]; // extra register at index 32 is used
|
||||
// to hold zero value
|
||||
FRegister fr[32];
|
||||
CPSRRegister cpsr;
|
||||
FPSRRegister fpsr;
|
||||
|
||||
public:
|
||||
|
||||
CPUState() {
|
||||
gr[20].value.u64 = 0; // establish initial condition for
|
||||
// checkAssertions()
|
||||
trace_counter = 0;
|
||||
}
|
||||
|
||||
// General Register access macros
|
||||
|
||||
// only xreg or xregs can be used as an lvalue in order to update a
|
||||
// register. this ensures that the top part of a register is always
|
||||
// assigned when it is written by the sim.
|
||||
|
||||
inline u_int64_t &xreg(GReg reg, int r31_is_sp) {
|
||||
if (reg == R31 && !r31_is_sp) {
|
||||
return gr[32].value.u64;
|
||||
} else {
|
||||
return gr[reg].value.u64;
|
||||
}
|
||||
}
|
||||
|
||||
inline int64_t &xregs(GReg reg, int r31_is_sp) {
|
||||
if (reg == R31 && !r31_is_sp) {
|
||||
return gr[32].value.s64;
|
||||
} else {
|
||||
return gr[reg].value.s64;
|
||||
}
|
||||
}
|
||||
|
||||
inline u_int32_t wreg(GReg reg, int r31_is_sp) {
|
||||
if (reg == R31 && !r31_is_sp) {
|
||||
return gr[32].value.u32;
|
||||
} else {
|
||||
return gr[reg].value.u32;
|
||||
}
|
||||
}
|
||||
|
||||
inline int32_t wregs(GReg reg, int r31_is_sp) {
|
||||
if (reg == R31 && !r31_is_sp) {
|
||||
return gr[32].value.s32;
|
||||
} else {
|
||||
return gr[reg].value.s32;
|
||||
}
|
||||
}
|
||||
|
||||
inline u_int32_t hreg(GReg reg, int r31_is_sp) {
|
||||
if (reg == R31 && !r31_is_sp) {
|
||||
return gr[32].value.u16;
|
||||
} else {
|
||||
return gr[reg].value.u16;
|
||||
}
|
||||
}
|
||||
|
||||
inline int32_t hregs(GReg reg, int r31_is_sp) {
|
||||
if (reg == R31 && !r31_is_sp) {
|
||||
return gr[32].value.s16;
|
||||
} else {
|
||||
return gr[reg].value.s16;
|
||||
}
|
||||
}
|
||||
|
||||
inline u_int32_t breg(GReg reg, int r31_is_sp) {
|
||||
if (reg == R31 && !r31_is_sp) {
|
||||
return gr[32].value.u8;
|
||||
} else {
|
||||
return gr[reg].value.u8;
|
||||
}
|
||||
}
|
||||
|
||||
inline int32_t bregs(GReg reg, int r31_is_sp) {
|
||||
if (reg == R31 && !r31_is_sp) {
|
||||
return gr[32].value.s8;
|
||||
} else {
|
||||
return gr[reg].value.s8;
|
||||
}
|
||||
}
|
||||
|
||||
// FP Register access macros
|
||||
|
||||
// all non-vector accessors return a reference so we can both read
|
||||
// and assign
|
||||
|
||||
inline float &sreg(VReg reg) {
|
||||
return fr[reg].value.s;
|
||||
}
|
||||
|
||||
inline double &dreg(VReg reg) {
|
||||
return fr[reg].value.d;
|
||||
}
|
||||
|
||||
inline long double &qreg(VReg reg) {
|
||||
return fr[reg].value.q;
|
||||
}
|
||||
|
||||
// all vector register accessors return a pointer
|
||||
|
||||
inline float *vsreg(VReg reg) {
|
||||
return &fr[reg].value.vs[0];
|
||||
}
|
||||
|
||||
inline double *vdreg(VReg reg) {
|
||||
return &fr[reg].value.vd[0];
|
||||
}
|
||||
|
||||
inline u_int8_t *vbreg(VReg reg) {
|
||||
return &fr[reg].value.vb[0];
|
||||
}
|
||||
|
||||
inline u_int16_t *vhreg(VReg reg) {
|
||||
return &fr[reg].value.vh[0];
|
||||
}
|
||||
|
||||
inline u_int32_t *vwreg(VReg reg) {
|
||||
return &fr[reg].value.vw[0];
|
||||
}
|
||||
|
||||
inline u_int64_t *vxreg(VReg reg) {
|
||||
return &fr[reg].value.vx[0];
|
||||
}
|
||||
|
||||
union GRegisterValue prev_sp, prev_fp;
|
||||
|
||||
static const int trace_size = 256;
|
||||
u_int64_t trace_buffer[trace_size];
|
||||
int trace_counter;
|
||||
|
||||
bool checkAssertions()
|
||||
{
|
||||
// Make sure that SP is 16-aligned
|
||||
// Also make sure that ESP is above SP.
|
||||
// We don't care about checking ESP if it is null, i.e. it hasn't
|
||||
// been used yet.
|
||||
if (gr[31].value.u64 & 0x0f) {
|
||||
asm volatile("nop");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// pc register accessors
|
||||
|
||||
// this instruction can be used to fetch the current PC
|
||||
u_int64_t getPC();
|
||||
// instead of setting the current PC directly you can
|
||||
// first set the next PC (either absolute or PC-relative)
|
||||
// and later copy the next PC into the current PC
|
||||
// this supports a default increment by 4 at instruction
|
||||
// fetch with an optional reset by control instructions
|
||||
u_int64_t getNextPC();
|
||||
void setNextPC(u_int64_t next);
|
||||
void offsetNextPC(int64_t offset);
|
||||
// install nextpc as current pc
|
||||
void updatePC();
|
||||
|
||||
// this instruction can be used to save the next PC to LR
|
||||
// just before installing a branch PC
|
||||
inline void saveLR() { gr[LR].value.u64 = nextpc; }
|
||||
|
||||
// cpsr register accessors
|
||||
u_int32_t getCPSRRegister();
|
||||
void setCPSRRegister(u_int32_t flags);
|
||||
// read a specific subset of the flags as a bit pattern
|
||||
// mask should be composed using elements of enum FlagMask
|
||||
u_int32_t getCPSRBits(u_int32_t mask);
|
||||
// assign a specific subset of the flags as a bit pattern
|
||||
// mask and value should be composed using elements of enum FlagMask
|
||||
void setCPSRBits(u_int32_t mask, u_int32_t value);
|
||||
// test the value of a single flag returned as 1 or 0
|
||||
u_int32_t testCPSR(CPSRRegister::CPSRIdx idx);
|
||||
// set a single flag
|
||||
void setCPSR(CPSRRegister::CPSRIdx idx);
|
||||
// clear a single flag
|
||||
void clearCPSR(CPSRRegister::CPSRIdx idx);
|
||||
// utility method to set ARM CSPR flags from an x86 bit mask generated by integer arithmetic
|
||||
void setCPSRRegisterFromX86(u_int64_t x86Flags);
|
||||
// utility method to set ARM CSPR flags from an x86 bit mask generated by floating compare
|
||||
void setCPSRRegisterFromX86FP(u_int64_t x86Flags);
|
||||
|
||||
// fpsr register accessors
|
||||
u_int32_t getFPSRRegister();
|
||||
void setFPSRRegister(u_int32_t flags);
|
||||
// read a specific subset of the fprs bits as a bit pattern
|
||||
// mask should be composed using elements of enum FPSRRegister::FlagMask
|
||||
u_int32_t getFPSRBits(u_int32_t mask);
|
||||
// assign a specific subset of the flags as a bit pattern
|
||||
// mask and value should be composed using elements of enum FPSRRegister::FlagMask
|
||||
void setFPSRBits(u_int32_t mask, u_int32_t value);
|
||||
// test the value of a single flag returned as 1 or 0
|
||||
u_int32_t testFPSR(FPSRRegister::FPSRIdx idx);
|
||||
// set a single flag
|
||||
void setFPSR(FPSRRegister::FPSRIdx idx);
|
||||
// clear a single flag
|
||||
void clearFPSR(FPSRRegister::FPSRIdx idx);
|
||||
|
||||
// debugger support
|
||||
void printPC(int pending, const char *trailing = "\n");
|
||||
void printInstr(u_int32_t instr, void (*dasm)(u_int64_t), const char *trailing = "\n");
|
||||
void printGReg(GReg reg, PrintFormat format = FMT_HEX, const char *trailing = "\n");
|
||||
void printVReg(VReg reg, PrintFormat format = FMT_HEX, const char *trailing = "\n");
|
||||
void printCPSR(const char *trailing = "\n");
|
||||
void printFPSR(const char *trailing = "\n");
|
||||
void dumpState();
|
||||
};
|
||||
|
||||
#endif // ifndef _CPU_STATE_H
|
||||
35
hotspot/src/cpu/aarch64/vm/debug_aarch64.cpp
Normal file
35
hotspot/src/cpu/aarch64/vm/debug_aarch64.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/nmethod.hpp"
|
||||
#include "runtime/frame.hpp"
|
||||
#include "runtime/init.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/top.hpp"
|
||||
|
||||
void pd_ps(frame f) {}
|
||||
412
hotspot/src/cpu/aarch64/vm/decode_aarch64.hpp
Normal file
412
hotspot/src/cpu/aarch64/vm/decode_aarch64.hpp
Normal file
@ -0,0 +1,412 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DECODE_H
|
||||
#define _DECODE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "cpustate_aarch64.hpp"
|
||||
|
||||
// bitfield immediate expansion helper
|
||||
|
||||
extern int expandLogicalImmediate(u_int32_t immN, u_int32_t immr,
|
||||
u_int32_t imms, u_int64_t &bimm);
|
||||
|
||||
|
||||
/*
|
||||
* codes used in conditional instructions
|
||||
*
|
||||
* these are passed to conditional operations to identify which
|
||||
* condition to test for
|
||||
*/
|
||||
enum CondCode {
|
||||
EQ = 0b0000, // meaning Z == 1
|
||||
NE = 0b0001, // meaning Z == 0
|
||||
HS = 0b0010, // meaning C == 1
|
||||
CS = HS,
|
||||
LO = 0b0011, // meaning C == 0
|
||||
CC = LO,
|
||||
MI = 0b0100, // meaning N == 1
|
||||
PL = 0b0101, // meaning N == 0
|
||||
VS = 0b0110, // meaning V == 1
|
||||
VC = 0b0111, // meaning V == 0
|
||||
HI = 0b1000, // meaning C == 1 && Z == 0
|
||||
LS = 0b1001, // meaning !(C == 1 && Z == 0)
|
||||
GE = 0b1010, // meaning N == V
|
||||
LT = 0b1011, // meaning N != V
|
||||
GT = 0b1100, // meaning Z == 0 && N == V
|
||||
LE = 0b1101, // meaning !(Z == 0 && N == V)
|
||||
AL = 0b1110, // meaning ANY
|
||||
NV = 0b1111 // ditto
|
||||
};
|
||||
|
||||
/*
|
||||
* certain addressing modes for load require pre or post writeback of
|
||||
* the computed address to a base register
|
||||
*/
|
||||
enum WriteBack {
|
||||
Post = 0,
|
||||
Pre = 1
|
||||
};
|
||||
|
||||
/*
|
||||
* certain addressing modes for load require an offset to
|
||||
* be optionally scaled so the decode needs to pass that
|
||||
* through to the execute routine
|
||||
*/
|
||||
enum Scaling {
|
||||
Unscaled = 0,
|
||||
Scaled = 1
|
||||
};
|
||||
|
||||
/*
|
||||
* when we do have to scale we do so by shifting using
|
||||
* log(bytes in data element - 1) as the shift count.
|
||||
* so we don't have to scale offsets when loading
|
||||
* bytes.
|
||||
*/
|
||||
enum ScaleShift {
|
||||
ScaleShift16 = 1,
|
||||
ScaleShift32 = 2,
|
||||
ScaleShift64 = 3,
|
||||
ScaleShift128 = 4
|
||||
};
|
||||
|
||||
/*
|
||||
* one of the addressing modes for load requires a 32-bit register
|
||||
* value to be either zero- or sign-extended for these instructions
|
||||
* UXTW or SXTW should be passed
|
||||
*
|
||||
* arithmetic register data processing operations can optionally
|
||||
* extend a portion of the second register value for these
|
||||
* instructions the value supplied must identify the portion of the
|
||||
* register which is to be zero- or sign-exended
|
||||
*/
|
||||
enum Extension {
|
||||
UXTB = 0,
|
||||
UXTH = 1,
|
||||
UXTW = 2,
|
||||
UXTX = 3,
|
||||
SXTB = 4,
|
||||
SXTH = 5,
|
||||
SXTW = 6,
|
||||
SXTX = 7
|
||||
};
|
||||
|
||||
/*
|
||||
* arithmetic and logical register data processing operations
|
||||
* optionally perform a shift on the second register value
|
||||
*/
|
||||
enum Shift {
|
||||
LSL = 0,
|
||||
LSR = 1,
|
||||
ASR = 2,
|
||||
ROR = 3
|
||||
};
|
||||
|
||||
/*
|
||||
* bit twiddling helpers for instruction decode
|
||||
*/
|
||||
|
||||
// 32 bit mask with bits [hi,...,lo] set
|
||||
|
||||
static inline u_int32_t mask32(int hi = 31, int lo = 0)
|
||||
{
|
||||
int nbits = (hi + 1) - lo;
|
||||
return ((1 << nbits) - 1) << lo;
|
||||
}
|
||||
|
||||
static inline u_int64_t mask64(int hi = 63, int lo = 0)
|
||||
{
|
||||
int nbits = (hi + 1) - lo;
|
||||
return ((1L << nbits) - 1) << lo;
|
||||
}
|
||||
|
||||
// pick bits [hi,...,lo] from val
|
||||
static inline u_int32_t pick32(u_int32_t val, int hi = 31, int lo = 0)
|
||||
{
|
||||
return (val & mask32(hi, lo));
|
||||
}
|
||||
|
||||
// pick bits [hi,...,lo] from val
|
||||
static inline u_int64_t pick64(u_int64_t val, int hi = 31, int lo = 0)
|
||||
{
|
||||
return (val & mask64(hi, lo));
|
||||
}
|
||||
|
||||
// pick bits [hi,...,lo] from val and shift to [(hi-(newlo - lo)),newlo]
|
||||
static inline u_int32_t pickshift32(u_int32_t val, int hi = 31,
|
||||
int lo = 0, int newlo = 0)
|
||||
{
|
||||
u_int32_t bits = pick32(val, hi, lo);
|
||||
if (lo < newlo) {
|
||||
return (bits << (newlo - lo));
|
||||
} else {
|
||||
return (bits >> (lo - newlo));
|
||||
}
|
||||
}
|
||||
// mask [hi,lo] and shift down to start at bit 0
|
||||
static inline u_int32_t pickbits32(u_int32_t val, int hi = 31, int lo = 0)
|
||||
{
|
||||
return (pick32(val, hi, lo) >> lo);
|
||||
}
|
||||
|
||||
// mask [hi,lo] and shift down to start at bit 0
|
||||
static inline u_int64_t pickbits64(u_int64_t val, int hi = 63, int lo = 0)
|
||||
{
|
||||
return (pick64(val, hi, lo) >> lo);
|
||||
}
|
||||
|
||||
/*
|
||||
* decode registers, immediates and constants of various types
|
||||
*/
|
||||
|
||||
static inline GReg greg(u_int32_t val, int lo)
|
||||
{
|
||||
return (GReg)pickbits32(val, lo + 4, lo);
|
||||
}
|
||||
|
||||
static inline VReg vreg(u_int32_t val, int lo)
|
||||
{
|
||||
return (VReg)pickbits32(val, lo + 4, lo);
|
||||
}
|
||||
|
||||
static inline u_int32_t uimm(u_int32_t val, int hi, int lo)
|
||||
{
|
||||
return pickbits32(val, hi, lo);
|
||||
}
|
||||
|
||||
static inline int32_t simm(u_int32_t val, int hi = 31, int lo = 0) {
|
||||
union {
|
||||
u_int32_t u;
|
||||
int32_t n;
|
||||
};
|
||||
|
||||
u = val << (31 - hi);
|
||||
n = n >> (31 - hi + lo);
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline int64_t simm(u_int64_t val, int hi = 63, int lo = 0) {
|
||||
union {
|
||||
u_int64_t u;
|
||||
int64_t n;
|
||||
};
|
||||
|
||||
u = val << (63 - hi);
|
||||
n = n >> (63 - hi + lo);
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline Shift shift(u_int32_t val, int lo)
|
||||
{
|
||||
return (Shift)pickbits32(val, lo+1, lo);
|
||||
}
|
||||
|
||||
static inline Extension extension(u_int32_t val, int lo)
|
||||
{
|
||||
return (Extension)pickbits32(val, lo+2, lo);
|
||||
}
|
||||
|
||||
static inline Scaling scaling(u_int32_t val, int lo)
|
||||
{
|
||||
return (Scaling)pickbits32(val, lo, lo);
|
||||
}
|
||||
|
||||
static inline WriteBack writeback(u_int32_t val, int lo)
|
||||
{
|
||||
return (WriteBack)pickbits32(val, lo, lo);
|
||||
}
|
||||
|
||||
static inline CondCode condcode(u_int32_t val, int lo)
|
||||
{
|
||||
return (CondCode)pickbits32(val, lo+3, lo);
|
||||
}
|
||||
|
||||
/*
|
||||
* operation decode
|
||||
*/
|
||||
// bits [28,25] are the primary dispatch vector
|
||||
|
||||
static inline u_int32_t dispatchGroup(u_int32_t val)
|
||||
{
|
||||
return pickshift32(val, 28, 25, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* the 16 possible values for bits [28,25] identified by tags which
|
||||
* map them to the 5 main instruction groups LDST, DPREG, ADVSIMD,
|
||||
* BREXSYS and DPIMM.
|
||||
*
|
||||
* An extra group PSEUDO is included in one of the unallocated ranges
|
||||
* for simulator-specific pseudo-instructions.
|
||||
*/
|
||||
enum DispatchGroup {
|
||||
GROUP_PSEUDO_0000,
|
||||
GROUP_UNALLOC_0001,
|
||||
GROUP_UNALLOC_0010,
|
||||
GROUP_UNALLOC_0011,
|
||||
GROUP_LDST_0100,
|
||||
GROUP_DPREG_0101,
|
||||
GROUP_LDST_0110,
|
||||
GROUP_ADVSIMD_0111,
|
||||
GROUP_DPIMM_1000,
|
||||
GROUP_DPIMM_1001,
|
||||
GROUP_BREXSYS_1010,
|
||||
GROUP_BREXSYS_1011,
|
||||
GROUP_LDST_1100,
|
||||
GROUP_DPREG_1101,
|
||||
GROUP_LDST_1110,
|
||||
GROUP_ADVSIMD_1111
|
||||
};
|
||||
|
||||
// bits [31, 29] of a Pseudo are the secondary dispatch vector
|
||||
|
||||
static inline u_int32_t dispatchPseudo(u_int32_t val)
|
||||
{
|
||||
return pickshift32(val, 31, 29, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* the 8 possible values for bits [31,29] in a Pseudo Instruction.
|
||||
* Bits [28,25] are always 0000.
|
||||
*/
|
||||
|
||||
enum DispatchPseudo {
|
||||
PSEUDO_UNALLOC_000, // unallocated
|
||||
PSEUDO_UNALLOC_001, // ditto
|
||||
PSEUDO_UNALLOC_010, // ditto
|
||||
PSEUDO_UNALLOC_011, // ditto
|
||||
PSEUDO_UNALLOC_100, // ditto
|
||||
PSEUDO_UNALLOC_101, // ditto
|
||||
PSEUDO_CALLOUT_110, // CALLOUT -- bits [24,0] identify call/ret sig
|
||||
PSEUDO_HALT_111 // HALT -- bits [24, 0] identify halt code
|
||||
};
|
||||
|
||||
// bits [25, 23] of a DPImm are the secondary dispatch vector
|
||||
|
||||
static inline u_int32_t dispatchDPImm(u_int32_t instr)
|
||||
{
|
||||
return pickshift32(instr, 25, 23, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* the 8 possible values for bits [25,23] in a Data Processing Immediate
|
||||
* Instruction. Bits [28,25] are always 100_.
|
||||
*/
|
||||
|
||||
enum DispatchDPImm {
|
||||
DPIMM_PCADR_000, // PC-rel-addressing
|
||||
DPIMM_PCADR_001, // ditto
|
||||
DPIMM_ADDSUB_010, // Add/Subtract (immediate)
|
||||
DPIMM_ADDSUB_011, // ditto
|
||||
DPIMM_LOG_100, // Logical (immediate)
|
||||
DPIMM_MOV_101, // Move Wide (immediate)
|
||||
DPIMM_BITF_110, // Bitfield
|
||||
DPIMM_EXTR_111 // Extract
|
||||
};
|
||||
|
||||
// bits [29,28:26] of a LS are the secondary dispatch vector
|
||||
|
||||
static inline u_int32_t dispatchLS(u_int32_t instr)
|
||||
{
|
||||
return (pickshift32(instr, 29, 28, 1) |
|
||||
pickshift32(instr, 26, 26, 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* the 8 possible values for bits [29,28:26] in a Load/Store
|
||||
* Instruction. Bits [28,25] are always _1_0
|
||||
*/
|
||||
|
||||
enum DispatchLS {
|
||||
LS_EXCL_000, // Load/store exclusive (includes some unallocated)
|
||||
LS_ADVSIMD_001, // AdvSIMD load/store (various -- includes some unallocated)
|
||||
LS_LIT_010, // Load register literal (includes some unallocated)
|
||||
LS_LIT_011, // ditto
|
||||
LS_PAIR_100, // Load/store register pair (various)
|
||||
LS_PAIR_101, // ditto
|
||||
LS_OTHER_110, // other load/store formats
|
||||
LS_OTHER_111 // ditto
|
||||
};
|
||||
|
||||
// bits [28:24:21] of a DPReg are the secondary dispatch vector
|
||||
|
||||
static inline u_int32_t dispatchDPReg(u_int32_t instr)
|
||||
{
|
||||
return (pickshift32(instr, 28, 28, 2) |
|
||||
pickshift32(instr, 24, 24, 1) |
|
||||
pickshift32(instr, 21, 21, 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* the 8 possible values for bits [28:24:21] in a Data Processing
|
||||
* Register Instruction. Bits [28,25] are always _101
|
||||
*/
|
||||
|
||||
enum DispatchDPReg {
|
||||
DPREG_LOG_000, // Logical (shifted register)
|
||||
DPREG_LOG_001, // ditto
|
||||
DPREG_ADDSHF_010, // Add/subtract (shifted register)
|
||||
DPREG_ADDEXT_011, // Add/subtract (extended register)
|
||||
DPREG_ADDCOND_100, // Add/subtract (with carry) AND
|
||||
// Cond compare/select AND
|
||||
// Data Processing (1/2 source)
|
||||
DPREG_UNALLOC_101, // Unallocated
|
||||
DPREG_3SRC_110, // Data Processing (3 source)
|
||||
DPREG_3SRC_111 // Data Processing (3 source)
|
||||
};
|
||||
|
||||
// bits [31,29] of a BrExSys are the secondary dispatch vector
|
||||
|
||||
static inline u_int32_t dispatchBrExSys(u_int32_t instr)
|
||||
{
|
||||
return pickbits32(instr, 31, 29);
|
||||
}
|
||||
|
||||
/*
|
||||
* the 8 possible values for bits [31,29] in a Branch/Exception/System
|
||||
* Instruction. Bits [28,25] are always 101_
|
||||
*/
|
||||
|
||||
enum DispatchBr {
|
||||
BR_IMM_000, // Unconditional branch (immediate)
|
||||
BR_IMMCMP_001, // Compare & branch (immediate) AND
|
||||
// Test & branch (immediate)
|
||||
BR_IMMCOND_010, // Conditional branch (immediate) AND Unallocated
|
||||
BR_UNALLOC_011, // Unallocated
|
||||
BR_IMM_100, // Unconditional branch (immediate)
|
||||
BR_IMMCMP_101, // Compare & branch (immediate) AND
|
||||
// Test & branch (immediate)
|
||||
BR_REG_110, // Unconditional branch (register) AND System AND
|
||||
// Excn gen AND Unallocated
|
||||
BR_UNALLOC_111 // Unallocated
|
||||
};
|
||||
|
||||
/*
|
||||
* TODO still need to provide secondary decode and dispatch for
|
||||
* AdvSIMD Insructions with instr[28,25] = 0111 or 1111
|
||||
*/
|
||||
|
||||
#endif // ifndef DECODE_H
|
||||
30
hotspot/src/cpu/aarch64/vm/depChecker_aarch64.cpp
Normal file
30
hotspot/src/cpu/aarch64/vm/depChecker_aarch64.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "depChecker_aarch64.hpp"
|
||||
|
||||
// Nothing to do on aarch64
|
||||
31
hotspot/src/cpu/aarch64/vm/depChecker_aarch64.hpp
Normal file
31
hotspot/src/cpu/aarch64/vm/depChecker_aarch64.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_DEPCHECKER_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_DEPCHECKER_AARCH64_HPP
|
||||
|
||||
// Nothing to do on aarch64
|
||||
|
||||
#endif // CPU_AARCH64_VM_DEPCHECKER_AARCH64_HPP
|
||||
37
hotspot/src/cpu/aarch64/vm/disassembler_aarch64.hpp
Normal file
37
hotspot/src/cpu/aarch64/vm/disassembler_aarch64.hpp
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_DISASSEMBLER_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_DISASSEMBLER_AARCH64_HPP
|
||||
|
||||
static int pd_instruction_alignment() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char* pd_cpu_opts() {
|
||||
return "";
|
||||
}
|
||||
|
||||
#endif // CPU_AARCH64_VM_DISASSEMBLER_AARCH64_HPP
|
||||
832
hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp
Normal file
832
hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp
Normal file
@ -0,0 +1,832 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/markOop.hpp"
|
||||
#include "oops/method.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "prims/methodHandles.hpp"
|
||||
#include "runtime/frame.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/monitorChunk.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/signature.hpp"
|
||||
#include "runtime/stubCodeGenerator.hpp"
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
#include "vmreg_aarch64.inline.hpp"
|
||||
#ifdef COMPILER1
|
||||
#include "c1/c1_Runtime1.hpp"
|
||||
#include "runtime/vframeArray.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef ASSERT
|
||||
void RegisterMap::check_location_valid() {
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Profiling/safepoint support
|
||||
|
||||
bool frame::safe_for_sender(JavaThread *thread) {
|
||||
address sp = (address)_sp;
|
||||
address fp = (address)_fp;
|
||||
address unextended_sp = (address)_unextended_sp;
|
||||
|
||||
// consider stack guards when trying to determine "safe" stack pointers
|
||||
static size_t stack_guard_size = os::uses_stack_guard_pages() ? (StackYellowPages + StackRedPages) * os::vm_page_size() : 0;
|
||||
size_t usable_stack_size = thread->stack_size() - stack_guard_size;
|
||||
|
||||
// sp must be within the usable part of the stack (not in guards)
|
||||
bool sp_safe = (sp < thread->stack_base()) &&
|
||||
(sp >= thread->stack_base() - usable_stack_size);
|
||||
|
||||
|
||||
if (!sp_safe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// unextended sp must be within the stack and above or equal sp
|
||||
bool unextended_sp_safe = (unextended_sp < thread->stack_base()) &&
|
||||
(unextended_sp >= sp);
|
||||
|
||||
if (!unextended_sp_safe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// an fp must be within the stack and above (but not equal) sp
|
||||
// second evaluation on fp+ is added to handle situation where fp is -1
|
||||
bool fp_safe = (fp < thread->stack_base() && (fp > sp) && (((fp + (return_addr_offset * sizeof(void*))) < thread->stack_base())));
|
||||
|
||||
// We know sp/unextended_sp are safe only fp is questionable here
|
||||
|
||||
// If the current frame is known to the code cache then we can attempt to
|
||||
// to construct the sender and do some validation of it. This goes a long way
|
||||
// toward eliminating issues when we get in frame construction code
|
||||
|
||||
if (_cb != NULL ) {
|
||||
|
||||
// First check if frame is complete and tester is reliable
|
||||
// Unfortunately we can only check frame complete for runtime stubs and nmethod
|
||||
// other generic buffer blobs are more problematic so we just assume they are
|
||||
// ok. adapter blobs never have a frame complete and are never ok.
|
||||
|
||||
if (!_cb->is_frame_complete_at(_pc)) {
|
||||
if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Could just be some random pointer within the codeBlob
|
||||
if (!_cb->code_contains(_pc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Entry frame checks
|
||||
if (is_entry_frame()) {
|
||||
// an entry frame must have a valid fp.
|
||||
|
||||
if (!fp_safe) return false;
|
||||
|
||||
// Validate the JavaCallWrapper an entry frame must have
|
||||
|
||||
address jcw = (address)entry_frame_call_wrapper();
|
||||
|
||||
bool jcw_safe = (jcw < thread->stack_base()) && ( jcw > fp);
|
||||
|
||||
return jcw_safe;
|
||||
|
||||
}
|
||||
|
||||
intptr_t* sender_sp = NULL;
|
||||
address sender_pc = NULL;
|
||||
|
||||
if (is_interpreted_frame()) {
|
||||
// fp must be safe
|
||||
if (!fp_safe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sender_pc = (address) this->fp()[return_addr_offset];
|
||||
sender_sp = (intptr_t*) addr_at(sender_sp_offset);
|
||||
|
||||
} else {
|
||||
// must be some sort of compiled/runtime frame
|
||||
// fp does not have to be safe (although it could be check for c1?)
|
||||
|
||||
// check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc
|
||||
if (_cb->frame_size() <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sender_sp = _unextended_sp + _cb->frame_size();
|
||||
sender_pc = (address) *(sender_sp-1);
|
||||
}
|
||||
|
||||
|
||||
// If the potential sender is the interpreter then we can do some more checking
|
||||
if (Interpreter::contains(sender_pc)) {
|
||||
|
||||
// fp is always saved in a recognizable place in any code we generate. However
|
||||
// only if the sender is interpreted/call_stub (c1 too?) are we certain that the saved fp
|
||||
// is really a frame pointer.
|
||||
|
||||
intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset);
|
||||
bool saved_fp_safe = ((address)saved_fp < thread->stack_base()) && (saved_fp > sender_sp);
|
||||
|
||||
if (!saved_fp_safe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// construct the potential sender
|
||||
|
||||
frame sender(sender_sp, saved_fp, sender_pc);
|
||||
|
||||
return sender.is_interpreted_frame_valid(thread);
|
||||
|
||||
}
|
||||
|
||||
// We must always be able to find a recognizable pc
|
||||
CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc);
|
||||
if (sender_pc == NULL || sender_blob == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Could be a zombie method
|
||||
if (sender_blob->is_zombie() || sender_blob->is_unloaded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Could just be some random pointer within the codeBlob
|
||||
if (!sender_blob->code_contains(sender_pc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We should never be able to see an adapter if the current frame is something from code cache
|
||||
if (sender_blob->is_adapter_blob()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Could be the call_stub
|
||||
if (StubRoutines::returns_to_call_stub(sender_pc)) {
|
||||
intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset);
|
||||
bool saved_fp_safe = ((address)saved_fp < thread->stack_base()) && (saved_fp > sender_sp);
|
||||
|
||||
if (!saved_fp_safe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// construct the potential sender
|
||||
|
||||
frame sender(sender_sp, saved_fp, sender_pc);
|
||||
|
||||
// Validate the JavaCallWrapper an entry frame must have
|
||||
address jcw = (address)sender.entry_frame_call_wrapper();
|
||||
|
||||
bool jcw_safe = (jcw < thread->stack_base()) && ( jcw > (address)sender.fp());
|
||||
|
||||
return jcw_safe;
|
||||
}
|
||||
|
||||
if (sender_blob->is_nmethod()) {
|
||||
nmethod* nm = sender_blob->as_nmethod_or_null();
|
||||
if (nm != NULL) {
|
||||
if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the frame size is 0 something (or less) is bad because every nmethod has a non-zero frame size
|
||||
// because the return address counts against the callee's frame.
|
||||
|
||||
if (sender_blob->frame_size() <= 0) {
|
||||
assert(!sender_blob->is_nmethod(), "should count return address at least");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We should never be able to see anything here except an nmethod. If something in the
|
||||
// code cache (current frame) is called by an entity within the code cache that entity
|
||||
// should not be anything but the call stub (already covered), the interpreter (already covered)
|
||||
// or an nmethod.
|
||||
|
||||
if (!sender_blob->is_nmethod()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Could put some more validation for the potential non-interpreted sender
|
||||
// frame we'd create by calling sender if I could think of any. Wait for next crash in forte...
|
||||
|
||||
// One idea is seeing if the sender_pc we have is one that we'd expect to call to current cb
|
||||
|
||||
// We've validated the potential sender that would be created
|
||||
return true;
|
||||
}
|
||||
|
||||
// Must be native-compiled frame. Since sender will try and use fp to find
|
||||
// linkages it must be safe
|
||||
|
||||
if (!fp_safe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Will the pc we fetch be non-zero (which we'll find at the oldest frame)
|
||||
|
||||
if ( (address) this->fp()[return_addr_offset] == NULL) return false;
|
||||
|
||||
|
||||
// could try and do some more potential verification of native frame if we could think of some...
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void frame::patch_pc(Thread* thread, address pc) {
|
||||
address* pc_addr = &(((address*) sp())[-1]);
|
||||
if (TracePcPatching) {
|
||||
tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]",
|
||||
p2i(pc_addr), p2i(*pc_addr), p2i(pc));
|
||||
}
|
||||
// Either the return address is the original one or we are going to
|
||||
// patch in the same address that's already there.
|
||||
assert(_pc == *pc_addr || pc == *pc_addr, "must be");
|
||||
*pc_addr = pc;
|
||||
_cb = CodeCache::find_blob(pc);
|
||||
address original_pc = nmethod::get_deopt_original_pc(this);
|
||||
if (original_pc != NULL) {
|
||||
assert(original_pc == _pc, "expected original PC to be stored before patching");
|
||||
_deopt_state = is_deoptimized;
|
||||
// leave _pc as is
|
||||
} else {
|
||||
_deopt_state = not_deoptimized;
|
||||
_pc = pc;
|
||||
}
|
||||
}
|
||||
|
||||
bool frame::is_interpreted_frame() const {
|
||||
return Interpreter::contains(pc());
|
||||
}
|
||||
|
||||
int frame::frame_size(RegisterMap* map) const {
|
||||
frame sender = this->sender(map);
|
||||
return sender.sp() - sp();
|
||||
}
|
||||
|
||||
intptr_t* frame::entry_frame_argument_at(int offset) const {
|
||||
// convert offset to index to deal with tsi
|
||||
int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize);
|
||||
// Entry frame's arguments are always in relation to unextended_sp()
|
||||
return &unextended_sp()[index];
|
||||
}
|
||||
|
||||
// sender_sp
|
||||
#ifdef CC_INTERP
|
||||
intptr_t* frame::interpreter_frame_sender_sp() const {
|
||||
assert(is_interpreted_frame(), "interpreted frame expected");
|
||||
// QQQ why does this specialize method exist if frame::sender_sp() does same thing?
|
||||
// seems odd and if we always know interpreted vs. non then sender_sp() is really
|
||||
// doing too much work.
|
||||
return get_interpreterState()->sender_sp();
|
||||
}
|
||||
|
||||
// monitor elements
|
||||
|
||||
BasicObjectLock* frame::interpreter_frame_monitor_begin() const {
|
||||
return get_interpreterState()->monitor_base();
|
||||
}
|
||||
|
||||
BasicObjectLock* frame::interpreter_frame_monitor_end() const {
|
||||
return (BasicObjectLock*) get_interpreterState()->stack_base();
|
||||
}
|
||||
|
||||
#else // CC_INTERP
|
||||
|
||||
intptr_t* frame::interpreter_frame_sender_sp() const {
|
||||
assert(is_interpreted_frame(), "interpreted frame expected");
|
||||
return (intptr_t*) at(interpreter_frame_sender_sp_offset);
|
||||
}
|
||||
|
||||
void frame::set_interpreter_frame_sender_sp(intptr_t* sender_sp) {
|
||||
assert(is_interpreted_frame(), "interpreted frame expected");
|
||||
ptr_at_put(interpreter_frame_sender_sp_offset, (intptr_t) sender_sp);
|
||||
}
|
||||
|
||||
|
||||
// monitor elements
|
||||
|
||||
BasicObjectLock* frame::interpreter_frame_monitor_begin() const {
|
||||
return (BasicObjectLock*) addr_at(interpreter_frame_monitor_block_bottom_offset);
|
||||
}
|
||||
|
||||
BasicObjectLock* frame::interpreter_frame_monitor_end() const {
|
||||
BasicObjectLock* result = (BasicObjectLock*) *addr_at(interpreter_frame_monitor_block_top_offset);
|
||||
// make sure the pointer points inside the frame
|
||||
assert(sp() <= (intptr_t*) result, "monitor end should be above the stack pointer");
|
||||
assert((intptr_t*) result < fp(), "monitor end should be strictly below the frame pointer");
|
||||
return result;
|
||||
}
|
||||
|
||||
void frame::interpreter_frame_set_monitor_end(BasicObjectLock* value) {
|
||||
*((BasicObjectLock**)addr_at(interpreter_frame_monitor_block_top_offset)) = value;
|
||||
}
|
||||
|
||||
// Used by template based interpreter deoptimization
|
||||
void frame::interpreter_frame_set_last_sp(intptr_t* sp) {
|
||||
*((intptr_t**)addr_at(interpreter_frame_last_sp_offset)) = sp;
|
||||
}
|
||||
#endif // CC_INTERP
|
||||
|
||||
frame frame::sender_for_entry_frame(RegisterMap* map) const {
|
||||
assert(map != NULL, "map must be set");
|
||||
// Java frame called from C; skip all C frames and return top C
|
||||
// frame of that chunk as the sender
|
||||
JavaFrameAnchor* jfa = entry_frame_call_wrapper()->anchor();
|
||||
assert(!entry_frame_is_first(), "next Java fp must be non zero");
|
||||
assert(jfa->last_Java_sp() > sp(), "must be above this frame on stack");
|
||||
map->clear();
|
||||
assert(map->include_argument_oops(), "should be set by clear");
|
||||
if (jfa->last_Java_pc() != NULL ) {
|
||||
frame fr(jfa->last_Java_sp(), jfa->last_Java_fp(), jfa->last_Java_pc());
|
||||
return fr;
|
||||
}
|
||||
frame fr(jfa->last_Java_sp(), jfa->last_Java_fp());
|
||||
return fr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// frame::verify_deopt_original_pc
|
||||
//
|
||||
// Verifies the calculated original PC of a deoptimization PC for the
|
||||
// given unextended SP. The unextended SP might also be the saved SP
|
||||
// for MethodHandle call sites.
|
||||
#ifdef ASSERT
|
||||
void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) {
|
||||
frame fr;
|
||||
|
||||
// This is ugly but it's better than to change {get,set}_original_pc
|
||||
// to take an SP value as argument. And it's only a debugging
|
||||
// method anyway.
|
||||
fr._unextended_sp = unextended_sp;
|
||||
|
||||
address original_pc = nm->get_original_pc(&fr);
|
||||
assert(nm->insts_contains(original_pc), "original PC must be in nmethod");
|
||||
assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be");
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// frame::adjust_unextended_sp
|
||||
void frame::adjust_unextended_sp() {
|
||||
// If we are returning to a compiled MethodHandle call site, the
|
||||
// saved_fp will in fact be a saved value of the unextended SP. The
|
||||
// simplest way to tell whether we are returning to such a call site
|
||||
// is as follows:
|
||||
|
||||
nmethod* sender_nm = (_cb == NULL) ? NULL : _cb->as_nmethod_or_null();
|
||||
if (sender_nm != NULL) {
|
||||
// If the sender PC is a deoptimization point, get the original
|
||||
// PC. For MethodHandle call site the unextended_sp is stored in
|
||||
// saved_fp.
|
||||
if (sender_nm->is_deopt_mh_entry(_pc)) {
|
||||
DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, _fp));
|
||||
_unextended_sp = _fp;
|
||||
}
|
||||
else if (sender_nm->is_deopt_entry(_pc)) {
|
||||
DEBUG_ONLY(verify_deopt_original_pc(sender_nm, _unextended_sp));
|
||||
}
|
||||
else if (sender_nm->is_method_handle_return(_pc)) {
|
||||
_unextended_sp = _fp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// frame::update_map_with_saved_link
|
||||
void frame::update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr) {
|
||||
// The interpreter and compiler(s) always save fp in a known
|
||||
// location on entry. We must record where that location is
|
||||
// so that if fp was live on callout from c2 we can find
|
||||
// the saved copy no matter what it called.
|
||||
|
||||
// Since the interpreter always saves fp if we record where it is then
|
||||
// we don't have to always save fp on entry and exit to c2 compiled
|
||||
// code, on entry will be enough.
|
||||
map->set_location(rfp->as_VMReg(), (address) link_addr);
|
||||
// this is weird "H" ought to be at a higher address however the
|
||||
// oopMaps seems to have the "H" regs at the same address and the
|
||||
// vanilla register.
|
||||
// XXXX make this go away
|
||||
if (true) {
|
||||
map->set_location(rfp->as_VMReg()->next(), (address) link_addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// frame::sender_for_interpreter_frame
|
||||
frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
|
||||
// SP is the raw SP from the sender after adapter or interpreter
|
||||
// extension.
|
||||
intptr_t* sender_sp = this->sender_sp();
|
||||
|
||||
// This is the sp before any possible extension (adapter/locals).
|
||||
intptr_t* unextended_sp = interpreter_frame_sender_sp();
|
||||
|
||||
#ifdef COMPILER2
|
||||
if (map->update_map()) {
|
||||
update_map_with_saved_link(map, (intptr_t**) addr_at(link_offset));
|
||||
}
|
||||
#endif // COMPILER2
|
||||
|
||||
return frame(sender_sp, unextended_sp, link(), sender_pc());
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// frame::sender_for_compiled_frame
|
||||
frame frame::sender_for_compiled_frame(RegisterMap* map) const {
|
||||
// we cannot rely upon the last fp having been saved to the thread
|
||||
// in C2 code but it will have been pushed onto the stack. so we
|
||||
// have to find it relative to the unextended sp
|
||||
|
||||
assert(_cb->frame_size() >= 0, "must have non-zero frame size");
|
||||
intptr_t* l_sender_sp = unextended_sp() + _cb->frame_size();
|
||||
intptr_t* unextended_sp = l_sender_sp;
|
||||
|
||||
// the return_address is always the word on the stack
|
||||
address sender_pc = (address) *(l_sender_sp-1);
|
||||
|
||||
intptr_t** saved_fp_addr = (intptr_t**) (l_sender_sp - frame::sender_sp_offset);
|
||||
|
||||
// assert (sender_sp() == l_sender_sp, "should be");
|
||||
// assert (*saved_fp_addr == link(), "should be");
|
||||
|
||||
if (map->update_map()) {
|
||||
// Tell GC to use argument oopmaps for some runtime stubs that need it.
|
||||
// For C1, the runtime stub might not have oop maps, so set this flag
|
||||
// outside of update_register_map.
|
||||
map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread()));
|
||||
if (_cb->oop_maps() != NULL) {
|
||||
OopMapSet::update_register_map(this, map);
|
||||
}
|
||||
|
||||
// Since the prolog does the save and restore of FP there is no
|
||||
// oopmap for it so we must fill in its location as if there was
|
||||
// an oopmap entry since if our caller was compiled code there
|
||||
// could be live jvm state in it.
|
||||
update_map_with_saved_link(map, saved_fp_addr);
|
||||
}
|
||||
|
||||
return frame(l_sender_sp, unextended_sp, *saved_fp_addr, sender_pc);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// frame::sender
|
||||
frame frame::sender(RegisterMap* map) const {
|
||||
// Default is we done have to follow them. The sender_for_xxx will
|
||||
// update it accordingly
|
||||
map->set_include_argument_oops(false);
|
||||
|
||||
if (is_entry_frame())
|
||||
return sender_for_entry_frame(map);
|
||||
if (is_interpreted_frame())
|
||||
return sender_for_interpreter_frame(map);
|
||||
assert(_cb == CodeCache::find_blob(pc()),"Must be the same");
|
||||
|
||||
// This test looks odd: why is it not is_compiled_frame() ? That's
|
||||
// because stubs also have OOP maps.
|
||||
if (_cb != NULL) {
|
||||
return sender_for_compiled_frame(map);
|
||||
}
|
||||
|
||||
// Must be native-compiled frame, i.e. the marshaling code for native
|
||||
// methods that exists in the core system.
|
||||
return frame(sender_sp(), link(), sender_pc());
|
||||
}
|
||||
|
||||
bool frame::interpreter_frame_equals_unpacked_fp(intptr_t* fp) {
|
||||
assert(is_interpreted_frame(), "must be interpreter frame");
|
||||
Method* method = interpreter_frame_method();
|
||||
// When unpacking an optimized frame the frame pointer is
|
||||
// adjusted with:
|
||||
int diff = (method->max_locals() - method->size_of_parameters()) *
|
||||
Interpreter::stackElementWords;
|
||||
return _fp == (fp - diff);
|
||||
}
|
||||
|
||||
bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
|
||||
// QQQ
|
||||
#ifdef CC_INTERP
|
||||
#else
|
||||
assert(is_interpreted_frame(), "Not an interpreted frame");
|
||||
// These are reasonable sanity checks
|
||||
if (fp() == 0 || (intptr_t(fp()) & (wordSize-1)) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (sp() == 0 || (intptr_t(sp()) & (wordSize-1)) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (fp() + interpreter_frame_initial_sp_offset < sp()) {
|
||||
return false;
|
||||
}
|
||||
// These are hacks to keep us out of trouble.
|
||||
// The problem with these is that they mask other problems
|
||||
if (fp() <= sp()) { // this attempts to deal with unsigned comparison above
|
||||
return false;
|
||||
}
|
||||
|
||||
// do some validation of frame elements
|
||||
|
||||
// first the method
|
||||
|
||||
Method* m = *interpreter_frame_method_addr();
|
||||
|
||||
// validate the method we'd find in this potential sender
|
||||
if (!m->is_valid_method()) return false;
|
||||
|
||||
// stack frames shouldn't be much larger than max_stack elements
|
||||
|
||||
if (fp() - sp() > 1024 + m->max_stack()*Interpreter::stackElementSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate bci/bcx
|
||||
|
||||
address bcp = interpreter_frame_bcp();
|
||||
if (m->validate_bci_from_bcp(bcp) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate constantPoolCache*
|
||||
ConstantPoolCache* cp = *interpreter_frame_cache_addr();
|
||||
if (cp == NULL || !cp->is_metaspace_object()) return false;
|
||||
|
||||
// validate locals
|
||||
|
||||
address locals = (address) *interpreter_frame_locals_addr();
|
||||
|
||||
if (locals > thread->stack_base() || locals < (address) fp()) return false;
|
||||
|
||||
// We'd have to be pretty unlucky to be mislead at this point
|
||||
|
||||
#endif // CC_INTERP
|
||||
return true;
|
||||
}
|
||||
|
||||
BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) {
|
||||
#ifdef CC_INTERP
|
||||
// Needed for JVMTI. The result should always be in the
|
||||
// interpreterState object
|
||||
interpreterState istate = get_interpreterState();
|
||||
#endif // CC_INTERP
|
||||
assert(is_interpreted_frame(), "interpreted frame expected");
|
||||
Method* method = interpreter_frame_method();
|
||||
BasicType type = method->result_type();
|
||||
|
||||
intptr_t* tos_addr;
|
||||
if (method->is_native()) {
|
||||
// TODO : ensure AARCH64 does the same as Intel here i.e. push v0 then r0
|
||||
// Prior to calling into the runtime to report the method_exit the possible
|
||||
// return value is pushed to the native stack. If the result is a jfloat/jdouble
|
||||
// then ST0 is saved before EAX/EDX. See the note in generate_native_result
|
||||
tos_addr = (intptr_t*)sp();
|
||||
if (type == T_FLOAT || type == T_DOUBLE) {
|
||||
// This is times two because we do a push(ltos) after pushing XMM0
|
||||
// and that takes two interpreter stack slots.
|
||||
tos_addr += 2 * Interpreter::stackElementWords;
|
||||
}
|
||||
} else {
|
||||
tos_addr = (intptr_t*)interpreter_frame_tos_address();
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case T_OBJECT :
|
||||
case T_ARRAY : {
|
||||
oop obj;
|
||||
if (method->is_native()) {
|
||||
#ifdef CC_INTERP
|
||||
obj = istate->_oop_temp;
|
||||
#else
|
||||
obj = cast_to_oop(at(interpreter_frame_oop_temp_offset));
|
||||
#endif // CC_INTERP
|
||||
} else {
|
||||
oop* obj_p = (oop*)tos_addr;
|
||||
obj = (obj_p == NULL) ? (oop)NULL : *obj_p;
|
||||
}
|
||||
assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check");
|
||||
*oop_result = obj;
|
||||
break;
|
||||
}
|
||||
case T_BOOLEAN : value_result->z = *(jboolean*)tos_addr; break;
|
||||
case T_BYTE : value_result->b = *(jbyte*)tos_addr; break;
|
||||
case T_CHAR : value_result->c = *(jchar*)tos_addr; break;
|
||||
case T_SHORT : value_result->s = *(jshort*)tos_addr; break;
|
||||
case T_INT : value_result->i = *(jint*)tos_addr; break;
|
||||
case T_LONG : value_result->j = *(jlong*)tos_addr; break;
|
||||
case T_FLOAT : {
|
||||
value_result->f = *(jfloat*)tos_addr;
|
||||
break;
|
||||
}
|
||||
case T_DOUBLE : value_result->d = *(jdouble*)tos_addr; break;
|
||||
case T_VOID : /* Nothing to do */ break;
|
||||
default : ShouldNotReachHere();
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
|
||||
int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize);
|
||||
return &interpreter_frame_tos_address()[index];
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
#define DESCRIBE_FP_OFFSET(name) \
|
||||
values.describe(frame_no, fp() + frame::name##_offset, #name)
|
||||
|
||||
void frame::describe_pd(FrameValues& values, int frame_no) {
|
||||
if (is_interpreted_frame()) {
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_sender_sp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_last_sp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_method);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_mdp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_cache);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_locals);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_bcp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
intptr_t *frame::initial_deoptimization_info() {
|
||||
// Not used on aarch64, but we must return something.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
intptr_t* frame::real_fp() const {
|
||||
if (_cb != NULL) {
|
||||
// use the frame size if valid
|
||||
int size = _cb->frame_size();
|
||||
if (size > 0) {
|
||||
return unextended_sp() + size;
|
||||
}
|
||||
}
|
||||
// else rely on fp()
|
||||
assert(! is_compiled_frame(), "unknown compiled frame size");
|
||||
return fp();
|
||||
}
|
||||
|
||||
#undef DESCRIBE_FP_OFFSET
|
||||
|
||||
#define DESCRIBE_FP_OFFSET(name) \
|
||||
{ \
|
||||
unsigned long *p = (unsigned long *)fp; \
|
||||
printf("0x%016lx 0x%016lx %s\n", (unsigned long)(p + frame::name##_offset), \
|
||||
p[frame::name##_offset], #name); \
|
||||
}
|
||||
|
||||
static __thread unsigned long nextfp;
|
||||
static __thread unsigned long nextpc;
|
||||
static __thread unsigned long nextsp;
|
||||
static __thread RegisterMap *reg_map;
|
||||
|
||||
static void printbc(Method *m, intptr_t bcx) {
|
||||
const char *name;
|
||||
char buf[16];
|
||||
if (m->validate_bci_from_bcp((address)bcx) < 0
|
||||
|| !m->contains((address)bcx)) {
|
||||
name = "???";
|
||||
snprintf(buf, sizeof buf, "(bad)");
|
||||
} else {
|
||||
int bci = m->bci_from((address)bcx);
|
||||
snprintf(buf, sizeof buf, "%d", bci);
|
||||
name = Bytecodes::name(m->code_at(bci));
|
||||
}
|
||||
ResourceMark rm;
|
||||
printf("%s : %s ==> %s\n", m->name_and_sig_as_C_string(), buf, name);
|
||||
}
|
||||
|
||||
void internal_pf(unsigned long sp, unsigned long fp, unsigned long pc, unsigned long bcx) {
|
||||
if (! fp)
|
||||
return;
|
||||
|
||||
DESCRIBE_FP_OFFSET(return_addr);
|
||||
DESCRIBE_FP_OFFSET(link);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_sender_sp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_last_sp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_method);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_mdp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_cache);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_locals);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_bcp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp);
|
||||
unsigned long *p = (unsigned long *)fp;
|
||||
|
||||
// We want to see all frames, native and Java. For compiled and
|
||||
// interpreted frames we have special information that allows us to
|
||||
// unwind them; for everything else we assume that the native frame
|
||||
// pointer chain is intact.
|
||||
frame this_frame((intptr_t*)sp, (intptr_t*)fp, (address)pc);
|
||||
if (this_frame.is_compiled_frame() ||
|
||||
this_frame.is_interpreted_frame()) {
|
||||
frame sender = this_frame.sender(reg_map);
|
||||
nextfp = (unsigned long)sender.fp();
|
||||
nextpc = (unsigned long)sender.pc();
|
||||
nextsp = (unsigned long)sender.unextended_sp();
|
||||
} else {
|
||||
nextfp = p[frame::link_offset];
|
||||
nextpc = p[frame::return_addr_offset];
|
||||
nextsp = (unsigned long)&p[frame::sender_sp_offset];
|
||||
}
|
||||
|
||||
if (bcx == -1ul)
|
||||
bcx = p[frame::interpreter_frame_bcp_offset];
|
||||
|
||||
if (Interpreter::contains((address)pc)) {
|
||||
Method* m = (Method*)p[frame::interpreter_frame_method_offset];
|
||||
if(m && m->is_method()) {
|
||||
printbc(m, bcx);
|
||||
} else
|
||||
printf("not a Method\n");
|
||||
} else {
|
||||
CodeBlob *cb = CodeCache::find_blob((address)pc);
|
||||
if (cb != NULL) {
|
||||
if (cb->is_nmethod()) {
|
||||
ResourceMark rm;
|
||||
nmethod* nm = (nmethod*)cb;
|
||||
printf("nmethod %s\n", nm->method()->name_and_sig_as_C_string());
|
||||
} else if (cb->name()) {
|
||||
printf("CodeBlob %s\n", cb->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void npf() {
|
||||
CodeBlob *cb = CodeCache::find_blob((address)nextpc);
|
||||
// C2 does not always chain the frame pointers when it can, instead
|
||||
// preferring to use fixed offsets from SP, so a simple leave() does
|
||||
// not work. Instead, it adds the frame size to SP then pops FP and
|
||||
// LR. We have to do the same thing to get a good call chain.
|
||||
if (cb && cb->frame_size())
|
||||
nextfp = nextsp + wordSize * (cb->frame_size() - 2);
|
||||
internal_pf (nextsp, nextfp, nextpc, -1);
|
||||
}
|
||||
|
||||
extern "C" void pf(unsigned long sp, unsigned long fp, unsigned long pc,
|
||||
unsigned long bcx, unsigned long thread) {
|
||||
RegisterMap map((JavaThread*)thread, false);
|
||||
if (!reg_map) {
|
||||
reg_map = (RegisterMap*)os::malloc(sizeof map, mtNone);
|
||||
}
|
||||
memcpy(reg_map, &map, sizeof map);
|
||||
{
|
||||
CodeBlob *cb = CodeCache::find_blob((address)pc);
|
||||
if (cb && cb->frame_size())
|
||||
fp = sp + wordSize * (cb->frame_size() - 2);
|
||||
}
|
||||
internal_pf(sp, fp, pc, bcx);
|
||||
}
|
||||
|
||||
// support for printing out where we are in a Java method
|
||||
// needs to be passed current fp and bcp register values
|
||||
// prints method name, bc index and bytecode name
|
||||
extern "C" void pm(unsigned long fp, unsigned long bcx) {
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_method);
|
||||
unsigned long *p = (unsigned long *)fp;
|
||||
Method* m = (Method*)p[frame::interpreter_frame_method_offset];
|
||||
printbc(m, bcx);
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// This is a generic constructor which is only used by pns() in debug.cpp.
|
||||
frame::frame(void* sp, void* fp, void* pc) {
|
||||
init((intptr_t*)sp, (intptr_t*)fp, (address)pc);
|
||||
}
|
||||
#endif
|
||||
216
hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp
Normal file
216
hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_FRAME_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_FRAME_AARCH64_HPP
|
||||
|
||||
#include "runtime/synchronizer.hpp"
|
||||
#include "utilities/top.hpp"
|
||||
|
||||
// A frame represents a physical stack frame (an activation). Frames can be
|
||||
// C or Java frames, and the Java frames can be interpreted or compiled.
|
||||
// In contrast, vframes represent source-level activations, so that one physical frame
|
||||
// can correspond to multiple source level frames because of inlining.
|
||||
// A frame is comprised of {pc, fp, sp}
|
||||
// ------------------------------ Asm interpreter ----------------------------------------
|
||||
// Layout of asm interpreter frame:
|
||||
// [expression stack ] * <- sp
|
||||
|
||||
// [monitors[0] ] \
|
||||
// ... | monitor block size = k
|
||||
// [monitors[k-1] ] /
|
||||
// [frame initial esp ] ( == &monitors[0], initially here) initial_sp_offset
|
||||
// [byte code index/pointr] = bcx() bcx_offset
|
||||
|
||||
// [pointer to locals ] = locals() locals_offset
|
||||
// [constant pool cache ] = cache() cache_offset
|
||||
|
||||
// [methodData ] = mdp() mdx_offset
|
||||
// [methodOop ] = method() method_offset
|
||||
|
||||
// [last esp ] = last_sp() last_sp_offset
|
||||
// [old stack pointer ] (sender_sp) sender_sp_offset
|
||||
|
||||
// [old frame pointer ] <- fp = link()
|
||||
// [return pc ]
|
||||
|
||||
// [last sp ]
|
||||
// [oop temp ] (only for native calls)
|
||||
|
||||
// [locals and parameters ]
|
||||
// <- sender sp
|
||||
// ------------------------------ Asm interpreter ----------------------------------------
|
||||
|
||||
// ------------------------------ C++ interpreter ----------------------------------------
|
||||
//
|
||||
// Layout of C++ interpreter frame: (While executing in BytecodeInterpreter::run)
|
||||
//
|
||||
// <- SP (current esp/rsp)
|
||||
// [local variables ] BytecodeInterpreter::run local variables
|
||||
// ... BytecodeInterpreter::run local variables
|
||||
// [local variables ] BytecodeInterpreter::run local variables
|
||||
// [old frame pointer ] fp [ BytecodeInterpreter::run's ebp/rbp ]
|
||||
// [return pc ] (return to frame manager)
|
||||
// [interpreter_state* ] (arg to BytecodeInterpreter::run) --------------
|
||||
// [expression stack ] <- last_Java_sp |
|
||||
// [... ] * <- interpreter_state.stack |
|
||||
// [expression stack ] * <- interpreter_state.stack_base |
|
||||
// [monitors ] \ |
|
||||
// ... | monitor block size |
|
||||
// [monitors ] / <- interpreter_state.monitor_base |
|
||||
// [struct interpretState ] <-----------------------------------------|
|
||||
// [return pc ] (return to callee of frame manager [1]
|
||||
// [locals and parameters ]
|
||||
// <- sender sp
|
||||
|
||||
// [1] When the c++ interpreter calls a new method it returns to the frame
|
||||
// manager which allocates a new frame on the stack. In that case there
|
||||
// is no real callee of this newly allocated frame. The frame manager is
|
||||
// aware of the additional frame(s) and will pop them as nested calls
|
||||
// complete. Howevers tTo make it look good in the debugger the frame
|
||||
// manager actually installs a dummy pc pointing to RecursiveInterpreterActivation
|
||||
// with a fake interpreter_state* parameter to make it easy to debug
|
||||
// nested calls.
|
||||
|
||||
// Note that contrary to the layout for the assembly interpreter the
|
||||
// expression stack allocated for the C++ interpreter is full sized.
|
||||
// However this is not as bad as it seems as the interpreter frame_manager
|
||||
// will truncate the unused space on succesive method calls.
|
||||
//
|
||||
// ------------------------------ C++ interpreter ----------------------------------------
|
||||
|
||||
public:
|
||||
enum {
|
||||
pc_return_offset = 0,
|
||||
// All frames
|
||||
link_offset = 0,
|
||||
return_addr_offset = 1,
|
||||
sender_sp_offset = 2,
|
||||
|
||||
#ifndef CC_INTERP
|
||||
|
||||
// Interpreter frames
|
||||
interpreter_frame_oop_temp_offset = 3, // for native calls only
|
||||
|
||||
interpreter_frame_sender_sp_offset = -1,
|
||||
// outgoing sp before a call to an invoked method
|
||||
interpreter_frame_last_sp_offset = interpreter_frame_sender_sp_offset - 1,
|
||||
interpreter_frame_method_offset = interpreter_frame_last_sp_offset - 1,
|
||||
interpreter_frame_mdp_offset = interpreter_frame_method_offset - 1,
|
||||
interpreter_frame_cache_offset = interpreter_frame_mdp_offset - 1,
|
||||
interpreter_frame_locals_offset = interpreter_frame_cache_offset - 1,
|
||||
interpreter_frame_bcp_offset = interpreter_frame_locals_offset - 1,
|
||||
interpreter_frame_initial_sp_offset = interpreter_frame_bcp_offset - 1,
|
||||
|
||||
interpreter_frame_monitor_block_top_offset = interpreter_frame_initial_sp_offset,
|
||||
interpreter_frame_monitor_block_bottom_offset = interpreter_frame_initial_sp_offset,
|
||||
|
||||
#endif // CC_INTERP
|
||||
|
||||
// Entry frames
|
||||
// n.b. these values are determined by the layout defined in
|
||||
// stubGenerator for the Java call stub
|
||||
entry_frame_after_call_words = 27,
|
||||
entry_frame_call_wrapper_offset = -8,
|
||||
|
||||
// we don't need a save area
|
||||
arg_reg_save_area_bytes = 0,
|
||||
|
||||
// TODO - check that this is still correct
|
||||
// Native frames
|
||||
|
||||
native_frame_initial_param_offset = 2
|
||||
|
||||
};
|
||||
|
||||
intptr_t ptr_at(int offset) const {
|
||||
return *ptr_at_addr(offset);
|
||||
}
|
||||
|
||||
void ptr_at_put(int offset, intptr_t value) {
|
||||
*ptr_at_addr(offset) = value;
|
||||
}
|
||||
|
||||
private:
|
||||
// an additional field beyond _sp and _pc:
|
||||
intptr_t* _fp; // frame pointer
|
||||
// The interpreter and adapters will extend the frame of the caller.
|
||||
// Since oopMaps are based on the sp of the caller before extension
|
||||
// we need to know that value. However in order to compute the address
|
||||
// of the return address we need the real "raw" sp. Since sparc already
|
||||
// uses sp() to mean "raw" sp and unextended_sp() to mean the caller's
|
||||
// original sp we use that convention.
|
||||
|
||||
intptr_t* _unextended_sp;
|
||||
void adjust_unextended_sp();
|
||||
|
||||
intptr_t* ptr_at_addr(int offset) const {
|
||||
return (intptr_t*) addr_at(offset);
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
// Used in frame::sender_for_{interpreter,compiled}_frame
|
||||
static void verify_deopt_original_pc( nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false);
|
||||
static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) {
|
||||
verify_deopt_original_pc(nm, unextended_sp, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
|
||||
frame(intptr_t* sp, intptr_t* fp, address pc);
|
||||
|
||||
frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc);
|
||||
|
||||
frame(intptr_t* sp, intptr_t* fp);
|
||||
|
||||
void init(intptr_t* sp, intptr_t* fp, address pc);
|
||||
|
||||
// accessors for the instance variables
|
||||
// Note: not necessarily the real 'frame pointer' (see real_fp)
|
||||
intptr_t* fp() const { return _fp; }
|
||||
|
||||
inline address* sender_pc_addr() const;
|
||||
|
||||
// return address of param, zero origin index.
|
||||
inline address* native_param_addr(int idx) const;
|
||||
|
||||
// expression stack tos if we are nested in a java call
|
||||
intptr_t* interpreter_frame_last_sp() const;
|
||||
|
||||
// helper to update a map with callee-saved RBP
|
||||
static void update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr);
|
||||
|
||||
#ifndef CC_INTERP
|
||||
// deoptimization support
|
||||
void interpreter_frame_set_last_sp(intptr_t* sp);
|
||||
#endif // CC_INTERP
|
||||
|
||||
#ifdef CC_INTERP
|
||||
inline interpreterState get_interpreterState() const;
|
||||
#endif // CC_INTERP
|
||||
|
||||
#endif // CPU_AARCH64_VM_FRAME_AARCH64_HPP
|
||||
348
hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp
Normal file
348
hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp
Normal file
@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_FRAME_AARCH64_INLINE_HPP
|
||||
#define CPU_AARCH64_VM_FRAME_AARCH64_INLINE_HPP
|
||||
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/vmreg.inline.hpp"
|
||||
|
||||
// Inline functions for AArch64 frames:
|
||||
|
||||
// Constructors:
|
||||
|
||||
inline frame::frame() {
|
||||
_pc = NULL;
|
||||
_sp = NULL;
|
||||
_unextended_sp = NULL;
|
||||
_fp = NULL;
|
||||
_cb = NULL;
|
||||
_deopt_state = unknown;
|
||||
}
|
||||
|
||||
static int spin;
|
||||
|
||||
inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
|
||||
intptr_t a = intptr_t(sp);
|
||||
intptr_t b = intptr_t(fp);
|
||||
#ifndef PRODUCT
|
||||
if (fp)
|
||||
if (sp > fp || (fp - sp > 0x100000))
|
||||
for(;;)
|
||||
asm("nop");
|
||||
#endif
|
||||
_sp = sp;
|
||||
_unextended_sp = sp;
|
||||
_fp = fp;
|
||||
_pc = pc;
|
||||
assert(pc != NULL, "no pc?");
|
||||
_cb = CodeCache::find_blob(pc);
|
||||
adjust_unextended_sp();
|
||||
|
||||
address original_pc = nmethod::get_deopt_original_pc(this);
|
||||
if (original_pc != NULL) {
|
||||
_pc = original_pc;
|
||||
_deopt_state = is_deoptimized;
|
||||
} else {
|
||||
_deopt_state = not_deoptimized;
|
||||
}
|
||||
}
|
||||
|
||||
inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
|
||||
init(sp, fp, pc);
|
||||
}
|
||||
|
||||
inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
|
||||
intptr_t a = intptr_t(sp);
|
||||
intptr_t b = intptr_t(fp);
|
||||
#ifndef PRODUCT
|
||||
if (fp)
|
||||
if (sp > fp || (fp - sp > 0x100000))
|
||||
for(;;)
|
||||
asm("nop");
|
||||
#endif
|
||||
_sp = sp;
|
||||
_unextended_sp = unextended_sp;
|
||||
_fp = fp;
|
||||
_pc = pc;
|
||||
assert(pc != NULL, "no pc?");
|
||||
_cb = CodeCache::find_blob(pc);
|
||||
adjust_unextended_sp();
|
||||
|
||||
address original_pc = nmethod::get_deopt_original_pc(this);
|
||||
if (original_pc != NULL) {
|
||||
_pc = original_pc;
|
||||
assert(((nmethod*)_cb)->insts_contains(_pc), "original PC must be in nmethod");
|
||||
_deopt_state = is_deoptimized;
|
||||
} else {
|
||||
_deopt_state = not_deoptimized;
|
||||
}
|
||||
}
|
||||
|
||||
inline frame::frame(intptr_t* sp, intptr_t* fp) {
|
||||
intptr_t a = intptr_t(sp);
|
||||
intptr_t b = intptr_t(fp);
|
||||
#ifndef PRODUCT
|
||||
if (fp)
|
||||
if (sp > fp || (fp - sp > 0x100000))
|
||||
for(;;)
|
||||
asm("nop");
|
||||
#endif
|
||||
_sp = sp;
|
||||
_unextended_sp = sp;
|
||||
_fp = fp;
|
||||
_pc = (address)(sp[-1]);
|
||||
|
||||
// Here's a sticky one. This constructor can be called via AsyncGetCallTrace
|
||||
// when last_Java_sp is non-null but the pc fetched is junk. If we are truly
|
||||
// unlucky the junk value could be to a zombied method and we'll die on the
|
||||
// find_blob call. This is also why we can have no asserts on the validity
|
||||
// of the pc we find here. AsyncGetCallTrace -> pd_get_top_frame_for_signal_handler
|
||||
// -> pd_last_frame should use a specialized version of pd_last_frame which could
|
||||
// call a specilaized frame constructor instead of this one.
|
||||
// Then we could use the assert below. However this assert is of somewhat dubious
|
||||
// value.
|
||||
// assert(_pc != NULL, "no pc?");
|
||||
|
||||
_cb = CodeCache::find_blob(_pc);
|
||||
adjust_unextended_sp();
|
||||
|
||||
address original_pc = nmethod::get_deopt_original_pc(this);
|
||||
if (original_pc != NULL) {
|
||||
_pc = original_pc;
|
||||
_deopt_state = is_deoptimized;
|
||||
} else {
|
||||
_deopt_state = not_deoptimized;
|
||||
}
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
inline bool frame::equal(frame other) const {
|
||||
bool ret = sp() == other.sp()
|
||||
&& unextended_sp() == other.unextended_sp()
|
||||
&& fp() == other.fp()
|
||||
&& pc() == other.pc();
|
||||
assert(!ret || ret && cb() == other.cb() && _deopt_state == other._deopt_state, "inconsistent construction");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Return unique id for this frame. The id must have a value where we can distinguish
|
||||
// identity and younger/older relationship. NULL represents an invalid (incomparable)
|
||||
// frame.
|
||||
inline intptr_t* frame::id(void) const { return unextended_sp(); }
|
||||
|
||||
// Relationals on frames based
|
||||
// Return true if the frame is younger (more recent activation) than the frame represented by id
|
||||
inline bool frame::is_younger(intptr_t* id) const { assert(this->id() != NULL && id != NULL, "NULL frame id");
|
||||
return this->id() < id ; }
|
||||
|
||||
// Return true if the frame is older (less recent activation) than the frame represented by id
|
||||
inline bool frame::is_older(intptr_t* id) const { assert(this->id() != NULL && id != NULL, "NULL frame id");
|
||||
return this->id() > id ; }
|
||||
|
||||
|
||||
|
||||
inline intptr_t* frame::link() const { return (intptr_t*) *(intptr_t **)addr_at(link_offset); }
|
||||
inline void frame::set_link(intptr_t* addr) { *(intptr_t **)addr_at(link_offset) = addr; }
|
||||
|
||||
|
||||
inline intptr_t* frame::unextended_sp() const { return _unextended_sp; }
|
||||
|
||||
// Return address:
|
||||
|
||||
inline address* frame::sender_pc_addr() const { return (address*) addr_at( return_addr_offset); }
|
||||
inline address frame::sender_pc() const { return *sender_pc_addr(); }
|
||||
|
||||
// return address of param, zero origin index.
|
||||
inline address* frame::native_param_addr(int idx) const { return (address*) addr_at( native_frame_initial_param_offset+idx); }
|
||||
|
||||
#ifdef CC_INTERP
|
||||
|
||||
inline interpreterState frame::get_interpreterState() const {
|
||||
return ((interpreterState)addr_at( -((int)sizeof(BytecodeInterpreter))/wordSize ));
|
||||
}
|
||||
|
||||
inline intptr_t* frame::sender_sp() const {
|
||||
// Hmm this seems awfully expensive QQQ, is this really called with interpreted frames?
|
||||
if (is_interpreted_frame()) {
|
||||
assert(false, "should never happen");
|
||||
return get_interpreterState()->sender_sp();
|
||||
} else {
|
||||
return addr_at(sender_sp_offset);
|
||||
}
|
||||
}
|
||||
|
||||
inline intptr_t** frame::interpreter_frame_locals_addr() const {
|
||||
assert(is_interpreted_frame(), "must be interpreted");
|
||||
return &(get_interpreterState()->_locals);
|
||||
}
|
||||
|
||||
inline intptr_t* frame::interpreter_frame_bcx_addr() const {
|
||||
assert(is_interpreted_frame(), "must be interpreted");
|
||||
return (intptr_t*) &(get_interpreterState()->_bcp);
|
||||
}
|
||||
|
||||
|
||||
// Constant pool cache
|
||||
|
||||
inline constantPoolCacheOop* frame::interpreter_frame_cache_addr() const {
|
||||
assert(is_interpreted_frame(), "must be interpreted");
|
||||
return &(get_interpreterState()->_constants);
|
||||
}
|
||||
|
||||
// Method
|
||||
|
||||
inline methodOop* frame::interpreter_frame_method_addr() const {
|
||||
assert(is_interpreted_frame(), "must be interpreted");
|
||||
return &(get_interpreterState()->_method);
|
||||
}
|
||||
|
||||
inline intptr_t* frame::interpreter_frame_mdx_addr() const {
|
||||
assert(is_interpreted_frame(), "must be interpreted");
|
||||
return (intptr_t*) &(get_interpreterState()->_mdx);
|
||||
}
|
||||
|
||||
// top of expression stack
|
||||
inline intptr_t* frame::interpreter_frame_tos_address() const {
|
||||
assert(is_interpreted_frame(), "wrong frame type");
|
||||
return get_interpreterState()->_stack + 1;
|
||||
}
|
||||
|
||||
#else /* asm interpreter */
|
||||
inline intptr_t* frame::sender_sp() const { return addr_at( sender_sp_offset); }
|
||||
|
||||
inline intptr_t** frame::interpreter_frame_locals_addr() const {
|
||||
return (intptr_t**)addr_at(interpreter_frame_locals_offset);
|
||||
}
|
||||
|
||||
inline intptr_t* frame::interpreter_frame_last_sp() const {
|
||||
return *(intptr_t**)addr_at(interpreter_frame_last_sp_offset);
|
||||
}
|
||||
|
||||
inline intptr_t* frame::interpreter_frame_bcp_addr() const {
|
||||
return (intptr_t*)addr_at(interpreter_frame_bcp_offset);
|
||||
}
|
||||
|
||||
inline intptr_t* frame::interpreter_frame_mdp_addr() const {
|
||||
return (intptr_t*)addr_at(interpreter_frame_mdp_offset);
|
||||
}
|
||||
|
||||
|
||||
// Constant pool cache
|
||||
|
||||
inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const {
|
||||
return (ConstantPoolCache**)addr_at(interpreter_frame_cache_offset);
|
||||
}
|
||||
|
||||
// Method
|
||||
|
||||
inline Method** frame::interpreter_frame_method_addr() const {
|
||||
return (Method**)addr_at(interpreter_frame_method_offset);
|
||||
}
|
||||
|
||||
// top of expression stack
|
||||
inline intptr_t* frame::interpreter_frame_tos_address() const {
|
||||
intptr_t* last_sp = interpreter_frame_last_sp();
|
||||
if (last_sp == NULL) {
|
||||
return sp();
|
||||
} else {
|
||||
// sp() may have been extended or shrunk by an adapter. At least
|
||||
// check that we don't fall behind the legal region.
|
||||
// For top deoptimized frame last_sp == interpreter_frame_monitor_end.
|
||||
assert(last_sp <= (intptr_t*) interpreter_frame_monitor_end(), "bad tos");
|
||||
return last_sp;
|
||||
}
|
||||
}
|
||||
|
||||
inline oop* frame::interpreter_frame_temp_oop_addr() const {
|
||||
return (oop *)(fp() + interpreter_frame_oop_temp_offset);
|
||||
}
|
||||
|
||||
#endif /* CC_INTERP */
|
||||
|
||||
inline int frame::pd_oop_map_offset_adjustment() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int frame::interpreter_frame_monitor_size() {
|
||||
return BasicObjectLock::size();
|
||||
}
|
||||
|
||||
|
||||
// expression stack
|
||||
// (the max_stack arguments are used by the GC; see class FrameClosure)
|
||||
|
||||
inline intptr_t* frame::interpreter_frame_expression_stack() const {
|
||||
intptr_t* monitor_end = (intptr_t*) interpreter_frame_monitor_end();
|
||||
return monitor_end-1;
|
||||
}
|
||||
|
||||
|
||||
inline jint frame::interpreter_frame_expression_stack_direction() { return -1; }
|
||||
|
||||
|
||||
// Entry frames
|
||||
|
||||
inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const {
|
||||
return (JavaCallWrapper**)addr_at(entry_frame_call_wrapper_offset);
|
||||
}
|
||||
|
||||
|
||||
// Compiled frames
|
||||
|
||||
inline int frame::local_offset_for_compiler(int local_index, int nof_args, int max_nof_locals, int max_nof_monitors) {
|
||||
return (nof_args - local_index + (local_index < nof_args ? 1: -1));
|
||||
}
|
||||
|
||||
inline int frame::monitor_offset_for_compiler(int local_index, int nof_args, int max_nof_locals, int max_nof_monitors) {
|
||||
return local_offset_for_compiler(local_index, nof_args, max_nof_locals, max_nof_monitors);
|
||||
}
|
||||
|
||||
inline int frame::min_local_offset_for_compiler(int nof_args, int max_nof_locals, int max_nof_monitors) {
|
||||
return (nof_args - (max_nof_locals + max_nof_monitors*2) - 1);
|
||||
}
|
||||
|
||||
inline bool frame::volatile_across_calls(Register reg) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline oop frame::saved_oop_result(RegisterMap* map) const {
|
||||
oop* result_adr = (oop *)map->location(r0->as_VMReg());
|
||||
guarantee(result_adr != NULL, "bad register save location");
|
||||
|
||||
return (*result_adr);
|
||||
}
|
||||
|
||||
inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) {
|
||||
oop* result_adr = (oop *)map->location(r0->as_VMReg());
|
||||
guarantee(result_adr != NULL, "bad register save location");
|
||||
|
||||
*result_adr = obj;
|
||||
}
|
||||
|
||||
#endif // CPU_AARCH64_VM_FRAME_AARCH64_INLINE_HPP
|
||||
58
hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp
Normal file
58
hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_GLOBALDEFINITIONS_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_GLOBALDEFINITIONS_AARCH64_HPP
|
||||
|
||||
const int StackAlignmentInBytes = 16;
|
||||
|
||||
// Indicates whether the C calling conventions require that
|
||||
// 32-bit integer argument values are properly extended to 64 bits.
|
||||
// If set, SharedRuntime::c_calling_convention() must adapt
|
||||
// signatures accordingly.
|
||||
const bool CCallingConventionRequiresIntsAsLongs = true;
|
||||
|
||||
#define SUPPORTS_NATIVE_CX8
|
||||
|
||||
// The maximum B/BL offset range on AArch64 is 128MB.
|
||||
#undef CODE_CACHE_DEFAULT_LIMIT
|
||||
#define CODE_CACHE_DEFAULT_LIMIT (128*M)
|
||||
|
||||
// According to the ARMv8 ARM, "Concurrent modification and execution
|
||||
// of instructions can lead to the resulting instruction performing
|
||||
// any behavior that can be achieved by executing any sequence of
|
||||
// instructions that can be executed from the same Exception level,
|
||||
// except where the instruction before modification and the
|
||||
// instruction after modification is a B, BL, NOP, BKPT, SVC, HVC, or
|
||||
// SMC instruction."
|
||||
//
|
||||
// This makes the games we play when patching difficult, so when we
|
||||
// come across an access that needs patching we deoptimize. There are
|
||||
// ways we can avoid this, but these would slow down C1-compiled code
|
||||
// in the defauilt case. We could revisit this decision if we get any
|
||||
// evidence that it's worth doing.
|
||||
#define DEOPTIMIZE_WHEN_PATCHING
|
||||
|
||||
#endif // CPU_AARCH64_VM_GLOBALDEFINITIONS_AARCH64_HPP
|
||||
129
hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp
Normal file
129
hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_GLOBALS_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_GLOBALS_AARCH64_HPP
|
||||
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
// Sets the default values for platform dependent flags used by the runtime system.
|
||||
// (see globals.hpp)
|
||||
|
||||
define_pd_global(bool, ConvertSleepToYield, true);
|
||||
define_pd_global(bool, ShareVtableStubs, true);
|
||||
define_pd_global(bool, CountInterpCalls, true);
|
||||
define_pd_global(bool, NeedsDeoptSuspend, false); // only register window machines need this
|
||||
|
||||
define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks
|
||||
define_pd_global(bool, TrapBasedNullChecks, false);
|
||||
define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast
|
||||
|
||||
// See 4827828 for this change. There is no globals_core_i486.hpp. I can't
|
||||
// assign a different value for C2 without touching a number of files. Use
|
||||
// #ifdef to minimize the change as it's late in Mantis. -- FIXME.
|
||||
// c1 doesn't have this problem because the fix to 4858033 assures us
|
||||
// the the vep is aligned at CodeEntryAlignment whereas c2 only aligns
|
||||
// the uep and the vep doesn't get real alignment but just slops on by
|
||||
// only assured that the entry instruction meets the 5 byte size requirement.
|
||||
#ifdef COMPILER2
|
||||
define_pd_global(intx, CodeEntryAlignment, 64);
|
||||
#else
|
||||
define_pd_global(intx, CodeEntryAlignment, 16);
|
||||
#endif // COMPILER2
|
||||
define_pd_global(intx, OptoLoopAlignment, 16);
|
||||
define_pd_global(intx, InlineFrequencyCount, 100);
|
||||
|
||||
define_pd_global(intx, StackYellowPages, 2);
|
||||
define_pd_global(intx, StackRedPages, 1);
|
||||
|
||||
define_pd_global(intx, StackShadowPages, 4 DEBUG_ONLY(+5));
|
||||
|
||||
define_pd_global(intx, PreInflateSpin, 10);
|
||||
|
||||
define_pd_global(bool, RewriteBytecodes, true);
|
||||
define_pd_global(bool, RewriteFrequentPairs, false);
|
||||
|
||||
define_pd_global(bool, UseMembar, true);
|
||||
|
||||
// GC Ergo Flags
|
||||
define_pd_global(uintx, CMSYoungGenPerWorker, 64*M); // default max size of CMS young gen, per GC worker thread
|
||||
|
||||
define_pd_global(uintx, TypeProfileLevel, 111);
|
||||
|
||||
// avoid biased locking while we are bootstrapping the aarch64 build
|
||||
define_pd_global(bool, UseBiasedLocking, false);
|
||||
|
||||
#if defined(COMPILER1) || defined(COMPILER2)
|
||||
define_pd_global(intx, InlineSmallCode, 1000);
|
||||
#endif
|
||||
|
||||
#ifdef BUILTIN_SIM
|
||||
#define UseBuiltinSim true
|
||||
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
|
||||
\
|
||||
product(bool, NotifySimulator, UseBuiltinSim, \
|
||||
"tell the AArch64 sim where we are in method code") \
|
||||
\
|
||||
product(bool, UseSimulatorCache, false, \
|
||||
"tell sim to cache memory updates until exclusive op occurs") \
|
||||
\
|
||||
product(bool, DisableBCCheck, true, \
|
||||
"tell sim not to invoke bccheck callback") \
|
||||
\
|
||||
product(bool, NearCpool, true, \
|
||||
"constant pool is close to instructions") \
|
||||
\
|
||||
notproduct(bool, UseAcqRelForVolatileFields, false, \
|
||||
"Use acquire and release insns for volatile fields") \
|
||||
\
|
||||
product(bool, UseCRC32, false, \
|
||||
"Use CRC32 instructions for CRC32 computation") \
|
||||
|
||||
// Don't attempt to use Neon on builtin sim until builtin sim supports it
|
||||
#define UseCRC32 false
|
||||
|
||||
#else
|
||||
#define UseBuiltinSim false
|
||||
#define NotifySimulator false
|
||||
#define UseSimulatorCache false
|
||||
#define DisableBCCheck true
|
||||
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
|
||||
\
|
||||
product(bool, NearCpool, true, \
|
||||
"constant pool is close to instructions") \
|
||||
\
|
||||
notproduct(bool, UseAcqRelForVolatileFields, false, \
|
||||
"Use acquire and release insns for volatile fields") \
|
||||
product(bool, UseNeon, false, \
|
||||
"Use Neon for CRC32 computation") \
|
||||
product(bool, UseCRC32, false, \
|
||||
"Use CRC32 instructions for CRC32 computation") \
|
||||
product(bool, TraceTraps, false, "Trace all traps the signal handler")
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // CPU_AARCH64_VM_GLOBALS_AARCH64_HPP
|
||||
77
hotspot/src/cpu/aarch64/vm/icBuffer_aarch64.cpp
Normal file
77
hotspot/src/cpu/aarch64/vm/icBuffer_aarch64.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "code/icBuffer.hpp"
|
||||
#include "gc_interface/collectedHeap.inline.hpp"
|
||||
#include "interpreter/bytecodes.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "nativeInst_aarch64.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/oop.inline2.hpp"
|
||||
|
||||
int InlineCacheBuffer::ic_stub_code_size() {
|
||||
return (MacroAssembler::far_branches() ? 6 : 4) * NativeInstruction::instruction_size;
|
||||
}
|
||||
|
||||
#define __ masm->
|
||||
|
||||
void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, void* cached_value, address entry_point) {
|
||||
ResourceMark rm;
|
||||
CodeBuffer code(code_begin, ic_stub_code_size());
|
||||
MacroAssembler* masm = new MacroAssembler(&code);
|
||||
// note: even though the code contains an embedded value, we do not need reloc info
|
||||
// because
|
||||
// (1) the value is old (i.e., doesn't matter for scavenges)
|
||||
// (2) these ICStubs are removed *before* a GC happens, so the roots disappear
|
||||
// assert(cached_value == NULL || cached_oop->is_perm(), "must be perm oop");
|
||||
|
||||
address start = __ pc();
|
||||
Label l;
|
||||
__ ldr(rscratch2, l);
|
||||
__ far_jump(ExternalAddress(entry_point));
|
||||
__ align(wordSize);
|
||||
__ bind(l);
|
||||
__ emit_int64((int64_t)cached_value);
|
||||
// Only need to invalidate the 1st two instructions - not the whole ic stub
|
||||
ICache::invalidate_range(code_begin, InlineCacheBuffer::ic_stub_code_size());
|
||||
assert(__ pc() - start == ic_stub_code_size(), "must be");
|
||||
}
|
||||
|
||||
address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) {
|
||||
NativeMovConstReg* move = nativeMovConstReg_at(code_begin); // creation also verifies the object
|
||||
NativeJump* jump = nativeJump_at(code_begin + 4);
|
||||
return jump->jump_destination();
|
||||
}
|
||||
|
||||
|
||||
void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) {
|
||||
// The word containing the cached value is at the end of this IC buffer
|
||||
uintptr_t *p = (uintptr_t *)(code_begin + ic_stub_code_size() - wordSize);
|
||||
void* o = (void*)*p;
|
||||
return o;
|
||||
}
|
||||
40
hotspot/src/cpu/aarch64/vm/icache_aarch64.cpp
Normal file
40
hotspot/src/cpu/aarch64/vm/icache_aarch64.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "runtime/icache.hpp"
|
||||
|
||||
extern void aarch64TestHook();
|
||||
|
||||
void ICacheStubGenerator::generate_icache_flush(
|
||||
ICache::flush_icache_stub_t* flush_icache_stub) {
|
||||
// Give anyone who calls this a surprise
|
||||
*flush_icache_stub = (ICache::flush_icache_stub_t)NULL;
|
||||
}
|
||||
|
||||
void ICache::initialize() {
|
||||
aarch64TestHook();
|
||||
}
|
||||
44
hotspot/src/cpu/aarch64/vm/icache_aarch64.hpp
Normal file
44
hotspot/src/cpu/aarch64/vm/icache_aarch64.hpp
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_ICACHE_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_ICACHE_AARCH64_HPP
|
||||
|
||||
// Interface for updating the instruction cache. Whenever the VM
|
||||
// modifies code, part of the processor instruction cache potentially
|
||||
// has to be flushed.
|
||||
|
||||
class ICache : public AbstractICache {
|
||||
public:
|
||||
static void initialize();
|
||||
static void invalidate_word(address addr) {
|
||||
__clear_cache((char *)addr, (char *)(addr + 3));
|
||||
}
|
||||
static void invalidate_range(address start, int nbytes) {
|
||||
__clear_cache((char *)start, (char *)(start + nbytes));
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CPU_AARCH64_VM_ICACHE_AARCH64_HPP
|
||||
315
hotspot/src/cpu/aarch64/vm/immediate_aarch64.cpp
Normal file
315
hotspot/src/cpu/aarch64/vm/immediate_aarch64.cpp
Normal file
@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "decode_aarch64.hpp"
|
||||
#include "immediate_aarch64.hpp"
|
||||
|
||||
// there are at most 2^13 possible logical immediate encodings
|
||||
// however, some combinations of immr and imms are invalid
|
||||
static const unsigned LI_TABLE_SIZE = (1 << 13);
|
||||
|
||||
static int li_table_entry_count;
|
||||
|
||||
// for forward lookup we just use a direct array lookup
|
||||
// and assume that the cient has supplied a valid encoding
|
||||
// table[encoding] = immediate
|
||||
static u_int64_t LITable[LI_TABLE_SIZE];
|
||||
|
||||
// for reverse lookup we need a sparse map so we store a table of
|
||||
// immediate and encoding pairs sorted by immediate value
|
||||
|
||||
struct li_pair {
|
||||
u_int64_t immediate;
|
||||
u_int32_t encoding;
|
||||
};
|
||||
|
||||
static struct li_pair InverseLITable[LI_TABLE_SIZE];
|
||||
|
||||
// comparator to sort entries in the inverse table
|
||||
int compare_immediate_pair(const void *i1, const void *i2)
|
||||
{
|
||||
struct li_pair *li1 = (struct li_pair *)i1;
|
||||
struct li_pair *li2 = (struct li_pair *)i2;
|
||||
if (li1->immediate < li2->immediate) {
|
||||
return -1;
|
||||
}
|
||||
if (li1->immediate > li2->immediate) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// helper functions used by expandLogicalImmediate
|
||||
|
||||
// for i = 1, ... N result<i-1> = 1 other bits are zero
|
||||
static inline u_int64_t ones(int N)
|
||||
{
|
||||
return (N == 64 ? (u_int64_t)-1UL : ((1UL << N) - 1));
|
||||
}
|
||||
|
||||
// result<0> to val<N>
|
||||
static inline u_int64_t pickbit(u_int64_t val, int N)
|
||||
{
|
||||
return pickbits64(val, N, N);
|
||||
}
|
||||
|
||||
|
||||
// SPEC bits(M*N) Replicate(bits(M) x, integer N);
|
||||
// this is just an educated guess
|
||||
|
||||
u_int64_t replicate(u_int64_t bits, int nbits, int count)
|
||||
{
|
||||
u_int64_t result = 0;
|
||||
// nbits may be 64 in which case we want mask to be -1
|
||||
u_int64_t mask = ones(nbits);
|
||||
for (int i = 0; i < count ; i++) {
|
||||
result <<= nbits;
|
||||
result |= (bits & mask);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// this function writes the supplied bimm reference and returns a
|
||||
// boolean to indicate success (1) or fail (0) because an illegal
|
||||
// encoding must be treated as an UNALLOC instruction
|
||||
|
||||
// construct a 32 bit immediate value for a logical immediate operation
|
||||
int expandLogicalImmediate(u_int32_t immN, u_int32_t immr,
|
||||
u_int32_t imms, u_int64_t &bimm)
|
||||
{
|
||||
int len; // ought to be <= 6
|
||||
u_int32_t levels; // 6 bits
|
||||
u_int32_t tmask_and; // 6 bits
|
||||
u_int32_t wmask_and; // 6 bits
|
||||
u_int32_t tmask_or; // 6 bits
|
||||
u_int32_t wmask_or; // 6 bits
|
||||
u_int64_t imm64; // 64 bits
|
||||
u_int64_t tmask, wmask; // 64 bits
|
||||
u_int32_t S, R, diff; // 6 bits?
|
||||
|
||||
if (immN == 1) {
|
||||
len = 6; // looks like 7 given the spec above but this cannot be!
|
||||
} else {
|
||||
len = 0;
|
||||
u_int32_t val = (~imms & 0x3f);
|
||||
for (int i = 5; i > 0; i--) {
|
||||
if (val & (1 << i)) {
|
||||
len = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (len < 1) {
|
||||
return 0;
|
||||
}
|
||||
// for valid inputs leading 1s in immr must be less than leading
|
||||
// zeros in imms
|
||||
int len2 = 0; // ought to be < len
|
||||
u_int32_t val2 = (~immr & 0x3f);
|
||||
for (int i = 5; i > 0; i--) {
|
||||
if (!(val2 & (1 << i))) {
|
||||
len2 = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (len2 >= len) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
levels = (1 << len) - 1;
|
||||
|
||||
if ((imms & levels) == levels) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
S = imms & levels;
|
||||
R = immr & levels;
|
||||
|
||||
// 6 bit arithmetic!
|
||||
diff = S - R;
|
||||
tmask_and = (diff | ~levels) & 0x3f;
|
||||
tmask_or = (diff & levels) & 0x3f;
|
||||
tmask = 0xffffffffffffffffULL;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int nbits = 1 << i;
|
||||
u_int64_t and_bit = pickbit(tmask_and, i);
|
||||
u_int64_t or_bit = pickbit(tmask_or, i);
|
||||
u_int64_t and_bits_sub = replicate(and_bit, 1, nbits);
|
||||
u_int64_t or_bits_sub = replicate(or_bit, 1, nbits);
|
||||
u_int64_t and_bits_top = (and_bits_sub << nbits) | ones(nbits);
|
||||
u_int64_t or_bits_top = (0 << nbits) | or_bits_sub;
|
||||
|
||||
tmask = ((tmask
|
||||
& (replicate(and_bits_top, 2 * nbits, 32 / nbits)))
|
||||
| replicate(or_bits_top, 2 * nbits, 32 / nbits));
|
||||
}
|
||||
|
||||
wmask_and = (immr | ~levels) & 0x3f;
|
||||
wmask_or = (immr & levels) & 0x3f;
|
||||
|
||||
wmask = 0;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int nbits = 1 << i;
|
||||
u_int64_t and_bit = pickbit(wmask_and, i);
|
||||
u_int64_t or_bit = pickbit(wmask_or, i);
|
||||
u_int64_t and_bits_sub = replicate(and_bit, 1, nbits);
|
||||
u_int64_t or_bits_sub = replicate(or_bit, 1, nbits);
|
||||
u_int64_t and_bits_top = (ones(nbits) << nbits) | and_bits_sub;
|
||||
u_int64_t or_bits_top = (or_bits_sub << nbits) | 0;
|
||||
|
||||
wmask = ((wmask
|
||||
& (replicate(and_bits_top, 2 * nbits, 32 / nbits)))
|
||||
| replicate(or_bits_top, 2 * nbits, 32 / nbits));
|
||||
}
|
||||
|
||||
if (diff & (1U << 6)) {
|
||||
imm64 = tmask & wmask;
|
||||
} else {
|
||||
imm64 = tmask | wmask;
|
||||
}
|
||||
|
||||
|
||||
bimm = imm64;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// constructor to initialise the lookup tables
|
||||
|
||||
static void initLITables() __attribute__ ((constructor));
|
||||
static void initLITables()
|
||||
{
|
||||
li_table_entry_count = 0;
|
||||
for (unsigned index = 0; index < LI_TABLE_SIZE; index++) {
|
||||
u_int32_t N = uimm(index, 12, 12);
|
||||
u_int32_t immr = uimm(index, 11, 6);
|
||||
u_int32_t imms = uimm(index, 5, 0);
|
||||
if (expandLogicalImmediate(N, immr, imms, LITable[index])) {
|
||||
InverseLITable[li_table_entry_count].immediate = LITable[index];
|
||||
InverseLITable[li_table_entry_count].encoding = index;
|
||||
li_table_entry_count++;
|
||||
}
|
||||
}
|
||||
// now sort the inverse table
|
||||
qsort(InverseLITable, li_table_entry_count,
|
||||
sizeof(InverseLITable[0]), compare_immediate_pair);
|
||||
}
|
||||
|
||||
// public APIs provided for logical immediate lookup and reverse lookup
|
||||
|
||||
u_int64_t logical_immediate_for_encoding(u_int32_t encoding)
|
||||
{
|
||||
return LITable[encoding];
|
||||
}
|
||||
|
||||
u_int32_t encoding_for_logical_immediate(u_int64_t immediate)
|
||||
{
|
||||
struct li_pair pair;
|
||||
struct li_pair *result;
|
||||
|
||||
pair.immediate = immediate;
|
||||
|
||||
result = (struct li_pair *)
|
||||
bsearch(&pair, InverseLITable, li_table_entry_count,
|
||||
sizeof(InverseLITable[0]), compare_immediate_pair);
|
||||
|
||||
if (result) {
|
||||
return result->encoding;
|
||||
}
|
||||
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
// floating point immediates are encoded in 8 bits
|
||||
// fpimm[7] = sign bit
|
||||
// fpimm[6:4] = signed exponent
|
||||
// fpimm[3:0] = fraction (assuming leading 1)
|
||||
// i.e. F = s * 1.f * 2^(e - b)
|
||||
|
||||
u_int64_t fp_immediate_for_encoding(u_int32_t imm8, int is_dp)
|
||||
{
|
||||
union {
|
||||
float fpval;
|
||||
double dpval;
|
||||
u_int64_t val;
|
||||
};
|
||||
|
||||
u_int32_t s, e, f;
|
||||
s = (imm8 >> 7 ) & 0x1;
|
||||
e = (imm8 >> 4) & 0x7;
|
||||
f = imm8 & 0xf;
|
||||
// the fp value is s * n/16 * 2r where n is 16+e
|
||||
fpval = (16.0 + f) / 16.0;
|
||||
// n.b. exponent is signed
|
||||
if (e < 4) {
|
||||
int epos = e;
|
||||
for (int i = 0; i <= epos; i++) {
|
||||
fpval *= 2.0;
|
||||
}
|
||||
} else {
|
||||
int eneg = 7 - e;
|
||||
for (int i = 0; i < eneg; i++) {
|
||||
fpval /= 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (s) {
|
||||
fpval = -fpval;
|
||||
}
|
||||
if (is_dp) {
|
||||
dpval = (double)fpval;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
u_int32_t encoding_for_fp_immediate(float immediate)
|
||||
{
|
||||
// given a float which is of the form
|
||||
//
|
||||
// s * n/16 * 2r
|
||||
//
|
||||
// where n is 16+f and imm1:s, imm4:f, simm3:r
|
||||
// return the imm8 result [s:r:f]
|
||||
//
|
||||
|
||||
union {
|
||||
float fpval;
|
||||
u_int32_t val;
|
||||
};
|
||||
fpval = immediate;
|
||||
u_int32_t s, r, f, res;
|
||||
// sign bit is 31
|
||||
s = (val >> 31) & 0x1;
|
||||
// exponent is bits 30-23 but we only want the bottom 3 bits
|
||||
// strictly we ought to check that the bits bits 30-25 are
|
||||
// either all 1s or all 0s
|
||||
r = (val >> 23) & 0x7;
|
||||
// fraction is bits 22-0
|
||||
f = (val >> 19) & 0xf;
|
||||
res = (s << 7) | (r << 4) | f;
|
||||
return res;
|
||||
}
|
||||
|
||||
54
hotspot/src/cpu/aarch64/vm/immediate_aarch64.hpp
Normal file
54
hotspot/src/cpu/aarch64/vm/immediate_aarch64.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _IMMEDIATE_H
|
||||
#define _IMMEDIATE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/*
|
||||
* functions to map backwards and forwards between logical or floating
|
||||
* point immediates and their corresponding encodings. the mapping
|
||||
* from encoding to immediate is required by the simulator. the reverse
|
||||
* mapping is required by the OpenJDK assembler.
|
||||
*
|
||||
* a logical immediate value supplied to or returned from a map lookup
|
||||
* is always 64 bits. this is sufficient for looking up 32 bit
|
||||
* immediates or their encodings since a 32 bit immediate has the same
|
||||
* encoding as the 64 bit immediate produced by concatenating the
|
||||
* immediate with itself.
|
||||
*
|
||||
* a logical immediate encoding is 13 bits N:immr:imms (3 fields of
|
||||
* widths 1:6:6 -- see the arm spec). they appear as bits [22:10] of a
|
||||
* logical immediate instruction. encodings are supplied and returned
|
||||
* as 32 bit values. if a given 13 bit immediate has no corresponding
|
||||
* encoding then a map lookup will return 0xffffffff.
|
||||
*/
|
||||
|
||||
u_int64_t logical_immediate_for_encoding(u_int32_t encoding);
|
||||
u_int32_t encoding_for_logical_immediate(u_int64_t immediate);
|
||||
u_int64_t fp_immediate_for_encoding(u_int32_t imm8, int is_dp);
|
||||
u_int32_t encoding_for_fp_immediate(float immediate);
|
||||
|
||||
#endif // _IMMEDIATE_H
|
||||
1682
hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp
Normal file
1682
hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp
Normal file
File diff suppressed because it is too large
Load Diff
291
hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp
Normal file
291
hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_INTERP_MASM_AARCH64_64_HPP
|
||||
#define CPU_AARCH64_VM_INTERP_MASM_AARCH64_64_HPP
|
||||
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "interpreter/invocationCounter.hpp"
|
||||
#include "runtime/frame.hpp"
|
||||
|
||||
// This file specializes the assember with interpreter-specific macros
|
||||
|
||||
|
||||
class InterpreterMacroAssembler: public MacroAssembler {
|
||||
#ifndef CC_INTERP
|
||||
protected:
|
||||
|
||||
protected:
|
||||
// Interpreter specific version of call_VM_base
|
||||
virtual void call_VM_leaf_base(address entry_point,
|
||||
int number_of_arguments);
|
||||
|
||||
virtual void call_VM_base(Register oop_result,
|
||||
Register java_thread,
|
||||
Register last_java_sp,
|
||||
address entry_point,
|
||||
int number_of_arguments,
|
||||
bool check_exceptions);
|
||||
|
||||
virtual void check_and_handle_popframe(Register java_thread);
|
||||
virtual void check_and_handle_earlyret(Register java_thread);
|
||||
|
||||
// base routine for all dispatches
|
||||
void dispatch_base(TosState state, address* table, bool verifyoop = true);
|
||||
#endif // CC_INTERP
|
||||
|
||||
public:
|
||||
InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code) {}
|
||||
|
||||
void load_earlyret_value(TosState state);
|
||||
|
||||
#ifdef CC_INTERP
|
||||
void save_bcp() { /* not needed in c++ interpreter and harmless */ }
|
||||
void restore_bcp() { /* not needed in c++ interpreter and harmless */ }
|
||||
|
||||
// Helpers for runtime call arguments/results
|
||||
void get_method(Register reg);
|
||||
|
||||
#else
|
||||
|
||||
// Interpreter-specific registers
|
||||
void save_bcp() {
|
||||
str(rbcp, Address(rfp, frame::interpreter_frame_bcp_offset * wordSize));
|
||||
}
|
||||
|
||||
void restore_bcp() {
|
||||
ldr(rbcp, Address(rfp, frame::interpreter_frame_bcp_offset * wordSize));
|
||||
}
|
||||
|
||||
void restore_locals() {
|
||||
ldr(rlocals, Address(rfp, frame::interpreter_frame_locals_offset * wordSize));
|
||||
}
|
||||
|
||||
void restore_constant_pool_cache() {
|
||||
ldr(rcpool, Address(rfp, frame::interpreter_frame_cache_offset * wordSize));
|
||||
}
|
||||
|
||||
void get_dispatch();
|
||||
|
||||
// Helpers for runtime call arguments/results
|
||||
|
||||
// Helpers for runtime call arguments/results
|
||||
void get_method(Register reg) {
|
||||
ldr(reg, Address(rfp, frame::interpreter_frame_method_offset * wordSize));
|
||||
}
|
||||
|
||||
void get_const(Register reg) {
|
||||
get_method(reg);
|
||||
ldr(reg, Address(reg, in_bytes(Method::const_offset())));
|
||||
}
|
||||
|
||||
void get_constant_pool(Register reg) {
|
||||
get_const(reg);
|
||||
ldr(reg, Address(reg, in_bytes(ConstMethod::constants_offset())));
|
||||
}
|
||||
|
||||
void get_constant_pool_cache(Register reg) {
|
||||
get_constant_pool(reg);
|
||||
ldr(reg, Address(reg, ConstantPool::cache_offset_in_bytes()));
|
||||
}
|
||||
|
||||
void get_cpool_and_tags(Register cpool, Register tags) {
|
||||
get_constant_pool(cpool);
|
||||
ldr(tags, Address(cpool, ConstantPool::tags_offset_in_bytes()));
|
||||
}
|
||||
|
||||
void get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset);
|
||||
void get_cache_and_index_at_bcp(Register cache, Register index, int bcp_offset, size_t index_size = sizeof(u2));
|
||||
void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2));
|
||||
void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2));
|
||||
void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2));
|
||||
void get_method_counters(Register method, Register mcs, Label& skip);
|
||||
|
||||
// load cpool->resolved_references(index);
|
||||
void load_resolved_reference_at_index(Register result, Register index);
|
||||
|
||||
void pop_ptr(Register r = r0);
|
||||
void pop_i(Register r = r0);
|
||||
void pop_l(Register r = r0);
|
||||
void pop_f(FloatRegister r = v0);
|
||||
void pop_d(FloatRegister r = v0);
|
||||
void push_ptr(Register r = r0);
|
||||
void push_i(Register r = r0);
|
||||
void push_l(Register r = r0);
|
||||
void push_f(FloatRegister r = v0);
|
||||
void push_d(FloatRegister r = v0);
|
||||
|
||||
void pop(Register r ) { ((MacroAssembler*)this)->pop(r); }
|
||||
|
||||
void push(Register r ) { ((MacroAssembler*)this)->push(r); }
|
||||
|
||||
void pop(TosState state); // transition vtos -> state
|
||||
void push(TosState state); // transition state -> vtos
|
||||
|
||||
void pop(RegSet regs, Register stack) { ((MacroAssembler*)this)->pop(regs, stack); }
|
||||
void push(RegSet regs, Register stack) { ((MacroAssembler*)this)->push(regs, stack); }
|
||||
|
||||
void empty_expression_stack() {
|
||||
ldr(esp, Address(rfp, frame::interpreter_frame_monitor_block_top_offset * wordSize));
|
||||
// NULL last_sp until next java call
|
||||
str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize));
|
||||
}
|
||||
|
||||
// Helpers for swap and dup
|
||||
void load_ptr(int n, Register val);
|
||||
void store_ptr(int n, Register val);
|
||||
|
||||
// Generate a subtype check: branch to ok_is_subtype if sub_klass is
|
||||
// a subtype of super_klass.
|
||||
void gen_subtype_check( Register sub_klass, Label &ok_is_subtype );
|
||||
|
||||
// Dispatching
|
||||
void dispatch_prolog(TosState state, int step = 0);
|
||||
void dispatch_epilog(TosState state, int step = 0);
|
||||
// dispatch via rscratch1
|
||||
void dispatch_only(TosState state);
|
||||
// dispatch normal table via rscratch1 (assume rscratch1 is loaded already)
|
||||
void dispatch_only_normal(TosState state);
|
||||
void dispatch_only_noverify(TosState state);
|
||||
// load rscratch1 from [rbcp + step] and dispatch via rscratch1
|
||||
void dispatch_next(TosState state, int step = 0);
|
||||
// load rscratch1 from [esi] and dispatch via rscratch1 and table
|
||||
void dispatch_via (TosState state, address* table);
|
||||
|
||||
// jump to an invoked target
|
||||
void prepare_to_jump_from_interpreted();
|
||||
void jump_from_interpreted(Register method, Register temp);
|
||||
|
||||
|
||||
// Returning from interpreted functions
|
||||
//
|
||||
// Removes the current activation (incl. unlocking of monitors)
|
||||
// and sets up the return address. This code is also used for
|
||||
// exception unwindwing. In that case, we do not want to throw
|
||||
// IllegalMonitorStateExceptions, since that might get us into an
|
||||
// infinite rethrow exception loop.
|
||||
// Additionally this code is used for popFrame and earlyReturn.
|
||||
// In popFrame case we want to skip throwing an exception,
|
||||
// installing an exception, and notifying jvmdi.
|
||||
// In earlyReturn case we only want to skip throwing an exception
|
||||
// and installing an exception.
|
||||
void remove_activation(TosState state,
|
||||
bool throw_monitor_exception = true,
|
||||
bool install_monitor_exception = true,
|
||||
bool notify_jvmdi = true);
|
||||
#endif // CC_INTERP
|
||||
|
||||
// FIXME: Give us a valid frame at a null check.
|
||||
virtual void null_check(Register reg, int offset = -1) {
|
||||
// #ifdef ASSERT
|
||||
// save_bcp();
|
||||
// set_last_Java_frame(esp, rfp, (address) pc());
|
||||
// #endif
|
||||
MacroAssembler::null_check(reg, offset);
|
||||
// #ifdef ASSERT
|
||||
// reset_last_Java_frame(true, false);
|
||||
// #endif
|
||||
}
|
||||
|
||||
// Object locking
|
||||
void lock_object (Register lock_reg);
|
||||
void unlock_object(Register lock_reg);
|
||||
|
||||
#ifndef CC_INTERP
|
||||
|
||||
// Interpreter profiling operations
|
||||
void set_method_data_pointer_for_bcp();
|
||||
void test_method_data_pointer(Register mdp, Label& zero_continue);
|
||||
void verify_method_data_pointer();
|
||||
|
||||
void set_mdp_data_at(Register mdp_in, int constant, Register value);
|
||||
void increment_mdp_data_at(Address data, bool decrement = false);
|
||||
void increment_mdp_data_at(Register mdp_in, int constant,
|
||||
bool decrement = false);
|
||||
void increment_mdp_data_at(Register mdp_in, Register reg, int constant,
|
||||
bool decrement = false);
|
||||
void increment_mask_and_jump(Address counter_addr,
|
||||
int increment, int mask,
|
||||
Register scratch, bool preloaded,
|
||||
Condition cond, Label* where);
|
||||
void set_mdp_flag_at(Register mdp_in, int flag_constant);
|
||||
void test_mdp_data_at(Register mdp_in, int offset, Register value,
|
||||
Register test_value_out,
|
||||
Label& not_equal_continue);
|
||||
|
||||
void record_klass_in_profile(Register receiver, Register mdp,
|
||||
Register reg2, bool is_virtual_call);
|
||||
void record_klass_in_profile_helper(Register receiver, Register mdp,
|
||||
Register reg2, int start_row,
|
||||
Label& done, bool is_virtual_call);
|
||||
|
||||
void update_mdp_by_offset(Register mdp_in, int offset_of_offset);
|
||||
void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp);
|
||||
void update_mdp_by_constant(Register mdp_in, int constant);
|
||||
void update_mdp_for_ret(Register return_bci);
|
||||
|
||||
void profile_taken_branch(Register mdp, Register bumped_count);
|
||||
void profile_not_taken_branch(Register mdp);
|
||||
void profile_call(Register mdp);
|
||||
void profile_final_call(Register mdp);
|
||||
void profile_virtual_call(Register receiver, Register mdp,
|
||||
Register scratch2,
|
||||
bool receiver_can_be_null = false);
|
||||
void profile_ret(Register return_bci, Register mdp);
|
||||
void profile_null_seen(Register mdp);
|
||||
void profile_typecheck(Register mdp, Register klass, Register scratch);
|
||||
void profile_typecheck_failed(Register mdp);
|
||||
void profile_switch_default(Register mdp);
|
||||
void profile_switch_case(Register index_in_scratch, Register mdp,
|
||||
Register scratch2);
|
||||
|
||||
void profile_obj_type(Register obj, const Address& mdo_addr);
|
||||
void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual);
|
||||
void profile_return_type(Register mdp, Register ret, Register tmp);
|
||||
void profile_parameters_type(Register mdp, Register tmp1, Register tmp2);
|
||||
|
||||
// Debugging
|
||||
// only if +VerifyOops && state == atos
|
||||
void verify_oop(Register reg, TosState state = atos);
|
||||
// only if +VerifyFPU && (state == ftos || state == dtos)
|
||||
void verify_FPU(int stack_depth, TosState state = ftos);
|
||||
|
||||
#endif // !CC_INTERP
|
||||
|
||||
typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode;
|
||||
|
||||
// support for jvmti/dtrace
|
||||
void notify_method_entry();
|
||||
void notify_method_exit(TosState state, NotifyMethodExitMode mode);
|
||||
|
||||
virtual void _call_Unimplemented(address call_site) {
|
||||
save_bcp();
|
||||
set_last_Java_frame(esp, rfp, (address) pc(), rscratch1);
|
||||
MacroAssembler::_call_Unimplemented(call_site);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CPU_AARCH64_VM_INTERP_MASM_AARCH64_64_HPP
|
||||
57
hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp
Normal file
57
hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_INTERPRETERGENERATOR_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_INTERPRETERGENERATOR_AARCH64_HPP
|
||||
|
||||
|
||||
// Generation of Interpreter
|
||||
//
|
||||
friend class AbstractInterpreterGenerator;
|
||||
|
||||
protected:
|
||||
|
||||
void bang_stack_shadow_pages(bool native_call);
|
||||
|
||||
private:
|
||||
|
||||
address generate_normal_entry(bool synchronized);
|
||||
address generate_native_entry(bool synchronized);
|
||||
address generate_abstract_entry(void);
|
||||
address generate_math_entry(AbstractInterpreter::MethodKind kind);
|
||||
address generate_jump_to_normal_entry(void);
|
||||
address generate_accessor_entry(void) { return generate_jump_to_normal_entry(); }
|
||||
address generate_empty_entry(void) { return generate_jump_to_normal_entry(); }
|
||||
void generate_transcendental_entry(AbstractInterpreter::MethodKind kind, int fpargs);
|
||||
address generate_Reference_get_entry();
|
||||
address generate_CRC32_update_entry();
|
||||
address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind);
|
||||
void lock_method(void);
|
||||
void generate_stack_overflow_check(void);
|
||||
|
||||
void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue);
|
||||
void generate_counter_overflow(Label* do_continue);
|
||||
|
||||
#endif // CPU_AARCH64_VM_INTERPRETERGENERATOR_AARCH64_HPP
|
||||
428
hotspot/src/cpu/aarch64/vm/interpreterRT_aarch64.cpp
Normal file
428
hotspot/src/cpu/aarch64/vm/interpreterRT_aarch64.cpp
Normal file
@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/interpreterRuntime.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/universe.inline.hpp"
|
||||
#include "oops/method.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/icache.hpp"
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
#include "runtime/signature.hpp"
|
||||
|
||||
#define __ _masm->
|
||||
|
||||
// Implementation of SignatureHandlerGenerator
|
||||
Register InterpreterRuntime::SignatureHandlerGenerator::from() { return rlocals; }
|
||||
Register InterpreterRuntime::SignatureHandlerGenerator::to() { return sp; }
|
||||
Register InterpreterRuntime::SignatureHandlerGenerator::temp() { return rscratch1; }
|
||||
|
||||
void InterpreterRuntime::SignatureHandlerGenerator::pass_int() {
|
||||
const Address src(from(), Interpreter::local_offset_in_bytes(offset()));
|
||||
|
||||
switch (_num_int_args) {
|
||||
case 0:
|
||||
__ ldr(c_rarg1, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
case 1:
|
||||
__ ldr(c_rarg2, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
case 2:
|
||||
__ ldr(c_rarg3, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
case 3:
|
||||
__ ldr(c_rarg4, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
case 4:
|
||||
__ ldr(c_rarg5, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
case 5:
|
||||
__ ldr(c_rarg6, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
case 6:
|
||||
__ ldr(c_rarg7, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
default:
|
||||
__ ldr(r0, src);
|
||||
__ str(r0, Address(to(), _stack_offset));
|
||||
_stack_offset += wordSize;
|
||||
_num_int_args++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterRuntime::SignatureHandlerGenerator::pass_long() {
|
||||
const Address src(from(), Interpreter::local_offset_in_bytes(offset() + 1));
|
||||
|
||||
switch (_num_int_args) {
|
||||
case 0:
|
||||
__ ldr(c_rarg1, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
case 1:
|
||||
__ ldr(c_rarg2, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
case 2:
|
||||
__ ldr(c_rarg3, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
case 3:
|
||||
__ ldr(c_rarg4, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
case 4:
|
||||
__ ldr(c_rarg5, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
case 5:
|
||||
__ ldr(c_rarg6, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
case 6:
|
||||
__ ldr(c_rarg7, src);
|
||||
_num_int_args++;
|
||||
break;
|
||||
default:
|
||||
__ ldr(r0, src);
|
||||
__ str(r0, Address(to(), _stack_offset));
|
||||
_stack_offset += wordSize;
|
||||
_num_int_args++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterRuntime::SignatureHandlerGenerator::pass_float() {
|
||||
const Address src(from(), Interpreter::local_offset_in_bytes(offset()));
|
||||
|
||||
if (_num_fp_args < Argument::n_float_register_parameters_c) {
|
||||
__ ldrs(as_FloatRegister(_num_fp_args++), src);
|
||||
} else {
|
||||
__ ldrh(r0, src);
|
||||
__ strh(r0, Address(to(), _stack_offset));
|
||||
_stack_offset += wordSize;
|
||||
_num_fp_args++;
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterRuntime::SignatureHandlerGenerator::pass_double() {
|
||||
const Address src(from(), Interpreter::local_offset_in_bytes(offset() + 1));
|
||||
|
||||
if (_num_fp_args < Argument::n_float_register_parameters_c) {
|
||||
__ ldrd(as_FloatRegister(_num_fp_args++), src);
|
||||
} else {
|
||||
__ ldr(r0, src);
|
||||
__ str(r0, Address(to(), _stack_offset));
|
||||
_stack_offset += wordSize;
|
||||
_num_fp_args++;
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterRuntime::SignatureHandlerGenerator::pass_object() {
|
||||
|
||||
switch (_num_int_args) {
|
||||
case 0:
|
||||
assert(offset() == 0, "argument register 1 can only be (non-null) receiver");
|
||||
__ add(c_rarg1, from(), Interpreter::local_offset_in_bytes(offset()));
|
||||
_num_int_args++;
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
__ add(r0, from(), Interpreter::local_offset_in_bytes(offset()));
|
||||
__ mov(c_rarg2, 0);
|
||||
__ ldr(temp(), r0);
|
||||
Label L;
|
||||
__ cbz(temp(), L);
|
||||
__ mov(c_rarg2, r0);
|
||||
__ bind(L);
|
||||
_num_int_args++;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
__ add(r0, from(), Interpreter::local_offset_in_bytes(offset()));
|
||||
__ mov(c_rarg3, 0);
|
||||
__ ldr(temp(), r0);
|
||||
Label L;
|
||||
__ cbz(temp(), L);
|
||||
__ mov(c_rarg3, r0);
|
||||
__ bind(L);
|
||||
_num_int_args++;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
__ add(r0, from(), Interpreter::local_offset_in_bytes(offset()));
|
||||
__ mov(c_rarg4, 0);
|
||||
__ ldr(temp(), r0);
|
||||
Label L;
|
||||
__ cbz(temp(), L);
|
||||
__ mov(c_rarg4, r0);
|
||||
__ bind(L);
|
||||
_num_int_args++;
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
__ add(r0, from(), Interpreter::local_offset_in_bytes(offset()));
|
||||
__ mov(c_rarg5, 0);
|
||||
__ ldr(temp(), r0);
|
||||
Label L;
|
||||
__ cbz(temp(), L);
|
||||
__ mov(c_rarg5, r0);
|
||||
__ bind(L);
|
||||
_num_int_args++;
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
__ add(r0, from(), Interpreter::local_offset_in_bytes(offset()));
|
||||
__ mov(c_rarg6, 0);
|
||||
__ ldr(temp(), r0);
|
||||
Label L;
|
||||
__ cbz(temp(), L);
|
||||
__ mov(c_rarg6, r0);
|
||||
__ bind(L);
|
||||
_num_int_args++;
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
__ add(r0, from(), Interpreter::local_offset_in_bytes(offset()));
|
||||
__ mov(c_rarg7, 0);
|
||||
__ ldr(temp(), r0);
|
||||
Label L;
|
||||
__ cbz(temp(), L);
|
||||
__ mov(c_rarg7, r0);
|
||||
__ bind(L);
|
||||
_num_int_args++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
__ add(r0, from(), Interpreter::local_offset_in_bytes(offset()));
|
||||
__ ldr(temp(), r0);
|
||||
Label L;
|
||||
__ cbnz(temp(), L);
|
||||
__ mov(r0, zr);
|
||||
__ bind(L);
|
||||
__ str(r0, Address(to(), _stack_offset));
|
||||
_stack_offset += wordSize;
|
||||
_num_int_args++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprint) {
|
||||
// generate code to handle arguments
|
||||
iterate(fingerprint);
|
||||
|
||||
// set the call format
|
||||
// n.b. allow extra 1 for the JNI_Env in c_rarg0
|
||||
unsigned int call_format = ((_num_int_args + 1) << 6) | (_num_fp_args << 2);
|
||||
|
||||
switch (method()->result_type()) {
|
||||
case T_VOID:
|
||||
call_format |= MacroAssembler::ret_type_void;
|
||||
break;
|
||||
case T_FLOAT:
|
||||
call_format |= MacroAssembler::ret_type_float;
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
call_format |= MacroAssembler::ret_type_double;
|
||||
break;
|
||||
default:
|
||||
call_format |= MacroAssembler::ret_type_integral;
|
||||
break;
|
||||
}
|
||||
|
||||
// // store the call format in the method
|
||||
// __ movw(r0, call_format);
|
||||
// __ str(r0, Address(rmethod, Method::call_format_offset()));
|
||||
|
||||
// return result handler
|
||||
__ lea(r0, ExternalAddress(Interpreter::result_handler(method()->result_type())));
|
||||
__ ret(lr);
|
||||
|
||||
__ flush();
|
||||
}
|
||||
|
||||
|
||||
// Implementation of SignatureHandlerLibrary
|
||||
|
||||
void SignatureHandlerLibrary::pd_set_handler(address handler) {}
|
||||
|
||||
|
||||
class SlowSignatureHandler
|
||||
: public NativeSignatureIterator {
|
||||
private:
|
||||
address _from;
|
||||
intptr_t* _to;
|
||||
intptr_t* _int_args;
|
||||
intptr_t* _fp_args;
|
||||
intptr_t* _fp_identifiers;
|
||||
unsigned int _num_int_args;
|
||||
unsigned int _num_fp_args;
|
||||
|
||||
virtual void pass_int()
|
||||
{
|
||||
jint from_obj = *(jint *)(_from+Interpreter::local_offset_in_bytes(0));
|
||||
_from -= Interpreter::stackElementSize;
|
||||
|
||||
if (_num_int_args < Argument::n_int_register_parameters_c-1) {
|
||||
*_int_args++ = from_obj;
|
||||
_num_int_args++;
|
||||
} else {
|
||||
*_to++ = from_obj;
|
||||
_num_int_args++;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void pass_long()
|
||||
{
|
||||
intptr_t from_obj = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1));
|
||||
_from -= 2*Interpreter::stackElementSize;
|
||||
|
||||
if (_num_int_args < Argument::n_int_register_parameters_c-1) {
|
||||
*_int_args++ = from_obj;
|
||||
_num_int_args++;
|
||||
} else {
|
||||
*_to++ = from_obj;
|
||||
_num_int_args++;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void pass_object()
|
||||
{
|
||||
intptr_t *from_addr = (intptr_t*)(_from + Interpreter::local_offset_in_bytes(0));
|
||||
_from -= Interpreter::stackElementSize;
|
||||
|
||||
if (_num_int_args < Argument::n_int_register_parameters_c-1) {
|
||||
*_int_args++ = (*from_addr == 0) ? NULL : (intptr_t)from_addr;
|
||||
_num_int_args++;
|
||||
} else {
|
||||
*_to++ = (*from_addr == 0) ? NULL : (intptr_t) from_addr;
|
||||
_num_int_args++;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void pass_float()
|
||||
{
|
||||
jint from_obj = *(jint*)(_from+Interpreter::local_offset_in_bytes(0));
|
||||
_from -= Interpreter::stackElementSize;
|
||||
|
||||
if (_num_fp_args < Argument::n_float_register_parameters_c) {
|
||||
*_fp_args++ = from_obj;
|
||||
_num_fp_args++;
|
||||
} else {
|
||||
*_to++ = from_obj;
|
||||
_num_int_args++;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void pass_double()
|
||||
{
|
||||
intptr_t from_obj = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1));
|
||||
_from -= 2*Interpreter::stackElementSize;
|
||||
|
||||
if (_num_fp_args < Argument::n_float_register_parameters_c) {
|
||||
*_fp_args++ = from_obj;
|
||||
*_fp_identifiers |= (1 << _num_fp_args); // mark as double
|
||||
_num_fp_args++;
|
||||
} else {
|
||||
*_to++ = from_obj;
|
||||
_num_int_args++;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
SlowSignatureHandler(methodHandle method, address from, intptr_t* to)
|
||||
: NativeSignatureIterator(method)
|
||||
{
|
||||
_from = from;
|
||||
_to = to;
|
||||
|
||||
_int_args = to - (method->is_static() ? 16 : 17);
|
||||
_fp_args = to - 8;
|
||||
_fp_identifiers = to - 9;
|
||||
*(int*) _fp_identifiers = 0;
|
||||
_num_int_args = (method->is_static() ? 1 : 0);
|
||||
_num_fp_args = 0;
|
||||
}
|
||||
|
||||
// n.b. allow extra 1 for the JNI_Env in c_rarg0
|
||||
unsigned int get_call_format()
|
||||
{
|
||||
unsigned int call_format = ((_num_int_args + 1) << 6) | (_num_fp_args << 2);
|
||||
|
||||
switch (method()->result_type()) {
|
||||
case T_VOID:
|
||||
call_format |= MacroAssembler::ret_type_void;
|
||||
break;
|
||||
case T_FLOAT:
|
||||
call_format |= MacroAssembler::ret_type_float;
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
call_format |= MacroAssembler::ret_type_double;
|
||||
break;
|
||||
default:
|
||||
call_format |= MacroAssembler::ret_type_integral;
|
||||
break;
|
||||
}
|
||||
|
||||
return call_format;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
IRT_ENTRY(address,
|
||||
InterpreterRuntime::slow_signature_handler(JavaThread* thread,
|
||||
Method* method,
|
||||
intptr_t* from,
|
||||
intptr_t* to))
|
||||
methodHandle m(thread, (Method*)method);
|
||||
assert(m->is_native(), "sanity check");
|
||||
|
||||
// handle arguments
|
||||
SlowSignatureHandler ssh(m, (address)from, to);
|
||||
ssh.iterate(UCONST64(-1));
|
||||
|
||||
// // set the call format
|
||||
// method->set_call_format(ssh.get_call_format());
|
||||
|
||||
// return result handler
|
||||
return Interpreter::result_handler(m->result_type());
|
||||
IRT_END
|
||||
66
hotspot/src/cpu/aarch64/vm/interpreterRT_aarch64.hpp
Normal file
66
hotspot/src/cpu/aarch64/vm/interpreterRT_aarch64.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_INTERPRETERRT_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_INTERPRETERRT_AARCH64_HPP
|
||||
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
// native method calls
|
||||
|
||||
class SignatureHandlerGenerator: public NativeSignatureIterator {
|
||||
private:
|
||||
MacroAssembler* _masm;
|
||||
unsigned int _call_format;
|
||||
unsigned int _num_fp_args;
|
||||
unsigned int _num_int_args;
|
||||
int _stack_offset;
|
||||
|
||||
void pass_int();
|
||||
void pass_long();
|
||||
void pass_float();
|
||||
void pass_double();
|
||||
void pass_object();
|
||||
|
||||
public:
|
||||
// Creation
|
||||
SignatureHandlerGenerator(methodHandle method, CodeBuffer* buffer) : NativeSignatureIterator(method) {
|
||||
_masm = new MacroAssembler(buffer);
|
||||
_num_int_args = (method->is_static() ? 1 : 0);
|
||||
_num_fp_args = 0;
|
||||
_stack_offset = 0;
|
||||
}
|
||||
|
||||
// Code generation
|
||||
void generate(uint64_t fingerprint);
|
||||
|
||||
// Code generation support
|
||||
static Register from();
|
||||
static Register to();
|
||||
static Register temp();
|
||||
};
|
||||
|
||||
#endif // CPU_AARCH64_VM_INTERPRETERRT_AARCH64_HPP
|
||||
289
hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp
Normal file
289
hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp
Normal file
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "interpreter/bytecodeHistogram.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/interpreterGenerator.hpp"
|
||||
#include "interpreter/interpreterRuntime.hpp"
|
||||
#include "interpreter/interp_masm.hpp"
|
||||
#include "interpreter/templateTable.hpp"
|
||||
#include "oops/arrayOop.hpp"
|
||||
#include "oops/methodData.hpp"
|
||||
#include "oops/method.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "prims/jvmtiThreadState.hpp"
|
||||
#include "prims/methodHandles.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/deoptimization.hpp"
|
||||
#include "runtime/frame.inline.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
#include "runtime/synchronizer.hpp"
|
||||
#include "runtime/timer.hpp"
|
||||
#include "runtime/vframeArray.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#ifdef COMPILER1
|
||||
#include "c1/c1_Runtime1.hpp"
|
||||
#endif
|
||||
|
||||
#define __ _masm->
|
||||
|
||||
|
||||
address AbstractInterpreterGenerator::generate_slow_signature_handler() {
|
||||
address entry = __ pc();
|
||||
|
||||
__ andr(esp, esp, -16);
|
||||
__ mov(c_rarg3, esp);
|
||||
// rmethod
|
||||
// rlocals
|
||||
// c_rarg3: first stack arg - wordSize
|
||||
|
||||
// adjust sp
|
||||
__ sub(sp, c_rarg3, 18 * wordSize);
|
||||
__ str(lr, Address(__ pre(sp, -2 * wordSize)));
|
||||
__ call_VM(noreg,
|
||||
CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::slow_signature_handler),
|
||||
rmethod, rlocals, c_rarg3);
|
||||
|
||||
// r0: result handler
|
||||
|
||||
// Stack layout:
|
||||
// rsp: return address <- sp
|
||||
// 1 garbage
|
||||
// 8 integer args (if static first is unused)
|
||||
// 1 float/double identifiers
|
||||
// 8 double args
|
||||
// stack args <- esp
|
||||
// garbage
|
||||
// expression stack bottom
|
||||
// bcp (NULL)
|
||||
// ...
|
||||
|
||||
// Restore LR
|
||||
__ ldr(lr, Address(__ post(sp, 2 * wordSize)));
|
||||
|
||||
// Do FP first so we can use c_rarg3 as temp
|
||||
__ ldrw(c_rarg3, Address(sp, 9 * wordSize)); // float/double identifiers
|
||||
|
||||
for (int i = 0; i < Argument::n_float_register_parameters_c; i++) {
|
||||
const FloatRegister r = as_FloatRegister(i);
|
||||
|
||||
Label d, done;
|
||||
|
||||
__ tbnz(c_rarg3, i, d);
|
||||
__ ldrs(r, Address(sp, (10 + i) * wordSize));
|
||||
__ b(done);
|
||||
__ bind(d);
|
||||
__ ldrd(r, Address(sp, (10 + i) * wordSize));
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
// c_rarg0 contains the result from the call of
|
||||
// InterpreterRuntime::slow_signature_handler so we don't touch it
|
||||
// here. It will be loaded with the JNIEnv* later.
|
||||
__ ldr(c_rarg1, Address(sp, 1 * wordSize));
|
||||
for (int i = c_rarg2->encoding(); i <= c_rarg7->encoding(); i += 2) {
|
||||
Register rm = as_Register(i), rn = as_Register(i+1);
|
||||
__ ldp(rm, rn, Address(sp, i * wordSize));
|
||||
}
|
||||
|
||||
__ add(sp, sp, 18 * wordSize);
|
||||
__ ret(lr);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Various method entries
|
||||
//
|
||||
|
||||
address InterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) {
|
||||
// rmethod: Method*
|
||||
// r13: sender sp
|
||||
// esp: args
|
||||
|
||||
if (!InlineIntrinsics) return NULL; // Generate a vanilla entry
|
||||
|
||||
// These don't need a safepoint check because they aren't virtually
|
||||
// callable. We won't enter these intrinsics from compiled code.
|
||||
// If in the future we added an intrinsic which was virtually callable
|
||||
// we'd have to worry about how to safepoint so that this code is used.
|
||||
|
||||
// mathematical functions inlined by compiler
|
||||
// (interpreter must provide identical implementation
|
||||
// in order to avoid monotonicity bugs when switching
|
||||
// from interpreter to compiler in the middle of some
|
||||
// computation)
|
||||
//
|
||||
// stack:
|
||||
// [ arg ] <-- esp
|
||||
// [ arg ]
|
||||
// retaddr in lr
|
||||
|
||||
address entry_point = NULL;
|
||||
Register continuation = lr;
|
||||
switch (kind) {
|
||||
case Interpreter::java_lang_math_abs:
|
||||
entry_point = __ pc();
|
||||
__ ldrd(v0, Address(esp));
|
||||
__ fabsd(v0, v0);
|
||||
__ mov(sp, r13); // Restore caller's SP
|
||||
break;
|
||||
case Interpreter::java_lang_math_sqrt:
|
||||
entry_point = __ pc();
|
||||
__ ldrd(v0, Address(esp));
|
||||
__ fsqrtd(v0, v0);
|
||||
__ mov(sp, r13);
|
||||
break;
|
||||
case Interpreter::java_lang_math_sin :
|
||||
case Interpreter::java_lang_math_cos :
|
||||
case Interpreter::java_lang_math_tan :
|
||||
case Interpreter::java_lang_math_log :
|
||||
case Interpreter::java_lang_math_log10 :
|
||||
case Interpreter::java_lang_math_exp :
|
||||
entry_point = __ pc();
|
||||
__ ldrd(v0, Address(esp));
|
||||
__ mov(sp, r13);
|
||||
__ mov(r19, lr);
|
||||
continuation = r19; // The first callee-saved register
|
||||
generate_transcendental_entry(kind, 1);
|
||||
break;
|
||||
case Interpreter::java_lang_math_pow :
|
||||
entry_point = __ pc();
|
||||
__ mov(r19, lr);
|
||||
continuation = r19;
|
||||
__ ldrd(v0, Address(esp, 2 * Interpreter::stackElementSize));
|
||||
__ ldrd(v1, Address(esp));
|
||||
__ mov(sp, r13);
|
||||
generate_transcendental_entry(kind, 2);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
if (entry_point) {
|
||||
__ br(continuation);
|
||||
}
|
||||
|
||||
return entry_point;
|
||||
}
|
||||
|
||||
// double trigonometrics and transcendentals
|
||||
// static jdouble dsin(jdouble x);
|
||||
// static jdouble dcos(jdouble x);
|
||||
// static jdouble dtan(jdouble x);
|
||||
// static jdouble dlog(jdouble x);
|
||||
// static jdouble dlog10(jdouble x);
|
||||
// static jdouble dexp(jdouble x);
|
||||
// static jdouble dpow(jdouble x, jdouble y);
|
||||
|
||||
void InterpreterGenerator::generate_transcendental_entry(AbstractInterpreter::MethodKind kind, int fpargs) {
|
||||
address fn;
|
||||
switch (kind) {
|
||||
case Interpreter::java_lang_math_sin :
|
||||
fn = CAST_FROM_FN_PTR(address, SharedRuntime::dsin);
|
||||
break;
|
||||
case Interpreter::java_lang_math_cos :
|
||||
fn = CAST_FROM_FN_PTR(address, SharedRuntime::dcos);
|
||||
break;
|
||||
case Interpreter::java_lang_math_tan :
|
||||
fn = CAST_FROM_FN_PTR(address, SharedRuntime::dtan);
|
||||
break;
|
||||
case Interpreter::java_lang_math_log :
|
||||
fn = CAST_FROM_FN_PTR(address, SharedRuntime::dlog);
|
||||
break;
|
||||
case Interpreter::java_lang_math_log10 :
|
||||
fn = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10);
|
||||
break;
|
||||
case Interpreter::java_lang_math_exp :
|
||||
fn = CAST_FROM_FN_PTR(address, SharedRuntime::dexp);
|
||||
break;
|
||||
case Interpreter::java_lang_math_pow :
|
||||
fpargs = 2;
|
||||
fn = CAST_FROM_FN_PTR(address, SharedRuntime::dpow);
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
const int gpargs = 0, rtype = 3;
|
||||
__ mov(rscratch1, fn);
|
||||
__ blrt(rscratch1, gpargs, fpargs, rtype);
|
||||
}
|
||||
|
||||
// Jump into normal path for accessor and empty entry to jump to normal entry
|
||||
// The "fast" optimization don't update compilation count therefore can disable inlining
|
||||
// for these functions that should be inlined.
|
||||
address InterpreterGenerator::generate_jump_to_normal_entry(void) {
|
||||
address entry_point = __ pc();
|
||||
|
||||
assert(Interpreter::entry_for_kind(Interpreter::zerolocals) != NULL, "should already be generated");
|
||||
__ b(Interpreter::entry_for_kind(Interpreter::zerolocals));
|
||||
return entry_point;
|
||||
}
|
||||
|
||||
// Abstract method entry
|
||||
// Attempt to execute abstract method. Throw exception
|
||||
address InterpreterGenerator::generate_abstract_entry(void) {
|
||||
// rmethod: Method*
|
||||
// r13: sender SP
|
||||
|
||||
address entry_point = __ pc();
|
||||
|
||||
// abstract method entry
|
||||
|
||||
// pop return address, reset last_sp to NULL
|
||||
__ empty_expression_stack();
|
||||
__ restore_bcp(); // bcp must be correct for exception handler (was destroyed)
|
||||
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
|
||||
|
||||
// throw exception
|
||||
__ call_VM(noreg, CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::throw_AbstractMethodError));
|
||||
// the call_VM checks for exception, so we should never return here.
|
||||
__ should_not_reach_here();
|
||||
|
||||
return entry_point;
|
||||
}
|
||||
|
||||
|
||||
void Deoptimization::unwind_callee_save_values(frame* f, vframeArray* vframe_array) {
|
||||
|
||||
// This code is sort of the equivalent of C2IAdapter::setup_stack_frame back in
|
||||
// the days we had adapter frames. When we deoptimize a situation where a
|
||||
// compiled caller calls a compiled caller will have registers it expects
|
||||
// to survive the call to the callee. If we deoptimize the callee the only
|
||||
// way we can restore these registers is to have the oldest interpreter
|
||||
// frame that we create restore these values. That is what this routine
|
||||
// will accomplish.
|
||||
|
||||
// At the moment we have modified c2 to not have any callee save registers
|
||||
// so this problem does not exist and this routine is just a place holder.
|
||||
|
||||
assert(f->is_interpreted_frame(), "must be interpreted");
|
||||
}
|
||||
43
hotspot/src/cpu/aarch64/vm/interpreter_aarch64.hpp
Normal file
43
hotspot/src/cpu/aarch64/vm/interpreter_aarch64.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_INTERPRETER_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_INTERPRETER_AARCH64_HPP
|
||||
|
||||
public:
|
||||
|
||||
// Offset from rsp (which points to the last stack element)
|
||||
static int expr_offset_in_bytes(int i) { return stackElementSize * i; }
|
||||
|
||||
// Stack index relative to tos (which points at value)
|
||||
static int expr_index_at(int i) { return stackElementWords * i; }
|
||||
|
||||
// Already negated by c++ interpreter
|
||||
static int local_index_at(int i) {
|
||||
assert(i <= 0, "local direction already negated");
|
||||
return stackElementWords * i;
|
||||
}
|
||||
|
||||
#endif // CPU_AARCH64_VM_INTERPRETER_AARCH64_HPP
|
||||
88
hotspot/src/cpu/aarch64/vm/javaFrameAnchor_aarch64.hpp
Normal file
88
hotspot/src/cpu/aarch64/vm/javaFrameAnchor_aarch64.hpp
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_JAVAFRAMEANCHOR_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_JAVAFRAMEANCHOR_AARCH64_HPP
|
||||
|
||||
private:
|
||||
|
||||
// FP value associated with _last_Java_sp:
|
||||
intptr_t* volatile _last_Java_fp; // pointer is volatile not what it points to
|
||||
|
||||
public:
|
||||
// Each arch must define reset, save, restore
|
||||
// These are used by objects that only care about:
|
||||
// 1 - initializing a new state (thread creation, javaCalls)
|
||||
// 2 - saving a current state (javaCalls)
|
||||
// 3 - restoring an old state (javaCalls)
|
||||
|
||||
void clear(void) {
|
||||
// clearing _last_Java_sp must be first
|
||||
_last_Java_sp = NULL;
|
||||
OrderAccess::release();
|
||||
_last_Java_fp = NULL;
|
||||
_last_Java_pc = NULL;
|
||||
}
|
||||
|
||||
void copy(JavaFrameAnchor* src) {
|
||||
// In order to make sure the transition state is valid for "this"
|
||||
// We must clear _last_Java_sp before copying the rest of the new data
|
||||
//
|
||||
// Hack Alert: Temporary bugfix for 4717480/4721647
|
||||
// To act like previous version (pd_cache_state) don't NULL _last_Java_sp
|
||||
// unless the value is changing
|
||||
//
|
||||
if (_last_Java_sp != src->_last_Java_sp) {
|
||||
_last_Java_sp = NULL;
|
||||
OrderAccess::release();
|
||||
}
|
||||
_last_Java_fp = src->_last_Java_fp;
|
||||
_last_Java_pc = src->_last_Java_pc;
|
||||
// Must be last so profiler will always see valid frame if has_last_frame() is true
|
||||
_last_Java_sp = src->_last_Java_sp;
|
||||
}
|
||||
|
||||
// Always walkable
|
||||
bool walkable(void) { return true; }
|
||||
// Never any thing to do since we are always walkable and can find address of return addresses
|
||||
void make_walkable(JavaThread* thread) { }
|
||||
|
||||
intptr_t* last_Java_sp(void) const { return _last_Java_sp; }
|
||||
|
||||
address last_Java_pc(void) { return _last_Java_pc; }
|
||||
|
||||
private:
|
||||
|
||||
static ByteSize last_Java_fp_offset() { return byte_offset_of(JavaFrameAnchor, _last_Java_fp); }
|
||||
|
||||
public:
|
||||
|
||||
void set_last_Java_sp(intptr_t* sp) { _last_Java_sp = sp; OrderAccess::release(); }
|
||||
|
||||
intptr_t* last_Java_fp(void) { return _last_Java_fp; }
|
||||
// Assert (last_Java_sp == NULL || fp == NULL)
|
||||
void set_last_Java_fp(intptr_t* fp) { OrderAccess::release(); _last_Java_fp = fp; }
|
||||
|
||||
#endif // CPU_AARCH64_VM_JAVAFRAMEANCHOR_AARCH64_HPP
|
||||
174
hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp
Normal file
174
hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "prims/jniFastGetField.hpp"
|
||||
#include "prims/jvm_misc.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
|
||||
#define __ masm->
|
||||
|
||||
#define BUFFER_SIZE 30*wordSize
|
||||
|
||||
// Instead of issuing a LoadLoad barrier we create an address
|
||||
// dependency between loads; this might be more efficient.
|
||||
|
||||
// Common register usage:
|
||||
// r0/v0: result
|
||||
// c_rarg0: jni env
|
||||
// c_rarg1: obj
|
||||
// c_rarg2: jfield id
|
||||
|
||||
static const Register robj = r3;
|
||||
static const Register rcounter = r4;
|
||||
static const Register roffset = r5;
|
||||
static const Register rcounter_addr = r6;
|
||||
static const Register result = r7;
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
|
||||
const char *name;
|
||||
switch (type) {
|
||||
case T_BOOLEAN: name = "jni_fast_GetBooleanField"; break;
|
||||
case T_BYTE: name = "jni_fast_GetByteField"; break;
|
||||
case T_CHAR: name = "jni_fast_GetCharField"; break;
|
||||
case T_SHORT: name = "jni_fast_GetShortField"; break;
|
||||
case T_INT: name = "jni_fast_GetIntField"; break;
|
||||
case T_LONG: name = "jni_fast_GetLongField"; break;
|
||||
case T_FLOAT: name = "jni_fast_GetFloatField"; break;
|
||||
case T_DOUBLE: name = "jni_fast_GetDoubleField"; break;
|
||||
default: ShouldNotReachHere();
|
||||
}
|
||||
ResourceMark rm;
|
||||
BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE);
|
||||
CodeBuffer cbuf(blob);
|
||||
MacroAssembler* masm = new MacroAssembler(&cbuf);
|
||||
address fast_entry = __ pc();
|
||||
|
||||
Label slow;
|
||||
|
||||
unsigned long offset;
|
||||
__ adrp(rcounter_addr,
|
||||
SafepointSynchronize::safepoint_counter_addr(), offset);
|
||||
Address safepoint_counter_addr(rcounter_addr, offset);
|
||||
__ ldrw(rcounter, safepoint_counter_addr);
|
||||
__ andw(rscratch1, rcounter, 1);
|
||||
__ cbnzw(rscratch1, slow);
|
||||
__ eor(robj, c_rarg1, rcounter);
|
||||
__ eor(robj, robj, rcounter); // obj, since
|
||||
// robj ^ rcounter ^ rcounter == robj
|
||||
// robj is address dependent on rcounter.
|
||||
__ ldr(robj, Address(robj, 0)); // *obj
|
||||
__ lsr(roffset, c_rarg2, 2); // offset
|
||||
|
||||
assert(count < LIST_CAPACITY, "LIST_CAPACITY too small");
|
||||
speculative_load_pclist[count] = __ pc(); // Used by the segfault handler
|
||||
switch (type) {
|
||||
case T_BOOLEAN: __ ldrb (result, Address(robj, roffset)); break;
|
||||
case T_BYTE: __ ldrsb (result, Address(robj, roffset)); break;
|
||||
case T_CHAR: __ ldrh (result, Address(robj, roffset)); break;
|
||||
case T_SHORT: __ ldrsh (result, Address(robj, roffset)); break;
|
||||
case T_FLOAT: __ ldrw (result, Address(robj, roffset)); break;
|
||||
case T_INT: __ ldrsw (result, Address(robj, roffset)); break;
|
||||
case T_DOUBLE:
|
||||
case T_LONG: __ ldr (result, Address(robj, roffset)); break;
|
||||
default: ShouldNotReachHere();
|
||||
}
|
||||
|
||||
// counter_addr is address dependent on result.
|
||||
__ eor(rcounter_addr, rcounter_addr, result);
|
||||
__ eor(rcounter_addr, rcounter_addr, result);
|
||||
__ ldrw(rscratch1, safepoint_counter_addr);
|
||||
__ cmpw(rcounter, rscratch1);
|
||||
__ br (Assembler::NE, slow);
|
||||
|
||||
switch (type) {
|
||||
case T_FLOAT: __ fmovs(v0, result); break;
|
||||
case T_DOUBLE: __ fmovd(v0, result); break;
|
||||
default: __ mov(r0, result); break;
|
||||
}
|
||||
__ ret(lr);
|
||||
|
||||
slowcase_entry_pclist[count++] = __ pc();
|
||||
__ bind(slow);
|
||||
address slow_case_addr;
|
||||
switch (type) {
|
||||
case T_BOOLEAN: slow_case_addr = jni_GetBooleanField_addr(); break;
|
||||
case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break;
|
||||
case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break;
|
||||
case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break;
|
||||
case T_INT: slow_case_addr = jni_GetIntField_addr(); break;
|
||||
case T_LONG: slow_case_addr = jni_GetLongField_addr(); break;
|
||||
case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break;
|
||||
case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break;
|
||||
default: ShouldNotReachHere();
|
||||
}
|
||||
|
||||
{
|
||||
__ enter();
|
||||
__ lea(rscratch1, ExternalAddress(slow_case_addr));
|
||||
__ blr(rscratch1);
|
||||
__ maybe_isb();
|
||||
__ leave();
|
||||
__ ret(lr);
|
||||
}
|
||||
__ flush ();
|
||||
|
||||
return fast_entry;
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_boolean_field() {
|
||||
return generate_fast_get_int_field0(T_BOOLEAN);
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_byte_field() {
|
||||
return generate_fast_get_int_field0(T_BYTE);
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_char_field() {
|
||||
return generate_fast_get_int_field0(T_CHAR);
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_short_field() {
|
||||
return generate_fast_get_int_field0(T_SHORT);
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_int_field() {
|
||||
return generate_fast_get_int_field0(T_INT);
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_long_field() {
|
||||
return generate_fast_get_int_field0(T_LONG);
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_float_field() {
|
||||
return generate_fast_get_int_field0(T_FLOAT);
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_double_field() {
|
||||
return generate_fast_get_int_field0(T_DOUBLE);
|
||||
}
|
||||
|
||||
107
hotspot/src/cpu/aarch64/vm/jniTypes_aarch64.hpp
Normal file
107
hotspot/src/cpu/aarch64/vm/jniTypes_aarch64.hpp
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_JNITYPES_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_JNITYPES_AARCH64_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "prims/jni.h"
|
||||
|
||||
// This file holds platform-dependent routines used to write primitive jni
|
||||
// types to the array of arguments passed into JavaCalls::call
|
||||
|
||||
class JNITypes : AllStatic {
|
||||
// These functions write a java primitive type (in native format)
|
||||
// to a java stack slot array to be passed as an argument to JavaCalls:calls.
|
||||
// I.e., they are functionally 'push' operations if they have a 'pos'
|
||||
// formal parameter. Note that jlong's and jdouble's are written
|
||||
// _in reverse_ of the order in which they appear in the interpreter
|
||||
// stack. This is because call stubs (see stubGenerator_sparc.cpp)
|
||||
// reverse the argument list constructed by JavaCallArguments (see
|
||||
// javaCalls.hpp).
|
||||
|
||||
public:
|
||||
// Ints are stored in native format in one JavaCallArgument slot at *to.
|
||||
static inline void put_int(jint from, intptr_t *to) { *(jint *)(to + 0 ) = from; }
|
||||
static inline void put_int(jint from, intptr_t *to, int& pos) { *(jint *)(to + pos++) = from; }
|
||||
static inline void put_int(jint *from, intptr_t *to, int& pos) { *(jint *)(to + pos++) = *from; }
|
||||
|
||||
// Longs are stored in native format in one JavaCallArgument slot at
|
||||
// *(to+1).
|
||||
static inline void put_long(jlong from, intptr_t *to) {
|
||||
*(jlong*) (to + 1) = from;
|
||||
}
|
||||
|
||||
static inline void put_long(jlong from, intptr_t *to, int& pos) {
|
||||
*(jlong*) (to + 1 + pos) = from;
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
static inline void put_long(jlong *from, intptr_t *to, int& pos) {
|
||||
*(jlong*) (to + 1 + pos) = *from;
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
// Oops are stored in native format in one JavaCallArgument slot at *to.
|
||||
static inline void put_obj(oop from, intptr_t *to) { *(oop *)(to + 0 ) = from; }
|
||||
static inline void put_obj(oop from, intptr_t *to, int& pos) { *(oop *)(to + pos++) = from; }
|
||||
static inline void put_obj(oop *from, intptr_t *to, int& pos) { *(oop *)(to + pos++) = *from; }
|
||||
|
||||
// Floats are stored in native format in one JavaCallArgument slot at *to.
|
||||
static inline void put_float(jfloat from, intptr_t *to) { *(jfloat *)(to + 0 ) = from; }
|
||||
static inline void put_float(jfloat from, intptr_t *to, int& pos) { *(jfloat *)(to + pos++) = from; }
|
||||
static inline void put_float(jfloat *from, intptr_t *to, int& pos) { *(jfloat *)(to + pos++) = *from; }
|
||||
|
||||
#undef _JNI_SLOT_OFFSET
|
||||
#define _JNI_SLOT_OFFSET 1
|
||||
// Doubles are stored in native word format in one JavaCallArgument
|
||||
// slot at *(to+1).
|
||||
static inline void put_double(jdouble from, intptr_t *to) {
|
||||
*(jdouble*) (to + 1) = from;
|
||||
}
|
||||
|
||||
static inline void put_double(jdouble from, intptr_t *to, int& pos) {
|
||||
*(jdouble*) (to + 1 + pos) = from;
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
static inline void put_double(jdouble *from, intptr_t *to, int& pos) {
|
||||
*(jdouble*) (to + 1 + pos) = *from;
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
// The get_xxx routines, on the other hand, actually _do_ fetch
|
||||
// java primitive types from the interpreter stack.
|
||||
// No need to worry about alignment on Intel.
|
||||
static inline jint get_int (intptr_t *from) { return *(jint *) from; }
|
||||
static inline jlong get_long (intptr_t *from) { return *(jlong *) (from + _JNI_SLOT_OFFSET); }
|
||||
static inline oop get_obj (intptr_t *from) { return *(oop *) from; }
|
||||
static inline jfloat get_float (intptr_t *from) { return *(jfloat *) from; }
|
||||
static inline jdouble get_double(intptr_t *from) { return *(jdouble *)(from + _JNI_SLOT_OFFSET); }
|
||||
#undef _JNI_SLOT_OFFSET
|
||||
};
|
||||
|
||||
#endif // CPU_AARCH64_VM_JNITYPES_AARCH64_HPP
|
||||
60
hotspot/src/cpu/aarch64/vm/jni_aarch64.h
Normal file
60
hotspot/src/cpu/aarch64/vm/jni_aarch64.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _JAVASOFT_JNI_MD_H_
|
||||
#define _JAVASOFT_JNI_MD_H_
|
||||
|
||||
#if defined(SOLARIS) || defined(LINUX) || defined(_ALLBSD_SOURCE)
|
||||
|
||||
|
||||
// Note: please do not change these without also changing jni_md.h in the JDK
|
||||
// repository
|
||||
#ifndef __has_attribute
|
||||
#define __has_attribute(x) 0
|
||||
#endif
|
||||
#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
|
||||
#define JNIEXPORT __attribute__((visibility("default")))
|
||||
#define JNIIMPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define JNIEXPORT
|
||||
#define JNIIMPORT
|
||||
#endif
|
||||
|
||||
#define JNICALL
|
||||
typedef int jint;
|
||||
typedef long jlong;
|
||||
|
||||
#else
|
||||
#define JNIEXPORT __declspec(dllexport)
|
||||
#define JNIIMPORT __declspec(dllimport)
|
||||
#define JNICALL __stdcall
|
||||
|
||||
typedef int jint;
|
||||
typedef __int64 jlong;
|
||||
#endif
|
||||
|
||||
typedef signed char jbyte;
|
||||
|
||||
#endif /* !_JAVASOFT_JNI_MD_H_ */
|
||||
4138
hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
Normal file
4138
hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1162
hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp
Normal file
1162
hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp
Normal file
File diff suppressed because it is too large
Load Diff
35
hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.inline.hpp
Normal file
35
hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.inline.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_MACROASSEMBLER_AARCH64_INLINE_HPP
|
||||
#define CPU_AARCH64_VM_MACROASSEMBLER_AARCH64_INLINE_HPP
|
||||
|
||||
#include "asm/assembler.hpp"
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
#endif // ndef PRODUCT
|
||||
|
||||
#endif // CPU_AARCH64_VM_MACROASSEMBLER_AARCH64_INLINE_HPP
|
||||
126
hotspot/src/cpu/aarch64/vm/metaspaceShared_aarch64.cpp
Normal file
126
hotspot/src/cpu/aarch64/vm/metaspaceShared_aarch64.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
|
||||
// Generate the self-patching vtable method:
|
||||
//
|
||||
// This method will be called (as any other Klass virtual method) with
|
||||
// the Klass itself as the first argument. Example:
|
||||
//
|
||||
// oop obj;
|
||||
// int size = obj->klass()->oop_size(this);
|
||||
//
|
||||
// for which the virtual method call is Klass::oop_size();
|
||||
//
|
||||
// The dummy method is called with the Klass object as the first
|
||||
// operand, and an object as the second argument.
|
||||
//
|
||||
|
||||
//=====================================================================
|
||||
|
||||
// All of the dummy methods in the vtable are essentially identical,
|
||||
// differing only by an ordinal constant, and they bear no relationship
|
||||
// to the original method which the caller intended. Also, there needs
|
||||
// to be 'vtbl_list_size' instances of the vtable in order to
|
||||
// differentiate between the 'vtable_list_size' original Klass objects.
|
||||
|
||||
#define __ masm->
|
||||
|
||||
extern "C" {
|
||||
void aarch64_prolog(void);
|
||||
}
|
||||
|
||||
void MetaspaceShared::generate_vtable_methods(void** vtbl_list,
|
||||
void** vtable,
|
||||
char** md_top,
|
||||
char* md_end,
|
||||
char** mc_top,
|
||||
char* mc_end) {
|
||||
|
||||
#ifdef BUILTIN_SIM
|
||||
// Write a dummy word to the writable shared metaspace.
|
||||
// MetaspaceShared::initialize_shared_spaces will fill it with the
|
||||
// address of aarch64_prolog().
|
||||
address *prolog_ptr = (address*)*md_top;
|
||||
*(intptr_t *)(*md_top) = (intptr_t)0;
|
||||
(*md_top) += sizeof(intptr_t);
|
||||
#endif
|
||||
|
||||
intptr_t vtable_bytes = (num_virtuals * vtbl_list_size) * sizeof(void*);
|
||||
*(intptr_t *)(*md_top) = vtable_bytes;
|
||||
*md_top += sizeof(intptr_t);
|
||||
void** dummy_vtable = (void**)*md_top;
|
||||
*vtable = dummy_vtable;
|
||||
*md_top += vtable_bytes;
|
||||
|
||||
// Get ready to generate dummy methods.
|
||||
|
||||
CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top);
|
||||
MacroAssembler* masm = new MacroAssembler(&cb);
|
||||
|
||||
Label common_code;
|
||||
for (int i = 0; i < vtbl_list_size; ++i) {
|
||||
for (int j = 0; j < num_virtuals; ++j) {
|
||||
dummy_vtable[num_virtuals * i + j] = (void*)masm->pc();
|
||||
|
||||
// We're called directly from C code.
|
||||
#ifdef BUILTIN_SIM
|
||||
__ c_stub_prolog(8, 0, MacroAssembler::ret_type_integral, prolog_ptr);
|
||||
#endif
|
||||
// Load rscratch1 with a value indicating vtable/offset pair.
|
||||
// -- bits[ 7..0] (8 bits) which virtual method in table?
|
||||
// -- bits[12..8] (5 bits) which virtual method table?
|
||||
__ mov(rscratch1, (i << 8) + j);
|
||||
__ b(common_code);
|
||||
}
|
||||
}
|
||||
|
||||
__ bind(common_code);
|
||||
|
||||
Register tmp0 = r10, tmp1 = r11; // AAPCS64 temporary registers
|
||||
__ enter();
|
||||
__ lsr(tmp0, rscratch1, 8); // isolate vtable identifier.
|
||||
__ mov(tmp1, (address)vtbl_list); // address of list of vtable pointers.
|
||||
__ ldr(tmp1, Address(tmp1, tmp0, Address::lsl(LogBytesPerWord))); // get correct vtable pointer.
|
||||
__ str(tmp1, Address(c_rarg0)); // update vtable pointer in obj.
|
||||
__ add(rscratch1, tmp1, rscratch1, ext::uxtb, LogBytesPerWord); // address of real method pointer.
|
||||
__ ldr(rscratch1, Address(rscratch1)); // get real method pointer.
|
||||
__ blrt(rscratch1, 8, 0, 1); // jump to the real method.
|
||||
__ leave();
|
||||
__ ret(lr);
|
||||
|
||||
*mc_top = (char*)__ pc();
|
||||
}
|
||||
|
||||
#ifdef BUILTIN_SIM
|
||||
void MetaspaceShared::relocate_vtbl_list(char **buffer) {
|
||||
void **sim_entry = (void**)*buffer;
|
||||
*sim_entry = (void*)aarch64_prolog;
|
||||
*buffer += sizeof(intptr_t);
|
||||
}
|
||||
#endif
|
||||
443
hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.cpp
Normal file
443
hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.cpp
Normal file
@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/interpreterRuntime.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "prims/methodHandles.hpp"
|
||||
|
||||
#define __ _masm->
|
||||
|
||||
#ifdef PRODUCT
|
||||
#define BLOCK_COMMENT(str) /* nothing */
|
||||
#else
|
||||
#define BLOCK_COMMENT(str) __ block_comment(str)
|
||||
#endif
|
||||
|
||||
#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
|
||||
|
||||
void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_reg) {
|
||||
if (VerifyMethodHandles)
|
||||
verify_klass(_masm, klass_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_Class),
|
||||
"MH argument is a Class");
|
||||
__ ldr(klass_reg, Address(klass_reg, java_lang_Class::klass_offset_in_bytes()));
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
static int check_nonzero(const char* xname, int x) {
|
||||
assert(x != 0, err_msg("%s should be nonzero", xname));
|
||||
return x;
|
||||
}
|
||||
#define NONZERO(x) check_nonzero(#x, x)
|
||||
#else //ASSERT
|
||||
#define NONZERO(x) (x)
|
||||
#endif //PRODUCT
|
||||
|
||||
#ifdef ASSERT
|
||||
void MethodHandles::verify_klass(MacroAssembler* _masm,
|
||||
Register obj, SystemDictionary::WKID klass_id,
|
||||
const char* error_message) {
|
||||
Klass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id);
|
||||
KlassHandle klass = SystemDictionary::well_known_klass(klass_id);
|
||||
Register temp = rscratch2;
|
||||
Register temp2 = rscratch1; // used by MacroAssembler::cmpptr
|
||||
Label L_ok, L_bad;
|
||||
BLOCK_COMMENT("verify_klass {");
|
||||
__ verify_oop(obj);
|
||||
__ cbz(obj, L_bad);
|
||||
__ push(RegSet::of(temp, temp2), sp);
|
||||
__ load_klass(temp, obj);
|
||||
__ cmpptr(temp, ExternalAddress((address) klass_addr));
|
||||
__ br(Assembler::EQ, L_ok);
|
||||
intptr_t super_check_offset = klass->super_check_offset();
|
||||
__ ldr(temp, Address(temp, super_check_offset));
|
||||
__ cmpptr(temp, ExternalAddress((address) klass_addr));
|
||||
__ br(Assembler::EQ, L_ok);
|
||||
__ pop(RegSet::of(temp, temp2), sp);
|
||||
__ bind(L_bad);
|
||||
__ stop(error_message);
|
||||
__ BIND(L_ok);
|
||||
__ pop(RegSet::of(temp, temp2), sp);
|
||||
BLOCK_COMMENT("} verify_klass");
|
||||
}
|
||||
|
||||
void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) { }
|
||||
|
||||
#endif //ASSERT
|
||||
|
||||
void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp,
|
||||
bool for_compiler_entry) {
|
||||
assert(method == rmethod, "interpreter calling convention");
|
||||
Label L_no_such_method;
|
||||
__ cbz(rmethod, L_no_such_method);
|
||||
__ verify_method_ptr(method);
|
||||
|
||||
if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) {
|
||||
Label run_compiled_code;
|
||||
// JVMTI events, such as single-stepping, are implemented partly by avoiding running
|
||||
// compiled code in threads for which the event is enabled. Check here for
|
||||
// interp_only_mode if these events CAN be enabled.
|
||||
|
||||
__ ldrb(rscratch1, Address(rthread, JavaThread::interp_only_mode_offset()));
|
||||
__ cbnz(rscratch1, run_compiled_code);
|
||||
__ ldr(rscratch1, Address(method, Method::interpreter_entry_offset()));
|
||||
__ br(rscratch1);
|
||||
__ BIND(run_compiled_code);
|
||||
}
|
||||
|
||||
const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() :
|
||||
Method::from_interpreted_offset();
|
||||
__ ldr(rscratch1,Address(method, entry_offset));
|
||||
__ br(rscratch1);
|
||||
__ bind(L_no_such_method);
|
||||
__ far_jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry()));
|
||||
}
|
||||
|
||||
void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm,
|
||||
Register recv, Register method_temp,
|
||||
Register temp2,
|
||||
bool for_compiler_entry) {
|
||||
BLOCK_COMMENT("jump_to_lambda_form {");
|
||||
// This is the initial entry point of a lazy method handle.
|
||||
// After type checking, it picks up the invoker from the LambdaForm.
|
||||
assert_different_registers(recv, method_temp, temp2);
|
||||
assert(recv != noreg, "required register");
|
||||
assert(method_temp == rmethod, "required register for loading method");
|
||||
|
||||
//NOT_PRODUCT({ FlagSetting fs(TraceMethodHandles, true); trace_method_handle(_masm, "LZMH"); });
|
||||
|
||||
// Load the invoker, as MH -> MH.form -> LF.vmentry
|
||||
__ verify_oop(recv);
|
||||
__ load_heap_oop(method_temp, Address(recv, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes())));
|
||||
__ verify_oop(method_temp);
|
||||
__ load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes())));
|
||||
__ verify_oop(method_temp);
|
||||
// the following assumes that a Method* is normally compressed in the vmtarget field:
|
||||
__ ldr(method_temp, Address(method_temp, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes())));
|
||||
|
||||
if (VerifyMethodHandles && !for_compiler_entry) {
|
||||
// make sure recv is already on stack
|
||||
__ ldr(temp2, Address(method_temp, Method::const_offset()));
|
||||
__ load_sized_value(temp2,
|
||||
Address(temp2, ConstMethod::size_of_parameters_offset()),
|
||||
sizeof(u2), /*is_signed*/ false);
|
||||
// assert(sizeof(u2) == sizeof(Method::_size_of_parameters), "");
|
||||
Label L;
|
||||
__ ldr(rscratch1, __ argument_address(temp2, -1));
|
||||
__ cmp(recv, rscratch1);
|
||||
__ br(Assembler::EQ, L);
|
||||
__ ldr(r0, __ argument_address(temp2, -1));
|
||||
__ hlt(0);
|
||||
__ BIND(L);
|
||||
}
|
||||
|
||||
jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry);
|
||||
BLOCK_COMMENT("} jump_to_lambda_form");
|
||||
}
|
||||
|
||||
// Code generation
|
||||
address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm,
|
||||
vmIntrinsics::ID iid) {
|
||||
const bool not_for_compiler_entry = false; // this is the interpreter entry
|
||||
assert(is_signature_polymorphic(iid), "expected invoke iid");
|
||||
if (iid == vmIntrinsics::_invokeGeneric ||
|
||||
iid == vmIntrinsics::_compiledLambdaForm) {
|
||||
// Perhaps surprisingly, the symbolic references visible to Java are not directly used.
|
||||
// They are linked to Java-generated adapters via MethodHandleNatives.linkMethod.
|
||||
// They all allow an appendix argument.
|
||||
__ hlt(0); // empty stubs make SG sick
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// r13: sender SP (must preserve; see prepare_to_jump_from_interpreted)
|
||||
// rmethod: Method*
|
||||
// r3: argument locator (parameter slot count, added to rsp)
|
||||
// r1: used as temp to hold mh or receiver
|
||||
// r0, r11: garbage temps, blown away
|
||||
Register argp = r3; // argument list ptr, live on error paths
|
||||
Register temp = r0;
|
||||
Register mh = r1; // MH receiver; dies quickly and is recycled
|
||||
|
||||
// here's where control starts out:
|
||||
__ align(CodeEntryAlignment);
|
||||
address entry_point = __ pc();
|
||||
|
||||
if (VerifyMethodHandles) {
|
||||
Label L;
|
||||
BLOCK_COMMENT("verify_intrinsic_id {");
|
||||
__ ldrb(rscratch1, Address(rmethod, Method::intrinsic_id_offset_in_bytes()));
|
||||
__ cmp(rscratch1, (int) iid);
|
||||
__ br(Assembler::EQ, L);
|
||||
if (iid == vmIntrinsics::_linkToVirtual ||
|
||||
iid == vmIntrinsics::_linkToSpecial) {
|
||||
// could do this for all kinds, but would explode assembly code size
|
||||
trace_method_handle(_masm, "bad Method*::intrinsic_id");
|
||||
}
|
||||
__ hlt(0);
|
||||
__ bind(L);
|
||||
BLOCK_COMMENT("} verify_intrinsic_id");
|
||||
}
|
||||
|
||||
// First task: Find out how big the argument list is.
|
||||
Address r3_first_arg_addr;
|
||||
int ref_kind = signature_polymorphic_intrinsic_ref_kind(iid);
|
||||
assert(ref_kind != 0 || iid == vmIntrinsics::_invokeBasic, "must be _invokeBasic or a linkTo intrinsic");
|
||||
if (ref_kind == 0 || MethodHandles::ref_kind_has_receiver(ref_kind)) {
|
||||
__ ldr(argp, Address(rmethod, Method::const_offset()));
|
||||
__ load_sized_value(argp,
|
||||
Address(argp, ConstMethod::size_of_parameters_offset()),
|
||||
sizeof(u2), /*is_signed*/ false);
|
||||
// assert(sizeof(u2) == sizeof(Method::_size_of_parameters), "");
|
||||
r3_first_arg_addr = __ argument_address(argp, -1);
|
||||
} else {
|
||||
DEBUG_ONLY(argp = noreg);
|
||||
}
|
||||
|
||||
if (!is_signature_polymorphic_static(iid)) {
|
||||
__ ldr(mh, r3_first_arg_addr);
|
||||
DEBUG_ONLY(argp = noreg);
|
||||
}
|
||||
|
||||
// r3_first_arg_addr is live!
|
||||
|
||||
trace_method_handle_interpreter_entry(_masm, iid);
|
||||
if (iid == vmIntrinsics::_invokeBasic) {
|
||||
generate_method_handle_dispatch(_masm, iid, mh, noreg, not_for_compiler_entry);
|
||||
|
||||
} else {
|
||||
// Adjust argument list by popping the trailing MemberName argument.
|
||||
Register recv = noreg;
|
||||
if (MethodHandles::ref_kind_has_receiver(ref_kind)) {
|
||||
// Load the receiver (not the MH; the actual MemberName's receiver) up from the interpreter stack.
|
||||
__ ldr(recv = r2, r3_first_arg_addr);
|
||||
}
|
||||
DEBUG_ONLY(argp = noreg);
|
||||
Register rmember = rmethod; // MemberName ptr; incoming method ptr is dead now
|
||||
__ pop(rmember); // extract last argument
|
||||
generate_method_handle_dispatch(_masm, iid, recv, rmember, not_for_compiler_entry);
|
||||
}
|
||||
|
||||
return entry_point;
|
||||
}
|
||||
|
||||
|
||||
void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm,
|
||||
vmIntrinsics::ID iid,
|
||||
Register receiver_reg,
|
||||
Register member_reg,
|
||||
bool for_compiler_entry) {
|
||||
assert(is_signature_polymorphic(iid), "expected invoke iid");
|
||||
// temps used in this code are not used in *either* compiled or interpreted calling sequences
|
||||
Register temp1 = r10;
|
||||
Register temp2 = r11;
|
||||
Register temp3 = r14; // r13 is live by this point: it contains the sender SP
|
||||
if (for_compiler_entry) {
|
||||
assert(receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : j_rarg0), "only valid assignment");
|
||||
assert_different_registers(temp1, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7);
|
||||
assert_different_registers(temp2, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7);
|
||||
assert_different_registers(temp3, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7);
|
||||
}
|
||||
|
||||
assert_different_registers(temp1, temp2, temp3, receiver_reg);
|
||||
assert_different_registers(temp1, temp2, temp3, member_reg);
|
||||
|
||||
if (iid == vmIntrinsics::_invokeBasic) {
|
||||
// indirect through MH.form.vmentry.vmtarget
|
||||
jump_to_lambda_form(_masm, receiver_reg, rmethod, temp1, for_compiler_entry);
|
||||
|
||||
} else {
|
||||
// The method is a member invoker used by direct method handles.
|
||||
if (VerifyMethodHandles) {
|
||||
// make sure the trailing argument really is a MemberName (caller responsibility)
|
||||
verify_klass(_masm, member_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_invoke_MemberName),
|
||||
"MemberName required for invokeVirtual etc.");
|
||||
}
|
||||
|
||||
Address member_clazz( member_reg, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()));
|
||||
Address member_vmindex( member_reg, NONZERO(java_lang_invoke_MemberName::vmindex_offset_in_bytes()));
|
||||
Address member_vmtarget( member_reg, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes()));
|
||||
|
||||
Register temp1_recv_klass = temp1;
|
||||
if (iid != vmIntrinsics::_linkToStatic) {
|
||||
__ verify_oop(receiver_reg);
|
||||
if (iid == vmIntrinsics::_linkToSpecial) {
|
||||
// Don't actually load the klass; just null-check the receiver.
|
||||
__ null_check(receiver_reg);
|
||||
} else {
|
||||
// load receiver klass itself
|
||||
__ null_check(receiver_reg, oopDesc::klass_offset_in_bytes());
|
||||
__ load_klass(temp1_recv_klass, receiver_reg);
|
||||
__ verify_klass_ptr(temp1_recv_klass);
|
||||
}
|
||||
BLOCK_COMMENT("check_receiver {");
|
||||
// The receiver for the MemberName must be in receiver_reg.
|
||||
// Check the receiver against the MemberName.clazz
|
||||
if (VerifyMethodHandles && iid == vmIntrinsics::_linkToSpecial) {
|
||||
// Did not load it above...
|
||||
__ load_klass(temp1_recv_klass, receiver_reg);
|
||||
__ verify_klass_ptr(temp1_recv_klass);
|
||||
}
|
||||
if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) {
|
||||
Label L_ok;
|
||||
Register temp2_defc = temp2;
|
||||
__ load_heap_oop(temp2_defc, member_clazz);
|
||||
load_klass_from_Class(_masm, temp2_defc);
|
||||
__ verify_klass_ptr(temp2_defc);
|
||||
__ check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, L_ok);
|
||||
// If we get here, the type check failed!
|
||||
__ hlt(0);
|
||||
// __ STOP("receiver class disagrees with MemberName.clazz");
|
||||
__ bind(L_ok);
|
||||
}
|
||||
BLOCK_COMMENT("} check_receiver");
|
||||
}
|
||||
if (iid == vmIntrinsics::_linkToSpecial ||
|
||||
iid == vmIntrinsics::_linkToStatic) {
|
||||
DEBUG_ONLY(temp1_recv_klass = noreg); // these guys didn't load the recv_klass
|
||||
}
|
||||
|
||||
// Live registers at this point:
|
||||
// member_reg - MemberName that was the trailing argument
|
||||
// temp1_recv_klass - klass of stacked receiver, if needed
|
||||
// r13 - interpreter linkage (if interpreted) ??? FIXME
|
||||
// r1 ... r0 - compiler arguments (if compiled)
|
||||
|
||||
Label L_incompatible_class_change_error;
|
||||
switch (iid) {
|
||||
case vmIntrinsics::_linkToSpecial:
|
||||
if (VerifyMethodHandles) {
|
||||
verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp3);
|
||||
}
|
||||
__ ldr(rmethod, member_vmtarget);
|
||||
break;
|
||||
|
||||
case vmIntrinsics::_linkToStatic:
|
||||
if (VerifyMethodHandles) {
|
||||
verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp3);
|
||||
}
|
||||
__ ldr(rmethod, member_vmtarget);
|
||||
break;
|
||||
|
||||
case vmIntrinsics::_linkToVirtual:
|
||||
{
|
||||
// same as TemplateTable::invokevirtual,
|
||||
// minus the CP setup and profiling:
|
||||
|
||||
if (VerifyMethodHandles) {
|
||||
verify_ref_kind(_masm, JVM_REF_invokeVirtual, member_reg, temp3);
|
||||
}
|
||||
|
||||
// pick out the vtable index from the MemberName, and then we can discard it:
|
||||
Register temp2_index = temp2;
|
||||
__ ldr(temp2_index, member_vmindex);
|
||||
|
||||
if (VerifyMethodHandles) {
|
||||
Label L_index_ok;
|
||||
__ cmpw(temp2_index, 0U);
|
||||
__ br(Assembler::GE, L_index_ok);
|
||||
__ hlt(0);
|
||||
__ BIND(L_index_ok);
|
||||
}
|
||||
|
||||
// Note: The verifier invariants allow us to ignore MemberName.clazz and vmtarget
|
||||
// at this point. And VerifyMethodHandles has already checked clazz, if needed.
|
||||
|
||||
// get target Method* & entry point
|
||||
__ lookup_virtual_method(temp1_recv_klass, temp2_index, rmethod);
|
||||
break;
|
||||
}
|
||||
|
||||
case vmIntrinsics::_linkToInterface:
|
||||
{
|
||||
// same as TemplateTable::invokeinterface
|
||||
// (minus the CP setup and profiling, with different argument motion)
|
||||
if (VerifyMethodHandles) {
|
||||
verify_ref_kind(_masm, JVM_REF_invokeInterface, member_reg, temp3);
|
||||
}
|
||||
|
||||
Register temp3_intf = temp3;
|
||||
__ load_heap_oop(temp3_intf, member_clazz);
|
||||
load_klass_from_Class(_masm, temp3_intf);
|
||||
__ verify_klass_ptr(temp3_intf);
|
||||
|
||||
Register rindex = rmethod;
|
||||
__ ldr(rindex, member_vmindex);
|
||||
if (VerifyMethodHandles) {
|
||||
Label L;
|
||||
__ cmpw(rindex, 0U);
|
||||
__ br(Assembler::GE, L);
|
||||
__ hlt(0);
|
||||
__ bind(L);
|
||||
}
|
||||
|
||||
// given intf, index, and recv klass, dispatch to the implementation method
|
||||
__ lookup_interface_method(temp1_recv_klass, temp3_intf,
|
||||
// note: next two args must be the same:
|
||||
rindex, rmethod,
|
||||
temp2,
|
||||
L_incompatible_class_change_error);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)));
|
||||
break;
|
||||
}
|
||||
|
||||
// live at this point: rmethod, r13 (if interpreted)
|
||||
|
||||
// After figuring out which concrete method to call, jump into it.
|
||||
// Note that this works in the interpreter with no data motion.
|
||||
// But the compiled version will require that r2_recv be shifted out.
|
||||
__ verify_method_ptr(rmethod);
|
||||
jump_from_method_handle(_masm, rmethod, temp1, for_compiler_entry);
|
||||
if (iid == vmIntrinsics::_linkToInterface) {
|
||||
__ bind(L_incompatible_class_change_error);
|
||||
__ far_jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void trace_method_handle_stub(const char* adaptername,
|
||||
oop mh,
|
||||
intptr_t* saved_regs,
|
||||
intptr_t* entry_sp) { }
|
||||
|
||||
// The stub wraps the arguments in a struct on the stack to avoid
|
||||
// dealing with the different calling conventions for passing 6
|
||||
// arguments.
|
||||
struct MethodHandleStubArguments {
|
||||
const char* adaptername;
|
||||
oopDesc* mh;
|
||||
intptr_t* saved_regs;
|
||||
intptr_t* entry_sp;
|
||||
};
|
||||
void trace_method_handle_stub_wrapper(MethodHandleStubArguments* args) { }
|
||||
|
||||
void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) { }
|
||||
#endif //PRODUCT
|
||||
62
hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.hpp
Normal file
62
hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// Platform-specific definitions for method handles.
|
||||
// These definitions are inlined into class MethodHandles.
|
||||
|
||||
// Adapters
|
||||
enum /* platform_dependent_constants */ {
|
||||
adapter_code_size = 32000 DEBUG_ONLY(+ 120000)
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
static void load_klass_from_Class(MacroAssembler* _masm, Register klass_reg);
|
||||
|
||||
static void verify_klass(MacroAssembler* _masm,
|
||||
Register obj, SystemDictionary::WKID klass_id,
|
||||
const char* error_message = "wrong klass") NOT_DEBUG_RETURN;
|
||||
|
||||
static void verify_method_handle(MacroAssembler* _masm, Register mh_reg) {
|
||||
verify_klass(_masm, mh_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_invoke_MethodHandle),
|
||||
"reference is a MH");
|
||||
}
|
||||
|
||||
static void verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) NOT_DEBUG_RETURN;
|
||||
|
||||
// Similar to InterpreterMacroAssembler::jump_from_interpreted.
|
||||
// Takes care of special dispatch from single stepping too.
|
||||
static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp,
|
||||
bool for_compiler_entry);
|
||||
|
||||
static void jump_to_lambda_form(MacroAssembler* _masm,
|
||||
Register recv, Register method_temp,
|
||||
Register temp2,
|
||||
bool for_compiler_entry);
|
||||
|
||||
static Register saved_last_sp_register() {
|
||||
// Should be in sharedRuntime, not here.
|
||||
return noreg;
|
||||
}
|
||||
324
hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.cpp
Normal file
324
hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.cpp
Normal file
@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "nativeInst_aarch64.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
#ifdef COMPILER1
|
||||
#include "c1/c1_Runtime1.hpp"
|
||||
#endif
|
||||
|
||||
void NativeCall::verify() { ; }
|
||||
|
||||
address NativeCall::destination() const {
|
||||
address addr = (address)this;
|
||||
address destination = instruction_address() + displacement();
|
||||
|
||||
// Do we use a trampoline stub for this call?
|
||||
CodeBlob* cb = CodeCache::find_blob_unsafe(addr); // Else we get assertion if nmethod is zombie.
|
||||
assert(cb && cb->is_nmethod(), "sanity");
|
||||
nmethod *nm = (nmethod *)cb;
|
||||
if (nm->stub_contains(destination) && is_NativeCallTrampolineStub_at(destination)) {
|
||||
// Yes we do, so get the destination from the trampoline stub.
|
||||
const address trampoline_stub_addr = destination;
|
||||
destination = nativeCallTrampolineStub_at(trampoline_stub_addr)->destination();
|
||||
}
|
||||
|
||||
return destination;
|
||||
}
|
||||
|
||||
// Similar to replace_mt_safe, but just changes the destination. The
|
||||
// important thing is that free-running threads are able to execute this
|
||||
// call instruction at all times.
|
||||
//
|
||||
// Used in the runtime linkage of calls; see class CompiledIC.
|
||||
//
|
||||
// Add parameter assert_lock to switch off assertion
|
||||
// during code generation, where no patching lock is needed.
|
||||
void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) {
|
||||
assert(!assert_lock ||
|
||||
(Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()),
|
||||
"concurrent code patching");
|
||||
|
||||
ResourceMark rm;
|
||||
int code_size = NativeInstruction::instruction_size;
|
||||
address addr_call = addr_at(0);
|
||||
assert(NativeCall::is_call_at(addr_call), "unexpected code at call site");
|
||||
|
||||
// Patch the constant in the call's trampoline stub.
|
||||
address trampoline_stub_addr = get_trampoline();
|
||||
if (trampoline_stub_addr != NULL) {
|
||||
assert (! is_NativeCallTrampolineStub_at(dest), "chained trampolines");
|
||||
nativeCallTrampolineStub_at(trampoline_stub_addr)->set_destination(dest);
|
||||
}
|
||||
|
||||
// Patch the call.
|
||||
if (Assembler::reachable_from_branch_at(addr_call, dest)) {
|
||||
set_destination(dest);
|
||||
} else {
|
||||
assert (trampoline_stub_addr != NULL, "we need a trampoline");
|
||||
set_destination(trampoline_stub_addr);
|
||||
}
|
||||
|
||||
ICache::invalidate_range(addr_call, instruction_size);
|
||||
}
|
||||
|
||||
address NativeCall::get_trampoline() {
|
||||
address call_addr = addr_at(0);
|
||||
|
||||
CodeBlob *code = CodeCache::find_blob(call_addr);
|
||||
assert(code != NULL, "Could not find the containing code blob");
|
||||
|
||||
address bl_destination
|
||||
= MacroAssembler::pd_call_destination(call_addr);
|
||||
if (code->content_contains(bl_destination) &&
|
||||
is_NativeCallTrampolineStub_at(bl_destination))
|
||||
return bl_destination;
|
||||
|
||||
// If the codeBlob is not a nmethod, this is because we get here from the
|
||||
// CodeBlob constructor, which is called within the nmethod constructor.
|
||||
return trampoline_stub_Relocation::get_trampoline_for(call_addr, (nmethod*)code);
|
||||
}
|
||||
|
||||
// Inserts a native call instruction at a given pc
|
||||
void NativeCall::insert(address code_pos, address entry) { Unimplemented(); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
void NativeMovConstReg::verify() {
|
||||
// make sure code pattern is actually mov reg64, imm64 instructions
|
||||
}
|
||||
|
||||
|
||||
intptr_t NativeMovConstReg::data() const {
|
||||
// das(uint64_t(instruction_address()),2);
|
||||
address addr = MacroAssembler::target_addr_for_insn(instruction_address());
|
||||
if (maybe_cpool_ref(instruction_address())) {
|
||||
return *(intptr_t*)addr;
|
||||
} else {
|
||||
return (intptr_t)addr;
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMovConstReg::set_data(intptr_t x) {
|
||||
if (maybe_cpool_ref(instruction_address())) {
|
||||
address addr = MacroAssembler::target_addr_for_insn(instruction_address());
|
||||
*(intptr_t*)addr = x;
|
||||
} else {
|
||||
MacroAssembler::pd_patch_instruction(instruction_address(), (address)x);
|
||||
ICache::invalidate_range(instruction_address(), instruction_size);
|
||||
}
|
||||
};
|
||||
|
||||
void NativeMovConstReg::print() {
|
||||
tty->print_cr(PTR_FORMAT ": mov reg, " INTPTR_FORMAT,
|
||||
p2i(instruction_address()), data());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
address NativeMovRegMem::instruction_address() const { return addr_at(instruction_offset); }
|
||||
|
||||
int NativeMovRegMem::offset() const {
|
||||
address pc = instruction_address();
|
||||
unsigned insn = *(unsigned*)pc;
|
||||
if (Instruction_aarch64::extract(insn, 28, 24) == 0b10000) {
|
||||
address addr = MacroAssembler::target_addr_for_insn(pc);
|
||||
return *addr;
|
||||
} else {
|
||||
return (int)(intptr_t)MacroAssembler::target_addr_for_insn(instruction_address());
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMovRegMem::set_offset(int x) {
|
||||
address pc = instruction_address();
|
||||
unsigned insn = *(unsigned*)pc;
|
||||
if (maybe_cpool_ref(pc)) {
|
||||
address addr = MacroAssembler::target_addr_for_insn(pc);
|
||||
*(long*)addr = x;
|
||||
} else {
|
||||
MacroAssembler::pd_patch_instruction(pc, (address)intptr_t(x));
|
||||
ICache::invalidate_range(instruction_address(), instruction_size);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMovRegMem::verify() {
|
||||
#ifdef ASSERT
|
||||
address dest = MacroAssembler::target_addr_for_insn(instruction_address());
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
void NativeJump::verify() { ; }
|
||||
|
||||
|
||||
void NativeJump::check_verified_entry_alignment(address entry, address verified_entry) {
|
||||
}
|
||||
|
||||
|
||||
address NativeJump::jump_destination() const {
|
||||
address dest = MacroAssembler::target_addr_for_insn(instruction_address());
|
||||
|
||||
// We use jump to self as the unresolved address which the inline
|
||||
// cache code (and relocs) know about
|
||||
|
||||
// return -1 if jump to self
|
||||
dest = (dest == (address) this) ? (address) -1 : dest;
|
||||
return dest;
|
||||
}
|
||||
|
||||
void NativeJump::set_jump_destination(address dest) {
|
||||
// We use jump to self as the unresolved address which the inline
|
||||
// cache code (and relocs) know about
|
||||
if (dest == (address) -1)
|
||||
dest = instruction_address();
|
||||
|
||||
MacroAssembler::pd_patch_instruction(instruction_address(), dest);
|
||||
ICache::invalidate_range(instruction_address(), instruction_size);
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
bool NativeInstruction::is_safepoint_poll() {
|
||||
// a safepoint_poll is implemented in two steps as either
|
||||
//
|
||||
// adrp(reg, polling_page);
|
||||
// ldr(zr, [reg, #offset]);
|
||||
//
|
||||
// or
|
||||
//
|
||||
// mov(reg, polling_page);
|
||||
// ldr(zr, [reg, #offset]);
|
||||
//
|
||||
// however, we cannot rely on the polling page address load always
|
||||
// directly preceding the read from the page. C1 does that but C2
|
||||
// has to do the load and read as two independent instruction
|
||||
// generation steps. that's because with a single macro sequence the
|
||||
// generic C2 code can only add the oop map before the mov/adrp and
|
||||
// the trap handler expects an oop map to be associated with the
|
||||
// load. with the load scheuled as a prior step the oop map goes
|
||||
// where it is needed.
|
||||
//
|
||||
// so all we can do here is check that marked instruction is a load
|
||||
// word to zr
|
||||
return is_ldrw_to_zr(address(this));
|
||||
}
|
||||
|
||||
bool NativeInstruction::is_adrp_at(address instr) {
|
||||
unsigned insn = *(unsigned*)instr;
|
||||
return (Instruction_aarch64::extract(insn, 31, 24) & 0b10011111) == 0b10010000;
|
||||
}
|
||||
|
||||
bool NativeInstruction::is_ldr_literal_at(address instr) {
|
||||
unsigned insn = *(unsigned*)instr;
|
||||
return (Instruction_aarch64::extract(insn, 29, 24) & 0b011011) == 0b00011000;
|
||||
}
|
||||
|
||||
bool NativeInstruction::is_ldrw_to_zr(address instr) {
|
||||
unsigned insn = *(unsigned*)instr;
|
||||
return (Instruction_aarch64::extract(insn, 31, 22) == 0b1011100101 &&
|
||||
Instruction_aarch64::extract(insn, 4, 0) == 0b11111);
|
||||
}
|
||||
|
||||
bool NativeInstruction::is_movz() {
|
||||
return Instruction_aarch64::extract(int_at(0), 30, 23) == 0b10100101;
|
||||
}
|
||||
|
||||
bool NativeInstruction::is_movk() {
|
||||
return Instruction_aarch64::extract(int_at(0), 30, 23) == 0b11100101;
|
||||
}
|
||||
|
||||
bool NativeInstruction::is_sigill_zombie_not_entrant() {
|
||||
return uint_at(0) == 0xd4bbd5a1; // dcps1 #0xdead
|
||||
}
|
||||
|
||||
void NativeIllegalInstruction::insert(address code_pos) {
|
||||
*(juint*)code_pos = 0xd4bbd5a1; // dcps1 #0xdead
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
// MT-safe inserting of a jump over a jump or a nop (used by
|
||||
// nmethod::make_not_entrant_or_zombie)
|
||||
|
||||
void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) {
|
||||
|
||||
assert(dest == SharedRuntime::get_handle_wrong_method_stub(), "expected fixed destination of patch");
|
||||
assert(nativeInstruction_at(verified_entry)->is_jump_or_nop()
|
||||
|| nativeInstruction_at(verified_entry)->is_sigill_zombie_not_entrant(),
|
||||
"Aarch64 cannot replace non-jump with jump");
|
||||
|
||||
// Patch this nmethod atomically.
|
||||
if (Assembler::reachable_from_branch_at(verified_entry, dest)) {
|
||||
ptrdiff_t disp = dest - verified_entry;
|
||||
guarantee(disp < 1 << 27 && disp > - (1 << 27), "branch overflow");
|
||||
|
||||
unsigned int insn = (0b000101 << 26) | ((disp >> 2) & 0x3ffffff);
|
||||
*(unsigned int*)verified_entry = insn;
|
||||
} else {
|
||||
// We use an illegal instruction for marking a method as
|
||||
// not_entrant or zombie.
|
||||
NativeIllegalInstruction::insert(verified_entry);
|
||||
}
|
||||
|
||||
ICache::invalidate_range(verified_entry, instruction_size);
|
||||
}
|
||||
|
||||
void NativeGeneralJump::verify() { }
|
||||
|
||||
void NativeGeneralJump::insert_unconditional(address code_pos, address entry) {
|
||||
NativeGeneralJump* n_jump = (NativeGeneralJump*)code_pos;
|
||||
|
||||
CodeBuffer cb(code_pos, instruction_size);
|
||||
MacroAssembler a(&cb);
|
||||
|
||||
a.mov(rscratch1, entry);
|
||||
a.br(rscratch1);
|
||||
|
||||
ICache::invalidate_range(code_pos, instruction_size);
|
||||
}
|
||||
|
||||
// MT-safe patching of a long jump instruction.
|
||||
void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
bool NativeInstruction::is_dtrace_trap() { return false; }
|
||||
|
||||
address NativeCallTrampolineStub::destination(nmethod *nm) const {
|
||||
return ptr_at(data_offset);
|
||||
}
|
||||
|
||||
void NativeCallTrampolineStub::set_destination(address new_destination) {
|
||||
set_ptr_at(data_offset, new_destination);
|
||||
OrderAccess::release();
|
||||
}
|
||||
491
hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp
Normal file
491
hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp
Normal file
@ -0,0 +1,491 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_NATIVEINST_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_NATIVEINST_AARCH64_HPP
|
||||
|
||||
#include "asm/assembler.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/icache.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/top.hpp"
|
||||
|
||||
// We have interfaces for the following instructions:
|
||||
// - NativeInstruction
|
||||
// - - NativeCall
|
||||
// - - NativeMovConstReg
|
||||
// - - NativeMovConstRegPatching
|
||||
// - - NativeMovRegMem
|
||||
// - - NativeMovRegMemPatching
|
||||
// - - NativeJump
|
||||
// - - NativeIllegalOpCode
|
||||
// - - NativeGeneralJump
|
||||
// - - NativeReturn
|
||||
// - - NativeReturnX (return with argument)
|
||||
// - - NativePushConst
|
||||
// - - NativeTstRegMem
|
||||
|
||||
// The base class for different kinds of native instruction abstractions.
|
||||
// Provides the primitive operations to manipulate code relative to this.
|
||||
|
||||
class NativeInstruction VALUE_OBJ_CLASS_SPEC {
|
||||
friend class Relocation;
|
||||
friend bool is_NativeCallTrampolineStub_at(address);
|
||||
public:
|
||||
enum { instruction_size = 4 };
|
||||
inline bool is_nop();
|
||||
bool is_dtrace_trap();
|
||||
inline bool is_illegal();
|
||||
inline bool is_return();
|
||||
bool is_jump();
|
||||
inline bool is_jump_or_nop();
|
||||
inline bool is_cond_jump();
|
||||
bool is_safepoint_poll();
|
||||
inline bool is_mov_literal64();
|
||||
bool is_movz();
|
||||
bool is_movk();
|
||||
bool is_sigill_zombie_not_entrant();
|
||||
|
||||
protected:
|
||||
address addr_at(int offset) const { return address(this) + offset; }
|
||||
|
||||
s_char sbyte_at(int offset) const { return *(s_char*) addr_at(offset); }
|
||||
u_char ubyte_at(int offset) const { return *(u_char*) addr_at(offset); }
|
||||
|
||||
jint int_at(int offset) const { return *(jint*) addr_at(offset); }
|
||||
juint uint_at(int offset) const { return *(juint*) addr_at(offset); }
|
||||
|
||||
address ptr_at(int offset) const { return *(address*) addr_at(offset); }
|
||||
|
||||
oop oop_at (int offset) const { return *(oop*) addr_at(offset); }
|
||||
|
||||
|
||||
void set_char_at(int offset, char c) { *addr_at(offset) = (u_char)c; }
|
||||
void set_int_at(int offset, jint i) { *(jint*)addr_at(offset) = i; }
|
||||
void set_uint_at(int offset, jint i) { *(juint*)addr_at(offset) = i; }
|
||||
void set_ptr_at (int offset, address ptr) { *(address*) addr_at(offset) = ptr; }
|
||||
void set_oop_at (int offset, oop o) { *(oop*) addr_at(offset) = o; }
|
||||
|
||||
public:
|
||||
|
||||
// unit test stuff
|
||||
static void test() {} // override for testing
|
||||
|
||||
inline friend NativeInstruction* nativeInstruction_at(address address);
|
||||
|
||||
static bool is_adrp_at(address instr);
|
||||
static bool is_ldr_literal_at(address instr);
|
||||
static bool is_ldrw_to_zr(address instr);
|
||||
|
||||
static bool maybe_cpool_ref(address instr) {
|
||||
return is_adrp_at(instr) || is_ldr_literal_at(instr);
|
||||
}
|
||||
};
|
||||
|
||||
inline NativeInstruction* nativeInstruction_at(address address) {
|
||||
return (NativeInstruction*)address;
|
||||
}
|
||||
|
||||
// The natural type of an AArch64 instruction is uint32_t
|
||||
inline NativeInstruction* nativeInstruction_at(uint32_t *address) {
|
||||
return (NativeInstruction*)address;
|
||||
}
|
||||
|
||||
inline NativeCall* nativeCall_at(address address);
|
||||
// The NativeCall is an abstraction for accessing/manipulating native call imm32/rel32off
|
||||
// instructions (used to manipulate inline caches, primitive & dll calls, etc.).
|
||||
|
||||
class NativeCall: public NativeInstruction {
|
||||
public:
|
||||
enum Aarch64_specific_constants {
|
||||
instruction_size = 4,
|
||||
instruction_offset = 0,
|
||||
displacement_offset = 0,
|
||||
return_address_offset = 4
|
||||
};
|
||||
|
||||
enum { cache_line_size = BytesPerWord }; // conservative estimate!
|
||||
address instruction_address() const { return addr_at(instruction_offset); }
|
||||
address next_instruction_address() const { return addr_at(return_address_offset); }
|
||||
int displacement() const { return (int_at(displacement_offset) << 6) >> 4; }
|
||||
address displacement_address() const { return addr_at(displacement_offset); }
|
||||
address return_address() const { return addr_at(return_address_offset); }
|
||||
address destination() const;
|
||||
|
||||
void set_destination(address dest) {
|
||||
int offset = dest - instruction_address();
|
||||
unsigned int insn = 0b100101 << 26;
|
||||
assert((offset & 3) == 0, "should be");
|
||||
offset >>= 2;
|
||||
offset &= (1 << 26) - 1; // mask off insn part
|
||||
insn |= offset;
|
||||
set_int_at(displacement_offset, insn);
|
||||
}
|
||||
|
||||
void verify_alignment() { ; }
|
||||
void verify();
|
||||
void print();
|
||||
|
||||
// Creation
|
||||
inline friend NativeCall* nativeCall_at(address address);
|
||||
inline friend NativeCall* nativeCall_before(address return_address);
|
||||
|
||||
static bool is_call_at(address instr) {
|
||||
const uint32_t insn = (*(uint32_t*)instr);
|
||||
return (insn >> 26) == 0b100101;
|
||||
}
|
||||
|
||||
static bool is_call_before(address return_address) {
|
||||
return is_call_at(return_address - NativeCall::return_address_offset);
|
||||
}
|
||||
|
||||
// MT-safe patching of a call instruction.
|
||||
static void insert(address code_pos, address entry);
|
||||
|
||||
static void replace_mt_safe(address instr_addr, address code_buffer);
|
||||
|
||||
// Similar to replace_mt_safe, but just changes the destination. The
|
||||
// important thing is that free-running threads are able to execute
|
||||
// this call instruction at all times. If the call is an immediate BL
|
||||
// instruction we can simply rely on atomicity of 32-bit writes to
|
||||
// make sure other threads will see no intermediate states.
|
||||
|
||||
// We cannot rely on locks here, since the free-running threads must run at
|
||||
// full speed.
|
||||
//
|
||||
// Used in the runtime linkage of calls; see class CompiledIC.
|
||||
// (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.)
|
||||
|
||||
// The parameter assert_lock disables the assertion during code generation.
|
||||
void set_destination_mt_safe(address dest, bool assert_lock = true);
|
||||
|
||||
address get_trampoline();
|
||||
};
|
||||
|
||||
inline NativeCall* nativeCall_at(address address) {
|
||||
NativeCall* call = (NativeCall*)(address - NativeCall::instruction_offset);
|
||||
#ifdef ASSERT
|
||||
call->verify();
|
||||
#endif
|
||||
return call;
|
||||
}
|
||||
|
||||
inline NativeCall* nativeCall_before(address return_address) {
|
||||
NativeCall* call = (NativeCall*)(return_address - NativeCall::return_address_offset);
|
||||
#ifdef ASSERT
|
||||
call->verify();
|
||||
#endif
|
||||
return call;
|
||||
}
|
||||
|
||||
// An interface for accessing/manipulating native mov reg, imm instructions.
|
||||
// (used to manipulate inlined 64-bit data calls, etc.)
|
||||
class NativeMovConstReg: public NativeInstruction {
|
||||
public:
|
||||
enum Aarch64_specific_constants {
|
||||
instruction_size = 3 * 4, // movz, movk, movk. See movptr().
|
||||
instruction_offset = 0,
|
||||
displacement_offset = 0,
|
||||
};
|
||||
|
||||
address instruction_address() const { return addr_at(instruction_offset); }
|
||||
address next_instruction_address() const {
|
||||
if (nativeInstruction_at(instruction_address())->is_movz())
|
||||
// Assume movz, movk, movk
|
||||
return addr_at(instruction_size);
|
||||
else if (is_adrp_at(instruction_address()))
|
||||
return addr_at(2*4);
|
||||
else if (is_ldr_literal_at(instruction_address()))
|
||||
return(addr_at(4));
|
||||
assert(false, "Unknown instruction in NativeMovConstReg");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
intptr_t data() const;
|
||||
void set_data(intptr_t x);
|
||||
|
||||
void flush() {
|
||||
if (! maybe_cpool_ref(instruction_address())) {
|
||||
ICache::invalidate_range(instruction_address(), instruction_size);
|
||||
}
|
||||
}
|
||||
|
||||
void verify();
|
||||
void print();
|
||||
|
||||
// unit test stuff
|
||||
static void test() {}
|
||||
|
||||
// Creation
|
||||
inline friend NativeMovConstReg* nativeMovConstReg_at(address address);
|
||||
inline friend NativeMovConstReg* nativeMovConstReg_before(address address);
|
||||
};
|
||||
|
||||
inline NativeMovConstReg* nativeMovConstReg_at(address address) {
|
||||
NativeMovConstReg* test = (NativeMovConstReg*)(address - NativeMovConstReg::instruction_offset);
|
||||
#ifdef ASSERT
|
||||
test->verify();
|
||||
#endif
|
||||
return test;
|
||||
}
|
||||
|
||||
inline NativeMovConstReg* nativeMovConstReg_before(address address) {
|
||||
NativeMovConstReg* test = (NativeMovConstReg*)(address - NativeMovConstReg::instruction_size - NativeMovConstReg::instruction_offset);
|
||||
#ifdef ASSERT
|
||||
test->verify();
|
||||
#endif
|
||||
return test;
|
||||
}
|
||||
|
||||
class NativeMovConstRegPatching: public NativeMovConstReg {
|
||||
private:
|
||||
friend NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address) {
|
||||
NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)(address - instruction_offset);
|
||||
#ifdef ASSERT
|
||||
test->verify();
|
||||
#endif
|
||||
return test;
|
||||
}
|
||||
};
|
||||
|
||||
// An interface for accessing/manipulating native moves of the form:
|
||||
// mov[b/w/l/q] [reg + offset], reg (instruction_code_reg2mem)
|
||||
// mov[b/w/l/q] reg, [reg+offset] (instruction_code_mem2reg
|
||||
// mov[s/z]x[w/b/q] [reg + offset], reg
|
||||
// fld_s [reg+offset]
|
||||
// fld_d [reg+offset]
|
||||
// fstp_s [reg + offset]
|
||||
// fstp_d [reg + offset]
|
||||
// mov_literal64 scratch,<pointer> ; mov[b/w/l/q] 0(scratch),reg | mov[b/w/l/q] reg,0(scratch)
|
||||
//
|
||||
// Warning: These routines must be able to handle any instruction sequences
|
||||
// that are generated as a result of the load/store byte,word,long
|
||||
// macros. For example: The load_unsigned_byte instruction generates
|
||||
// an xor reg,reg inst prior to generating the movb instruction. This
|
||||
// class must skip the xor instruction.
|
||||
|
||||
class NativeMovRegMem: public NativeInstruction {
|
||||
enum AArch64_specific_constants {
|
||||
instruction_size = 4,
|
||||
instruction_offset = 0,
|
||||
data_offset = 0,
|
||||
next_instruction_offset = 4
|
||||
};
|
||||
|
||||
public:
|
||||
// helper
|
||||
int instruction_start() const;
|
||||
|
||||
address instruction_address() const;
|
||||
|
||||
address next_instruction_address() const;
|
||||
|
||||
int offset() const;
|
||||
|
||||
void set_offset(int x);
|
||||
|
||||
void add_offset_in_bytes(int add_offset) { set_offset ( ( offset() + add_offset ) ); }
|
||||
|
||||
void verify();
|
||||
void print ();
|
||||
|
||||
// unit test stuff
|
||||
static void test() {}
|
||||
|
||||
private:
|
||||
inline friend NativeMovRegMem* nativeMovRegMem_at (address address);
|
||||
};
|
||||
|
||||
inline NativeMovRegMem* nativeMovRegMem_at (address address) {
|
||||
NativeMovRegMem* test = (NativeMovRegMem*)(address - NativeMovRegMem::instruction_offset);
|
||||
#ifdef ASSERT
|
||||
test->verify();
|
||||
#endif
|
||||
return test;
|
||||
}
|
||||
|
||||
class NativeMovRegMemPatching: public NativeMovRegMem {
|
||||
private:
|
||||
friend NativeMovRegMemPatching* nativeMovRegMemPatching_at (address address) {Unimplemented(); return 0; }
|
||||
};
|
||||
|
||||
// An interface for accessing/manipulating native leal instruction of form:
|
||||
// leal reg, [reg + offset]
|
||||
|
||||
class NativeLoadAddress: public NativeMovRegMem {
|
||||
static const bool has_rex = true;
|
||||
static const int rex_size = 1;
|
||||
public:
|
||||
|
||||
void verify();
|
||||
void print ();
|
||||
|
||||
// unit test stuff
|
||||
static void test() {}
|
||||
};
|
||||
|
||||
class NativeJump: public NativeInstruction {
|
||||
public:
|
||||
enum AArch64_specific_constants {
|
||||
instruction_size = 4,
|
||||
instruction_offset = 0,
|
||||
data_offset = 0,
|
||||
next_instruction_offset = 4
|
||||
};
|
||||
|
||||
address instruction_address() const { return addr_at(instruction_offset); }
|
||||
address next_instruction_address() const { return addr_at(instruction_size); }
|
||||
address jump_destination() const;
|
||||
void set_jump_destination(address dest);
|
||||
|
||||
// Creation
|
||||
inline friend NativeJump* nativeJump_at(address address);
|
||||
|
||||
void verify();
|
||||
|
||||
// Unit testing stuff
|
||||
static void test() {}
|
||||
|
||||
// Insertion of native jump instruction
|
||||
static void insert(address code_pos, address entry);
|
||||
// MT-safe insertion of native jump at verified method entry
|
||||
static void check_verified_entry_alignment(address entry, address verified_entry);
|
||||
static void patch_verified_entry(address entry, address verified_entry, address dest);
|
||||
};
|
||||
|
||||
inline NativeJump* nativeJump_at(address address) {
|
||||
NativeJump* jump = (NativeJump*)(address - NativeJump::instruction_offset);
|
||||
#ifdef ASSERT
|
||||
jump->verify();
|
||||
#endif
|
||||
return jump;
|
||||
}
|
||||
|
||||
class NativeGeneralJump: public NativeJump {
|
||||
public:
|
||||
enum AArch64_specific_constants {
|
||||
instruction_size = 4 * 4,
|
||||
instruction_offset = 0,
|
||||
data_offset = 0,
|
||||
next_instruction_offset = 4 * 4
|
||||
};
|
||||
static void insert_unconditional(address code_pos, address entry);
|
||||
static void replace_mt_safe(address instr_addr, address code_buffer);
|
||||
static void verify();
|
||||
};
|
||||
|
||||
inline NativeGeneralJump* nativeGeneralJump_at(address address) {
|
||||
NativeGeneralJump* jump = (NativeGeneralJump*)(address);
|
||||
debug_only(jump->verify();)
|
||||
return jump;
|
||||
}
|
||||
|
||||
class NativePopReg : public NativeInstruction {
|
||||
public:
|
||||
// Insert a pop instruction
|
||||
static void insert(address code_pos, Register reg);
|
||||
};
|
||||
|
||||
|
||||
class NativeIllegalInstruction: public NativeInstruction {
|
||||
public:
|
||||
// Insert illegal opcode as specific address
|
||||
static void insert(address code_pos);
|
||||
};
|
||||
|
||||
// return instruction that does not pop values of the stack
|
||||
class NativeReturn: public NativeInstruction {
|
||||
public:
|
||||
};
|
||||
|
||||
// return instruction that does pop values of the stack
|
||||
class NativeReturnX: public NativeInstruction {
|
||||
public:
|
||||
};
|
||||
|
||||
// Simple test vs memory
|
||||
class NativeTstRegMem: public NativeInstruction {
|
||||
public:
|
||||
};
|
||||
|
||||
inline bool NativeInstruction::is_nop() {
|
||||
uint32_t insn = *(uint32_t*)addr_at(0);
|
||||
return insn == 0xd503201f;
|
||||
}
|
||||
|
||||
inline bool NativeInstruction::is_jump() {
|
||||
uint32_t insn = *(uint32_t*)addr_at(0);
|
||||
|
||||
if (Instruction_aarch64::extract(insn, 30, 26) == 0b00101) {
|
||||
// Unconditional branch (immediate)
|
||||
return true;
|
||||
} else if (Instruction_aarch64::extract(insn, 31, 25) == 0b0101010) {
|
||||
// Conditional branch (immediate)
|
||||
return true;
|
||||
} else if (Instruction_aarch64::extract(insn, 30, 25) == 0b011010) {
|
||||
// Compare & branch (immediate)
|
||||
return true;
|
||||
} else if (Instruction_aarch64::extract(insn, 30, 25) == 0b011011) {
|
||||
// Test & branch (immediate)
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool NativeInstruction::is_jump_or_nop() {
|
||||
return is_nop() || is_jump();
|
||||
}
|
||||
|
||||
// Call trampoline stubs.
|
||||
class NativeCallTrampolineStub : public NativeInstruction {
|
||||
public:
|
||||
|
||||
enum AArch64_specific_constants {
|
||||
instruction_size = 4 * 4,
|
||||
instruction_offset = 0,
|
||||
data_offset = 2 * 4,
|
||||
next_instruction_offset = 4 * 4
|
||||
};
|
||||
|
||||
address destination(nmethod *nm = NULL) const;
|
||||
void set_destination(address new_destination);
|
||||
ptrdiff_t destination_offset() const;
|
||||
};
|
||||
|
||||
inline bool is_NativeCallTrampolineStub_at(address addr) {
|
||||
// Ensure that the stub is exactly
|
||||
// ldr xscratch1, L
|
||||
// br xscratch1
|
||||
// L:
|
||||
uint32_t *i = (uint32_t *)addr;
|
||||
return i[0] == 0x58000048 && i[1] == 0xd61f0100;
|
||||
}
|
||||
|
||||
inline NativeCallTrampolineStub* nativeCallTrampolineStub_at(address addr) {
|
||||
assert(is_NativeCallTrampolineStub_at(addr), "no call trampoline found");
|
||||
return (NativeCallTrampolineStub*)addr;
|
||||
}
|
||||
|
||||
#endif // CPU_AARCH64_VM_NATIVEINST_AARCH64_HPP
|
||||
45
hotspot/src/cpu/aarch64/vm/registerMap_aarch64.hpp
Normal file
45
hotspot/src/cpu/aarch64/vm/registerMap_aarch64.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_REGISTERMAP_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_REGISTERMAP_AARCH64_HPP
|
||||
|
||||
// machine-dependent implemention for register maps
|
||||
friend class frame;
|
||||
|
||||
private:
|
||||
// This is the hook for finding a register in an "well-known" location,
|
||||
// such as a register block of a predetermined format.
|
||||
// Since there is none, we just return NULL.
|
||||
// See registerMap_sparc.hpp for an example of grabbing registers
|
||||
// from register save areas of a standard layout.
|
||||
address pd_location(VMReg reg) const {return NULL;}
|
||||
|
||||
// no PD state to clear or copy:
|
||||
void pd_clear() {}
|
||||
void pd_initialize() {}
|
||||
void pd_initialize_from(const RegisterMap* map) {}
|
||||
|
||||
#endif // CPU_AARCH64_VM_REGISTERMAP_AARCH64_HPP
|
||||
54
hotspot/src/cpu/aarch64/vm/register_aarch64.cpp
Normal file
54
hotspot/src/cpu/aarch64/vm/register_aarch64.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "register_aarch64.hpp"
|
||||
|
||||
const int ConcreteRegisterImpl::max_gpr = RegisterImpl::number_of_registers << 1;
|
||||
|
||||
const int ConcreteRegisterImpl::max_fpr
|
||||
= ConcreteRegisterImpl::max_gpr + (FloatRegisterImpl::number_of_registers << 1);
|
||||
|
||||
const char* RegisterImpl::name() const {
|
||||
const char* names[number_of_registers] = {
|
||||
"c_rarg0", "c_rarg1", "c_rarg2", "c_rarg3", "c_rarg4", "c_rarg5", "c_rarg6", "c_rarg7",
|
||||
"rscratch1", "rscratch2",
|
||||
"r10", "r11", "r12", "r13", "r14", "r15", "r16",
|
||||
"r17", "r18", "r19",
|
||||
"resp", "rdispatch", "rbcp", "r23", "rlocals", "rmonitors", "rcpool", "rheapbase",
|
||||
"rthread", "rfp", "lr", "sp"
|
||||
};
|
||||
return is_valid() ? names[encoding()] : "noreg";
|
||||
}
|
||||
|
||||
const char* FloatRegisterImpl::name() const {
|
||||
const char* names[number_of_registers] = {
|
||||
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
|
||||
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
|
||||
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
|
||||
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
|
||||
};
|
||||
return is_valid() ? names[encoding()] : "noreg";
|
||||
}
|
||||
250
hotspot/src/cpu/aarch64/vm/register_aarch64.hpp
Normal file
250
hotspot/src/cpu/aarch64/vm/register_aarch64.hpp
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_REGISTER_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_REGISTER_AARCH64_HPP
|
||||
|
||||
#include "asm/register.hpp"
|
||||
|
||||
class VMRegImpl;
|
||||
typedef VMRegImpl* VMReg;
|
||||
|
||||
// Use Register as shortcut
|
||||
class RegisterImpl;
|
||||
typedef RegisterImpl* Register;
|
||||
|
||||
inline Register as_Register(int encoding) {
|
||||
return (Register)(intptr_t) encoding;
|
||||
}
|
||||
|
||||
class RegisterImpl: public AbstractRegisterImpl {
|
||||
public:
|
||||
enum {
|
||||
number_of_registers = 32,
|
||||
number_of_byte_registers = 32
|
||||
};
|
||||
|
||||
// derived registers, offsets, and addresses
|
||||
Register successor() const { return as_Register(encoding() + 1); }
|
||||
|
||||
// construction
|
||||
inline friend Register as_Register(int encoding);
|
||||
|
||||
VMReg as_VMReg();
|
||||
|
||||
// accessors
|
||||
int encoding() const { assert(is_valid(), "invalid register"); return (intptr_t)this; }
|
||||
bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; }
|
||||
bool has_byte_register() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_byte_registers; }
|
||||
const char* name() const;
|
||||
int encoding_nocheck() const { return (intptr_t)this; }
|
||||
unsigned long bit(bool yes = true) const { return yes << encoding(); }
|
||||
};
|
||||
|
||||
// The integer registers of the aarch64 architecture
|
||||
|
||||
CONSTANT_REGISTER_DECLARATION(Register, noreg, (-1));
|
||||
|
||||
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r0, (0));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r1, (1));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r2, (2));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r3, (3));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r4, (4));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r5, (5));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r6, (6));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r7, (7));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r8, (8));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r9, (9));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r10, (10));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r11, (11));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r12, (12));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r13, (13));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r14, (14));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r15, (15));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r16, (16));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r17, (17));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r18, (18));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r19, (19));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r20, (20));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r21, (21));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r22, (22));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r23, (23));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r24, (24));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r25, (25));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r26, (26));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r27, (27));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r28, (28));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r29, (29));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r30, (30));
|
||||
|
||||
CONSTANT_REGISTER_DECLARATION(Register, r31_sp, (31));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, zr, (32));
|
||||
CONSTANT_REGISTER_DECLARATION(Register, sp, (33));
|
||||
|
||||
// Use FloatRegister as shortcut
|
||||
class FloatRegisterImpl;
|
||||
typedef FloatRegisterImpl* FloatRegister;
|
||||
|
||||
inline FloatRegister as_FloatRegister(int encoding) {
|
||||
return (FloatRegister)(intptr_t) encoding;
|
||||
}
|
||||
|
||||
// The implementation of floating point registers for the architecture
|
||||
class FloatRegisterImpl: public AbstractRegisterImpl {
|
||||
public:
|
||||
enum {
|
||||
number_of_registers = 32
|
||||
};
|
||||
|
||||
// construction
|
||||
inline friend FloatRegister as_FloatRegister(int encoding);
|
||||
|
||||
VMReg as_VMReg();
|
||||
|
||||
// derived registers, offsets, and addresses
|
||||
FloatRegister successor() const { return as_FloatRegister(encoding() + 1); }
|
||||
|
||||
// accessors
|
||||
int encoding() const { assert(is_valid(), "invalid register"); return (intptr_t)this; }
|
||||
int encoding_nocheck() const { return (intptr_t)this; }
|
||||
bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; }
|
||||
const char* name() const;
|
||||
|
||||
};
|
||||
|
||||
// The float registers of the AARCH64 architecture
|
||||
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, fnoreg , (-1));
|
||||
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v0 , ( 0));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v1 , ( 1));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v2 , ( 2));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v3 , ( 3));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v4 , ( 4));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v5 , ( 5));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v6 , ( 6));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v7 , ( 7));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v8 , ( 8));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v9 , ( 9));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v10 , (10));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v11 , (11));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v12 , (12));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v13 , (13));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v14 , (14));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v15 , (15));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v16 , (16));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v17 , (17));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v18 , (18));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v19 , (19));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v20 , (20));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v21 , (21));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v22 , (22));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v23 , (23));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v24 , (24));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v25 , (25));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v26 , (26));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v27 , (27));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v28 , (28));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v29 , (29));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v30 , (30));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v31 , (31));
|
||||
|
||||
// Need to know the total number of registers of all sorts for SharedInfo.
|
||||
// Define a class that exports it.
|
||||
class ConcreteRegisterImpl : public AbstractRegisterImpl {
|
||||
public:
|
||||
enum {
|
||||
// A big enough number for C2: all the registers plus flags
|
||||
// This number must be large enough to cover REG_COUNT (defined by c2) registers.
|
||||
// There is no requirement that any ordering here matches any ordering c2 gives
|
||||
// it's optoregs.
|
||||
|
||||
number_of_registers = (2 * RegisterImpl::number_of_registers +
|
||||
2 * FloatRegisterImpl::number_of_registers +
|
||||
1) // flags
|
||||
};
|
||||
|
||||
// added to make it compile
|
||||
static const int max_gpr;
|
||||
static const int max_fpr;
|
||||
};
|
||||
|
||||
// A set of registers
|
||||
class RegSet {
|
||||
uint32_t _bitset;
|
||||
|
||||
RegSet(uint32_t bitset) : _bitset(bitset) { }
|
||||
|
||||
public:
|
||||
|
||||
RegSet() : _bitset(0) { }
|
||||
|
||||
RegSet(Register r1) : _bitset(r1->bit()) { }
|
||||
|
||||
RegSet operator+(const RegSet aSet) const {
|
||||
RegSet result(_bitset | aSet._bitset);
|
||||
return result;
|
||||
}
|
||||
|
||||
RegSet operator-(const RegSet aSet) const {
|
||||
RegSet result(_bitset & ~aSet._bitset);
|
||||
return result;
|
||||
}
|
||||
|
||||
RegSet &operator+=(const RegSet aSet) {
|
||||
*this = *this + aSet;
|
||||
return *this;
|
||||
}
|
||||
|
||||
static RegSet of(Register r1) {
|
||||
return RegSet(r1);
|
||||
}
|
||||
|
||||
static RegSet of(Register r1, Register r2) {
|
||||
return of(r1) + r2;
|
||||
}
|
||||
|
||||
static RegSet of(Register r1, Register r2, Register r3) {
|
||||
return of(r1, r2) + r3;
|
||||
}
|
||||
|
||||
static RegSet of(Register r1, Register r2, Register r3, Register r4) {
|
||||
return of(r1, r2, r3) + r4;
|
||||
}
|
||||
|
||||
static RegSet range(Register start, Register end) {
|
||||
uint32_t bits = ~0;
|
||||
bits <<= start->encoding();
|
||||
bits <<= 31 - end->encoding();
|
||||
bits >>= 31 - end->encoding();
|
||||
|
||||
return RegSet(bits);
|
||||
}
|
||||
|
||||
uint32_t bits() const { return _bitset; }
|
||||
};
|
||||
|
||||
#endif // CPU_AARCH64_VM_REGISTER_AARCH64_HPP
|
||||
155
hotspot/src/cpu/aarch64/vm/register_definitions_aarch64.cpp
Normal file
155
hotspot/src/cpu/aarch64/vm/register_definitions_aarch64.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/assembler.hpp"
|
||||
#include "asm/register.hpp"
|
||||
#include "register_aarch64.hpp"
|
||||
# include "interp_masm_aarch64.hpp"
|
||||
|
||||
REGISTER_DEFINITION(Register, r0);
|
||||
REGISTER_DEFINITION(Register, r1);
|
||||
REGISTER_DEFINITION(Register, r2);
|
||||
REGISTER_DEFINITION(Register, r3);
|
||||
REGISTER_DEFINITION(Register, r4);
|
||||
REGISTER_DEFINITION(Register, r5);
|
||||
REGISTER_DEFINITION(Register, r6);
|
||||
REGISTER_DEFINITION(Register, r7);
|
||||
REGISTER_DEFINITION(Register, r8);
|
||||
REGISTER_DEFINITION(Register, r9);
|
||||
REGISTER_DEFINITION(Register, r10);
|
||||
REGISTER_DEFINITION(Register, r11);
|
||||
REGISTER_DEFINITION(Register, r12);
|
||||
REGISTER_DEFINITION(Register, r13);
|
||||
REGISTER_DEFINITION(Register, r14);
|
||||
REGISTER_DEFINITION(Register, r15);
|
||||
REGISTER_DEFINITION(Register, r16);
|
||||
REGISTER_DEFINITION(Register, r17);
|
||||
REGISTER_DEFINITION(Register, r18);
|
||||
REGISTER_DEFINITION(Register, r19);
|
||||
REGISTER_DEFINITION(Register, r20);
|
||||
REGISTER_DEFINITION(Register, r21);
|
||||
REGISTER_DEFINITION(Register, r22);
|
||||
REGISTER_DEFINITION(Register, r23);
|
||||
REGISTER_DEFINITION(Register, r24);
|
||||
REGISTER_DEFINITION(Register, r25);
|
||||
REGISTER_DEFINITION(Register, r26);
|
||||
REGISTER_DEFINITION(Register, r27);
|
||||
REGISTER_DEFINITION(Register, r28);
|
||||
REGISTER_DEFINITION(Register, r29);
|
||||
REGISTER_DEFINITION(Register, r30);
|
||||
REGISTER_DEFINITION(Register, sp);
|
||||
|
||||
REGISTER_DEFINITION(FloatRegister, v0);
|
||||
REGISTER_DEFINITION(FloatRegister, v1);
|
||||
REGISTER_DEFINITION(FloatRegister, v2);
|
||||
REGISTER_DEFINITION(FloatRegister, v3);
|
||||
REGISTER_DEFINITION(FloatRegister, v4);
|
||||
REGISTER_DEFINITION(FloatRegister, v5);
|
||||
REGISTER_DEFINITION(FloatRegister, v6);
|
||||
REGISTER_DEFINITION(FloatRegister, v7);
|
||||
REGISTER_DEFINITION(FloatRegister, v8);
|
||||
REGISTER_DEFINITION(FloatRegister, v9);
|
||||
REGISTER_DEFINITION(FloatRegister, v10);
|
||||
REGISTER_DEFINITION(FloatRegister, v11);
|
||||
REGISTER_DEFINITION(FloatRegister, v12);
|
||||
REGISTER_DEFINITION(FloatRegister, v13);
|
||||
REGISTER_DEFINITION(FloatRegister, v14);
|
||||
REGISTER_DEFINITION(FloatRegister, v15);
|
||||
REGISTER_DEFINITION(FloatRegister, v16);
|
||||
REGISTER_DEFINITION(FloatRegister, v17);
|
||||
REGISTER_DEFINITION(FloatRegister, v18);
|
||||
REGISTER_DEFINITION(FloatRegister, v19);
|
||||
REGISTER_DEFINITION(FloatRegister, v20);
|
||||
REGISTER_DEFINITION(FloatRegister, v21);
|
||||
REGISTER_DEFINITION(FloatRegister, v22);
|
||||
REGISTER_DEFINITION(FloatRegister, v23);
|
||||
REGISTER_DEFINITION(FloatRegister, v24);
|
||||
REGISTER_DEFINITION(FloatRegister, v25);
|
||||
REGISTER_DEFINITION(FloatRegister, v26);
|
||||
REGISTER_DEFINITION(FloatRegister, v27);
|
||||
REGISTER_DEFINITION(FloatRegister, v28);
|
||||
REGISTER_DEFINITION(FloatRegister, v29);
|
||||
REGISTER_DEFINITION(FloatRegister, v30);
|
||||
REGISTER_DEFINITION(FloatRegister, v31);
|
||||
|
||||
REGISTER_DEFINITION(Register, zr);
|
||||
|
||||
REGISTER_DEFINITION(Register, c_rarg0);
|
||||
REGISTER_DEFINITION(Register, c_rarg1);
|
||||
REGISTER_DEFINITION(Register, c_rarg2);
|
||||
REGISTER_DEFINITION(Register, c_rarg3);
|
||||
REGISTER_DEFINITION(Register, c_rarg4);
|
||||
REGISTER_DEFINITION(Register, c_rarg5);
|
||||
REGISTER_DEFINITION(Register, c_rarg6);
|
||||
REGISTER_DEFINITION(Register, c_rarg7);
|
||||
|
||||
REGISTER_DEFINITION(FloatRegister, c_farg0);
|
||||
REGISTER_DEFINITION(FloatRegister, c_farg1);
|
||||
REGISTER_DEFINITION(FloatRegister, c_farg2);
|
||||
REGISTER_DEFINITION(FloatRegister, c_farg3);
|
||||
REGISTER_DEFINITION(FloatRegister, c_farg4);
|
||||
REGISTER_DEFINITION(FloatRegister, c_farg5);
|
||||
REGISTER_DEFINITION(FloatRegister, c_farg6);
|
||||
REGISTER_DEFINITION(FloatRegister, c_farg7);
|
||||
|
||||
REGISTER_DEFINITION(Register, j_rarg0);
|
||||
REGISTER_DEFINITION(Register, j_rarg1);
|
||||
REGISTER_DEFINITION(Register, j_rarg2);
|
||||
REGISTER_DEFINITION(Register, j_rarg3);
|
||||
REGISTER_DEFINITION(Register, j_rarg4);
|
||||
REGISTER_DEFINITION(Register, j_rarg5);
|
||||
REGISTER_DEFINITION(Register, j_rarg6);
|
||||
REGISTER_DEFINITION(Register, j_rarg7);
|
||||
|
||||
REGISTER_DEFINITION(FloatRegister, j_farg0);
|
||||
REGISTER_DEFINITION(FloatRegister, j_farg1);
|
||||
REGISTER_DEFINITION(FloatRegister, j_farg2);
|
||||
REGISTER_DEFINITION(FloatRegister, j_farg3);
|
||||
REGISTER_DEFINITION(FloatRegister, j_farg4);
|
||||
REGISTER_DEFINITION(FloatRegister, j_farg5);
|
||||
REGISTER_DEFINITION(FloatRegister, j_farg6);
|
||||
REGISTER_DEFINITION(FloatRegister, j_farg7);
|
||||
|
||||
REGISTER_DEFINITION(Register, rscratch1);
|
||||
REGISTER_DEFINITION(Register, rscratch2);
|
||||
REGISTER_DEFINITION(Register, esp);
|
||||
REGISTER_DEFINITION(Register, rdispatch);
|
||||
REGISTER_DEFINITION(Register, rcpool);
|
||||
REGISTER_DEFINITION(Register, rmonitors);
|
||||
REGISTER_DEFINITION(Register, rlocals);
|
||||
REGISTER_DEFINITION(Register, rmethod);
|
||||
REGISTER_DEFINITION(Register, rbcp);
|
||||
|
||||
REGISTER_DEFINITION(Register, lr);
|
||||
REGISTER_DEFINITION(Register, rfp);
|
||||
REGISTER_DEFINITION(Register, rthread);
|
||||
REGISTER_DEFINITION(Register, rheapbase);
|
||||
|
||||
REGISTER_DEFINITION(Register, r31_sp);
|
||||
|
||||
// TODO : x86 uses rbp to save SP in method handle code
|
||||
// we may need to do the same with fp
|
||||
// REGISTER_DEFINITION(Register, rbp_mh_SP_save)
|
||||
113
hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp
Normal file
113
hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "code/relocInfo.hpp"
|
||||
#include "nativeInst_aarch64.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
|
||||
|
||||
void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) {
|
||||
if (verify_only)
|
||||
return;
|
||||
|
||||
int bytes;
|
||||
|
||||
switch(type()) {
|
||||
case relocInfo::oop_type:
|
||||
{
|
||||
oop_Relocation *reloc = (oop_Relocation *)this;
|
||||
if (NativeInstruction::is_ldr_literal_at(addr())) {
|
||||
address constptr = (address)code()->oop_addr_at(reloc->oop_index());
|
||||
bytes = MacroAssembler::pd_patch_instruction_size(addr(), constptr);
|
||||
assert(*(address*)constptr == x, "error in oop relocation");
|
||||
} else{
|
||||
bytes = MacroAssembler::patch_oop(addr(), x);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
bytes = MacroAssembler::pd_patch_instruction_size(addr(), x);
|
||||
break;
|
||||
}
|
||||
ICache::invalidate_range(addr(), bytes);
|
||||
}
|
||||
|
||||
address Relocation::pd_call_destination(address orig_addr) {
|
||||
assert(is_call(), "should be a call here");
|
||||
if (is_call()) {
|
||||
address trampoline = nativeCall_at(addr())->get_trampoline();
|
||||
if (trampoline) {
|
||||
return nativeCallTrampolineStub_at(trampoline)->destination();
|
||||
}
|
||||
}
|
||||
if (orig_addr != NULL) {
|
||||
return MacroAssembler::pd_call_destination(orig_addr);
|
||||
}
|
||||
return MacroAssembler::pd_call_destination(addr());
|
||||
}
|
||||
|
||||
|
||||
void Relocation::pd_set_call_destination(address x) {
|
||||
assert(is_call(), "should be a call here");
|
||||
if (NativeCall::is_call_at(addr())) {
|
||||
address trampoline = nativeCall_at(addr())->get_trampoline();
|
||||
if (trampoline) {
|
||||
nativeCall_at(addr())->set_destination_mt_safe(x, /* assert_lock */false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(addr() != x, "call instruction in an infinite loop");
|
||||
MacroAssembler::pd_patch_instruction(addr(), x);
|
||||
assert(pd_call_destination(addr()) == x, "fail in reloc");
|
||||
}
|
||||
|
||||
address* Relocation::pd_address_in_code() {
|
||||
return (address*)(addr() + 8);
|
||||
}
|
||||
|
||||
|
||||
address Relocation::pd_get_address_from_code() {
|
||||
return MacroAssembler::pd_call_destination(addr());
|
||||
}
|
||||
|
||||
void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) {
|
||||
if (NativeInstruction::maybe_cpool_ref(addr())) {
|
||||
address old_addr = old_addr_for(addr(), src, dest);
|
||||
MacroAssembler::pd_patch_instruction(addr(), MacroAssembler::target_addr_for_insn(old_addr));
|
||||
}
|
||||
}
|
||||
|
||||
void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) {
|
||||
if (NativeInstruction::maybe_cpool_ref(addr())) {
|
||||
address old_addr = old_addr_for(addr(), src, dest);
|
||||
MacroAssembler::pd_patch_instruction(addr(), MacroAssembler::target_addr_for_insn(old_addr));
|
||||
}
|
||||
}
|
||||
|
||||
void metadata_Relocation::pd_fix_value(address x) {
|
||||
}
|
||||
38
hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.hpp
Normal file
38
hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.hpp
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_RELOCINFO_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_RELOCINFO_AARCH64_HPP
|
||||
|
||||
// machine-dependent parts of class relocInfo
|
||||
private:
|
||||
enum {
|
||||
// Relocations are byte-aligned.
|
||||
offset_unit = 1,
|
||||
// We don't use format().
|
||||
format_width = 0
|
||||
};
|
||||
|
||||
#endif // CPU_AARCH64_VM_RELOCINFO_AARCH64_HPP
|
||||
42
hotspot/src/cpu/aarch64/vm/runtime_aarch64.cpp
Normal file
42
hotspot/src/cpu/aarch64/vm/runtime_aarch64.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#ifdef COMPILER2
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "code/vmreg.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "opto/runtime.hpp"
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
#include "runtime/vframeArray.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "vmreg_aarch64.inline.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
3063
hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp
Normal file
3063
hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2562
hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp
Normal file
2562
hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp
Normal file
File diff suppressed because it is too large
Load Diff
275
hotspot/src/cpu/aarch64/vm/stubRoutines_aarch64.cpp
Normal file
275
hotspot/src/cpu/aarch64/vm/stubRoutines_aarch64.cpp
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "runtime/deoptimization.hpp"
|
||||
#include "runtime/frame.inline.hpp"
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
|
||||
// Implementation of the platform-specific part of StubRoutines - for
|
||||
// a description of how to extend it, see the stubRoutines.hpp file.
|
||||
|
||||
address StubRoutines::aarch64::_get_previous_fp_entry = NULL;
|
||||
address StubRoutines::aarch64::_get_previous_sp_entry = NULL;
|
||||
|
||||
address StubRoutines::aarch64::_f2i_fixup = NULL;
|
||||
address StubRoutines::aarch64::_f2l_fixup = NULL;
|
||||
address StubRoutines::aarch64::_d2i_fixup = NULL;
|
||||
address StubRoutines::aarch64::_d2l_fixup = NULL;
|
||||
address StubRoutines::aarch64::_float_sign_mask = NULL;
|
||||
address StubRoutines::aarch64::_float_sign_flip = NULL;
|
||||
address StubRoutines::aarch64::_double_sign_mask = NULL;
|
||||
address StubRoutines::aarch64::_double_sign_flip = NULL;
|
||||
|
||||
/**
|
||||
* crc_table[] from jdk/src/share/native/java/util/zip/zlib-1.2.5/crc32.h
|
||||
*/
|
||||
juint StubRoutines::aarch64::_crc_table[]
|
||||
__attribute__ ((aligned(4096))) =
|
||||
{
|
||||
// Table 0
|
||||
0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
|
||||
0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
|
||||
0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
|
||||
0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
|
||||
0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
|
||||
0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
|
||||
0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
|
||||
0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
|
||||
0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
|
||||
0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
|
||||
0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
|
||||
0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
|
||||
0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
|
||||
0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
|
||||
0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
|
||||
0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
|
||||
0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
|
||||
0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
|
||||
0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
|
||||
0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
|
||||
0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
|
||||
0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
|
||||
0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
|
||||
0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
|
||||
0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
|
||||
0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
|
||||
0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
|
||||
0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
|
||||
0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
|
||||
0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
|
||||
0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
|
||||
0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
|
||||
0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
|
||||
0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
|
||||
0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
|
||||
0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
|
||||
0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
|
||||
0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
|
||||
0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
|
||||
0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
|
||||
0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
|
||||
0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
|
||||
0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
|
||||
0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
|
||||
0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
|
||||
0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
|
||||
0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
|
||||
0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
|
||||
0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
|
||||
0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
|
||||
0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
|
||||
0x2d02ef8dUL,
|
||||
|
||||
// Table 1
|
||||
0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
|
||||
0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
|
||||
0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
|
||||
0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
|
||||
0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
|
||||
0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
|
||||
0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
|
||||
0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
|
||||
0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
|
||||
0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
|
||||
0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
|
||||
0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
|
||||
0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
|
||||
0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
|
||||
0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
|
||||
0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
|
||||
0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
|
||||
0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
|
||||
0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
|
||||
0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
|
||||
0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
|
||||
0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
|
||||
0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
|
||||
0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
|
||||
0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
|
||||
0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
|
||||
0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
|
||||
0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
|
||||
0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
|
||||
0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
|
||||
0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
|
||||
0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
|
||||
0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
|
||||
0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
|
||||
0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
|
||||
0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
|
||||
0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
|
||||
0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
|
||||
0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
|
||||
0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
|
||||
0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
|
||||
0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
|
||||
0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
|
||||
0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
|
||||
0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
|
||||
0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
|
||||
0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
|
||||
0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
|
||||
0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
|
||||
0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
|
||||
0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
|
||||
0x9324fd72UL,
|
||||
|
||||
// Table 2
|
||||
0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
|
||||
0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
|
||||
0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
|
||||
0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
|
||||
0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
|
||||
0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
|
||||
0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
|
||||
0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
|
||||
0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
|
||||
0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
|
||||
0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
|
||||
0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
|
||||
0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
|
||||
0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
|
||||
0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
|
||||
0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
|
||||
0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
|
||||
0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
|
||||
0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
|
||||
0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
|
||||
0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
|
||||
0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
|
||||
0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
|
||||
0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
|
||||
0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
|
||||
0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
|
||||
0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
|
||||
0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
|
||||
0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
|
||||
0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
|
||||
0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
|
||||
0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
|
||||
0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
|
||||
0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
|
||||
0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
|
||||
0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
|
||||
0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
|
||||
0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
|
||||
0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
|
||||
0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
|
||||
0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
|
||||
0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
|
||||
0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
|
||||
0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
|
||||
0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
|
||||
0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
|
||||
0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
|
||||
0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
|
||||
0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
|
||||
0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
|
||||
0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
|
||||
0xbe9834edUL,
|
||||
|
||||
// Table 3
|
||||
0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
|
||||
0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
|
||||
0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
|
||||
0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
|
||||
0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
|
||||
0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
|
||||
0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
|
||||
0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
|
||||
0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
|
||||
0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
|
||||
0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
|
||||
0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
|
||||
0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
|
||||
0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
|
||||
0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
|
||||
0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
|
||||
0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
|
||||
0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
|
||||
0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
|
||||
0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
|
||||
0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
|
||||
0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
|
||||
0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
|
||||
0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
|
||||
0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
|
||||
0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
|
||||
0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
|
||||
0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
|
||||
0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
|
||||
0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
|
||||
0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
|
||||
0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
|
||||
0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
|
||||
0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
|
||||
0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
|
||||
0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
|
||||
0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
|
||||
0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
|
||||
0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
|
||||
0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
|
||||
0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
|
||||
0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
|
||||
0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
|
||||
0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
|
||||
0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
|
||||
0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
|
||||
0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
|
||||
0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
|
||||
0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
|
||||
0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
|
||||
0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
|
||||
0xde0506f1UL,
|
||||
// Constants for Neon CRC232 implementation
|
||||
// k3 = 0x78ED02D5 = x^288 mod poly - bit reversed
|
||||
// k4 = 0xED627DAE = x^256 mod poly - bit reversed
|
||||
0x78ED02D5UL, 0xED627DAEUL, // k4:k3
|
||||
0xED78D502UL, 0x62EDAE7DUL, // byte swap
|
||||
0x02D578EDUL, 0x7DAEED62UL, // word swap
|
||||
0xD502ED78UL, 0xAE7D62EDUL, // byte swap of word swap
|
||||
};
|
||||
121
hotspot/src/cpu/aarch64/vm/stubRoutines_aarch64.hpp
Normal file
121
hotspot/src/cpu/aarch64/vm/stubRoutines_aarch64.hpp
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_STUBROUTINES_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_STUBROUTINES_AARCH64_HPP
|
||||
|
||||
// This file holds the platform specific parts of the StubRoutines
|
||||
// definition. See stubRoutines.hpp for a description on how to
|
||||
// extend it.
|
||||
|
||||
// n.b. if we are notifying entry/exit to the simulator then the call
|
||||
// stub does a notify at normal return placing
|
||||
// call_stub_return_address one instruction beyond the notify. the
|
||||
// latter address is sued by the stack unwind code when doign an
|
||||
// exception return.
|
||||
static bool returns_to_call_stub(address return_pc) {
|
||||
return return_pc == _call_stub_return_address + (NotifySimulator ? -4 : 0);
|
||||
}
|
||||
|
||||
enum platform_dependent_constants {
|
||||
code_size1 = 19000, // simply increase if too small (assembler will crash if too small)
|
||||
code_size2 = 22000 // simply increase if too small (assembler will crash if too small)
|
||||
};
|
||||
|
||||
class aarch64 {
|
||||
friend class StubGenerator;
|
||||
|
||||
private:
|
||||
static address _get_previous_fp_entry;
|
||||
static address _get_previous_sp_entry;
|
||||
|
||||
static address _f2i_fixup;
|
||||
static address _f2l_fixup;
|
||||
static address _d2i_fixup;
|
||||
static address _d2l_fixup;
|
||||
|
||||
static address _float_sign_mask;
|
||||
static address _float_sign_flip;
|
||||
static address _double_sign_mask;
|
||||
static address _double_sign_flip;
|
||||
|
||||
public:
|
||||
|
||||
static address get_previous_fp_entry()
|
||||
{
|
||||
return _get_previous_fp_entry;
|
||||
}
|
||||
|
||||
static address get_previous_sp_entry()
|
||||
{
|
||||
return _get_previous_sp_entry;
|
||||
}
|
||||
|
||||
static address f2i_fixup()
|
||||
{
|
||||
return _f2i_fixup;
|
||||
}
|
||||
|
||||
static address f2l_fixup()
|
||||
{
|
||||
return _f2l_fixup;
|
||||
}
|
||||
|
||||
static address d2i_fixup()
|
||||
{
|
||||
return _d2i_fixup;
|
||||
}
|
||||
|
||||
static address d2l_fixup()
|
||||
{
|
||||
return _d2l_fixup;
|
||||
}
|
||||
|
||||
static address float_sign_mask()
|
||||
{
|
||||
return _float_sign_mask;
|
||||
}
|
||||
|
||||
static address float_sign_flip()
|
||||
{
|
||||
return _float_sign_flip;
|
||||
}
|
||||
|
||||
static address double_sign_mask()
|
||||
{
|
||||
return _double_sign_mask;
|
||||
}
|
||||
|
||||
static address double_sign_flip()
|
||||
{
|
||||
return _double_sign_flip;
|
||||
}
|
||||
|
||||
private:
|
||||
static juint _crc_table[];
|
||||
|
||||
};
|
||||
|
||||
#endif // CPU_AARCH64_VM_STUBROUTINES_AARCH64_HPP
|
||||
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_TEMPLATEINTERPRETERGENERATOR_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_TEMPLATEINTERPRETERGENERATOR_AARCH64_HPP
|
||||
|
||||
protected:
|
||||
|
||||
void generate_fixed_frame(bool native_call);
|
||||
|
||||
// address generate_asm_interpreter_entry(bool synchronized);
|
||||
|
||||
#endif // CPU_AARCH64_VM_TEMPLATEINTERPRETERGENERATOR_AARCH64_HPP
|
||||
2078
hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp
Normal file
2078
hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp
Normal file
File diff suppressed because it is too large
Load Diff
39
hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.hpp
Normal file
39
hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_TEMPLATEINTERPRETER_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_TEMPLATEINTERPRETER_AARCH64_HPP
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Size of interpreter code. Increase if too small. Interpreter will
|
||||
// fail with a guarantee ("not enough space for interpreter generation");
|
||||
// if too small.
|
||||
// Run with +PrintInterpreter to get the VM to print out the size.
|
||||
// Max size with JVMTI
|
||||
const static int InterpreterCodeSize = 200 * 1024;
|
||||
|
||||
#endif // CPU_AARCH64_VM_TEMPLATEINTERPRETER_AARCH64_HPP
|
||||
3697
hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp
Normal file
3697
hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp
Normal file
File diff suppressed because it is too large
Load Diff
42
hotspot/src/cpu/aarch64/vm/templateTable_aarch64.hpp
Normal file
42
hotspot/src/cpu/aarch64/vm/templateTable_aarch64.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_TEMPLATETABLE_AARCH64_64_HPP
|
||||
#define CPU_AARCH64_VM_TEMPLATETABLE_AARCH64_64_HPP
|
||||
|
||||
static void prepare_invoke(int byte_no,
|
||||
Register method, // linked method (or i-klass)
|
||||
Register index = noreg, // itable index, MethodType, etc.
|
||||
Register recv = noreg, // if caller wants to see it
|
||||
Register flags = noreg // if caller wants to test it
|
||||
);
|
||||
static void invokevirtual_helper(Register index, Register recv,
|
||||
Register flags);
|
||||
|
||||
// Helpers
|
||||
static void index_check(Register array, Register index);
|
||||
static void index_check_without_pop(Register array, Register index);
|
||||
|
||||
#endif // CPU_AARCH64_VM_TEMPLATETABLE_AARCH64_64_HPP
|
||||
50
hotspot/src/cpu/aarch64/vm/vmStructs_aarch64.hpp
Normal file
50
hotspot/src/cpu/aarch64/vm/vmStructs_aarch64.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_VMSTRUCTS_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_VMSTRUCTS_AARCH64_HPP
|
||||
|
||||
// These are the CPU-specific fields, types and integer
|
||||
// constants required by the Serviceability Agent. This file is
|
||||
// referenced by vmStructs.cpp.
|
||||
|
||||
#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
|
||||
\
|
||||
/******************************/ \
|
||||
/* JavaCallWrapper */ \
|
||||
/******************************/ \
|
||||
/******************************/ \
|
||||
/* JavaFrameAnchor */ \
|
||||
/******************************/ \
|
||||
volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*)
|
||||
|
||||
|
||||
#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
|
||||
|
||||
#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
|
||||
|
||||
#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
|
||||
|
||||
#endif // CPU_AARCH64_VM_VMSTRUCTS_AARCH64_HPP
|
||||
217
hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp
Normal file
217
hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/stubCodeGenerator.hpp"
|
||||
#include "vm_version_aarch64.hpp"
|
||||
#ifdef TARGET_OS_FAMILY_linux
|
||||
# include "os_linux.inline.hpp"
|
||||
#endif
|
||||
|
||||
#ifndef BUILTIN_SIM
|
||||
#include <sys/auxv.h>
|
||||
#include <asm/hwcap.h>
|
||||
#else
|
||||
#define getauxval(hwcap) 0
|
||||
#endif
|
||||
|
||||
#ifndef HWCAP_AES
|
||||
#define HWCAP_AES (1<<3)
|
||||
#endif
|
||||
|
||||
#ifndef HWCAP_SHA1
|
||||
#define HWCAP_SHA1 (1<<5)
|
||||
#endif
|
||||
|
||||
#ifndef HWCAP_SHA2
|
||||
#define HWCAP_SHA2 (1<<6)
|
||||
#endif
|
||||
|
||||
#ifndef HWCAP_CRC32
|
||||
#define HWCAP_CRC32 (1<<7)
|
||||
#endif
|
||||
|
||||
int VM_Version::_cpu;
|
||||
int VM_Version::_model;
|
||||
int VM_Version::_stepping;
|
||||
int VM_Version::_cpuFeatures;
|
||||
const char* VM_Version::_features_str = "";
|
||||
|
||||
static BufferBlob* stub_blob;
|
||||
static const int stub_size = 550;
|
||||
|
||||
extern "C" {
|
||||
typedef void (*getPsrInfo_stub_t)(void*);
|
||||
}
|
||||
static getPsrInfo_stub_t getPsrInfo_stub = NULL;
|
||||
|
||||
|
||||
class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
public:
|
||||
|
||||
VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
|
||||
|
||||
address generate_getPsrInfo() {
|
||||
StubCodeMark mark(this, "VM_Version", "getPsrInfo_stub");
|
||||
# define __ _masm->
|
||||
address start = __ pc();
|
||||
|
||||
#ifdef BUILTIN_SIM
|
||||
__ c_stub_prolog(1, 0, MacroAssembler::ret_type_void);
|
||||
#endif
|
||||
|
||||
// void getPsrInfo(VM_Version::CpuidInfo* cpuid_info);
|
||||
|
||||
address entry = __ pc();
|
||||
|
||||
// TODO : redefine fields in CpuidInfo and generate
|
||||
// code to fill them in
|
||||
|
||||
__ ret(lr);
|
||||
|
||||
# undef __
|
||||
|
||||
return start;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void VM_Version::get_processor_features() {
|
||||
_supports_cx8 = true;
|
||||
_supports_atomic_getset4 = true;
|
||||
_supports_atomic_getadd4 = true;
|
||||
_supports_atomic_getset8 = true;
|
||||
_supports_atomic_getadd8 = true;
|
||||
|
||||
if (FLAG_IS_DEFAULT(AllocatePrefetchDistance))
|
||||
FLAG_SET_DEFAULT(AllocatePrefetchDistance, 256);
|
||||
if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize))
|
||||
FLAG_SET_DEFAULT(AllocatePrefetchStepSize, 64);
|
||||
FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 256);
|
||||
FLAG_SET_DEFAULT(PrefetchFieldsAhead, 256);
|
||||
FLAG_SET_DEFAULT(PrefetchCopyIntervalInBytes, 256);
|
||||
FLAG_SET_DEFAULT(UseSSE42Intrinsics, true);
|
||||
|
||||
unsigned long auxv = getauxval(AT_HWCAP);
|
||||
|
||||
char buf[512];
|
||||
|
||||
strcpy(buf, "simd");
|
||||
if (auxv & HWCAP_CRC32) strcat(buf, ", crc");
|
||||
if (auxv & HWCAP_AES) strcat(buf, ", aes");
|
||||
if (auxv & HWCAP_SHA1) strcat(buf, ", sha1");
|
||||
if (auxv & HWCAP_SHA2) strcat(buf, ", sha256");
|
||||
|
||||
_features_str = strdup(buf);
|
||||
|
||||
if (FLAG_IS_DEFAULT(UseCRC32)) {
|
||||
UseCRC32 = (auxv & HWCAP_CRC32) != 0;
|
||||
}
|
||||
if (UseCRC32 && (auxv & HWCAP_CRC32) == 0) {
|
||||
warning("UseCRC32 specified, but not supported on this CPU");
|
||||
}
|
||||
if (auxv & HWCAP_AES) {
|
||||
UseAES = UseAES || FLAG_IS_DEFAULT(UseAES);
|
||||
UseAESIntrinsics =
|
||||
UseAESIntrinsics || (UseAES && FLAG_IS_DEFAULT(UseAESIntrinsics));
|
||||
if (UseAESIntrinsics && !UseAES) {
|
||||
warning("UseAESIntrinsics enabled, but UseAES not, enabling");
|
||||
UseAES = true;
|
||||
}
|
||||
} else {
|
||||
if (UseAES) {
|
||||
warning("UseAES specified, but not supported on this CPU");
|
||||
}
|
||||
if (UseAESIntrinsics) {
|
||||
warning("UseAESIntrinsics specified, but not supported on this CPU");
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) {
|
||||
UseCRC32Intrinsics = true;
|
||||
}
|
||||
|
||||
if (auxv & (HWCAP_SHA1 | HWCAP_SHA2)) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA)) {
|
||||
FLAG_SET_DEFAULT(UseSHA, true);
|
||||
}
|
||||
} else if (UseSHA) {
|
||||
warning("SHA instructions are not available on this CPU");
|
||||
FLAG_SET_DEFAULT(UseSHA, false);
|
||||
}
|
||||
|
||||
if (!UseSHA) {
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
} else {
|
||||
if (auxv & HWCAP_SHA1) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA1Intrinsics) {
|
||||
warning("SHA1 instruction is not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
|
||||
}
|
||||
if (auxv & HWCAP_SHA2) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA256Intrinsics) {
|
||||
warning("SHA256 instruction (for SHA-224 and SHA-256) is not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
|
||||
}
|
||||
if (UseSHA512Intrinsics) {
|
||||
warning("SHA512 instruction (for SHA-384 and SHA-512) is not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
if (FLAG_IS_DEFAULT(OptoScheduling)) {
|
||||
OptoScheduling = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void VM_Version::initialize() {
|
||||
ResourceMark rm;
|
||||
|
||||
stub_blob = BufferBlob::create("getPsrInfo_stub", stub_size);
|
||||
if (stub_blob == NULL) {
|
||||
vm_exit_during_initialization("Unable to allocate getPsrInfo_stub");
|
||||
}
|
||||
|
||||
CodeBuffer c(stub_blob);
|
||||
VM_Version_StubGenerator g(&c);
|
||||
getPsrInfo_stub = CAST_TO_FN_PTR(getPsrInfo_stub_t,
|
||||
g.generate_getPsrInfo());
|
||||
|
||||
get_processor_features();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user